New To muds and scripting please help :)

Post Reply
zoul
Posts: 5
Joined: Fri Jun 16, 2017 6:46 am

New To muds and scripting please help :)

Post by zoul »

Hello I just starting exploring the world of MUDs, and I gotta say its' a little daunting at first.

the main problem I'm having is learning how to script. i' cant seem to wrap my head around it.

Basically what I want to do in my script is setup a monster list so when i walk in a room it gets the name of the monster and selects it as my target from the list. From that list i would like to setup an alias to a macro so it will select and attack the monster when I press F1

#Example#
Monster list:
"Rabbit"
"Frog"
"Deer"
"Bear"


also I would like to be able to add targets to the list when I attack a monster for the first time so it automatically adds it to the list so i don't have to keep typing kill rabbit, kill rabbit....etc.

Attack "Target"
Target goes to monster list
press F1, Selects a target from monster list and attack it.

If any one can help a newbie like me learn how to do this. i would much appreciate it thanks :D

Jor'Mox
Posts: 1146
Joined: Wed Apr 03, 2013 2:19 am

Re: New To muds and scripting please help :)

Post by Jor'Mox »

So, you are going to need a number of different things set up to make this work.

First, you are going to need a script, with which everything else will interact (I like to put all the real code in scripts so you can make changes centrally, without having to find little bits in triggers and aliases and such). The script will have all of the functions that I mention later on, and it will also be used to maintain your list of targets, as a table. I'll put together some example code for that toward the bottom of the post.

Second, you will need a trigger that will look for the presence of potential enemies in the room. I don't know exactly how your particular MUD signifies that, but it might have a pattern that looks something like this:
^[aA]n? ([\w\s]+) is here.$
The ^ signifies the beginning of a line of text, and the $ signifies the end. The square brackets group things together into a "class" of characters, any of which can be matched by that position (so the [aA] will match either 'a' or 'A'), the ? means that the preceding character is optional (so there can be a 'n' or no 'n'), and \w signifies a "word" character (letters, numbers, and underscores), and \s signifies a "white space" character, spaces, tabs, etc., and the + means one or more of the preceding characters (so [\w\s]+ will match any number of word and white space characters in a row, up until capturing more will make the pattern not match any more). The parentheses signify a "capture group", which means that whatever is inside them will be available to reference with your code.

The trigger will then call a function, and pass the captured name of whatever enemy to that function for it to do something with. This function will be in the script mentioned above, and we are going to call it: check_enemy. The trigger's code will look like this: check_enemy(matches[2])
That will call the function, and pass along the second match for the trigger (the first match is always the entire text matching the trigger pattern, which in this case would be the whole line).

Then you will need an alias, that will let you capture the names of enemies that you attack, and store in your list. The pattern will look something like this: ^attack (\w+)$
Note that you can change the 'attack' portion to be whatever you want, like 'k' or 'aa', or whatever.
The alias will then call a function we will call: attack_enemy. The alias's code will look like this: attack_enemy(matches[2])

And then you need a key/macro, bound to F1, and it will call a function that we will call next_enemy. And its code will look like this: next_enemy()
Note that you MUST have the parentheses after the function name, even if you aren't giving it any arguments.

