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, 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 ➜ AutoIt for scripting

AutoIt for scripting

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


Pages: 1 2  

Posted by Atreju   (2 posts)  Bio
Date Tue 22 Apr 2008 06:33 PM (UTC)
Message
Hello, everybody.

As many other people playing muds I have recently come to the conclusion that scripting can make your virtual life much easier, esp. that concerns leveling, where a lot of routine work has to be done. Getting to the top level for the first time was quite a lot of fun, but killing the same monsters and wandering around the same rooms all over again just for the sake of getting a top level character of another class or without all these mistakes in stats or skills distribution that new players inevitably make, looked a bit boring. So I set myself to write that easy script, that just walks along the set rout, kills the set monsters and rests when the hp check says so.

As Lua was highly recommended at this site, I first started writing the script in this language, but I was disappointed to find few or scant manuals on Lua. Actually, I'm very far from programming in my real life, I graduated from a language department a few years ago. So to understand the logic and structure of a scripting language I need quite a comprehensive help. Anyway, when I spent half a day trying to figure out how the "if" argument works in Lua, I thought it would be a better idea to stick to AutoIt, another scripting language, with the help of which I have already made some programs of different type. The only problem with it was that it couldn't read lines directly from any client.

So what I’ve done, was a little function in Lua, that puts the demanded line into the clipboard:

function copy (x)
x=x-1
total_lines = GetLinesInBufferCount ()
SetClipboard(GetLineInfo (total_lines - x, 1))
end -- copy

AutoIt sends commands to the client through direct input to the command line, that is, it imitates a user typing. By sending the "/copy()" command it gets data from the game through the clipboard, processes it and sends commands back through the command line. I know how awful that must look like, but it works :)

Still, another method would evidently be much more welcome, since this clipboard/direct input interface appears somewhat abnormal, plus you can't use the computer while the script is working - for it to be able to type things into the client, the latter has to be active all the time, not in the background.

So I would appreciate any suggestions on how to get the external script and the client work together through a more convenient way then the one I have invented.

And thanks for reading the many letters above :)
Top

Posted by Toruk   (15 posts)  Bio
Date Reply #1 on Tue 22 Apr 2008 07:05 PM (UTC)

Amended on Tue 22 Apr 2008 07:08 PM (UTC) by Toruk

Message
Honestly Not to be mean But i think it would be better to try to stick with Lua. I just started learning it and it gets easier as time goes on. Im actually working on a auto hunter and i've got it working somewhat and I just started learning lua today.

Only thing i havent got set up is for it to follow a speedwalk and pause that speedwalk anytime it finds a mob then resume it after its dead.. As of right now It randomly chooses a direction and goes.


But i just found a script that I can use for it. And as far as everything else most of it was just using triggers and timers.. I only used a few if statements and the rest of the scripting I did was just turning off and on triggers..
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #2 on Tue 22 Apr 2008 09:24 PM (UTC)
Message
First, the book by the author of Lua is very good. This is the online version:

http://www.lua.org/pil/

You can order the hard-copy from Amazon or a similar place, if you prefer to have a book by your side.

Quote:

Anyway, when I spent half a day trying to figure out how the "if" argument works in Lua, I thought it would be a better idea to stick to AutoIt


The "if" statement works really simply. I suggest you post what you are trying if you can't make it work. You are best off using Lua rather than trying to do things with AutoIt because AutoIt won't have access to all the script functions built into the client.

As a simple example of an "if":


if health < 100 then
  print ("Oh no! health is low")
else
  print ("health is good")
end


Check out some of the many script examples of Lua on this site, it is rare to find one which does not use "if".

As for your planned bot, assuming the MUD doesn't mind that, I will give a small example in Lua of how you might get started.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #3 on Tue 22 Apr 2008 10:42 PM (UTC)
Message
OK this might help get you started. Writing an intelligent fighting bot is not a trivial task. This might be a good start. The first trick would be to move around a set route. I am doing this below with a timer that fires every two seconds, and simply walks a predefined path. You would need to start the timer at the starting point, and make sure that the path "loops", so that when it ends, you are back at the starting point.


