Bombchu Link's Beginners Guide to NPC hacking

Feb 14, 2014 at 12:42 AM
The TideWalker
Modding Community Discord Founder
"That dog!"
Join Date: Apr 5, 2013
Location: In my mind and of my body.
Posts: 1640
Age: 26
That's right kids, step right up and come and enter the wonderful world of ASM hacking!


Have you ever wanted to modify or create an NPC?

Are you tired of pestering the pros to do it for you?

Did you ever want to make a full fledged ASM boss on your own?

Have you been struggling with or gave up on ASM classes?

Then THIS is the guide for YOU! We will learn about variables, registers, optimization,
problem solving, creating attack patterns, making your ASM do more for less, and even create Cats along the way!


Are you ready?!
Version 2.0



Feel free to ask a question if you're having any trouble understanding anything about anything.

And yes, I did steal CarrotLords style of HTMLing.

also you might need this defines.txt
 
Feb 14, 2014 at 12:42 AM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
p179801-0-nhrfkcm.png

*squints*
 
Feb 14, 2014 at 12:50 AM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
If you want I can give you some so that information's out of date and no longer useful
 
Feb 14, 2014 at 1:56 AM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
- I would recommend running this through a spellchecker or getting a proofreader of which I am not

This stores the pointer to the NPC function table
It would be more accurate to call it a pointer to the NPC object / data because a) there actually is an NPC function table and b) there aren't really any 'functions' in the entity data, just variables.
Now using the pointer, the next line of code adds 54 to the EAX which is the NPC's Left frame renderer.
It would be good to illustrate this point by referencing the entity object variable offsets list, conveniently placed in the spoiler below
+0x00: Event.InUse (N) ; is the event active? 0 kills.
+0x04: Event.Collision (N) ; flag to show what it's colliding w/
+0x08: Event.X (N) ; Position [x]
+0x0C: Event.Y (N) ; Poxition [y]
+0x10: Event.MoveX ; xvel, add to event.x each step
+0x14: Event.MoveY ; yvel
+0x18: Event.AltVel ;
+0x1C: Event.AltVel ;
+0x20: Event.Unknown1 ; For entities such as curly that use
+0x24: Event.Unknown2 ; the targeting macro.
+0x28: Event.NPCID (N) ; sprite #
+0x2C: Event.EntityID (N) ; Entity ID, as seen in CE
+0x30: Event.EventNum (N) ; Event #, as seen in CE
+0x34: Event.Tileset (N) ; The tileset # as seen in a NPC.tbl editor
+0x38: Event.HurtSound (N) ;
+0x3C: Event.DeathSound (N) ;
+0x40: Event.Health (N) ; health/damagetaken
+0x44: Event.EXP (N) ; EXP dropped
+0x48: Event.Size(N) ;
+0x4C: Event.Direction (N) ;
+0x50: Event.Flags (N) ; Entity flags
+0x54: Event.Frame_L (N) ; left side of the frame rect
+0x58: Event.Frame_U (N) ; top side of the frame rect
+0x5C: Event.Frame_R (N) ; right side of the frame rect
+0x60: Event.Frame_D (N) ; bottom side of the frame rect
+0x64: Event.FrameTimer ;
+0x68: Event.FrameNum ;
+0x6C: Event.ObjectTimer ;
+0x70: Event.Directive ; Usually something from the parent.
+0x74: Event.ScriptState ;
+0x78: Event.ScriptTimer ;
+0x7C: Event.HitRect_L (N) ;
+0x80: Event.HitRect_U (N) ;
+0x84: Event.HitRect_R (N) ;
+0x88: Event.HitRect_D (N) ;
+0x8C: Event.Display_L (N) ; Used to calc. how far left/right to offset the sprite when displaying
+0x90: Event.Display_U (N) ; Used to calc. how far up/down to offset the sprite when displaying
+0x94: Event.Display_R (N) ; Sometimes used as the radius of the entity for making smoke appear from it
+0x98: Event.Display_D (N) ; no known use
+0x9c: Event.HitTrue [N] ; Has the entity been Hit?
+0xA0: Event.DamageTaken(N) ; Damage displayed by damage numbers
+0xA4: Event.Damage (N) ; Damage done to Player
+0xA8: Event.Parent [N] ; It's like the ebp+8 of the parent entity.
to reinforce the concept that [ebp+8] just contains a number that refers to the start of one of these "sets" of variables and adding or subtracting from it will change the 'offset' of a particular desired field appropriately

