Bots need to be aware of what actions are available to them. Some skills/spells are learned over time rather than granted to the character upon creation.
Further, being able to check skills can avoid writing multiple bots for different character types, instead basing behavior on available skills and assigned roles and goals.
For the bot to know whether it currently has a skill, the two most obvious approaches are:
- Attempt to use it and observe the server response to see if the result amounts to “you don’t have this skill” or if it’s a response associated with actual use and success/failure.
- Use the practice command to check the skills list and set flags for skills attained
The second approach has two advantages: it scales better for checking large numbers of skills and we can use it more generally because some skill checks might have resource costs or take time to execute. A skill might also cause annoyance or harm to bystanders, making blind repetitive tests undesirable.
Again using the NukeFire mud and CMUD for our example, we will set up the following logic:
- issue the ‘practice’ command (alias)
- receive the success/start of list message (trigger)
- receive a series of lines representing the skills available (separate triggers)
- then receive a prompt line (trigger)
- OR time out without receiving the start of list message
- receive the success/start of list message (trigger)
It would also be possible to check for more specific failure messages without waiting for a timeout, but skill checks should generally only be performed during downtime when a possible delay of a few seconds should be acceptable.
For NukeFire, the successful response to the ‘practice’ command is a line saying “Skill Information:” followed by other information including class and individual skills. For this example, we’ll ignore some of the details in favor of simply noting which skills are present (regardless of skill level and class).
The regular expression for one of the skills is:
^([a-zA-Z]([a-zA-Z]|[ ][a-zA-Z])*).*}
We do have a choice here, though: we can either use a general purpose trigger such as the above to catch each skill as we go along and process it or we could create individual triggers for each of the skills we’re interested in.
If we use the single trigger to build up a list of available skills, then that lets us build this generic set of triggers to assemble a skill list and then let other scripts look at the list to decide how to handle it.
This leads to better modularity because other triggers can store the results in whatever way is most convenient for them rather than modifying this set of skill triggers to set flags in different ways when additional functionality as added downstream.
CMUD supports list variables and provides functions to review and edit the lists, so it is very easy to just build up a string list of skills we have as we work through the list.
#TRIGGER {^([a-zA-Z]([a-zA-Z]|[ ][a-zA-Z])*).*} {#ADDITEM skills %1} "" "regex"
Putting it all together, we create a class which contains aliases and triggers to ask the server for the skills list, handling failure if the server doesn’t provide a success response within the expected time.
Upon success, a global variable “skills” will be populated with a list of the skills attained. Viewed as a string, it will look like “Firstskill|Second Skill” etc., where spaces are allowed and the pipe is the separator. CMUD’s %ismember function allows you to test whether a given skill is available to the character, such as #IF (%ismember(“self repair”, @skills)) {#PRINT We have selfrepair!}
#ALIAS {getskills} {#ALARM {+5} {endgetskills};#VAR skillcheck 0;#T+ skills;practice}
#alias {endgetskills} {#IF (@skillcheck==0) {#ECHO "SKILL CHECK FAILED"} {#ECHO Skillcheck: @skillcheck};#T- tmpskill;#T- tmpblank;#T- skills}
#TRIGGER tmpskill {^([a-zA-Z]([a-zA-Z]+|([ ]([a-zA-Z])+))*)[ ].*} {#ADDITEM skills %1;#VAR skillcheck 1} "skills" "regex|disable"
#TRIGGER tmpblank {^$} {#IF (@skillcheck == 1) {#T- tmpskill;#T- tmpblank}} "skills" "disable"
#TRIGGER {^Skill Information\:} {#VAR skills "";#T+ tmpskill;#T+ tmpblank} "skills" "regex"
#T- skills
The only tricky part here is the enabling/disabling of triggers to capture different types of lines without firing when they shouldn’t and being neatly grouped for modular code. This highlights an issue common to most of the major mud clients: difficulty providing a flexible way to handle multiple line command responses in a way that recognizes a correct pattern of multiple lines, possibly including a list for which each item should be captured. The syntax to handle such a pattern and capture is beyond standard regular expressions.
CMUD in particular has a feature for triggers with states (#CONDITION). For this demonstration, using that feature would have made the concepts harder to understand and to use in other clients such as Tintin, Mushclient, or Mudlet.