Jump to content

Introduction to modding/hacking


peterthepigeon

Recommended Posts

Can you figure out what's wrong with the existing Overrun (TiberiumOverrun in 1.06 I think) option that makes it prevent all tiberium spawning? Should be fairly easy to trace from te ini key :P

 

Just check the map logic.

 

005D1230    800D A3E45300 04                 OR BYTE PTR DS:[53E4A3],04

 

No tiberium on maps and won't spawn, which is cute and interesting at the same time.

 

CPU Disasm
Address   Hex dump                 Command                                  Comments
0048F42B  |> \F605 A3E45300 04     TEST BYTE PTR DS:[53E4A3],04

 

sorta ontopic

 

I think we'll cover the bail count next and why it's clamped to 28 and how to increase it so you too can be hood rich and thus acquire street cred like Kane did when he made Tiberium based bling.

 

Link to comment
Share on other sites

  • Replies 63
  • Created
  • Last Reply

Top Posters In This Topic

No, no, you misunderstand... just tracing that bit switch is peanuts. The problem with the Overrun option is that it's not supposed to stop all tiberium spawning. According to the strings file text for the hidden ingame options screen containing the option, it's supposed to make tiberium grow and spawn faster. Since you looked into the growing logic, I just wondered if you could see what they messed up in that code.

Link to comment
Share on other sites

For the record, the Overrun option just stops tiberium from spawning and has nothing to do with growth and speed aside from spawning new tiberium.  Why it's called overrun and not StopTiberiumSpread, beyond me.

 

Ok so.  In order to speed up the growth rate of tiberium we need the location of the growth(MapClass::RunLogic) function.

 

It's located at:

 

0x004689F8

 

Now the important pieces relating to tiberium growth are as follows:

 

CPU Disasm
Address   Hex dump                  Command                                  Comments
00468A1D  |.  BA 1E000000           MOV EDX,1E

 

This controls how many cells we iterate through.  So 30 cells.  Let's patch that to 256.

 

Now it should look like:

 

CPU Disasm
Address   Hex dump                  Command                                  Comments
00468A1D      BA 00010000           MOV EDX,100

 

Let the game run...

 

Nothing?  Tiberium doesn't even seem be affected by this... Or maybe we're missing something?  Perhaps...

 

CPU Disasm
Address   Hex dump                  Command                                  Comments
00468B75  |.  BD 01000000           MOV EBP,1

 

and

 

CPU Disasm
Address   Hex dump                  Command                                  Comments
00468B91  |> \C70424 02000000       MOV DWORD PTR SS:[LOCAL.13],2

 

Let's patch both of these to 16 cells and see what happens...

 

CPU Disasm
Address   Hex dump                  Command                                  Comments
00468B75      BD 10000000           MOV EBP,10

 

CPU Disasm
Address   Hex dump                  Command                                  Comments
00468B91     \C704E4 10000000       MOV DWORD PTR SS:[ESP],10

 

Now we're getting somewhere, stuff is growing much faster, but we want a tiberium world here, so let's go to 256.

 

Annnd... there we go.  There's several tricks to make it instagrow to 12, and make concrete walls spawn tiberium, etc, and even make tiberium spawn whatever you can think of. 

 

As far as harvester bail counts are thus concerned:

 

CPU Disasm
Address   Hex dump             Command                                  Comments
00436B55  |.  BB 1C000000      MOV EBX,1C

 

CPU Disasm
Address   Hex dump             Command                                  Comments
004BA430  |.  B8 1C000000      MOV EAX,1C

 

Keep in mind you are limited to 255 bails, unless of course you patch the code.

 

Oh and boys and girls, this does affect the computer.  So even if you gave him just a blossom tree and 1 harvester, well it balances itself out nicely.

Link to comment
Share on other sites

For the record, the Overrun option just stops tiberium from spawning and has nothing to do with growth and speed aside from spawning new tiberium.  Why it's called overrun and not StopTiberiumSpread, beyond me.

Oh, wow. Typical Westwood XD

 

Thanks for this ;)

 

Link to comment
Share on other sites

Last time we messed around we changed the projectile of the obelisk.  That's pretty neat, but we could've just changed the animation to get the nuke, or ion cannon or any number of effects we want.  All I will say about that is modify the laser entry and change index 39 accordingly it's a byte folks.  Experiment to see what happens, it's rather curious and funny at the same time.  Why no tutorial?  Because if you've been following along, you should be able to do it by yourself.

 