- I would recommend prefixing hexadecimal numbers with '0x' in prose to make sure people are aware that you're talking about a different base

- Oh, I see you cover that on page 3. I dunno, I think that is definitely something that should be worked into the previous thing. It's good to know where you're working from before you dive ahead toooo much.

it's called the NPC command table (not an official term)
This seems inconsistent with what you referred to it as earlier, and that's still not a very good name imo. Although it's a bit better than calling them functions.
Also, specifically using ECX always for them might confuse people into thinking that you /have/ to, and although that was generally my personal convention for writing NPC code it's not mandatory.

- Touch on how the entries in the defines.txt file relate to the values that I gave in the table above to hopefully make some connections between things they've seen and things they are going to use

- I would copy-paste it

- Technically varying the register used for those operations is part of a compiler optimization technique but that's a thousand light-years ahead of anything I want to explain so I'll just leave it at that. I wouldn't call it ineffective though. It's not a bad idea to mention using ECX as the pointer register as a coding convention though.

- I'm pretty sure setting inUse to 0 ignores run on death script? Setting health to 0 should trigger that event I'm p sure. but inUse=0 will always mean the object is inactive.

- Maybe specify that npcID is only used in selecting which function gets run every frame as the NPC's AI, changing it won't affect any other property of the entity.

- Deathgraphic is actually size now and changing it will affect the amount of tiles that the engine checks when doing map collisions, so if you have a large NPC it's important that is set correctly.

Checks to see if the entity is hit. (uses a single byte of data (1 or 0))
A byte of data is 0-255 or -128 to 127. Also I do believe that is actually an internal timer of sorts so it won't necessarily be just 1 or 0.

You need to add damage taken to NPC.health, to get anywhere though.
this is done automatically?? I'm not sure what you are trying to say here

- I feel like the scriptstates lesson (particularly the bit involving switch cases) assumes a bit too much prior knowledge about how the assembler works. I know you told them to study it but when writing guides it's a good idea to always assume that the reader is actively trying to be as incompetent as possible. Repetition is key. Discuss how the labels work, and how each one represents the address of a particular instruction in your code. Print writes that instruction as a 4-byte value which is why we multiply eax by 4 when computing the states.

then render the left border
* store
remember, unless you're calling 40C3C0 yourself you aren't technically arbitrating the rendering yourself, you're just telling the game how it should be done at a later point in time.



ok that's all I got for now.
 
Oct 31, 2014 at 3:44 AM
The TideWalker
Modding Community Discord Founder
"That dog!"
Join Date: Apr 5, 2013
Location: In my mind and of my body.
Posts: 1640
Age: 26
Noxid said:
-A lot of good stuff-
- I would recommend running this through a spellchecker or getting a proofreader of which I am not
I went through it once manually, I'll do it again and/or run it through a spellchecker then.

It would be more accurate to call it a pointer to the NPC object / data because a) there actually is an NPC function table and b) there aren't really any 'functions' in the entity data, just variables.
It would be good to illustrate this point by referencing the entity object variable offsets list
Alright, I will fix that.

(please bear with me that I just picked up pieces and am pretty much self taught. )

-to reinforce the concept that [ebp+8] just contains a number that refers to the start of one of these "sets" of variables and adding or subtracting from it will change the 'offset' of a particular desired field appropriately
Read above.

