fixing performance in BTD3

The classic Bloons Tower Defense 3 is known to lag badly, despite being a rather simple game. Here's how to fix it just in time for a Flash-discontinuation-nostalgia playthrough.

cause

Strangely, Ninja Kiwi decided to add an ENTER_FRAME handler to every single Bloon, unnecessarily causing thousands of event listeners to run concurrently each frame.

solution

Performance can be dramatically improved by using a single for loop instead.

prerequisites


decryption

Open the SWF in FFDec and find the mochicrypt.Preloader script.
Add import flash.net.FileReference; near the top.
Add new FileReference().save(data); at the end of the finish() function.



Running the game should now prompt you to save a decrypted SWF.

BloonsTD patches

Open the decrypted SWF, navigate to the BloonsTD class, find the EnterFrame() function, and insert the following code at the start:
for(var i=0;this.bloonholder.numChildren>i;i++) { this.bloonholder.getChildAt(i).Update(null); }

However, FFDec's direct AS3 editor will corrupt this script upon saving. Writing P-code (Flash assembly language) is difficult. The easiest solution is to make the change in AS3, copy the equivalent P-code (everything from pushbyte 0 to the first ifgt), reload the SWF, and then re-insert the P-code.



Rename the ofsXXXX labels in the pasted P-code, or they might collide with existing ones.

Bloon patches

Find Bloon's constructor and click the addEventListener() call. Once again, editing the AS3 will cause corruption, so delete the call via P-code.



It's also necessary to make Update() public so BloonsTD can call it. Change PackageInternalNs to PackageNamespace in the function's P-code's first line.

framerate

Optionally, change the framerate in the header from 40 to 60 FPS.

result

On my 2010 MacBook, this allows the game to run smoothly into freeplay mode. Normally, it slows to a crawl by round 30. The game balance should be unchanged, since Bloons don't interact, and towers are updated later.