We will cover handles soon, and then we'll start talking about how to actually add ini support so we can mod this game into oblivion.

 

Questions and useful comments are always welcome.

 

Link to comment
Share on other sites

Nuke animation is a bit of a special case, though, IIRC. Like the ion cannon, it's an animation that does damage all by itself, just by playing it. There's some odd "play animation with damage" logic attached to those.

 

This has the peculiar effect you can make a bomb truck just by changing a unit's dying animation to the nuke.

Link to comment
Share on other sites

Nuke animation is a bit of a special case, though, IIRC. Like the ion cannon, it's an animation that does damage all by itself, just by playing it. There's some odd "play animation with damage" logic attached to those.

 

This has the peculiar effect you can make a bomb truck just by changing a unit's dying animation to the nuke.

 

Visceroids should explode in a nuclear fireball.  For the record you're correct, but other animations also do damage as well, so don't forget that.

Link to comment
Share on other sites

Yes, yes, I know. I was simplifying things. That's how dying grenadiers and flamethrowers tend to take out the entire group :P

 

I'm not entirely sure of the details surrounding the use of said animations for weapon impacts, though (like, the SSM missile uses the same fireball as the exploding flame tank); I assume that just plays the animation without that specific damage, and uses the weapon's configured damage/warhead instead?

 

I wish they put these "damage-dealing animations" in objects as well... from what I can see it's just a whole mess of exceptions in that 'play animation' function -_-

Link to comment
Share on other sites

Yes, yes, I know. I was simplifying things. That's how dying grenadiers and flamethrowers tend to take out the entire group :P

 

I'm not entirely sure of the details surrounding the use of said animations for weapon impacts, though (like, the SSM missile uses the same fireball as the exploding flame tank); I assume that just plays the animation without that specific damage, and uses the weapon's configured damage/warhead instead?

 

I wish they put these "damage-dealing animations" in objects as well... from what I can see it's just a whole mess of exceptions in that 'play animation' function -_-

 

I might make a post investigating this, it won't be fully in depth just enough to get the ball rolling because I still have to cover handles and start explaining how to implement an ini system.  As tempted as I am to use existing tools for the job, I would rather write my own so everything fits together neatly.  I've even considered github for the whole ordeal so people can contribute.

Link to comment
Share on other sites

Well, I already implemented it for the music list... though I rewrote pretty much all functions for handling the music theme objects for that, to remove a bunch of bugs and oddities in it, and to fix the displayed length of the hidden remix versions in the music playlist ingame. Besides that, the basic way is just the same as TS; a continuous index list which holds the filenames without extensions, and then a specific info section for each of those names:

 

http://nyerguds.arsaneus-design.com/cnc95upd/inirules/themes.ini

 

Internally, it uses Westwood's Vector class, and I hacked my new vectors into the global game variables list so they are initialized on startup and cleaned up on exit, and I used the ini read functions already in the game for opening and reading the actual ini file. And I wrote my own ini read function (built on the basic "get string") for reading booleans. (Same lazy method WW uses in Dune II for that, by only checking the first character :P)

Oh, and I added an extra vector for custom names, so people can add music without any need to edit the game's strings file. Though technically this conflicts with my language switching system, since those names aren't overridable. Heh.

 

There seem to be two vector types; one to hold objects and one to just hold ints. I think the 'objects' variant's destructor automatically cleans up the allocated heap space for the objects in the list. Pretty handy. If you want to see the dumbest use of vectors ever, though... look into how they used it for the multiplayer map names in the original unpatched game. They make the vector hold consecutive addresses for fixed length strings, reserved in the actual non-heap memory of the program. Basically it's a vector abused to serve as nothing more than an array index value O_o

Link to comment
Share on other sites

  • 4 weeks later...

Well, I already implemented it for the music list... though I rewrote pretty much all functions for handling the music theme objects for that, to remove a bunch of bugs and oddities in it, and to fix the displayed length of the hidden remix versions in the music playlist ingame. Besides that, the basic way is just the same as TS; a continuous index list which holds the filenames without extensions, and then a specific info section for each of those names:

 

http://nyerguds.arsaneus-design.com/cnc95upd/inirules/themes.ini

 