- I would recommend prefixing hexadecimal numbers with '0x' in prose to make sure people are aware that you're talking about a different base
Will do.

- Oh, I see you cover that on page 3. I dunno, I think that is definitely something that should be worked into the previous thing. It's good to know where you're working from before you dive ahead toooo much.
yes, I did notice that, but it's just hard to tell someone about one little thing without having the whole guide pulled into one lesson.

I *think* it's excusable because it's in the next lesson.

This seems inconsistent with what you referred to it as earlier, and that's still not a very good name imo. Although it's a bit better than calling them functions.
Also, specifically using ECX always for them might confuse people into thinking that you /have/ to, and although that was generally my personal convention for writing NPC code it's not mandatory.
I'm just now realising how high my words would be held when a n00b stumbles across this.

I'll make sure to mention it, but I also say that if it ain't broke, don't fix it.


- Touch on how the entries in the defines.txt file relate to the values that I gave in the table above to hopefully make some connections between things they've seen and things they are going to use
I'll do that.

- I would copy-paste it
It was a picture, but I realized a fatal error in the code and didn't retake it and just put the text up there.

- Technically varying the register used for those operations is part of a compiler optimization technique but that's a thousand light-years ahead of anything I want to explain so I'll just leave it at that. I wouldn't call it ineffective though. It's not a bad idea to mention using ECX as the pointer register as a coding convention though.
alright then.

- I'm pretty sure setting inUse to 0 ignores run on death script? Setting health to 0 should trigger that event I'm p sure. but inUse=0 will always mean the object is inactive.
I haven't done any testing with it myself so I can't confirm it. I was assuming that it was the same as bullet.inuse

- Maybe specify that npcID is only used in selecting which function gets run every frame as the NPC's AI, changing it won't affect any other property of the entity.
Yeah, I should do that.

A byte of data is 0-255 or -128 to 127. Also I do believe that is actually an internal timer of sorts so it won't necessarily be just 1 or 0.
I was looking for the word bit then (or was I)

I'm not very antiquated with those

this is done automatically?? I'm not sure what you are trying to say here
I'm saying that the game doesn't automatically subtract/add/move stuff for you and everything has to be done manually.
- Deathgraphic is actually size now and changing it will affect the amount of tiles that the engine checks when doing map collisions, so if you have a large NPC it's important that is set correctly.
Hmm, you'll have to explain this in greater detail to me on how it works.

- I feel like the scriptstates lesson (particularly the bit involving switch cases) assumes a bit too much prior knowledge about how the assembler works. I know you told them to study it but when writing guides it's a good idea to always assume that the reader is actively trying to be as incompetent as possible. Repetition is key. Discuss how the labels work, and how each one represents the address of a particular instruction in your code. Print writes that instruction as a 4-byte value which is why we multiply eax by 4 when computing the states.
Hmm, I think the label thing isn't *that* much of an issue, but I will go over the Print instruction for sure.


* store
remember, unless you're calling 40C3C0 yourself you aren't technically arbitrating the rendering yourself, you're just telling the game how it should be done at a later point in time.
OK, I'll fix that, I've just learned myself from picking up bits and pieces after all.

it's a good idea to always assume that the reader is actively trying to be as incompetent as possible.
I understand your point, but I don't think I have to stoop to low. I mean, it requires that you already understand a decent amount from Carrot's guide so I was expecting at least medium intelligent level.



ok that's all I got for now.


Thank you for all the feedback!

It's (not) dead Jim.

https://www.dropbox.com/s/xaad3u9rt4bc85u/Bombchu%20Link%27s%20Guide%20to%20NPC%20hacking%202.0.zip


I finally decided to finish this thing.

The optimizing your code lesson, and the Troubleshooting code lesson's aren't very...detailed because well, I can't remember the common errors I experienced, and all I know for optimization is xor eax, eax is the same as mov eax, 0.

Have fun
 
Top