It seems not many people is interested on this these days, anyway, I am enjoying studying the power of MHS and, while having a break of a Hooks stuff, I decided to improve my AlmostNoCooldown skill limit.
Note that this does not work on all skills well. Only some (low level/rank) skills and buffs accepts this blindly. For example, Art of Cure (if it is the right name of it) cools earlier, but you just can't use the skill until the cooldown time has reached. Seems server-sided but I have not tested deeply. Maybe the timer is just somewhere else. For Cure, buffs (for buffs its useless, noDelay suffices for buffs), sword and magic skills until maybe nv60 rank, they work. For attack skills, if you spam too much the same skill in too few seconds, you get booted off. You can spam cure as you wish but the actual cure comes only by ~0.8 to 0.8 secs. You can flood with dash and retreat as much as you like and your MP allows.
So, instead of one address for every skill slot, this time we will add a single address. You still have to find the main address. The main advantage is you don't need to change every address if the address shifts from one update to another. You are now allowed to right click and 'move selected' (which you couldn't on complex address -- at least I did not find out how). As before, you will add a script lock which is the script below. Remember you are no longer using complex address, so leave the box of complex address unchecked. We are using normal address and script lock.
To the script:
- Code: Select all
int timenow=0;
// Reduce cooldown for this slot?
bool lock_slot[]={
// Sword slots
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0..15
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 16..31
// Magic slots
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, // 0..15
0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0 // 16..31
};
// Reduce cooldown time by 'cd_reduce' seconds (one for each slot)
float cd_reduce[]= {
// sword
0.5, 0.5, 0.5, 0.5, //0..3
0.5, 0.5, 0.5, 0.5, //4..7
0.5, 0.5, 0.5, 0.5, //8..11
0.5, 0.5, 0.5, 0.5, //12..15
0.5, 0.5, 0.5, 0.5, //16..19
0.5, 0.5, 0.5, 0.5, //20..23
0.5, 0.5, 0.5, 0.5, //24..27
0.5, 0.5, 0.5, 0.5, //28..31
// magic
0.5, 0.5, 0.5, 1.5, //0..3
0.5, 0.5, 0.5, 0.5, //4..7
0.5, 0.5, 0.5, 0.5, //8..11
0.5, 0.5, 0.5, 0.5, //12..15
0.5, 0.5, 1.0, 0.5, //16..19
100.5, 0.5, 0.5, 0.5, //20..23
0.5, 0.5, 0.5, 0.5, //24..27
0.5, 0.5, 0.5, 0.5, //28..31
};
float lastused[]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
VOID Lock(MHS_ADDRESS address, INT ItemID) {
extern UINT_PTR slotsptr={"",address};
int time=Time();
int i=0;
if (time - timenow > 250) { // limit the rate to save CPU cycles
timenow=time;
for (i=0;i<64;i++) {
if (lock_slot[i]) {
lockSlotById(slotsptr,i);
}
}
}
}
VOID lockSlotById(UINT_PTR address, INT sid) {
extern UINT_PTR slotptr={"",address+(sid*4)};
UINT_PTR test;
//if (IsBadReadPtr((void *)slotptr, sizeof(DWORD))) return;
if (!slotptr) {
PrintF("ERROR: coulnd't get a pointer to the desired skill slot!");
return;
}
test=slotptr;
extern float cdvalue={"",slotptr+0x20};
extern float cdvaltwo={"",slotptr+0x28};
// Avoid catching multiple keypresses on one by waiting 250ms between triggers for a single cooldown
if (cdvalue-lastused[sid] > 0.250) {
lastused[sid]=cdvalue;
cdvalue-=cd_reduce[sid];
cdvaltwo=cdvalue;
PrintF("Applying lowCoolDown to %s skill on slot %i. Time reduced by %f secs.",(sid>31)?"magic":"sword",(sid>31)?sid-31:sid+1,cd_reduce[sid]);
} else if(cdvalue < lastused[sid])
lastused[sid]=cdvalue;
}
// [[05A9B924]+(i*4)]+0x20
So, what we have here:
- lock_slot: there are 32 of each. 32 for sword skills and 32 for magic skills. You set '1' to the corresponding skill slot you wanna the cooldown 'faster' than normal.
- cd_reduce: there, you set by how many seconds you want the skill to cool faster. For example if it takes 3.2s to cooldown, you can put 1.2 seconds to make it cooldown as quick as 2 seconds (in average, you will see why later).
- lastused: this is just a control to avoid double-usages, specially if you have set the timer below too low. This makes it count a single skill usage by every 250ms. Before, it would just use the skill repeatedly both banning you faster and making you waste mana. This is initialized as 0, and might not be changed. It is updated as you use the skill. If you put arbitrary values here will not make anything faster, they will just be zeroed again.
- time - timenow > 250: here I've imposed a time limit (not the one I told above) to reduce cycles calculating pointers and checking the actual value of the cooldown. This value of 250ms is good enough to use the skills very fast. Yet, I valorize the connection keeping not the flooding and DC'ing.
- cdvalue-lastused[sid] > 0.250: almost in the end of the script there's another 0.250. This is the actual skill timer to avoid multiple skill usage. Maybe this has rendered useless due to the above timer but it is here shall you feel like you wanna let your CPU keep resolving those pointer addresses.
- Last, there's a PrintF. Why, if it can't be shown anywhere?.. Wrong. If you open the script editor in MHS, you will see the output and see the script working on your cooldown. If you don't want it, just comment it out, it makes no difference.
I thing the most CPU intensive change on the script you can make is changing the 'time-timenow > 250' (notice here we speak in milisseconds, on the other places, seconds, thus 0.250). If you make this like 'time-timenow > 1' or so, you might not be harmed in performance but you are truly wasting cpu cycles on calculations that would not change your 'gaming experience'.
Now, a question to L'Spiro or whom knows about it. I saw in a recent post about an unreal tournament hack (team hack) about using ::IsBadReadPtr() to check pointers' reachability. I just couldn't compile the script lock using it, and I believe the syntax and parameters are correct despite I did use a different casting syntax sugar (which worked among the script). Any light to why it does not work? I know the alternative I chosen does not guarantee MHS wouldn't crash but the fact I extracted the address via extern <blahblah> should help at least by giving a null pointer where I can't reach a memory address.
Have fun!