<timers>
  <timer 
   enabled="y" 
   second="2.00" 
   offset_second="0.00"    
   send_to="12"
>
  <send>

route = {
  "s", "s", "e", "n",  -- to butcher
  "s", "w", "n", "n",  -- back again
  }

-- stay here if we are fighting or recovering

if fighting or resting then
  return
end  -- if


loc = (loc or 0) + 1  -- next way to walk

-- if past end, go back to start

if loc &gt; #route then
  loc = 1
end -- if

Send (route [loc])
</send>

  </timer>
</timers>


In that timer I have an "if" check, that if we are fighting or resting, it doesn't move you. That lets you stay in one place while you are fighting or resting.

Now you need to know when you are fighting, so you would need some sort of trigger (eg. "A * is in the room with you") that starts a fight, and another trigger that tells you when the fight is over (eg. "The * is dead!").

The trigger that starts the fight would have to make the fighting variable true, eg.


fighting = true


And when the fight is over you need to make it false again, eg.


fighting = false


That way your movement timer knows not to move you.

You would do a similar thing to rest. eg.


if hp < 150 and not resting then
  Send ("rest")
  resting = true
end -- if


A smarter system might actually work out where to go by looking at the exits. There have been a few posts about this already, search for "wilderness walker" or such thing. I think a few people have already written systems that walk around, taking whatever exits they see, fight anything they see, and just keep going.

- Nick Gammon

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

Posted by Atreju   (2 posts)  Bio
Date Reply #4 on Thu 24 Apr 2008 08:04 AM (UTC)
Message
Thanks a lot for the hints. I actually managed to create an automatic system that I wanted, and it is much more functional then before. This approach of making a complex of triggers, scripts and timers instead of a single exe was new to me, in AutoIt i had something more like a hardcode, with linear action. Now it's something much more flexible and efficient. Thanks again, for the help :)
Top

Posted by Toruk   (15 posts)  Bio
Date Reply #5 on Thu 24 Apr 2008 02:33 PM (UTC)
Message
Not sure if You know this but if you have a lot of triggers and timers and such Mushclient has an auto plug in wizard which will make all your triggers and scripts into a plug in you can use and it will clear up your triggers..
Top

Posted by Eldeon   (9 posts)  Bio
Date Reply #6 on Tue 22 Jun 2010 05:21 PM (UTC)
Message
I'm a bit confused at this actually. I know this timer takes you through the area. So do you have to make triggers for when a creature is in the room? You mentioned a trigger setting the value fighting = true so would that be the trigger that when something is in the room that your timer moves you to it sends 'kill *' to the screen? (* being a random mob name) Also I'd like to know if there is any exception or something you would have to add if the mobs move rooms. I see this script is good and all for mobs that stay where they are at. But I want to know what you'd have to do if they move.
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #7 on Tue 22 Jun 2010 08:44 PM (UTC)
Message
You basically have to replicate your thought processes. So you move around by looking for exits, and taking an exit if you aren't fighting.

Once entering a room you look for mobs. If they are the right type (eg. level) you might choose one to fight. If the mob leaves the room (the mob you are fighting) you might follow it.

For example, if you know you are fighting the kobold, and a trigger sees:


The kobold flees west!


Then that might be your cue to go west to follow it.

- Nick Gammon

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

Posted by Eloni   (28 posts)  Bio
Date Reply #8 on Thu 02 Dec 2010 08:06 AM (UTC)
Message
I've been searching the forums for hours, and I'm still quite confused on how to begin writing a script like the one above. I don't expect to be an expert scripter over night, but I don't know where to begin exactly. I have very limited experience with with Java and Ruby, so I know some basics, like what methods, variables and if/else loops are.

Most of Nick's timer method above makes sense to me, but I don't know what language it's written in, and I don't know how I would run the script through my mud client.

I plan to make bot such as this--one that wanders around killing things for me--but I don't have much knowledge of any scripting languages. I'm trying to learn lua, since most people seem to suggest it. I was wondering if there are any more excellent examples such as this, or finished scripts that I can draw intelligent solutions from.

