suggestions for code changes for looting and resting

Runes of Magic/Radiant Arcana (http://www.runesofmagic.com)
Post Reply
Message
Author
d003232
Posts: 1252
Joined: Wed Jun 03, 2009 4:27 pm

suggestions for code changes for looting and resting

#1 Post by d003232 » Wed Jun 10, 2009 6:17 pm

I did three modifications for the following points:

- stopping and rest before a new fight if mana or hp is under a certain limit
- skip loot if near mobs are around the death one
- skip loot if getting aggro befor looting

I think that points make the bot a little smarter and look more human. Here my code:

1. Stop and rest before a new fight:

I suggest to use potions. You get them from the merchant, they are cheap and speed up your botting. I use potions at 30%. But if you fall under a certain limit with your mana or hp, it is not usefull to start a new fight. The hard coded default is 15%. You can set that in your profile. If you fall under that limit, the bot will wait and rest. He will still fight if he get aggro and use buffs and potions. The resting time is random between 30-99 seconds.

You need two new options in your profile *charname*.xml

Code: Select all

<option name="HP_REST" value="15" />
<option name="MP_REST" value="15" />
new entrys in the language files

Code: Select all

	[36] = "resting %s sec for full mana and full HP\n",
	[37] = "get aggro at sec %s\n",
	[38] = "full at sec %s\n",
in the english.lua and

Code: Select all

	[36] = "warte %s sek bis Mana und HP voll sindP\n",
	[37] = "Aggro bei Sekunde %s\n",
	[38] = "voll bei Sekunde %s\n",
in the deutsch.lua

then add in the player.lua at line 107 after function CPlayer:fight()

Code: Select all

function CPlayer:fight()

-- wait if mana or hp is lower than x%
if( self.Battling == false ) then		-- only if no aggro 

	if( settings.profile.options.MP_REST == nil ) then  settings.profile.options.MP_REST = 15; end;
	if( settings.profile.options.HP_REST == nil ) then  settings.profile.options.HP_REST = 15; end;

	-- some classes dont have mana, in that cases Player.mana = 0
	hf_mana_rest = (player.MaxMana * settings.profile.options.MP_REST / 100);	-- rest if mana is lower then
	hf_hp_rest   = (player.MaxHP   * settings.profile.options.HP_REST / 100);	-- rest if HP is lower then

	if( player.Mana < hf_mana_rest  or 
	    player.HP   < hf_hp_rest   ) then
		self:clearTarget();          -- get rid of mob, so we dont cast while resting
		hf_count = 30 + math.random( 69 );			-- set rest counter, up to 99 sec pause
		cprintf(cli.green, language[36], hf_count);		-- resting x sec for Mana and HP
		while hf_count > 0 do
--			printf("%s Mana: %s MaxMana: %s HP: %s MaxHP %s\n", hf_count, player.Mana, player.MaxMana, player.HP, player.MaxHP);  -- debug info
			yrest(1000);
			hf_count = hf_count - 1;	
			self:update();
			if( self.Battling ) then          -- we get aggro,
				self:clearTarget();       -- get rid of mob to be able to target attackers
				printf(language[37], hf_count );   -- get aggro at sec x
				hf_count = 0;		-- stop countdown
			end;
--			printf("ManaPZ %s HPPZ: %s\n", (player.Mana/player.MaxMana*100), (player.HP/player.MaxHP*100) );   -- debug
			if( player.Mana == player.MaxMana  and		-- some chars have MaxMana = 0
	 	 	    player.HP   == player.MaxHP ) then		-- Mana and HP are full
				printf(language[38], hf_count );   -- full at sec x
				hf_count = 0;				-- stop countdown
			end;

			self:checkPotions();   
			self:checkSkills(); 		-- check if we need to cast buffs/heals.
		end;			-- end of while
	end;				-- end of MP/HP < xx
end;				-- end of self.battling
2. Skip loot if nearby mobs arround

If you fight a mob in a mobgroup, it is not usefull und not human after the fight to run into that group for looting. It is better to skip the looting and fight the other mobs first.

Enter the following code in player.lua nearby line 300

Code: Select all

	if( type(settings.profile.events.onLeaveCombat) == "function" ) then
		local status,err = pcall(settings.profile.events.onLeaveCombat);
		if( status == false ) then
			local msg = sprintf("onLeaveCombat error: %s", err);
			error(msg);
		end
	end

-- Modifikation Stephen: skip loot if nearby mobs
	hf_skip_loot = false;
	keyboardPress(settings.hotkeys.TARGET.key);      -- more mobs there?
	if( self:haveTarget() ) then
		hf_skip_loot = true;
		cprintf(cli.green, language[50]);	-- skip loot, more mobs around\n
	end;
-- End of modifikation
It should also be possible to fight only mobs in the direction to the death mob and in a specific aggro distance. But thats to deep for me at the moment to realize. Hope someone other could do that.


3. Skip loot if getting aggro before looting

It is not usefull and not common human behaivor to go and loot the death mob, if you still have aggro from another mob. The following code will skip looting and first fight the aggroing mob.

Enter the following code in player.lua nearby line 300 before 'if( settings.profile.options.LOOT == true ) then'

Code: Select all

-- Modifikation Stephen, skip loot if getting aggro
	yrest(800);                          -- wait a little for battling flag update in client STEPHEN

	-- Monster is dead (0 HP) but still targeted.
	-- Loot and clear target.
	self:update();
	
	if( self.Battling ) then             --  skip looting if aggro STEPHEN
		cprintf(cli.green, language[39]);	-- aggro, skip looting
		self:clearTarget();               -- get rid of the death mob
		hf_skip_loot = true;
	end;

 	if( hf_skip_loot == false  and  self.TargetPtr ~= 0 ) then	
--	if( self.TargetPtr ~= 0 ) then       -- old code, replaced by line before
-- End of modifikation
		if( settings.profile.options.LOOT == true ) then
and new entrys for english.lua

Code: Select all

[39] = "aggro, skip looting\n",
[50] = "skip loot, nearby mobs around\n",
and deutsch.lua

Code: Select all

[39] = "\129berspringe Looten, Aggro\n",
[50] = "skip loot, nearby mobs around\n",
Modification 2 and 3 belong together.

I would be happy, if some of the code findes his way into the standard bot. I tested it with different chars, but surly not with all possibe combinations. :-(
The RoM Bot Online Wiki needs your help!

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: suggestions for code changes for looting and resting

#2 Post by Administrator » Wed Jun 10, 2009 7:03 pm

The implementation of #1 can probably be fixed up a bit. I think it belongs outside of the fight loop so that it is taken care of outside of a battle rather than inside. It could also be made a big cleaner, I think. Good job anyways, it's a proof of concept and will provide useful.

#2 could be troublesome. It could potentially lead the character running off far from his waypoints if there happens to be enemies within targetting range. Even if you check the distance between character and enemy, you would still end up attacking that target after looting. The only decent way to do this would be to clear the target after each test, but all the resting that needs to be done to synchronize variables could slow down the botting process a few seconds for each combat, which would appear very blocky and bot-like.

#3 is quite good, but it might be possible to improve the speed of it.

Code: Select all

			if( dist < lootdist ) then -- only loot when close by
				cprintf(cli.green, language[31]);
				-- "attack" is also the hotkey to loot, strangely.
				yrest(500);
				keyboardPress(settings.profile.hotkeys.ATTACK.key);
				yrest(settings.profile.options.LOOT_TIME + dist*15); -- dist*15 = rough calculation of how long it takes to walk there

				-- now take a 'step' backward (closes loot bag if full inventory)
				keyboardPress(settings.hotkeys.MOVE_BACKWARD.key);

				-- Maybe take a step forward to pick up a buff.
				if( math.random(100) > 20 ) then
					keyboardHold(settings.hotkeys.MOVE_FORWARD.key);
					yrest(500);
					keyboardRelease(settings.hotkeys.MOVE_FORWARD.key);
				end
			else
The first yrest(500) in that section of code could provide the resting, and then check after that whether or not you are still in combat. This means it would require 800 less milliseconds to run, and would only take effect when in looting range.

d003232
Posts: 1252
Joined: Wed Jun 03, 2009 4:27 pm

Re: suggestions for code changes for looting and resting

#3 Post by d003232 » Fri Jun 12, 2009 5:47 pm

Rest function:

I played a little more with the code and create a function CPlayer:rest()

Code: Select all

function CPlayer:rest()
-- rest to restore mana and healthpoint if under a certain level

	if( self.Battling == true) then return; end;		-- if aggro, go back

	if( settings.profile.options.MP_REST == nil ) then  settings.profile.options.MP_REST = 15; end;
	if( settings.profile.options.HP_REST == nil ) then  settings.profile.options.HP_REST = 15; end;

	-- some classes dont have mana, in that cases Player.mana = 0
	hf_mana_rest = (player.MaxMana * settings.profile.options.MP_REST / 100);	-- rest if mana is lower then
	hf_hp_rest   = (player.MaxHP   * settings.profile.options.HP_REST / 100);	-- rest if HP is lower then

	if( player.Mana >= hf_mana_rest  and player.HP >= hf_hp_rest   ) then	-- nothing to do
		return;								-- go back
	end;
	
	self:clearTarget();          -- get rid of mob, so we dont cast while resting
	hf_count = 30 + math.random( 69 );			-- set rest time, up to 99 sec pause
	cprintf(cli.green, language[36], hf_count);		-- resting x sec for Mana and HP
	while hf_count > 0 do
		yrest(1000);
		hf_count = hf_count - 1;	
		self:update();

		if( self.Battling ) then          -- we get aggro,
			self:clearTarget();       -- get rid of mob to be able to target attackers
			printf(language[37], hf_count );   -- get aggro at sec x
			hf_count = 0;		-- stop countdown
		end;
--		printf("ManaPZ %s HPPZ: %s\n", (player.Mana/player.MaxMana*100), (player.HP/player.MaxHP*100) );   -- debug
		if( player.Mana == player.MaxMana  and		-- some chars have MaxMana = 0
 	 	    player.HP   == player.MaxHP ) then		-- Mana and HP are full
			printf(language[38], hf_count );   -- full at sec x
			hf_count = 0;				-- stop countdown
		end;

		self:checkPotions();   
		self:checkSkills(); 		-- check if we need to cast buffs/heals.

	end;			-- end of while
end
Now the rest function is outside of the fight stuff and is called within the bot.lua at line 218, directly before the fight starts:

Code: Select all

		if( player:haveTarget() ) then
			if( player.Target == player.Address ) then
				player:clearTarget();
				-- Clear target so that we can more easily pick up aggroed monsters.
			end;

			player:rest();	-- HERE IS THE NEW REST FUNCTION

			local target = player:getTarget();
That are my first tries with lua. So I'm surly don't understand all what I'm doing. Since I make it as a function I get a yellow memory read error. I don't know why and I seems not to disturb the bot???
Attachments
error.gif
The RoM Bot Online Wiki needs your help!

d003232
Posts: 1252
Joined: Wed Jun 03, 2009 4:27 pm

Re: suggestions for code changes for looting and resting

#4 Post by d003232 » Fri Jun 12, 2009 6:24 pm

Administrator wrote:#2 could be troublesome. It could potentially lead the character running off far from his waypoints if there happens to be enemies within targetting range. Even if you check the distance between character and enemy, you would still end up attacking that target after looting.
Skip looting if there are more mobs around:

I think a way could be to use that only for ranged attack chars. They will not run away. Just stand and kill the mobs standing there. And melee chars have better armor :-) They have better chances to survive if they run into mob groups.

Code: Select all

	hf_skip_loot = false;
	if( settings.profile.options.COMBAT_TYPE == "ranged"  ) then
		keyboardPress(settings.hotkeys.TARGET.key);      -- more mobs there?
		if( self:haveTarget() ) then
			hf_skip_loot = true;
			cprintf(cli.green, language[50]);	-- skip loot, more mobs around\n
		end;
	end;
The whole loot stuff is behind the fight things in the player.lua. Wouldn't it better also to have a 'loot' function which is called in the bot.lua?
The RoM Bot Online Wiki needs your help!

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: suggestions for code changes for looting and resting

#5 Post by Administrator » Sat Jun 13, 2009 2:57 am

Good work. I'm not sure why you're getting that warning off-hand. The best thing to do is to add a few printf() statements every few lines that print some unique text. Once you've done that, run the bot again and wait till you see the warning. Look at which text shows up directly prior to the warning, and that will help give you an idea of where the problem is.

Alternatively, you can also open bot.lua and change

Code: Select all

DEBUG_ASSERT = false;
to

Code: Select all

DEBUG_ASSERT = true;
and run the bot again. It should help tell you which object the error is in (if it's in CPlayer, then you know it's a problem with the player, if it's a CPawn with your target's name, then this tells you that it's a problem with reading information from your target).

d003232
Posts: 1252
Joined: Wed Jun 03, 2009 4:27 pm

Re: suggestions for code changes for looting and resting

#6 Post by d003232 » Sun Jun 14, 2009 11:31 am

I'm trying the 'DEBUG_ASSERT = true;' option but there are not more messages. Don't know why.

Then I set printf commands. So I found that the error message happens in the bot.lua line 219

Code: Select all

				if( target:haveTarget() and target:getTarget().Address ~= player.Address and (not player:isFriend(CPawn(target.TargetPtr))) ) then
I go one step deeper and set an printf in pawn.lua

Code: Select all

function CPawn:haveTarget()
	local proc = getProc();
printf("DEBUG: CPawn:haveTarget vor mem\n");	-- STEPHEN
printf("proc: %s self.Address: %s charTargetPtr_offset: %s\n", proc, self.Address, charTargetPtr_offset );   -- debug
	self.TargetPtr = memoryReadInt(proc, self.Address + charTargetPtr_offset);
printf("DEBUG: CPawn:haveTarget nach mem\n");	-- STEPHEN
	if( self.TargetPtr == nil ) then self.TargetPtr = 0; end;
As an result if get directly befor the 'buggy' memoryReadInt from the printc the field content:

proc = 'userdata: 03534BF0'
self.Address = '0'
charTargetPtr_offset = '608'

I cant do anything with that informations. Hope it helps you.
Attachments
screenshot.gif
The RoM Bot Online Wiki needs your help!

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: suggestions for code changes for looting and resting

#7 Post by Administrator » Sun Jun 14, 2009 4:15 pm

I think the problem might be in player.lua. Look for this:

Code: Select all

function CPlayer:haveTarget()
	if( CPawn.haveTarget(self) ) then
		local target = self:getTarget();
Directly under that last line (local target = self:getTarget()), add this:

Code: Select all

		if( target == nil ) then
			return false;
		end;

d003232
Posts: 1252
Joined: Wed Jun 03, 2009 4:27 pm

Re: suggestions for code changes for looting and resting

#8 Post by d003232 » Sun Jun 14, 2009 7:01 pm

That didn't help.

I suppose it is the 'target:haveTarget()' in the line

Code: Select all

if( target:haveTarget() and target:getTarget().Address ~= player.Address and (not player:isFriend(CPawn(target.TargetPtr))) ) then
Because in the rest function shortly before I do a 'self:clearTarget();' to be able to target attacking mobs while resting.
The RoM Bot Online Wiki needs your help!

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: suggestions for code changes for looting and resting

#9 Post by Administrator » Sun Jun 14, 2009 7:20 pm

The problem seems to come from player:haveTarget(). It seems to be returning true indicating that it has a target, which then causes target:haveTarget() to try to be called. The problem is that target's address is 0, which is invalid.

Try adding a few more debug statements to function CPawn:haveTarget() to print the object's name, address, targetPtr, and other information.

Code: Select all

printf("Name: [%s], Address: 0x%X, Target: 0x%X\n", tostring(self.Name), tostring(self.Address), tostring(self.TargetPtr));

d003232
Posts: 1252
Joined: Wed Jun 03, 2009 4:27 pm

Re: suggestions for code changes for looting and resting

#10 Post by d003232 » Sun Jun 14, 2009 7:48 pm

The result is <UNNOWN> and Adress 0x0 and Target 0x0.

Should it also be the name of my char? Or the name of the target?
Attachments
error.gif
The RoM Bot Online Wiki needs your help!

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: suggestions for code changes for looting and resting

#11 Post by Administrator » Sun Jun 14, 2009 8:14 pm

Now, in pawn.lua (CPawn:haveTarget()), find this:

Code: Select all

	self.TargetPtr = memoryReadInt(proc, self.Address + charTargetPtr_offset);
	if( self.TargetPtr == nil ) then self.TargetPtr = 0; end;
Under that, add another printf statement to display what self.TargetPtr is.

And, under this:

Code: Select all

	local tmp = CPawn(self.TargetPtr);
Add:

Code: Select all

printf("%s's target: %s\n", tostring(self.Name), tostring(tmp.Name));

d003232
Posts: 1252
Joined: Wed Jun 03, 2009 4:27 pm

Re: suggestions for code changes for looting and resting

#12 Post by d003232 » Mon Jun 15, 2009 3:44 am

Some more informations: It is coming from the 'target:haveTarget()' at line 219 in bot.lua

Code: Select all

				if( target:haveTarget() and target:getTarget().Address ~= player.Address and (not player:isFriend(CPawn(target.TargetPtr))) ) then
					cprintf(cli.red, language[5], target.Name);
				else
If I do x-times some 'printf( target:haveTarget() );' before that line I get the error x-times.

And it happens, because in my modification to rest, that I call as a function in bot.lua straight before, I have a 'self:clearTarget();'. If I add

Code: Select all

	keyboardPress(settings.hotkeys.TARGET.key);		-- STEPH03 more mobs there?
	self:update();
at the end of my function to get some new target, then there is no error anymore.

Think there should be a

Code: Select all

if( CPawn(self.Address) == 0  then return false; ...(
or something like that BEFORE the 'self.TargetPtr = memoryReadInt(proc, self.Address + charTargetPtr_offset);' in the pawn.lua.
The RoM Bot Online Wiki needs your help!

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: suggestions for code changes for looting and resting

#13 Post by Administrator » Mon Jun 15, 2009 3:57 am

player:haveTarget() should be returning false in the case that you are clearing the target. You are clearing the target after the calls to check if there is a target which is to protect from enacting on nil targets. This is the problem.

You should move your call to player:rest() outside of that check.

aasi888
Posts: 64
Joined: Fri May 15, 2009 5:13 am

Re: suggestions for code changes for looting and resting

#14 Post by aasi888 » Sat Jul 04, 2009 5:24 am

Admin could you add this to the bot? I tried myself but it gives me errors. Atm the bot doesn't check if there is enough hp when starting combat.

d003232
Posts: 1252
Joined: Wed Jun 03, 2009 4:27 pm

Re: suggestions for code changes for looting and resting

#15 Post by d003232 » Mon Jul 06, 2009 7:30 am

aasi888 wrote:Admin could you add this to the bot? I tried myself but it gives me errors. Atm the bot doesn't check if there is enough hp when starting combat.
Atm I'm in holiday. If I'm back at home after the 11th I can describe a little better, how to clean implement the rest function.
The RoM Bot Online Wiki needs your help!

d003232
Posts: 1252
Joined: Wed Jun 03, 2009 4:27 pm

Re: suggestions for code changes for looting and resting

#16 Post by d003232 » Sat Jul 11, 2009 6:13 pm

aasi888 wrote:Admin could you add this to the bot? I tried myself but it gives me errors. Atm the bot doesn't check if there is enough hp when starting combat.
I described the modification in a new post here
The RoM Bot Online Wiki needs your help!

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 7 guests