NPCs

Jul 6, 2006 at 10:22 PM
The Bartender
"All your forum are belong to us!"
Join Date: Jun 18, 2006
Location: Montreal, Canada
Posts: 581
Age: 39
I've been toying around with NPCs lately and wanted to change the Mannan into a cannon of sorts. This would mean flipping its rect 90'. The NPC.tbl file, as has already been covered, doesn't permit this. I figured there may've been another table in the exe that handles this. After some poking around and hunting down pointers, I figured out how the game handles everything NPC-related.

Just like weapons, they're all handled through code. Sorry - NPC.tbl seems to be the most that a hex editor and no assembly knowhow will get you. Even the rendering bit is coded via assembly. For instance, the Mannan's frames are all RECTs MOVed into the stack byte by byte. Its code starts at 0x0002CCB0.

Once I finish my hack and begin releasing my info, I'll attempt to compile a list of each NPCs' relevant values when directly editable. As with weapons, there are a number of calculated values (particularly when an enemy can face multiple directions while being animated.) So no assembly knowhow can only get someone so far...

The pointer table SEEMS to start at 0x00098540. If you want to duplicate an enemy in the NPC.tbl file, you will have to duplicate its pointer (4 bytes each.) It should work, but I never tried it out.

diph.php


Edit: Found some stuff out about how it makes an NPC spawn other NPCs (for instance, the Mannan firing out its projectile). First it pushes a large number of parameters on the stack (code simplified to save some space...)

push 0x0100 ; ?
push 0x00 ; ?
push [[ebp + 08] + 4c] ; ?
push 0x00 ; ?
push 0x00 ; ?
push XPOSITION
push YPOSITION
push NPC_ID

Then it makes a call to 0x0046efd0.

I saw that in the Heavy Press code when doing some research for caveoholic; it did the same with the butes. I'm still not clear on some parameters though. I suspect the 3rd one is the direction...

There's a function table for Mannan at 0x0002cffd. Screwing with it was a fun experience...

diph.php


It won't stop exploding and showering me with items!! :o

Edit: Little correction. That's 0x00098548, not 0x00098540.
 
Jul 7, 2006 at 10:25 AM
The Bartender
"All your forum are belong to us!"
Join Date: Jun 18, 2006
Location: Montreal, Canada
Posts: 581
Age: 39
I modified the Mannan to constantly fire every couple of moments. This was necessary because I changed them into cannons - it would be kinda stupid to have them fire only when hit.

Get ready for some assembly...

0x03B7B0 Change this value from 0x64 to 0x38. This is a simple value tested against to determine if the projectile should be killed. I'm reducing it to make it so the shots don't cover the screen, since they get fired kinda often now.

The Event structure contains a timer which can be used to flip through states over time. I decided I'd use this and call the "Mannan is shot!" event every 0x30 units instead of just when the player actually shoots it.

First I grab the timer and increment it, and check if it's time to fire a round.

Code:
002cd80 8B 45 08		mov eax,[ebp+08]
002cd83 0F B6 48 78		movzx ecx,byte ptr [eax+78]
002cd87 41			inc ecx
002cd88 83 F9 30		cmp ecx,30
002cd8b 75 43			jne 0042cdd0

Now I fill up the "create event" structure in order to make the call...

Code:
002cd8d C6 40 78 00		mov byte ptr [eax+78],00
002cd91 68 00 01 00 00		push 0100
002cd96 6a 00			push 00
002cd98 8B 55 08		mov edx,[ebp+08]
002cd9b 8B 4A 4C		mov ecx,[edx+4c]
002cd9e 51			push ecx
002cd9f 6A 00			push 00
002cda1 6A 00			push 00
002cda3 8B 42 0C		mov eax,[edx+0c]
002cda6 05 00 18 00 00		add eax,00001800
002cdab 50			push eax

Wait now, we have two possible directions to face... I'm going to make the calculations for the shot depend on the direction, otherwise they'll just go in one direction at all times.

Code:
002cdac 83 7A 4C 00		cmp dword ptr [edx+4c],00
002cdb0 75 0B			jne 0042cdbd
002cdb2 8B 4A 08		mov ecx,[edx+08]
002cdb5 81 E9 00 20 00 00	sub ecx,00002000
002cdbb EB 09			jmp 0042cdc6
002cdbd 8B 4A 08		mov ecx,[edx+08]
002cdc0 81 C1 00 40 00 00	add ecx,00004000

Now I complete the structure and make the call.

Code:
002cdc6 51			push ecx
002cdc7 6A 67			push 67
002cdc9 E8 02 22 04 00		call 0046efd0
002cdce EB 34			jmp 0042ce04

Finally, in the event that the time wasn't reset, I'm storing the updated value back.

Code:
002cdd0 89 48 78		mov byte ptr [eax+78], ecx
002cdd3 EB 50			jmp 0042CE25

Huzzah! Simple as pie! It just doesn't get any easier than this. Enjoy the first ever modified NPC script.

Given the pointer table mentionned earlier and this example code, a skilled hacker shouldn't have any problems messing around and creating 100% new enemies like this one (new sprite, new set of flags and stats, different size, different script...) Now if any of youse start bitching that I keep too much info to myself, what more could you want? A step by step guide to assembly for people who've never programmed at all so that everyone could understand? What am I, a miracle-worker? :o

These guys are majorly deadly in my hack now, especially considering some enemies on that map are invulnerable and that there are tight jumps... most of them guarded by a live cannon!!
 
Jul 9, 2006 at 8:30 PM
The Bartender
"All your forum are belong to us!"
Join Date: Jun 18, 2006
Location: Montreal, Canada
Posts: 581
Age: 39
I started work on a guide mentioning which states an entity can be in (for use with script commands - I'm leaving out internal states and such) as well as the bounding rectangles used to identify which frames an enemy has. This won't be released until after I complete my hack (not like I could before anyhow, 361 entities means a lot of typing!!) but given the amount of work it involves I figured I'd get started right away.

So I was extracting the pointer table from the ROM. The code states explicitely that there are 361 entities - no more, no less. It's a hardcoded constant in the code itself. So I was a little surprised when I turned up having not 361 pointers, but 371. Huh. It didn't take very long to realize these pointers were WAY off from the others so I figured they were for something else. But what?

The first points to nothing. Ie, it's an empty entity 100%. But the rest point to huge chunks of code. I briefly had a look through them and noticed they also include bounding rects to identify animation frames. My first thought was, "Oh hey, these are probably bullets from the weapons!" Then I remember that, nope, that's not the case at all - I already have this info elsewhere and, hell, that's a LOT of code for a simple bullet... And it hit me - the most logical possibility would be, boss code.

I'll add this to the little guide I'm building. If anyone wants to poke around at it, they're the last 10 pointers after the enemy AI pointers (easily identifiable - the rest of the data is a series of 0x00s which, obviously, can't point to valid code...)

This also means, as was most likely suspected, that bosses are 100% seperate from regular entities code-wise. Which explains why adding them to a map requires extra work.

I'm totally creating custom bosses for my hack. :o
 
Jul 10, 2006 at 4:46 AM
Slacker
"Big Joe Tire and Battery Restaurant! Opening Soon! Eat at Big Joes!"
Join Date: Apr 10, 2006
Location: Mississippi
Posts: 544
Age: 35
Ooo..custom bosses sound fun. Very fun indeed.
 
Top