First of all I wanna apologize if the owner or the private server is on here.
Due my curiosity I decide to build bot for AO V3.
but I got several problem or maybe a lot of problem
what I did so far is I already found the entity list (or similar) it contains
Monster/NPC ID
Current X Coordinate (on Map not Screen)
Current Y Coordinate (same as above)
Current Map ID
Name as unicode string
The rest is idk because the stride offset between entity is large like 0xFB68
Now the problem is, I cannot find the 'world2screen' or camera function that translate from 'Map' to X and Y coordinate screen. or maybe wanna try different approach like the title of this thread "CALLING IN GAME FUNCTION"
AFAIK the MMORPG game is using packet to communicate between client and server right?
but when I hook WSASend function to log packet that sent to server, its encrypted, I try do tracing function that encrypt packet but no luck or maybe I just suck at this.
or maybe someone can give me a clue instead rebuilding packets just find a function that move to certain XY Coordinate and MapID? back again I'm suck at this tracing function , and yes I already tried that and guess what? I stuck at event loop on WM_TranslateMessage or similar (forgot the right term)
any advice that what to do next?
Why don't you use the bot I attached it works on v3.xx.xx servers.
Run uMod or Texmod whichever works and open texture/package (atlantica.tpf) it's in the AO_TextMod folder. Then simply run AutoGrinder_08C.au3 or AutoGrinder_08C.exe
Why don't you use the bot I attached it works on v3.xx.xx servers.
Run uMod or Texmod whichever works and open texture/package (atlantica.tpf) it's in the AO_TextMod folder. Then simply run AutoGrinder_08C.au3 or AutoGrinder_08C.exe
Password for archive is: 12345
hey, thanks for your reply, your Bot is amazing.
is this autogrinder based on autoit right?
so the feature is limited like "simulate" user input then?
back again my goals is due "curiosity" on calling in game function
so I wanna "simulate" the function that run under the hood.
thanks again for references.
void ClickOnMonster(int EntityIndex)
{
DWORD monsterClickPointer = ReadDWordPointer(MainBaseAddress, 2, AutoClickMonster_Offset_1, AutoClickMonster_Offset_2);
if (monsterClickPointer)
{
// Monster ID
DWORD monsterId = ReadDWordPointer(MainBaseAddress, 3, AutoClickMonster_Offset_1, 4 * EntityIndex + AutoClickMonster_EntityOffset, AutoClickMonster_Offset_3);
if (monsterId) {
//(Active Attack Clock)
DWORD ActiveAttackClock = ReadDWordPointer(MainBaseAddress, 1, AutoClickMonster_Offset_4);// old = 0xB94 new = 0xBA4
//myprintf(true, false, false, TextColor::RED, "Clicking on Monster %X, monsterId = %X entity index = %d \n", monsterClickPointer, monsterId, EntityIndex);
WritePointer(monsterClickPointer + AutoClickMonster_Offset_5, monsterId, 4, 0); //Monster Id
WritePointer(monsterClickPointer + AutoClickMonster_Offset_6, 5, 1, 0); // (5 = walk to monster) (4 = arrived to monster) (2 = fight starting)
WritePointer(monsterClickPointer + AutoClickMonster_Offset_7, EntityIndex, 1, 0); // 0x154 = old 0x21C = new
WritePointer(monsterClickPointer + AutoClickMonster_Offset_8, GetMapId(), 2, 0); // 0x158 = old 0x220 = new (Map ID)
WritePointer(monsterClickPointer + AutoClickMonster_Offset_9, ActiveAttackClock, 4, 0); // 0x244 is old = 0x30C = new (Attack Clock)
WritePointer(monsterClickPointer + AutoClickMonster_Offset_10, 30, 1, 0); // Change this value to 30.. when you click a monster [29 = walk][30 = click on monster][1 = stand still]
}
else {
myprintf(true, false, false, TextColor::RED, "Failed to attack monster! (trying next monster)\n");
}
}
}
Hey thanks its very helpfull.
So my approach from start is on wrong direction then? I mean I was thinking like Aimbot so I messing up with NiCamera object to determine w2s function. But from what I see from you source code it calling internal function to move on monster address that stored in array of entity list right? Or it just write to correct value on pointer to match event loop on mainthread?
using NiCamera and World2Screen function is the old way of doing it that's how AOBot v1.0 was.. it involved hooking DirectX but it wasn't as fast with clicking mouse coordinates on screen, this one can move to monster without even seeing the monster on screen which is faster..
EntityIndex I believe is just a number index in a array of all monsters it starts from 6 I believe and goes very high, EntityIndex = 1 is your character.
I think max is 510 monsters in one area is limit.
Here is my code how I find closest monster to attack
Code:
signed int GetClosestMonsterInArea(float MaxDistance)
{
float myX;
float myY;
float mobX;
float mobY;
int EntityIndex = 6;
int closestEntityIndex = -1;
int index = 0;
int entityOffset = 0x40;
while (index < 510) //old value was 2040 and entityOffset was 0x40 going by 4 every loop.
{
entityOffset = ((index * 4) + 0x40);
//Skip the monsters that you already tried to attack.
std::unordered_set<DWORD>::const_iterator alreadyAttackedBeforeMonster = LastAttackedMonsters.find(EntityIndex);
if (alreadyAttackedBeforeMonster != LastAttackedMonsters.end()) {
++index;
++EntityIndex;
continue; //Skip the monsters that you already tried to attack.
}
if (lastTargetedMonsterIndexCached != EntityIndex //Avoid attacking the last monster you targeted before.
&& isGoodNpcId(EntityIndex, entityOffset) == 1) // Is good Npc Id (bad skins could mean it will click on players etc..)
{
myX = (float)MapX(1);
myY = (float)MapY(1);
mobX = (float)MapX(EntityIndex);
mobY = (float)MapY(EntityIndex);
// (33 = attacked monster)
// (34 = monster dead)
// (35 = probably also something like dead but unknown)
// (28 = Walking Monster)
// (1 = Standing Still Monster)
//&& (ReadMemory(MainBaseAddress, "byte", 3, 0x828, entityOffset, 0x38) == 1 // (1 = Standing Still Monster?)
//|| ReadMemory(MainBaseAddress, "byte", 3, 0x828, entityOffset, 0x38) == 28))
if (GetDistance(mobX, mobY, myX, myY) < MaxDistance
&& (ReadBytePointer(MainBaseAddress, 3, AutoClickMonster_Offset_1, entityOffset, AutoClickMonster_Offset_10) == 1 // (1 = Standing Still Monster)
|| ReadBytePointer(MainBaseAddress, 3, AutoClickMonster_Offset_1, entityOffset, AutoClickMonster_Offset_10) == 28)) //(28 = Walking Monster)
{
if (Fix_AttackMerc) {
DWORD isAttackablePlayerOrMonsterId = ReadDWordPointer(MainBaseAddress, 4, isMonsterAttackable_Offset_1, entityOffset, isMonsterAttackable_Offset_2, isMonsterAttackable_Offset_3);
myprintf(true, false, false, TextColor::RED, XorStr("isAttackablePlayerOrMonsterId = %X\n"), isAttackablePlayerOrMonsterId);
DWORD addressNpcOrMonster = (DWORD)(*(DWORD*)(*(DWORD*)((*(DWORD*)((*(DWORD*)(MainBaseAddress)) + (isMonsterAttackable_Offset_1))) + (entityOffset)) + (isMonsterAttackable_Offset_2)) + (isMonsterAttackable_Offset_3));
myprintf(true, false, false, TextColor::RED, XorStr("Attacking Address = [%X]\n"), addressNpcOrMonster);
DWORD npcCheck = getNpcId(EntityIndex);
DWORD npcIdsSize = sizeof(NpcIds) / sizeof(NpcIds[0]);
if (npcCheck < npcIdsSize)
myprintf(true, false, false, TextColor::RED, XorStr("Attacking = [%d] %s\n"), npcCheck, NpcIds[npcCheck].c_str());
else
myprintf(true, false, false, TextColor::RED, XorStr("Bug: Attacking unknown npc [%d]\n"), npcCheck);
}
closestEntityIndex = EntityIndex;
}
}
++index;
++EntityIndex;
}
return closestEntityIndex;
}
Here is my code to call both functions.
Code:
float CheckDistances[] = { 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 };
DWORD WalkTimes[] = { 2000, 2000, 3000, 3000, 4000, 5000, 6000, 6000, 7000, 8000 }; //2 to 8 seconds.
int distanceCheckIndex = 0;
while (distanceCheckIndex < 10) {
checkTargetedMonsterEntityId= GetClosestMonsterInArea(CheckDistances[distanceCheckIndex]);
if (checkTargetedMonsterEntityId!= -1)
break;
distanceCheckIndex++;
}
if (checkTargetedMonsterEntityId== -1) {
//No monsters were found for all Distances, clear the monster queue list to atleast get some action.
LastAttackedMonsters.clear();
return;
}
if ((clock() - TimmerClick) > WalkTimes[distanceCheckIndex]) //2 to 8 seconds.
{
//Cannot attack monster for 15 seconds, force teleport to monster.
if (conf_use_avoid_collisions && (clock() - TimmerLastTargetMonsterToAttack) > 30000) {
if (GetMapId() != 0 || (MapX(checkTargetedMonsterEntityId) != 0 && MapY(checkTargetedMonsterEntityId) != 0))
Teleport(GetMapId(), MapX(checkTargetedMonsterEntityId), MapY(checkTargetedMonsterEntityId));
TimmerLastTargetMonsterToAttack = clock();
}
ClickOnMonster(checkTargetedMonsterEntityId);
LastAttackedMonsters.insert(checkTargetedMonsterEntityId); //add to queue of monsters it checked.
as_action = CLOSE_WINDOWS; //fix to stop clicking non-stop this caused lag.
lastTargetedMonsterReset = true;
TimmerClick = clock();
}
using NiCamera and World2Screen function is the old way of doing it that's how AOBot v1.0 was.. it involved hooking DirectX but it wasn't as fast with clicking mouse coordinates on screen, this one can move to monster without even seeing the monster on screen which is faster..
EntityIndex I believe is just a number index in a array of all monsters it starts from 6 I believe and goes very high, EntityIndex = 1 is your character.
I think max is 510 monsters in one area is limit.
Here is my code how I find closest monster to attack
Code:
signed int GetClosestMonsterInArea(float MaxDistance)
{
float myX;
float myY;
float mobX;
float mobY;
int EntityIndex = 6;
int closestEntityIndex = -1;
int index = 0;
int entityOffset = 0x40;
while (index < 510) //old value was 2040 and entityOffset was 0x40 going by 4 every loop.
{
entityOffset = ((index * 4) + 0x40);
//Skip the monsters that you already tried to attack.
std::unordered_set<DWORD>::const_iterator alreadyAttackedBeforeMonster = LastAttackedMonsters.find(EntityIndex);
if (alreadyAttackedBeforeMonster != LastAttackedMonsters.end()) {
++index;
++EntityIndex;
continue; //Skip the monsters that you already tried to attack.
}
if (lastTargetedMonsterIndexCached != EntityIndex //Avoid attacking the last monster you targeted before.
&& isGoodNpcId(EntityIndex, entityOffset) == 1) // Is good Npc Id (bad skins could mean it will click on players etc..)
{
myX = (float)MapX(1);
myY = (float)MapY(1);
mobX = (float)MapX(EntityIndex);
mobY = (float)MapY(EntityIndex);
// (33 = attacked monster)
// (34 = monster dead)
// (35 = probably also something like dead but unknown)
// (28 = Walking Monster)
// (1 = Standing Still Monster)
//&& (ReadMemory(MainBaseAddress, "byte", 3, 0x828, entityOffset, 0x38) == 1 // (1 = Standing Still Monster?)
//|| ReadMemory(MainBaseAddress, "byte", 3, 0x828, entityOffset, 0x38) == 28))
if (GetDistance(mobX, mobY, myX, myY) < MaxDistance
&& (ReadBytePointer(MainBaseAddress, 3, AutoClickMonster_Offset_1, entityOffset, AutoClickMonster_Offset_10) == 1 // (1 = Standing Still Monster)
|| ReadBytePointer(MainBaseAddress, 3, AutoClickMonster_Offset_1, entityOffset, AutoClickMonster_Offset_10) == 28)) //(28 = Walking Monster)
{
if (Fix_AttackMerc) {
DWORD isAttackablePlayerOrMonsterId = ReadDWordPointer(MainBaseAddress, 4, isMonsterAttackable_Offset_1, entityOffset, isMonsterAttackable_Offset_2, isMonsterAttackable_Offset_3);
myprintf(true, false, false, TextColor::RED, XorStr("isAttackablePlayerOrMonsterId = %X\n"), isAttackablePlayerOrMonsterId);
DWORD addressNpcOrMonster = (DWORD)(*(DWORD*)(*(DWORD*)((*(DWORD*)((*(DWORD*)(MainBaseAddress)) + (isMonsterAttackable_Offset_1))) + (entityOffset)) + (isMonsterAttackable_Offset_2)) + (isMonsterAttackable_Offset_3));
myprintf(true, false, false, TextColor::RED, XorStr("Attacking Address = [%X]\n"), addressNpcOrMonster);
DWORD npcCheck = getNpcId(EntityIndex);
DWORD npcIdsSize = sizeof(NpcIds) / sizeof(NpcIds[0]);
if (npcCheck < npcIdsSize)
myprintf(true, false, false, TextColor::RED, XorStr("Attacking = [%d] %s\n"), npcCheck, NpcIds[npcCheck].c_str());
else
myprintf(true, false, false, TextColor::RED, XorStr("Bug: Attacking unknown npc [%d]\n"), npcCheck);
}
closestEntityIndex = EntityIndex;
}
}
++index;
++EntityIndex;
}
return closestEntityIndex;
}
Here is my code to call both functions.
Code:
float CheckDistances[] = { 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 };
DWORD WalkTimes[] = { 2000, 2000, 3000, 3000, 4000, 5000, 6000, 6000, 7000, 8000 }; //2 to 8 seconds.
int distanceCheckIndex = 0;
while (distanceCheckIndex < 10) {
checkTargetedMonsterEntityId= GetClosestMonsterInArea(CheckDistances[distanceCheckIndex]);
if (checkTargetedMonsterEntityId!= -1)
break;
distanceCheckIndex++;
}
if (checkTargetedMonsterEntityId== -1) {
//No monsters were found for all Distances, clear the monster queue list to atleast get some action.
LastAttackedMonsters.clear();
return;
}
if ((clock() - TimmerClick) > WalkTimes[distanceCheckIndex]) //2 to 8 seconds.
{
//Cannot attack monster for 15 seconds, force teleport to monster.
if (conf_use_avoid_collisions && (clock() - TimmerLastTargetMonsterToAttack) > 30000) {
if (GetMapId() != 0 || (MapX(checkTargetedMonsterEntityId) != 0 && MapY(checkTargetedMonsterEntityId) != 0))
Teleport(GetMapId(), MapX(checkTargetedMonsterEntityId), MapY(checkTargetedMonsterEntityId));
TimmerLastTargetMonsterToAttack = clock();
}
ClickOnMonster(checkTargetedMonsterEntityId);
LastAttackedMonsters.insert(checkTargetedMonsterEntityId); //add to queue of monsters it checked.
as_action = CLOSE_WINDOWS; //fix to stop clicking non-stop this caused lag.
lastTargetedMonsterReset = true;
TimmerClick = clock();
}
Ah I see thats why the NiCamera approach is need zoom bound.
Yes I was able to determine nearest monster approximate to character using my first entity list (with large stride)
Because when I use offset of entity list from your examples in aoth it just contains monsterId and it just one pointer not two like yours.
And it just contains monsterId not pointer to target or maybe different structure? Because aoth is v16 and mine is v3? Idk either.
Also I was able to replicate the click function based on your example via cheat engine, but I wasn't able to find AttackClock and AutoclickMonster_Offset_5 is not monsterId on V3 but something else in memory, Idk like 2 bytes.
But again when I click the random monster first then I set value of entity index (monsterClickPointer + AutoClickMonster_Offset_7), currentMapId (monsterClickPointer + AutoClickMonster_Offset_8) and actionState (monsterClickPointer + AutoClickMonster_Offset_10) to 30
It gonna click the monster BUT the problem is it must click at random monster first. Maybe you can help me again 😂
Ps: I cannot find what attackClock is because maybe its different struct or login when it comes to v3 or v16. Maybe its like flag by timestamp to determine that event sent by user input is "fresh" or idk
v3 atlantica should have the same AttackClock etc to find it mess around with IDA PRO on the unpacked Thailand game.. then find same pattern in v3 client too.
To get random monster first, use (rand() % 510) + 1 and check if its a valid monster in a loop like so
v3 atlantica should have the same AttackClock etc to find it mess around with IDA PRO on the unpacked Thailand game.. then find same pattern in v3 client too.
To get random monster first, use (rand() % 510) + 1 and check if its a valid monster in a loop like so
Use Plugin BinDiff to find it quickly in less then 5 minutes.
I PM'd you with a download link to IDA PRO 9.2 Beta 1 and Plugins I use.
Found the clock for you in V3 in less then a minute
0xBAC in Thailand
0xB4C in Atlantica V3.
Hey I already done with Attack Monster on world map thanks to you.
And also I already done with attack and loot monster on Battle Map/Room (just attack not magic, im too lazy too mapping magic order)
Now I have question on teleport
Is the teleport is calling in game function or direct changing value like move to target? Or its by Sending WSASend packet? I already found the encrypt/decrypt packets function using your IDA.
So where to start if I wanna do teleport with assigning MapId, X and Y?
Thanks
v3 atlantica should have the same AttackClock etc to find it mess around with IDA PRO on the unpacked Thailand game.. then find same pattern in v3 client too.
To get random monster first, use (rand() % 510) + 1 and check if its a valid monster in a loop like so
battlespeed is written down in my update notes as so.
Code:
00856E3E 55 PUSH EBP
00856E3F 8BEC MOV EBP,ESP
00856E41 51 PUSH ECX
00856E42 53 PUSH EBX
00856E43 56 PUSH ESI
00856E44 8B35 AC04C901 MOV ESI,DWORD PTR DS:[0x1C904AC]
00856E4A 57 PUSH EDI
00856E4B 8BD9 MOV EBX,ECX
00856E4D 8B8E 84100000 MOV ECX,DWORD PTR DS:[ESI+0x1084]
00856E53 6A 00 PUSH 0x0
00856E55 E8 C0C4D2FF CALL 0058331A
00856E5A 6A 02 PUSH 0x2
00856E5C E8 FFA61200 CALL 00981560
00856E61 59 POP ECX
00856E62 E8 25A71200 CALL 0098158C
00856E67 8B78 18 MOV EDI,DWORD PTR DS:[EAX+0x18]
00856E6A 8BCF MOV ECX,EDI
00856E6C E8 12B21300 CALL 00992083
00856E71 DB05 C47F4902 FILD DWORD PTR DS:[0x2497FC4] //THIS IS SPEED ADDRESS
00856E77 51 PUSH ECX
00856E78 8BCF MOV ECX,EDI
00856E7A DC05 88928501 FADD QWORD PTR DS:[0x1859288]
00856E80 D95D FC FSTP DWORD PTR SS:[EBP-0x4]
00856E83 D945 FC FLD DWORD PTR SS:[EBP-0x4]
00856E86 DC35 A8928501 FDIV QWORD PTR DS:[0x18592A8]
00856E8C D95D FC FSTP DWORD PTR SS:[EBP-0x4]
00856E8F D945 FC FLD DWORD PTR SS:[EBP-0x4]
00856E92 D91C24 FSTP DWORD PTR SS:[ESP]
00856E95 E8 85A11300 CALL 0099101F
00856E9A 6A 02 PUSH 0x2
00856E9C B9 487F4902 MOV ECX,0x2497F48
00856EA1 E8 6FD5D0FF CALL 00564415
00856EA6 8BCB MOV ECX,EBX
00856EA8 E8 01F3FFFF CALL 008561AE
00856EAD 8BCB MOV ECX,EBX
00856EAF E8 C6D9FFFF CALL 0085487A
00856EB4 8B86 BC100000 MOV EAX,DWORD PTR DS:[ESI+0x10BC]
00856EBA 5F POP EDI
00856EBB 5E POP ESI
00856EBC C640 01 01 MOV BYTE PTR DS:[EAX+0x1],0x1
00856EC0 5B POP EBX
00856EC1 C9 LEAVE
00856EC2 C3 RETN
//The speed value is always set to 0x82 in this area good place to steal the address from.
005D8F5F 50 PUSH EAX
005D8F60 E8 831AFCFF CALL 0059A9E8
005D8F65 85C0 TEST EAX,EAX
005D8F67 74 0A JE SHORT 005D8F73
005D8F69 C705 C47F4902 82000000 MOV DWORD PTR DS:[0x2497FC4],0x82 //Speed address.
005D8F73 5F POP EDI
005D8F74 5E POP ESI
005D8F75 C2 1000 RETN 0x10
C7 05 ?? ?? ?? ?? 82 00 00 00 works perfectly to find it.
//System->Settings->System->Set Battle Speed = Very Slow = 80
//System->Settings->System->Set Battle Speed = Medium = 100
Default speed is 130
Hey, thanks again. I was able to create bot on version 3 with some basic feature using ImGui for creating form.
but I was struggle to replicate your teleport function
my current bot can do teleport or automove using send packet teleport. but I cannot bypass Will Requirement and Map Information restrictions.
can you also give me help on that?
or just clue is fine.
also on my current bot, on TBS/Skirmish its limited to do guard or skip. I was wondering if I can move to tile X? or its too much to do? because the function of move to tile X is also passing parameter that have like "valid tile to move" etc.
thanks
Calling ingame function through C++? [Question] 01/25/2022 - Last Chaos - 3 Replies Hello!
I have a question.
I know, that C++ can call ingame functions through pushing register to it.
But when I was debugging LC through x64dbg, I noticed that every ingame function get called from packet sending through messageDispatcher (but I'mm not sure..).
So here is a question:
Can I execute call ingame functions not through packets? Or the only way to it - packet sending?
std::function of a function returning an std::function 11/11/2013 - C/C++ - 19 Replies Nun muss ich nach langer Zeit auch mal wieder einen Thread erstellen, weil mir Google nicht mehr weiterhelfen kann.
Ich verzweifle an Folgendem Vorhaben:
#include <Windows.h>
#include <string>
#include <iostream>
using namespace std;
Need some help calling function for height 07/27/2011 - Perfect World - 2 Replies Hey there, for some reason I keep crashing upon trying to call this function and it's really pissing me off. I was wondering if somebody could give me some advice as to what I'm doing wrong :(
The function is being called inside a function starting at address 0x465730 in PWI
The function I'm looking for is called twice here, namely at 0x4657C7 and 0x465879. The code where it is called looks something like this:
http://img94.imageshack.us/img94/9867/coordfuncti on.png
Now, I'm...
Help, calling an ingame function 03/13/2010 - General Coding - 2 Replies Im trying with my dll to set off the "set stat function". The one that u press when you add a stat point to str, dex or what ever. My goal is to make players able to set there Stats to whatever they use to have from an earlier saved point. So if you play against different sort of mobs or players you reform your stats to be suetable for that sertan task in just 1 second right where you stand. Im thinking this is very useful for many ppl here.
So now i could use help with the actuall call of...
Help with calling this function! 03/13/2010 - 12Sky2 - 6 Replies First off: sorry for my poor english!
Im trying with my dll to set off the "set stat function". The one that u press when you add a stat point to str, dex or what ever. My goal is to make players able to set there Stats to whatever they use to have from an earlier saved point. So if you play against different sort of mobs or players you reform your stats to be suetable for that sertan task in just 1 second right where you stand. Im thinking this is very useful for many ppl here.
So now i...