I can write out what the script should do logically (in human english :) ) to navigate the mud and kill things, but I have no idea what lua commands I will need to accomplish these things, or even how to run a script through the mud client. (I imagine it's something like' /run myBot.lua' )

Would anyone have any advice, examples, or lua guides (hopefully as specific to making a mud bot as possible) to offer?

Thanks for the great examples on this post and many others. ;)
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #9 on Thu 02 Dec 2010 08:54 AM (UTC)

Amended on Thu 02 Dec 2010 09:04 AM (UTC) by Twisol

Message
Eloni said:
Most of Nick's timer method above makes sense to me, but I don't know what language it's written in, and I don't know how I would run the script through my mud client.

The language is Lua, within an XML wrapper representing the timer object. You can edit timer objects directly from the GUI (Game -> Configure -> Timers, click Add), but the XML format is used for (a) plugins and (b) giving it to other people. To import a timer like that, just copy everything (from <timers> to </timers>, inclusive) and click the Load button on the Timers dialog.

Eloni said:
I plan to make bot such as this--one that wanders around killing things for me--but I don't have much knowledge of any scripting languages. I'm trying to learn lua, since most people seem to suggest it. I was wondering if there are any more excellent examples such as this, or finished scripts that I can draw intelligent solutions from.

Make sure your MUD allows bots first. ;)

If you want to learn Lua, I recommend reading Programming in Lua [1]. Don't worry if you don't understand some of the more advanced material like metatables or coroutines, but it's a very good way to understand the language in general. You can also run arbitrary scripts within MUSHclient using the Immediate window (Ctrl+I or Game -> Immediate).

MUSHclient's scripting can be a little obscure sometimes, but that's what we (and the documentation) are here for. Play around with some smaller scripts, including using triggers/timers/aliases, so you understand how they work.

Eloni said:
Would anyone have any advice, examples, or lua guides (hopefully as specific to making a mud bot as possible) to offer?

Apart from the above, I would recommend building one piece at a time. For example, if you want a bot that "walks around and kill things", several things spring to mind that you may want to think about:

1. "Walking around": How will the bot know how to get from point A to point B? How will it know what point B is? Automappers have been done; the degree of difficulty depends on how hard it is to get a unique identifier for a room and its exits, and then creating a graph of rooms internally. ([EDIT]: Unless you just want to wander around at random like someone mentioned above.) Once you know your path, you need to handle any obstacles that come your way: doors, swimming, and anything else that can hinder movement.

2. "Kill things": How will it know what to kill? How will it kill? Should it pick up any loot that drops? Beside the obvious healing/mana/whatever keepup, if your MUD has any other afflictions, you'll want to handle those somehow. Combat systems have been done, but (at least on the MUD I play, which BTW doesn't allow botting) they're complex and varied machines. Your mileage may vary.

I don't mean to discourage you. I just want to bring your attention to these issues so you know about them ahead of time. Like I said, both parts above are possible and have been done in some form.

Best of luck!

[1] http://www.lua.org/pil/

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Eloni   (28 posts)  Bio
Date Reply #10 on Thu 02 Dec 2010 10:11 AM (UTC)
Message
Thanks for taking the time to type that really informative reply! It's helping a lot :]

I was in the process of writing some pseudo code for my bot, but now I'm looking at the book you linked and I'll see if I can't turn it in to LUA code.
Top

Posted by Eloni   (28 posts)  Bio
Date Reply #11 on Thu 02 Dec 2010 01:46 PM (UTC)

Amended on Thu 02 Dec 2010 08:12 PM (UTC) by Nick Gammon

Message
Thanks. The book was a tremendous help, and I bookmarked it for later reference.

Here's what I got so far. I haven't made the triggers that change the global variables and I've already encountered a problem. I'm not sure how to implement the wait function.



--- Coded by Eloni --!>
---AlmostLua v1.0 --!>

require "wait"

--- VARIABLES ---!>

