Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ MUSHclient ➜ General ➜ AI Script

AI Script

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Nobody   (38 posts)  Bio
Date Wed 04 Oct 2006 06:38 AM (UTC)
Message
Hello,

I'm interested in creating a kind of AI helper script for myself. The kind of thing(s) I'm hoping it can do, is monitor my health, and use a cure potion if I get too low without realising it. Or keep track of group mates, of 'buff' spells, basically I want it to monitor everything that I normally would but which I often miss because of spam in huge fights.

While I'm not asking for any code or anything, I'm more interested in what people think of an idea such as this. I'd like it to keep track of items in my inventory, in my containers, my eq, my health, my spells, the fighting going on (if any), and so on. Is this plausible? Or am I asking way too much? Note that I didn't say "Is this possible?", because I'm sure it's "possible", but it might be too complex to be worth the investment in time. I would like this to be like a helper bot that you get in other games (like FPS) that take care of stuff if the player drops the ball. Your thoughts?

While I'm here, another thought I had is an equipment manager. My ideal goal for this would be something that maintains a complete database of every single item in the game (obviously I'd have to put the info into it - that's not an issue). But what I'd like to do is to have "substitutions" of eq. So, for example, if you see an object on the ground:
"A shining shield made of candy is lying here."

The plugin would look that up in the item database, and replace it with:
"A shining shield made of candy is lying here. [+1000 bash, +1000 HP, +1000 food]"

This would also apply to when you look at another players eq set:

<worn on head> a silver helm of candy [+100 food, +100 WIS]

and so on. The reason I'm asking about this, is 2-fold. First off, I'm worried that doing database lookups and lots and lots of queries on just about every single line that comes from the mud might slow down gameplay to a crawl. Would it make a difference if it was an SQL server running on a different machine (but connected via a LAN)? Is there any way of doing this without introducing crippling slowdowns?

Secondly, I know that substitutions are a huge "problem" (for want of a better term) in mushclient because of how text is processed. I guess ideally I'd like to simply replace the original line with the new line containing stats, or simply append the stats on the end of the line.

I'd appreciate your thoughts on viability, complexity, possibilities, and ideas on these two ideas I've presented here. Thank you.
Top

Posted by Nick Gammon   Australia  (23,121 posts)  Bio   Forum Administrator
Date Reply #1 on Wed 04 Oct 2006 07:23 AM (UTC)

Amended on Wed 04 Oct 2006 07:26 AM (UTC) by Nick Gammon

Message
This is a good question.

I think it can be done with reasonably small amount of effort.

I would recommend storing the data in a Lua table (or set of tables). This could be saved into a file (eg. mydatabase.lua), and loaded in when the plugin loads (eg. dofile "mydatabase.lua").

If you use the name of the item as the key to the items in the table it will be very quick, as table lookups are by a hash lookup.

As an example of the time involved, there is a plugin for World of Warcraft which does a similar thing (called Informant).

It stores its data in a (Lua) file along those lines.

That file is 13082 lines long, and 728 Kb in size. This loads in under a second - which you only do once per session. In fact, I tested it - it loaded 100 times in 9 seconds, so that is about 1/10 of a second to load that file. Lua is designed for this sort of thing.

It has a few things inside this file, but the main item is a database of objects, which contains 11693 items.

I think the easy way of displaying the data would be to use a trigger to omit from output, and replace with your own line which incorporates the extra information from the database. You could also colour the line to indicate the value of the item in question.

Personally I would stick to the Lua lookup, doing an SQL query for every line *would* be slow, and the Lua way is demonstrably very quick.

For the lookup time, a quick test showed I could look up 2,380,952 items *per second* in the Lua table (of 11693 items in total). In their case they were using an integer key, not a string key, but I think you will find that the performance with string keys will be acceptable. ;)

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,121 posts)  Bio   Forum Administrator
Date Reply #2 on Wed 04 Oct 2006 07:37 AM (UTC)
Message
I was really responding to the 2nd part of your question then.

As for the heals and so on, that has been tackled before on this forum with an "auto-cure" script a little while back.

I think that is certainly feasible, you detect what needs doing (cures, hunger, thirst, stuns etc.) and order them into priority.

Then you apply the appropriate cure, detect when you can do another one, and repeat. It should be easy enough to do.

You could look into using coroutines for that purpose, that might simplify the writing of the code.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,121 posts)  Bio   Forum Administrator
Date Reply #3 on Wed 04 Oct 2006 07:42 AM (UTC)
Message
Here is an example of a auto-cure routine:

http://www.gammon.com.au/forum/?id=6074

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nobody   (38 posts)  Bio
Date Reply #4 on Wed 04 Oct 2006 07:52 AM (UTC)
Message
Thanks for all the info Nick. I'll have to do my own testing on the lua tables thing, because I'm a little unsure as to how to get it to work, how to store each item, and so on, but from the sounds of things it'll be fine. Am I correct in thinking that it basically loads everything into memory at the start of a session, so it's basically just grabbing (and replacing) lines from memory without file or network-sql lookups? Do you have any example code or plugins that use a lua table database so I can see how it works?

As for the AI part, I don't want just a cure script. That's one minor part of the whole that I want. Cure scripts are pretty basic too from what I've seen. It monitors your hp, and if it gets below a certain percentage/number, it quaffs a potion. Easy as pie. What I want is a script that monitors everything, from affects on you, to affects on groupmates, on the mob you're fighting, to food/water, to items in the room, even (if possible) to making it intelligently handle various room and combat options. I don't want it simply to be a whole bunch of triggers that fire when certain conditions are met. I want it to analyse the situation, and with all available information, decide what to do. For example, if you get hungry, eating food is a good idea. I'd like for it to keep track of which containers in your inventory have food. I'd like for it to notice if you're in combat (or some other condition that prevents you from eating), and when those conditions wear off, it handles the food thing. In fact, it doesn't even have to handle it automatically, it can just print a nice little message to screen informing yu something you may have missed. Do you see what I'm trying to get it to do?
Top