Internally, it uses Westwood's Vector class, and I hacked my new vectors into the global game variables list so they are initialized on startup and cleaned up on exit, and I used the ini read functions already in the game for opening and reading the actual ini file. And I wrote my own ini read function (built on the basic "get string") for reading booleans. (Same lazy method WW uses in Dune II for that, by only checking the first character :P)

Oh, and I added an extra vector for custom names, so people can add music without any need to edit the game's strings file. Though technically this conflicts with my language switching system, since those names aren't overridable. Heh.

 

There seem to be two vector types; one to hold objects and one to just hold ints. I think the 'objects' variant's destructor automatically cleans up the allocated heap space for the objects in the list. Pretty handy. If you want to see the dumbest use of vectors ever, though... look into how they used it for the multiplayer map names in the original unpatched game. They make the vector hold consecutive addresses for fixed length strings, reserved in the actual non-heap memory of the program. Basically it's a vector abused to serve as nothing more than an array index value O_o

 

Every C++ vector implementation I've seen cleans up it's allocations once the destructor is called.  That's just normal implementation, as for their fixed length stuff, it could be a compiler optimization although I find that difficult to believe.

Link to comment
Share on other sites

Every C++ vector implementation I've seen cleans up it's allocations once the destructor is called.

Right, but said cleanup would probably crash enthusiastically if the vector doesn't contain allocated heap addresses but just bare ints. Hence the two types.

Link to comment
Share on other sites

Every C++ vector implementation I've seen cleans up it's allocations once the destructor is called.

Right, but said cleanup would probably crash enthusiastically if the vector doesn't contain allocated heap addresses but just bare ints. Hence the two types.

 

Then I would just call it a weird array wannabe vector.

Link to comment
Share on other sites

  • 2 weeks later...
  • 5 weeks later...

Here we are, a very brief overview of handles.

 

What is a handle at heart?  Well we can think back to C++, if you wish.  When you design private member variables, do you want them exposed to the real world?  No, so how do we interact with them?  We implement methods right?  A handle is a fairly similar approach if you will allow the metaphor to be stretched a little.

 

Rather than allowing a piece of code or application to directly interact with an object, we instead implement handles to provide a means to access them.  A handle can represent a thread, process, mutex, file, section object, etc.

 

For more information please reference:

 

https://msdn.microsoft.com/en-us/library/windows/desktop/ms724457%28v=vs.85%29.aspx

 

Please also reference:

 

https://msdn.microsoft.com/en-us/library/windows/desktop/ms724461(v=vs.85).aspx

 

Note that when you close a handle to certain things like say a snapshot from CreateToolHelp32Snapshot  it automatically cleans up the section allocation it made.

 

Any time you want to read from a file, or a process, whatever, you need a handle.  They are a critical part of the operating system and thus you can't hope to mod without them.

 

Further posts will cover them in depth, but this is just to get you on the right track.

 

I am actually in the process of starting the .ini system!  Wee!

Link to comment
Share on other sites

If only you could get EA's approval (which I highly doubt), or somehow bypass the copyright :P, you could visit lulu.com to turn this into an ebook and make some money out of it, or at the very least have the satisfaction of writing your own book. There are a looOOoot of 'hacking' books out there, but nothing specifically on classic C&C.

Link to comment
Share on other sites

  • 4 weeks later...

Working on reversing the setup routines for the core stuff, bullets.ini, etc.  Should be done with this next week and have it setup on the repo for people to follow.

 

For fun:

 

CPU Disasm
Address   Hex dump          Command                                  Comments
0041D1B1  |.  8066 69 9F    AND BYTE PTR DS:[ESI+69],9F

 

 

CPU Disasm
Address   Hex dump          Command                                  Comments
0041D872      80E5 9F       AND CH,9F

 

This resets the obelisk charging animation.  Change the immediate to 0xFF or whatever.  Then your obelisk can super fire.  PS this code only executes if the obelisk's weapon is the laser.

Link to comment
Share on other sites

Well, ALL units and structures have a point at which the projectile spawns, that generally matches the end of the barrel, so I just don't really see what the difference would be :-\

 

Mind you, I haven't actually found these firing offsets so far. A cloned extra unit I added just used the actual unit center.

Link to comment
Share on other sites

  • 2 months later...

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...