The only "tricky" AoB here was the invincibility. The others were fairly trivial; so, invincibility will come last.
To learn a skill, what do we need? Upgrade points. So I searched for "upgradepoints" (case insensitive of course.) Wait for it...just a minute...it's a large swf, let it search...
ok, one of the very first search results looks really really promising:
if (HeroInfo.upgradePoints > 0)
{
_loc_3.addEventListener(MouseEvent.ROLL_OVER, upgradeBtnRollOver, false, 0, true);
_loc_3.addEventListener(MouseEvent.ROLL_OUT, upgradeBtnRollOut, false, 0, true);
_loc_3.addEventListener(MouseEvent.MOUSE_UP, upgradeBtnRelease, false, 0, true);
_loc_3.addEventListener(MouseEvent.MOUSE_UP, Global.buttonClickSound, false, 0, true);
}
It was simply removing the if statement - that way, it will always execute.
For the skill points, it was nearly the same process: Searched for "skillPoints", found this:
if (HeroInfo.skillPoints >= _loc_7.SP_needed)
{
_loc_7.canLearn = true;
}
Once again, removed the if statement.
The spell recharge was a little bit different. I got to it by actually doing the "skills cost no mana" AoB. Started looking for things like "mana", and after some cycles searched for "mp". It gave me tons of results, and I'm lazy, so I searched for "mp -", as we're looking for the point where our mp decreases. First result:
HeroInfo.Obj.MP = HeroInfo.Obj.MP - this.atkClass.MP;
ok, so we know it's done by calling castSpell, so in the same file I looked for "castSpell", which led me here:
if (HeroInfo.Obj.MP >= this.atkClass.MP)
{
HeroInfo.Obj.endBlinkTimer();
HeroInfo.Obj.endBreathTimer();
HeroInfo.Obj.charMC.char.gotoAndPlay("backslash");
HeroInfo.Obj.equip();
this.beginCooldown();
setTimeout(this.castSpell, 300);
HeroInfo.Obj.attacking = true;
HeroInfo.Obj.walking = false;
}
See the target? "beginCooldown" looks suspicious. Wondering what it does, I went to that function and saw it doing stuff with timers. Well, I then wondered what will happen if the function never executed. So I took the first few bytes of it (we need only that function, nothing else) and changed the first byte to a return statement.
When you return from a function, it's like going back home from the salt mines - it doesn't matter if you just entered or there is more to it, you will exit the salt mines.
I'm going to leave the gold hacks alone, as it really was trivial. Just instead of the jump I did in the first one, you can replace stuff with NOP commands.
Now, the really juicy thing - the invincibility hack. Started off by looking for "hp -". I ignored the first result, as it was a unique case and you're big boys, so now looking at the second result.
param2.HP = param2.HP - _loc_7;It doesn't distinguish between friend and foe. It doesn't care who the target is or who the attacker is - all it cares about is to reduce the hp of at attacked object. Now, that's no good for us. We need to hurry up and leave before our hp is reduced.
So I poked around the function, looking for a way to distinguish between your enemies and you. Found this later on:
param2.charType == "hero"Now we know how to check for us, but we need to apply that before we get hit. Luckily, we have an if statement before that:
if (param3.atkName == "NoDamage")
{
_loc_7 = 0;
}
So, we theoretically, we want:
if (param2.charType == "hero")
{
return;
}
However, when returning from the salt mines, we are expected to bring something back. I know this by looking at the end of the function:
return _loc_8;
So instead, we change our theoretical case into the actual case:
if (param3.atkName == "NoDamage")
{
_loc_7 = 0;
}
turns into
if (param2.charType == "hero")
{
return _loc_8;
}
This hack was achieved through sheer luck really, as it was dependent on many things (there was a condition beforehand, there was character type checking, the returned value was defined before, etc) but as a practice it's a nice one.
Hope this somehow helped.