Posted by Nick Gammon   Australia  (23,121 posts)  Bio   Forum Administrator
Date Reply #5 on Wed 04 Oct 2006 09:43 PM (UTC)
Message
Sure, sounds like a fun project.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nobody   (38 posts)  Bio
Date Reply #6 on Fri 03 Nov 2006 11:24 PM (UTC)
Message
Nick,

I've finally got around to implementing my item database. It works just fine, except for one problem. It's slow. Very very slow. Not just in loading (it takes about 8 seconds to load, but since that's done at the start of a session it doesn't bother me), but in execution.

Let me give details of the exact setup, and then I'll show you just how slow it is.

The datafile I'm loading is 725kb, comprising 28,615 lines. Roughly in the same format as I mentioned earlier:
Affects: HITPOINTS by +1000

There's other things in there too, but I've got the code loading everything into a lua table just fine, using the object name as the key in the table.

Now, the trigger matches on *, and runs through a script that basically has to search the entire table of items (comprising some 2715 objects) and then replace the found text (if any) with the text+stats.

	function mytrigger (name, line, wildcards, styles)
	local temp;
		for k, v in ipairs (styles) do
			for k1, v1 in pairs (db) do
				if v1["short_d"] ~= nil then

					if string.find(v.text, nocase(v1["short_d"])) then
					local temp_line = build_lore(v1)
					v.text = string.gsub(v.text, nocase(v1["short_d"]), v1["short_d"]..' ' ..temp_line)
				end -- if
	end -- if			
	if v1["long_d"] ~= nil  then
	if string.find(v.text, nocase(v1["long_d"])) then
					local temp_line = build_lore(v1) --["damage"]
					v.text = string.gsub(v.text, nocase(v1["long_D"]), v1["long_D"]..' ' ..temp_line)
				end -- if
				end -- if
	
			end -- for
			ColourTell (RGBColourToName (v.textcolour), RGBColourToName (v.backcolour), v.text)
	
		end -- for loop
	  Note ""
	
	end -- function


Now, as you can see, on every line, it has to loop through 2700 objects, and use a string.find on the line for each of them. I knew it would be slow, but I never knew just how slow....

My test: I have a linux machine, and my windows machine, each connected to a gigbit switched network. To test the speed, I connect to the linux machine, and issue the following command: "time cat /etc/termcap-BSD". The file is 16470 lines long, and 706385 bytes. With no triggers enabled, this takes 0.525 seconds to send the entire file to mushclient. With the trigger enabled, it takes 3 minutes, 9 seconds. It's roughly 360 times slower with this trigger.

My machine is a dual-core athlon, each core is 1.7GHz, and I have 2gb of RAM. My video card is a 7800GT, with 256MB of memory and the latest drivers.

Your thoughts ?
Top

Posted by Nick Gammon   Australia  (23,121 posts)  Bio   Forum Administrator
Date Reply #7 on Sat 04 Nov 2006 04:03 AM (UTC)

Amended on Sat 04 Nov 2006 04:04 AM (UTC) by Nick Gammon

Message
Quote:

There's other things in there too, but I've got the code loading everything into a lua table just fine, using the object name as the key in the table.

Now, the trigger matches on *, and runs through a script that basically has to search the entire table of items (comprising some 2715 objects) and then replace the found text (if any) with the text+stats.


Well I am not surprised it is slow, because you are not using a keyed lookup. Not only that, but you are checking each style, for the long description and the short description. So, for 16,470 lines, with each line having maybe 2 styles, and you are checking 2,715 objects for a short and long description, you are doing something like 16,470 * 2 * 2,715 * 2 = 178,864,200 lookups.

I was expecting that you would identify the text to be substituted, eg. in your example:


<worn on head> a silver helm of candy [+100 food, +100 WIS]


So, from the MUD you get:


<worn on head> a silver helm of candy


Now you want a trigger like this:


Match: <worn on *> *


The second wildcard is the object description, so you do a keyed lookup, not a linear search, eg.


details = db ["%2"]


In other words, if the item is "a silver helm of candy" then you are doing:


details = db ["a silver helm of candy"] --> [+100 food, +100 WIS]


That would be fast. You have to design it in such a way that you can make use of keyed lookups, or it will be slow. For your other example of something lying on the ground, you would need something like:


Match: * is lying here.



- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,121 posts)  Bio   Forum Administrator
Date Reply #8 on Sat 04 Nov 2006 04:14 AM (UTC)
Message
Quote:

The file is 16470 lines long, and 706385 bytes. With no triggers enabled, this takes 0.525 seconds to send the entire file to mushclient. With the trigger enabled, it takes 3 minutes, 9 seconds. It's roughly 360 times slower with this trigger.


My other comment here is that you are still getting 87 lines per second through here. It is much slower than usual, but probably keeping up with the MUD. I mean, I can't read 87 lines a second personally.

Even using your approach you might get acceptable speed out of it by not simply matching on a "*" wildcard, which would be every line including room descriptions etc., but make it match stuff like "is lying here" and "<worn on *>". By reducing the number of lines it has to process, even your brute-force technique might be fast enough.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


23,000 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.