News:

Don't forget to visit the main site! There's lots of helpful docs, patches, and more!

Main Menu

[SM] [ENEMY] AI format

Started by Vener, January 18, 2012, 10:32:29 AM

Previous topic - Next topic

Vener

I observe in the site that since some month , people are more and more interested by the way to create customised ennemies .
And people more and more work to disassemble ennemies's AI .
I already found very great docs here , like scyser's ennemie animations format , or disassembly of bank $B2 by crashtour , etc ...

But , something still tease me about the Initiation AI and the Running AI format . 
In the first place , someone can CLEARLY explain what is the difference between Initiation and running ? The animation pointers are stored in which of those two ?

And anyway , secondly , you see , i ask you if there is a certain order (way) to store instructions and pointers in both AI . Let's take the exemple of room headers/ennemies headers/FX headers : in those cases , there is always a certain amount of bytes , and each of those are always stored at the same place . These orders are invariable .

Then , i wonder if the running or/and initiation start always with the same bytes Process , OR , if instructions , animations pointers , etc .. are stored with no special rules , depending on what the ennemie have to do . 

I would like that someone explain those two formats here , and why not with an exemle of simple AI , disassembled and commented .

And in the case of an ennemie have zero functions , just animated and considered like normal solid blocs (for exemple , i think to change the elevator PLM to an ennemie) , BUT stored in bank $E0 , what's the code should be ? 

I thank you all for your help  :razz:

P.JBoy

Take a read through this.

The different between initiation AI and running AI is that the initiation AI is only run once - when the enemy's spawned - whereas the running AI is run every following frame the enemy still exists

Vener

Okey .
The "initiation" is animation pointers , and the "running" read the initiation in buckle , and add delays between movements , subpixel deplacements , etc ... 

Then , in an abstracted way, we can ~ say :

Initiation = ROM = invariable
Running = RAM = variable     ?

Also , in your exemple :

Waver ROM entry

0006 8786 1E00 0A00 0800 0800 A3   00     4700 0000 ED86 01000000 4C87 0A80 4C80 4180 0000 0000 00000000 0000 000000000000 2380 2D80 000000 86AE 05 00F2 1CEC 87E1
tile pal  hp   dmg  wide high Bank # of   hurt Boss AI            Norm Grap Hurt Froz XRay die           PB                Tch. Beam        tile  | |    |    |
get  ptr                      Ptr  "hurt" snd. num  Init          Move AI   AI   AI   or   anim          Flag              Pntr Pntr        set   | |    |    name pointer
lgth                               frames           Run           AI?                 Rsrv                                                        | |    pointer to enemy resistances
???                                                 Once                              AI                                                          | pointer to enemy drop chances
                                                                                                                                                  background/foreground

AI Initialization (A3:86ED)
LDX $0E54    ;Enemy Index
LDA #$0180
AND #$FF00
XBA
STA $0FAA, X ;Custom use. Horizontal Speed, pixel
LDA #$0180
AND #$00FF
XBA
STA $0FA8, X ;Custom use. Horizontal Speed, subpixel
LDA $0FB4, X ;Speed
AND #$0001

BNE BRANCH_ALPHA

