Jump to content

Weapons Research in Tiberian Dawn


peterthepigeon

Recommended Posts

A repost of what I posted on dune2k forum.  From start to finish?  Maybe 4 hours of on and off work to put it all together.  Nyerguds weapons.ini had the indices which made testing easier.

 

So let's get to work.  Where is the weapons' data stored?

 

You can find it in the .data section of c&c, specifically in C&C95, at address 0x5034D8.

 

0044114A  |. 8A84C1 D834500>MOV AL,BYTE PTR DS:[ECX+EAX*8+5034D8]

 

To walk the entries, it's important to remember there are a total of 24(?) weapons.

 

#define MAX_WEAPONS 24

typedef struct
{
BYTE m_bProjectile;
BYTE m_bDamage;
BYTE m_bRateOfFire;
DWORD m_dwRange; // BYTE m_bRange * 0x100, bRange = m_bRange >> 8;
BYTE m_bReportSound;

}Weapon_t;
Weapon_t* pWeaponBase = ( Weapon_t* )0x5034D8;

for ( iCounter = 0; iCounter < MAX_WEAPONS; iCounter++ )
{
SetupWeapon ( &pWeaponBase [ iCounter ], iCounter );
}

 

Keep in mind that Rate of Fire has 3 added to it by the game.  To truly have it set to 0 you either:

 

C&C95 location: 004B1766

 

004B1766  |. 83C0 03           ADD EAX,3

 

1)  Byte patch

1a) Byte patch immediate to 0

 

2) Set Rate of Fire to FD to cause overflow.  This works because game only uses bytes for weapon data as documented above.

 

Link to comment
Share on other sites

Continuing on, there are a max of 18 projectiles.

 

004B62FD  |. 8B1495 BC295000     MOV EDX,DWORD PTR DS:[EDX*4+5029BC]

 

5029BC is the projectile base.

 

Projectile 00 - 50cal

Projectile 01 - 50cal

Projectile 02 - 120mm

Projectile 03 - 120mm

Projectile 04 - DRAGON

Projectile 05 - DRAGON

Projectile 06 - MISSILE

Projectile 07 - DRAGON

Projectile 08 - FLAME

Projectile 09 - FLAME

Projectile 10 - BOMBLET

Projectile 11 - BOMB

Projectile 12 - Laser

Projectile 13 - ATOMICUP

Projectile 14 - ATOMICDN

Projectile 15 - MISSILE

Projectile 16 - 50cal

Projectile 17 - GORE

Projectile 18 - CHEW

Link to comment
Share on other sites

The struct for weapons is not exactly correct. Those m_bUnknown/m_bRange/m_bUnknown2/m_bUnknown3 bytes are actually simply one dword containing one value, which is the weapon range * 100h.

 

Note that the Bullet types (projectiles) aren't really identifiable by those names, since those are just the ptrs to the filename strings of the SHP graphics they use. They can't really be uniquely identified by anything except ID, unless they're given new names. I've got a list of those, with better names, in my bullets.ini, by the way.

Link to comment
Share on other sites

The struct for weapons is not exactly correct. Those m_bUnknown/m_bRange/m_bUnknown2/m_bUnknown3 bytes are actually simply one dword containing one value, which is the weapon range * 100h.

 

Note that the Bullet types (projectiles) aren't really identifiable by those names, since those are just the ptrs to the filename strings of the SHP graphics they use. They can't really be uniquely identified by anything except ID, unless they're given new names. I've got a list of those, with better names, in my bullets.ini, by the way.

 

I reversed the struct that way because I felt it would make things clearer.  The bitshifting done by the game to obtain data is a bit odd.

 

As far as the naming convention goes, I find it odd that WW didn't think to more descriptively name their files.  Also the range is just a BYTE which is bitshifted out of the DWORD.

Link to comment
Share on other sites

Uhh, I don't think they use any bit shifting for that value...

 

the function at 0x004B1F78 is the weapons range getter.

 

With the struct properly configured, it gives this code:

 

 

004B1FA5  mov     eax, array_weapons.Range_x100h[ebx+eax*8]

004B1FC0  mov     eax, array_weapons.Range_x100h[ebx+eax*8]

(with the *8 being there because that's the length of the struct)

Link to comment
Share on other sites

Uhh, I don't think they use any bit shifting for that value...

 

the function at 0x004B1F78 is the weapons range getter.

 

With the struct properly configured, it gives this code:

 

 

004B1FA5  mov     eax, array_weapons.Range_x100h[ebx+eax*8]

004B1FC0  mov     eax, array_weapons.Range_x100h[ebx+eax*8]

(with the *8 being there because that's the length of the struct)

 

004B0E52  |. 89C2                  MOV EDX,EAX
004B0E54  |. C1FA 1F               SAR EDX,1F
004B0E57  |. C1E2 08               SHL EDX,8
004B0E5A  |. 1BC2                  SBB EAX,EDX
004B0E5C  |. C1F8 08               SAR EAX,8

 

SAR EAX, 8

Link to comment
Share on other sites

I'm... not exactly sure where this fits in with the range calling code, since I can't trace the "call dword ptr [ebx+168h]" stuff without debugging.... but that seems to be related to the fact that the stored value is the range x100h :P

 

They probably need to shift it down at some point to do by-cell range calculations, or something.

Link to comment
Share on other sites

I'm... not exactly sure where this fits in with the range calling code, since I can't trace the "call dword ptr [ebx+168h]" stuff without debugging.... but that seems to be related to the fact that the stored value is the range x100h :P

 

They probably need to shift it down at some point to do by-cell range calculations, or something.

 

Right on the money.  Now do you see why I did it as BYTE?  I think at any rate, now that I think about it.  Maybe they wanted to use bitshifting to pack data in the struct?

Link to comment
Share on other sites

It's clearly stored as dword in the struct though. There's no need to treat it as anything else when it's clearly retrieved as dword, and the data in the structs clearly shows that it's indeed just the range accurate to two figures after the hexadecimal point, and, to store that as pure int, simply multiplied by 100h.

 

The only thing that really matters in a struct is how data is stored and retrieved. What exactly that data is irrelevant; only the grouping really counts. Well, unless they're bit flags or something, in which case you could define them as boolean bits in a theoretical struct (though not in a real implementation), but that's not the case here at all.

 

Well, anyway, I'm not going to argue with you about what appears to be a "style choice"  :P

Link to comment
Share on other sites

My point is mainly just that these things are not "unknown". Especially not the first unknown, which is the fraction of the range.

 

I've reversed games where they've done similar things to this, but the data was packed in HIWORD and LOWORD, or they would pack the data as DWORD and shift it out.  I've amended it, but at the end of the day we can both say that it's stored as a DWORD but used as a BYTE. 

Link to comment
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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...