ready = false  --(determined by health/mana/movement trigger, how to link the trigger to this script?)
fighting = false --(determined by multiple triggers that all indicate you're in combat)
currentPath = "none"
currentPathLocation = 1

recallWasSucessful = true --(determined by the string that displays when the spell is sucessful)


--- END VARIABLES ---!>


---  ARRAYS ---!>

--- paths ---!>
gardenPath = { "n", "w", "n", "down", "open door", "e" }
cityPath = { "w", "w", "w", "w", "n", "n" }
dungeonPath = { "s", "s", "open door", "down", "down", "s" }

listOfPaths = { gardenPath, cityPath, dungeonPath, }

--- end paths ---!>


basicCombat = { "kick", "b_bs", "cast fireball", "cast slow" }

---  END ARRAYS ---!>


---  METHODS ---!>


function pickRandomPath ()  --Picks a random area to go to when the method is called and sets it to currentPath
    currentPath = listOfPaths[rand(3)]
    print ("Current destination: " + currentPath)
end -- pickRandomPath

function moveOnPath ()
    send "currentPath[currentPathLocation]"
    currentPathLocation = currentPathLocation + 1
end -- moveOnPath

--Selects a random attack from the array when the method is called
function basicCombatEngine ()  
   -- (commented this out because I don't know the random function for lua)
   send "cry" -- basicCombat[rand(4)] 
end -- combatEngine

--Makes you sleep when the loop deems it necessary, 
--and resets the path to "none" so you're not walking around while you sleep
function regen () 
    currentPath = "none"
    Send ("sleep")
    require "wait"
    
--wait function doesn't fire at all (instintaneously prints both "sleep" and "wake"
--pretty sure it's implemented wrong
    
    wait.make (function ()   
      wait.time(180)
    end) 

    Send ("wake")
    ready = true
  
end -- regen

function sleepTimer()  --tried using this in regen(), didn't work
    wait.make (function ()
      wait.time(180)
    end)
end

---large if/else loop that determines your actions based on ready == true, and other variables ---!>

--somehow set it on a timer that's short enough not to get my character killed, and long enough so that 
--it can attack mobs it sees in the room (with a trigger)?

--will the "wait" function PAUSE THE ENTIRE SCRIPT and 
--keep the timer from checking to see if I need to escape from combat?

--ready = false(low hp and mana) and fighting = true, 
--so need to get out of combat quick & reset the bot

if ready == false and fighting == true and recallWasSucessful == false then 

  send "flee"
  send "cast recall"
  
--need to regen, not fighting, so: go back to start & regen
  
elseif ready == false and fighting == false and recallWasSucessful == true then 

--also sets currentPath to none, so the loop can continue after the "wait" is over
  regen()  

--if hp and mana are up, not fighting, and not on a path  
elseif ready == true and fighting == false and currentPath == "none" then 

  pickRandomPath()
  currentPathLocation = 1

--if hp and mana are up, not fighting, and ON A PATH  
elseif ready == true and fighting == false and currentPath ~= "none" then 

  moveOnPath()
  
elseif ready == true and fighting == true then

  basicCombatEngine()

end

  
---  END METHODS ---!>






The code compiles error free, but there is no pause between sleeping and resting.

I think a wait function is ideal in the regen() function, but I can't tell until I test it. I might be wrong, but: It bothers me that the bot could get attacked while sleeping, and it wouldn't be able to respond because the 'wait' function has paused the script.

Maybe a timer that runs separately from the 'waited' code that constantly checks to see if fighting = true, and if so 'unwaits' the code... somehow. I haven't experimented with timers yet, so I'm not sure how they work, but I assume they're ran from the mud, and not from inside the lua script.

Are there help files for the wait function? All I have are examples from this post:
http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=4956&page=1
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #12 on Thu 02 Dec 2010 08:23 PM (UTC)

Amended on Thu 02 Dec 2010 08:24 PM (UTC) by Nick Gammon

Message
I reformatted your code a bit - the very long lines made it a bit unreadable on the forum.

First point:

You don't need to do this multiple times:


require "wait"


What "require" does is load a module (wait) if it isn't already loaded. Thus you only ever need to do it once.

Second, this won't work, as you noticed:


 Send ("sleep")
    require "wait"
    
--wait function doesn't fire at all (instintaneously prints both "sleep" and "wake"
--pretty sure it's implemented wrong
    
    wait.make (function ()   
      wait.time(180)
    end) 

    Send ("wake")
    ready = true


It prints "sleep", and then makes a coroutine which starts a timer which fires in 180 seconds. Anything after wait.time(180) will be delayed. However that is inside the scope of wait.make. Your subsequent line of "wake" is not inside that scope.

In other words:


    require "wait"
   
    wait.make (function ()   
      Send ("sleep")
      wait.time(180)
      Send ("wake")  --> after 180 seconds
    end) 



The client can't actually sleep. What it can do is defer the things inside the wait.make blocks for later.

Eloni said:

I think a wait function is ideal in the regen() function, but I can't tell until I test it. I might be wrong, but: It bothers me that the bot could get attacked while sleeping, and it wouldn't be able to respond because the 'wait' function has paused the script.


Certainly you can make all this work. In fact one large coroutine might be able to run indefinitely. Check out this thread as well:

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

That describes how you can wait for something from the MUD, or a time to elapse, whichever comes sooner. So this is the ideal way of checking if you are attacked.

Something like this:


require "wait"
   
wait.make (function ()   
 
  Send ("sleep")
  mobname = wait.match ("* attacks you!", 10)

  -- if mobname, trigger matched
  if mobname then
    Send ("stand")
    Send ("cast fireball " .. mobname")
  else
  -- otherwise timed out
    Send ("cure light wounds")
  end

end) 


In this case the wait.match function returns either when the trigger matches, or some time has elapsed. This lets you react to an attack, or wait for some time.

- Nick Gammon

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

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #13 on Thu 02 Dec 2010 08:33 PM (UTC)
Message
Eloni said:
The code compiles error free, but there is no pause between sleeping and resting.

I'm splitting hairs here, but Lua isn't a compiled language. The Lua interpreter parses the script and turns it into bytecode for its own virtual machine, which it then executes. But it's never actually compiled into machine code.

Eloni said:
I think a wait function is ideal in the regen() function, but I can't tell until I test it. I might be wrong, but: It bothers me that the bot could get attacked while sleeping, and it wouldn't be able to respond because the 'wait' function has paused the script.

Maybe a timer that runs separately from the 'waited' code that constantly checks to see if fighting = true, and if so 'unwaits' the code... somehow. I haven't experimented with timers yet, so I'm not sure how they work, but I assume they're ran from the mud, and not from inside the lua script.

Nick ninja'd me, but the reason your waiting doesn't work is because wait.make creates a coroutine and runs it. When you call wait.time() inside it, it yields that coroutine back to the original context (which would be within wait.make, which returns at that point). wait.time() creates a temporary timer within MUSHclient, and the timer's script resumes the waiting coroutine.

Also keep in mind that MUSHclient is not multithreaded. When control is within a script, nothing else happens (including triggers, aliases, timers, etc.) until the script returns back. Coroutines let you save your context within a multi-step task. In this case - as Nick showed - your first (and only) task is to wait some time and then wake up. But anything outside the wait.make() block will be executed as soon as your coroutine yields control, which you seem to send "wake" immediately.

Coroutines are really fun and highly useful, they just take some extra thought and practice to build up that essential mental model.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #14 on Thu 02 Dec 2010 09:01 PM (UTC)
Message
Twisol said:

I'm splitting hairs here, but Lua isn't a compiled language. The Lua interpreter parses the script and turns it into bytecode for its own virtual machine, which it then executes. But it's never actually compiled into machine code.


I don't think compiling strictly means "to output machine code". In fact even gcc turns C source into intermediate code, which another step then turns into machine code.

From this page:

http://www.lua.org/pil/24.1.html

PiL said:

For each line the user enters, the program first calls luaL_loadbuffer to compile the code.


(my emphasis).

Anyway, I think we know what he means. The code "compiled" in that it didn't have syntax errors, but the runtime behaviour was not as expected.

- 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.


84,081 views.

This is page 1, subject is 2 pages long: 1 2  [Next page]

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.