LDA #$0180   ;This stuff swaps the orientation (go left instead of right)
EOR #$FFFF
INC A
AND #$FF00
XBA
JSL $A0AFEA  ;  If A has bit 7 set, A = A OR #$FF00
STA $0FAA, X ; $0FAA,X = FFFE
LDA #$0180
EOR #$FFFF
INC A
AND #$00FF
XBA
JSL $A0AFEA  ;  If A has bit 7 set(which it doesn't), A = A OR #$FF00
STA $0FA8, X ; $0FA8,X = 8000

BRANCH_ALPHA

STZ $0FB2, X ;Custom use, orientation
STZ $0FAC, X ;Custom use, previous orientation
STZ $0FB0, X ;Custom use, orientation clear trigger
LDA #$86A7
STA $0F92, X ;Pointer to current Enemy Instruction
LDA $0FB4, X ;Speed
AND #$0001
STA $0FB2, X ;Custom use, orientation
JSR $87FE  ;  $1187FE IN ROM
RTL

A3:87FE
LDX $0E54    ;Enemy Index. redundant
LDA $0FB2, X ;Custom use, orientation
CMP $0FAC, X ;Custom use, previous orientation

BEQ BRANCH_ALPHA

STA $0FAC, X ;00 - 03
ASL A
TAY
LDA $86DB, Y ;0 = 86A7, 2 = 86AD, 4 = 86B3, 6 = 86C7
STA $0F92, X ;Pointer to current Enemy Instruction
LDA #$0001
STA $0F94, X ;Enemy Instruction Delay
STZ $0F90, X ;Unknown. Variable?

BRANCH_ALPHA

RTS

A3:874C (Normal Move AI)
LDX $0E54    ;Enemy index
LDA $0FA8, X ;Custom, horizontal speed in subpixels
STA $12
LDA $0FAA, X ;Custom, horizontal speed in pixels
STA $14
JSL $A0C6AB  ;Common (but not universal) horizontal movement for enemies. TODO

BCC BRANCH_ALPHA ;If SEC, you hit a wall. Switch directions

LDA $0FA9, X ;Speed
STA $12
EOR #$FFFF
INC A
AND #$FF00
XBA
JSL $A0AFEA  ;  $102FEA IN ROM
STA $0FAA, X ;Horizontal Speed, pixels
LDA $12
EOR #$FFFF
INC A
AND #$00FF
XBA
JSL $A0AFEA  ;  $102FEA IN ROM
STA $0FA8, X ;Horizontal Speed, subpixels
LDA $0FB2, X ;Orientation
EOR #$0001
AND #$0001
STA $0FB2, X ;Orientation
JSR $87FE  ;  $1187FE IN ROM
JMP $87CF  ;  $1187CF IN ROM

BRANCH_ALPHA

LDA #$0004
STA $0E32
LDA $0FAE, X ;Custom use, vertical speed in pixels?
AND #$00FF
JSL $A0B0C6  ;  Sine function!
STA $14
STZ $12
JSL $A0C786  ;Common (but not universal) vertical movement for enemies. TODO

BCC BRANCH_BETA
             ;Bounce off roof/floor
LDX $0E54
LDA $0FAE, X
CLC
ADC #$0080
AND #$00FF
STA $0FAE, X

BRA BRANCH_GAMMA

BRANCH_BETA
             ;Accelerate
LDX $0E54
LDA $0FAE, X
CLC
ADC #$0002
STA $0FAE, X

$1187CF ALTERNATE ENTRY POINT
BRANCH_GAMMA

LDX $0E54
LDA $0FAE, X
AND #$007F
CMP #$0038

BNE BRANCH_DELTA

LDA $0FB2, X ;Orientation
ORA #$0002
STA $0FB2, X
JSR $87FE  ;  $1187FE IN ROM

BRANCH_DELTA

LDA $0FB0, X

BEQ BRANCH_EPSILON

STZ $0FB0, X
LDA $0FB2, X
AND #$0001
STA $0FB2, X
JSR $87FE  ;  $1187FE IN ROM

BRANCH_EPSILON

RTL


Enemy Instructions
A3:86A7
01 00 4A 88 2F 81
A3:86AD
01 00 B3 88 2F 81
A3:86B3
08 00 5B 88 08 00 71 88 08 00 1E 88 08 00 34 88 E3 86 2F 81
A3:86C7
08 00 C4 88 08 00 DA 88 08 00 87 88 08 00 9D 88 E3 86 2F 81

812F: Store this instruction to 0F92 and RTL to A0:C2AF ? I assume that's the equivalent of PLMs' PLA, RTS, and this is the equivalent of 86B4.
86E3: Store 1 to 0FB0,X. Huh.


i see

LDX $0E54    ;Enemy Index

What is Enemy index ? it's used for what exactly ? How to figurate it ?

I know only the index for the ennemies placed in a room (first is 00 , second 01 , etc ..) , but there is no reports , i know lol ..


P.JBoy

There is RAM available for 32 enemies; the game goes through each slot to process the enemy in the order they were loaded into the RAM; while processing the enemy, its slot is held in $7E0E54.  The enemy can be put into any slot when it's spawned, so to make sure it's using the correct RAM, every access of an enemy's RAM is indexed by $7E0E54

Vener

#4
 Ahh okey  :grin: , actualy it's the same thing for the PLMs ; $32 (50) is the maximal amount possible of subroutines loaded Simultaneously .

it's like a special ennemie done by Sadyztik for me .
The initiation is :


LDX $0E54
LDA $0FB4,X
BIT #$8000 : BNE SetupKagoWall
JSL $808233
LDX $0E54
BCC SetupKagoWall
STZ $0F78,X
SetupKagoWall:
LDA #Tilemap : STA $0F92,X
LDA $0FB6,X : AND #$0FFF : STA $0FA8,X


Then , index is the first step in the "initiation" , and start always with an LDX at $7E0E54 .

P.JBoy

Almost every enemy uses it; the exception is the bosses.  I'm also gonna nitpick: 0x32 = 50

Vener

#6
 ______________________________

Vener

What the running AI should be for an ennemie if it is used only like a extra GFX for the scenery ?
It means an ennemie with no movements (but not necessarily without animation), nothing . Just something considered as normal solide blocks . Exemple : Elevator PLM -> Elevator ennemie .   


Crashtour99

If it's not doing anything other than cycling through an animation, just have your Running AI be RTL (68 in hex).  Since the enemy doesn't have to do anything, you really don't have to have any code running either.  Whether it's solid or not depends on your Touch AI, just like it's shot reaction and the Shot AI.

Vener

#9
Ah okey . I already seen this RTL in some ennemies codes , but i wasn't sure . It's easier than what i thought !  :yay:

But there is still something's wrong .. If i make this , anyway , i am going to meet this problem :

Already since a long time , i noticed this enemie glich , but now i wish to fix it .
It appear in the shutters and in the two chozos (and probably in much more others); when you walk horizontally around those ennemies , everything is normal , but vertically (when you fall or jump near them), you will see that those enemies will be removed if they will be out of the screen , they disappears and will be repeated a bit screwed up in each vertical screens . How it can be fixed ? 

Crashtour99

Hmmm...  No idea what could cause a glitch like that.  The only thing that I can think of is maybe use the Koma enemy as a prototype, since it is mostly the same as what you described.

Vener

Ok . good idea  :^_^: Black Falcon disassembled it and shared it on his website . I am going to check what the hell with this .
By hoping that it's not a story of ennemie tilemap size :S

Scyzer

QuoteIf it's not doing anything other than cycling through an animation, just have your Running AI be RTL (68 in hex).  Since the enemy doesn't have to do anything, you really don't have to have any code running either.  Whether it's solid or not depends on your Touch AI, just like it's shot reaction and the Shot AI.

RTL is 6B in hex.
Whether an enemy is solid depends on a bit in $0F86,X (Special) - Just click "Platform". The touch AI only tells the game what happens when Samus touches it, not whether to let her through it.

An enemy will not be drawn if it is offscreen unless "Move Offscreen" is checked. An enemy is considered offscreen if the center/middle of the enemy hitbox is out of view. The game does no check tilemaps, so even if some of the enemy is still visible, as soon as the center goes offscreen, the whole enemy ceases to run and animate.

Crashtour99

QuoteRTL is 6B in hex.
Doh, had a brain fart there.  haha
QuoteWhether an enemy is solid depends on a bit in $0F86,X (Special) - Just click "Platform". The touch AI only tells the game what happens when Samus touches it, not whether to let her through it.
I don't know how I forgot about that.  It was even right there in the Enemy-Mem.txt documentation...

Note to self, don't post when excessively tired.

Vener

So Scyzer ,
QuoteThe game does no check tilemaps, so even if some of the enemy is still visible, as soon as the center goes offscreen, the whole enemy ceases to run and animate.
I have this problem also for an ennemie that you have made for me :S
It's impossible to fix it ?
If "move offscreen" is selected or not (i tested), this "bug" happens . I noticed it in 3 ennemies , the chozo statue , the shutters , and the custom other. You can test by yourself . They could be safely used only in horizontal rooms with no screens upside (like in the game), but in vertical or free scroll rooms , those are screwed up . those 3 are a platforme type , but there is in the game , other ennemies considered as "platforme" , and with a hitbox size bigger than 1 tile , and even vertically , there is no bugs ... 

A_red_monk_called_Key

#15
not imposable samus' ship somehow stays drawn in off screen. i too would like to know how this is done.