And then you need a trigger that will tell your script to clear the list of enemies it sees in the room, so that as you move around, it doesn't continue to think that the enemies in the first room are in the second room, etc. Generally, the easiest thing to trigger off of here is the line that shows the exits in the room you are walking into/looking at. Since you don't need to actually know what the exits are, you can just trigger off the beginning of the line. In the game I play, that line looks like this: [Exits: east west north south]
So, to capture that, I would use a pattern like this: ^\[Exits:
Note the backslash before the square bracket. Any character that would normally have special meaning in a trigger pattern should have a backslash before it to "escape" it, so that the pattern looks for that character, instead of interpreting it in the normal way it is used.
Your exits trigger will then call a function we will call: reset_enemies. And its code will look like this: reset_enemies()

Here is some quickly thrown together code to help fill in the blanks, and get things going for you. Note that I haven't tested this, so there might be typos and bugs and such that I failed to catch.
Code: [show] | [select all] lua
local my_enemies = my_enemies or {}  -- creates a table to store enemies to attack
local enemies_here = {}              -- creates a table to store enemies in the room
local enemy_index = 0                -- creates a variable to store the table index you are on

function check_enemy(enemy)
    for k,v in ipairs(my_enemies) do     -- goes through all known enemies, one at a time
        if string.find(enemy,v) then     -- looks for the name of an enemy anywhere in the captured text
            table.insert(enemies_here,v) -- stores the name of an enemy in the enemies_here list
            break                        -- stops the loop, since each any should only be listed once
        end
    end
end

function attack_enemy(enemy)
    if not table.contains(my_enemies,enemy) then  -- checks to make sure the enemy isn't already in the list
        table.insert(my_enemies,enemy)            -- adds the enemy to the list
    end
    send("attack " .. enemy)                      -- sends the actual command to attack the enemy
end

function next_enemy()
    enemy_index = (enemy_index or 0) + 1          -- increases the index used in the list of current enemies, so each press will attack the next enemy, in turn
    if not enemies_here[enemy_index] then         -- checks if there are no more enemies in the list
        enemy_index = 1                           -- starts over at the beginning
    end
    send("attack " .. enemies_here[enemy_index])  -- sends the actual command to attack the enemy
end

function reset_enemies()
    enemy_index = 0    -- resets the enemy index used by next_enemy
    enemies_here = {}  -- clears the list of enemies in the room
end
If you have questions about what I did or why, I'd be happy to explain, just try to ask specific questions so I can give clear answers.

zoul
Posts: 5
Joined: Fri Jun 16, 2017 6:46 am

Re: New To muds and scripting please help :)

Post by zoul »

Wow :D Thanks for the reply and explaining thing's very thoroughly. I've briefly read over what you've wrote. i'm gonna give it a good read through later and see if I can't figure out how to get this to work.

Im going to give you a little bit more information about the mud I play.

currently I'm playing a mud called zombie-mud.

This is how some of the mobs appear in the room.

A white goose waddling around
A white goose waddling around
A small yellow chicken
A small yellow chicken
A small yellow chicken
A gray sheep-dog with floppy ears
A brown rooster with green tail feathers
Denulf the farmer, inspecting his properties
A friendly lion cub
A friendly lion cub
A friendly lion cub
A friendly lion cub
A lithe white lioness
A lithe white lioness
A lithe white lioness
A regal white lion
A regal white lion
An old, scruffy rat
An old, scruffy rat
A plump rat with a long tail
A watchman of the City Guard, keeping the peace
A nondescript man selling nondescript products inna bun
A hungry looking duck
An old duck with ragged feathers
A mallard duck with a green head
An iron-clad watchman of the City Guard
A fat ermine with a black tail tip
A large fox-squirrel
A gray squirrel with a bushy tail

if you need any more information let me know.

BTW thanks a Mega-ton I really do appreciate it.
Attachments
screenshot of the mud
screenshot of the mud

zoul
Posts: 5
Joined: Fri Jun 16, 2017 6:46 am

Re: New To muds and scripting please help :)

Post by zoul »

Okay.. I think I set up every thing correctly, but it's just not working for me.

any clue what i'm doing wrong?

--Aliases--
Alias name: attack_enemy
Pattern: ^k (\w
Code: attack_enemy(matches[2])

--Triggers--
Trigger name: Colored_Area
0: Colored Trigger Fg Magenta Bg Black
|
|--Trigger Name: check_enemy
0: ^(.*)$ Perl regex
Code: check_enemy(matches[2])
|
|--Trigger Name: Close
0: return isPrompt() Lua function

--Macros--
Macro name: next_enemy
Key: F1
Code: next_enemy()

Also i changed the send command to kill instead of attack in the script

I made a visual aid of what i'm trying to do in the pic below.
Attachments
Visual script.png

Jor'Mox
Posts: 1146
Joined: Wed Apr 03, 2013 2:19 am

Re: New To muds and scripting please help :)

Post by Jor'Mox »

So, if your alias pattern is as you have it, it is missing a bit, but I'm assuming that is just a typo.

Also, you didn't list a trigger for capturing the exits, which you may have simply left out.

The problem is likely the triggers, and given that the enemies are always a particular color, what you want to do is, rather than having 3 triggers, have a single trigger, that just has the proper color to match as the pattern, and then use matches[1] instead of matches[2] (since you are using the entire line anyway). If you want to highlight the matched enemy names, so you get a visual confirmation that it is matching them correctly, you will need to modify the check_enemy function slightly, to be something like this:
Code: [show] | [select all] lua
function check_enemy(enemy)
    for k,v in ipairs(my_enemies) do     -- goes through all known enemies, one at a time
        if string.find(enemy,v) then     -- looks for the name of an enemy anywhere in the captured text
            table.insert(enemies_here,v) -- stores the name of an enemy in the enemies_here list
            selectString(v,1)            -- selects the first instance of the matched word in the current line
            setFgColor(255,255,255)      -- sets the color of the selected text to white, color set with RGB values
            -- you can also use setBgColor in exactly the same way, if you want to highlight by changing the background color
            break                        -- stops the loop, since each any should only be listed once
        end
    end
end

zoul
Posts: 5
Joined: Fri Jun 16, 2017 6:46 am

Re: New To muds and scripting please help :)

Post by zoul »

Nice!!! I got it to work w00t!. Thanks a lot man.

the script works nice but I've noticed after awhile monster stop highlighting and my macro stop working. its like the game forgets all the inputs from kill stuff. is that because i'm adding and editing different alias?

Just one more thing though. lets say i wanted to make another macro that does the same exact thing as this but with a spell. how would I go about doing this?

Example: Scom kill
Example: cast magic missile at

Jor'Mox
Posts: 1146
Joined: Wed Apr 03, 2013 2:19 am

Re: New To muds and scripting please help :)

Post by Jor'Mox »

So, regarding losing track of the enemies you have listed, any time you open up a script, and then move to anything else, the script is run again, on the assumption that something was changed. When that happens, variables get reset. I tried to bypass that with the way I declared the variable at the top, but in all likelihood, it didn't work because I used a local variable. If you want it to be more persistent, without having to worry about opening the script up, you can just remove the "local" from the front of the first declaration, and it will become a global variable. Then, the way it is declared will ensure that it persists even if you make changes to the script.

As far as changing things to allow for different ways to attack your intended target, that should be fairly simple. The easiest way is going to be changing the next_enemy function to accept an argument, that tells it what command to use, like this.
Code: [show] | [select all] lua
function next_enemy(cmd)
    enemy_index = (enemy_index or 0) + 1          -- increases the index used in the list of current enemies, so each press will attack the next enemy, in turn
    if not enemies_here[enemy_index] then         -- checks if there are no more enemies in the list
        enemy_index = 1                           -- starts over at the beginning
    end
    cmd = cmd .. " "
    send(cmd .. enemies_here[enemy_index])  -- sends the actual command to attack the enemy
end
Then, change your macros to pass along whatever text you need before the name of the target, like this: next_enemy("cast magic missile at") or next_enemy("kill")

EDIT:
Alternately, you can make some changes to the attack_enemy function to allow for different commands, and then have the next_enemy function call the attack_enemy function, so that there is only ever one place that a command is sent from (to keep things organized, and allow all changes to propagate throughout whatever you have set up more easily). Like this:
Code: [show] | [select all] lua
function attack_enemy(enemy, cmd)
    if not table.contains(my_enemies,enemy) then  -- checks to make sure the enemy isn't already in the list
        table.insert(my_enemies,enemy)            -- adds the enemy to the list
    end
    cmd = (cmd or "kill") .. " "                  -- creates a default 'kill' command, and ensures there is a space between the command and the enemy name
    send(cmd .. enemy)                            -- sends the actual command to attack the enemy
end

function next_enemy(cmd)
    enemy_index = (enemy_index or 0) + 1          -- increases the index used in the list of current enemies, so each press will attack the next enemy, in turn
    if not enemies_here[enemy_index] then         -- checks if there are no more enemies in the list
        enemy_index = 1                           -- starts over at the beginning
    end
    attack_enemy(enemies_here[enemy_index],cmd)   -- calls the attack_enemy function to send the relevant command
end
Note that this defaults to "kill" as the command, so if you want to use kill, you don't need to include any command. This means you don't need to change your original alias or macro, and only need to make the new macro include a command, with the same code for the macro as I had for the first option.

zoul
Posts: 5
Joined: Fri Jun 16, 2017 6:46 am

Re: New To muds and scripting please help :)

Post by zoul »

Man you are the best! thanks a lot my friend. :D

Post Reply