MUSH Client Scripting

JorachimJorachim Member Posts: 83 ✭✭✭
edited October 2012 in Scripting
Because everyone else uses those other, sadder clients.

If you need help with it, come here.
Someone powerful says, "Its broken. No more pulling the guillotine."
Post edited by Garryn on
Abigail
«1

Comments

  • AbigailAbigail Member Posts: 332 ✭✭✭
    edited October 2012
    I use MUSHclient! It's actually a really fantastic and fast little client, and I can actually figure out how to make an alias or a trigger on it without having to sacrifice my cat to Yug-cthaaug, the Duke of Sin.

    The only thing is, advanced scripting fails me. Things like "how to make my targeting alias echo the chosen target and/or call the target on RT when I target it".
  • DelrayneDelrayne Member Posts: 457 ✭✭✭
    if you can make aliases that send commands to the game, then you can add the ability to RT your target the same way.

  • JorachimJorachim Member Posts: 83 ✭✭✭
    Abigail said:
    I use MUSHclient! It's actually a really fantastic and fast little client, and I can actually figure out how to make an alias or a trigger on it without having to sacrifice my cat to Yug-cthaaug, the Duke of Sin.

    The only thing is, advanced scripting fails me. Things like "how to make my targeting alias echo the chosen target and/or call the target on RT when I target it".
    I use Lua coding, so assuming an alias of t *

    SetVariable("target", "%1")
    Send("rt Targetting: %1")
    Someone powerful says, "Its broken. No more pulling the guillotine."
    Abigail
  • KhizanKhizan Member Posts: 2,648 ✭✭✭✭✭
    edited October 2012
    Abigail said:
    The only thing is, advanced scripting fails me. Things like "how to make my targeting alias echo the chosen target and/or call the target on RT when I target it".
      If you do this, put a switch in there so that you don't spam ring with "target: rat" or "target: demon" or other crap like that all the time. That is the most irritating goddamn thing.

    "On the battlefield I am a god. I love war. The steel, the smell, the corpses. I wish there were more. On the first day I drove the Northmen back alone at the ford. Alone! On the second I carried the bridge! Me! Yesterday I climbed the Heroes! I love war! I… I wish it wasn’t over."

    JorachimApoloc
  • AbigailAbigail Member Posts: 332 ✭✭✭
    Delrayne said:
    if you can make aliases that send commands to the game, then you can add the ability to RT your target the same way.
    Eh, basic alias scripting for Mushclient works like this:

    image

    Basically, I can either send to output, or send to a variable, but I can't do both without scripting. You can do some basic Lua scripting and suchlike, but I couldn't code my way out of a wet paper bag (something that I actually tried doing in a MOO once.)
  • DelrayneDelrayne Member Posts: 457 ✭✭✭
    Jorachim said:
    Abigail said:
    I use MUSHclient! It's actually a really fantastic and fast little client, and I can actually figure out how to make an alias or a trigger on it without having to sacrifice my cat to Yug-cthaaug, the Duke of Sin.

    The only thing is, advanced scripting fails me. Things like "how to make my targeting alias echo the chosen target and/or call the target on RT when I target it".
    I use Lua coding, so assuming an alias of t *

    SetVariable("target", "%1")
    Send("rt Targetting: %1")
    @Abigail

  • JorachimJorachim Member Posts: 83 ✭✭✭
    alias t *

    announce = GetVariable("announceTarget") or "0"

    SetVariable("target", "%1")

    if announce == "1" then
    Send("rt Targeting: %1")
    end

    -----

    alias ann

    announce = GetVariable("announceTarget") or "0"

    if announce == "1" then
    SetVariable("announceTarget", "0")
    ColourNote("#FF0000", "", "Won't announce the target to ring.")
    else
    SetVariable("announceTarget", "1")
    ColourNote("#00FF00", "", "Announcing the target to ring.")
    end

    -----

    alias bash

    target = GetVariable("target")
    Send(string.format("kill %s", target))
    Someone powerful says, "Its broken. No more pulling the guillotine."
    Abigail
  • AbigailAbigail Member Posts: 332 ✭✭✭
    Thank you, you're awesome. I might actually learn something from this, too!
  • KyrockKyrock Member Posts: 35 ✭✭

    Abigail said:
    Delrayne said:
    if you can make aliases that send commands to the game, then you can add the ability to RT your target the same way.
    Eh, basic alias scripting for Mushclient works like this:

    image

    Basically, I can either send to output, or send to a variable, but I can't do both without scripting. You can do some basic Lua scripting and suchlike, but I couldn't code my way out of a wet paper bag (something that I actually tried doing in a MOO once.)
    you can do both without scripting. You make two aliases the same.Chane the sequence that sends to variable to 99 instead of the default 100 and check keep evaluating and then make the other with a sequence 100 and send to mud with rt %1
  • AbigailAbigail Member Posts: 332 ✭✭✭
    Yeah, taking a look at Jorachim's couple of aliases, I think Lua seems simple enough to get a basic hold of. I've always had a phobia of coding. I scream like a little girl and run away whenever I see semicolons.
  • KyrockKyrock Member Posts: 35 ✭✭
    well, I don't use lua, but I think it doesn't use semicolons...maybe for loops but I doubt you'll be touching those for a while...or that loop. :P
  • KyrockKyrock Member Posts: 35 ✭✭
    edited October 2012
    oh, and you should go here if you really want to get into it.
  • JorachimJorachim Member Posts: 83 ✭✭✭
    Kyrock said:
    oh, and you should go here if you really want to get into it.
    MUSHclient uses Lua 5.1, last I recall. There are some differences, although not much:

    Kyrock said:
    you can do both without scripting. You make two aliases the same.Chane the sequence that sends to variable to 99 instead of the default 100 and check keep evaluating and then make the other with a sequence 100 and send to mud with rt %1
    You can, but I -hate- splitting aliases, and then on top of that your problem doesn't solve turning off RT when they don't want to say it. They'd have to manually activate/deactivate the alias.

    They can label the aliases for help, though.
    Someone powerful says, "Its broken. No more pulling the guillotine."
  • AbigailAbigail Member Posts: 332 ✭✭✭
    I made a nice little autobashing script after taking a look at that targeting script! It's pretty much an alias that toggles a variable and a trigger that does 'kill <target>' on regaining EQ if that variable is 1. So you only have to hit a target once and it'll keep attacking until it's dead.

    I feel so proud! Even though a monkey with a typewriter could have done the same thing.
  • KyrockKyrock Member Posts: 35 ✭✭
    edited October 2012
    @jorachim I was just showing that it wasn't impossible without coding. Just like solving the rt on and off thing isn't. aliases: anon send to var announce: announcebash, anoff send to var announce: bash,  t * send to var target: %1, t * send to execute: @announce, bash send to world: kill @target, announcebash send to world rt @target;kill @target.

    @abigail welcome to addicting world of coding. It's like a puzzle...even though I don't like puzzles :p
  • KyrockKyrock Member Posts: 35 ✭✭
    Been working on my new healer and just got the logic left. I read a textbook on discrete mathematics, in six days (*flex brain*), to get as far as I have already. I'm thinking there might be a way to calculate a probability of producing an empty set then the current way I'm going about it. I.e. h1 = {a1,a2,a3}, h2 = {a1,a2,a3},h3 = {a1,a2} P(a1) then figure out the odds of a1 and a2 being cured via h1 and h2...But, since 6 days of reading does not make me a master at set theory and all that jazz, then this is the way I'm going about it:

    //this is in javascript.

    function test() {
        world.Note("<---begin test--->");
        var h1 = new Utilities.Set([{name:"a1",value:"a1"},
                                    {name:"a2",value:"a2"},
                                    {name:"a3",value:"a3"}
                                    ]);
        var h2 = new Utilities.Set([{name:"a1",value:"a1"},
                                    {name:"a2",value:"a2"},
                                    {name:"a3",value:"a3"}
                                    ]);
        var h3 = new Utilities.Set([{name:"a1",value:"a1"},
                                    {name:"a2",value:"a2"}
                                    ]);
        var h4 = new Utilities.Set([{name:"a1",value:"a1"},
                                    {name:"a2",value:"a2"},
                                    {name:"a3",value:"a3"},
                                    {name:"a4",value:"a4"}
                                    ]);
        var hSet = new Utilities.Set([{name:"h1",value:h1},
                                      {name:"h2",value:h2},
                                      {name:"h3",value:h3}//,
                                      //{name:"h4",value:h4}
                                     ]);                                 
        //how many combinations there are without repeats.
        var permutations = Utilities.factorial(hSet.size);
        //this function modifies the position for mathmatical purposes later in another function.
        function posAllowed(pos) {
            pos += 1;
            //this is the total amount of times an element
            //is allowed to show in any given column.
            return Utilities.factorial(pos)/pos;
        }
        //gets a copy of the array elements held in a set object.
        //this is used as an absolute reference for wrkArray.
        var path = hSet.elements.concat();
        //wrkArray holds pointers to relative position.
        //i.e. path ='s ["H1","H2","H3"];
        //if wrkArray = [0,2,1] then
        //it would make a path of: H1,H3,H2
        var wrkArray = [];
        //initializes wrkArray to 0,1,2...
        for (var pc = 0;pc < path.length;pc++) {
            wrkArray.push(pc);
        }
        //a display function for testing.
        function testing(rAry,rPath) {
            var str = "path: " + rPath[rAry[0]];
            for (var tCount = 1;tCount < rPath.length;tCount++){
                str += ", " + rPath[rAry[tCount]];
            }
            world.note(str);
        }
        //should've named this something else.
        //this function is used in a loop and is passed the count(iteration)
        //and a reference to an absolute path and pointer array.
        //it then modifies the pointer array that makes it possible
        //to get all combinations(without repeat) of a given set.
        //In this sample situation, it is given a path of [h1,h2,h3]
        //and a pointer array of [0,1,2]. give the combinations
        //h1,h2,h3
        //h1,h3,h2
        //h2,h3,h1
        //h2,h1,h3
        //h3,h1,h2
        //h3,h2,h1
        //some math to notice. As said before, the amount of combinations
        //without repeat is a factorial of the amount of elements. In this case
        //there is 3 elements: h1,h2,h3. factorial of 3 is 3 * 2 * 1 = 6.
        //also note that the total amount of any element in any column is 2 in this case.
        //I got a general formula of (exlemation mark is used to say factorial) -
        //(number of elements)! / number of elements. This will give the given amount
        //of any element in a column. 6/3 = 2.
        function possibleCombinations(iteration, rAry, rPath) {
            //prevents some divide by zero errors.
            if (iteration != 0) {
                //pos = current position...starting right to left.
                var pos;
                for (var pCount = 0;pCount < rPath.length - 1;pCount++) {
                    //-1 because we don't like out of range errors *sage nod*.
                    pos = rPath.length - 1 - pCount;
                    //posAllowed give me(in this case) the 6/3 = 2 thing.
                    //the way this logic works is if it's at position 1 or 2(right to left)
                    //it will just switch position 1 and 2. This works out because position
                    //1 and 2 are the last elements to be checked for switching. If any positions
                    //are switched before it, then it returns out of the function...this function
                    //only switches once in any given iteration.
                    if (iteration % posAllowed(pos) == 0) {
                        var temp;//holding variable.
                        //this checks if it's in position 2 and switches 1 and 2 if it is.
                        if (rPath.length - pCount == 2) {
                            temp =rAry[pCount];
                            rAry[pCount] = rAry[pCount + 1];
                            rAry[pCount + 1] = temp;
                        } else {//else it's in position 3 or greater.               
                            temp = rAry[pCount];
                            rAry[pCount] += 1;
                            //this searches for the position of the element that is
                            //pointing at the element it needs to switch to.
                            //so, at h1,h3,h2 rAry is [0,2,1] and rAry[0] needs to be incremented
                            //to 1, so it searches for the position that holds one and makes it 0.
                            //( in the case that the position is deeper, which would happen in 4+
                            //element sets, it increments to the next available value isn't behind it.
                            if (rAry[pCount] >= rPath.length) {
                                var fCount = 0,increment = 0;
                                while (fCount < pCount) {
                                    if (rAry[fCount] == increment) {
                                        increment++;
                                        fCount = 0;
                                    }
                                    fCount++;
                                }
                                rAry[pCount] = increment;
                            }
                            //search for pointer with the same value.
                            var sCount = 0;
                            var sBool = false;
                            while (sCount < rAry.length && sBool == false) {
                                if (rAry[sCount] == rAry[pCount] && sCount != pCount) {
                                    if (sCount < pCount) {
                                        rAry[pCount] += 1;
                                        sCount = 0;
                                    } else {
                                        rAry[sCount] = temp;
                                        sBool = true;
                                    }
                                } else {
                                    sCount++;
                                }
                            }
                        }
                        return;
                    }
                }
            }
        }
        //check if it can cause an empty set. returns true if it does.
        function pathCheck(rAry,rPath) {
            var c = 0, i = 0, k = 0;
            var cPath, pPath;
            var missBool = false, checkPath;
            var currentSet;
            while (c < rPath.length && missBool == false) {
                currentSet = hSet[rPath[rAry[c]]];
                //not possible to produce empty sets if there's not even enough
                //healing methods to remove all elements in it.
                //so, if current amount of elements is <= the amount of methods before the current methods position.
                if (currentSet.size <= rPath.length - (rPath.length - c)) {
                    cPath = currentSet.elements.concat();
                    pPath = [];
                    //populate pointers
                    for (var j = 0;j < cPath.length;j++) {
                        pPath.push(j);
                    }
                    //while i < the amount of permutations of the current healing method.
                    while (i < Utilities.factorial(currentSet.size) && missBool == false) {
                        possibleCombinations(i,pPath,cPath);
                        testing(pPath,cPath);
                        checkPath = true;
                        while (k < cPath.length && checkPath == true) {
                            if (!(cPath[pPath[k]] in hSet[rPath[rAry[c]]])) {
                                checkPath = false;
                            }
                            k++;
                        }
                        if (checkPath == true) {
                            missBool = true;
                        }
                        i++;
                    }
                }
                c++;
            }
            return missBool;
        }
        for (var c = 0;c < permutations;c++) {
            possibleCombinations(c,wrkArray,path);
            if (!pathCheck(wrkArray,path)) {
                testing(wrkArray,path);
                world.Note ("is a path that doesn't miss");
                c = permutations;
            }
        }
        world.Note("<-----end test------>");
    }
  • KyrockKyrock Member Posts: 35 ✭✭
    meh, this would give me an output of:
    h1,h3,h2
    is a path that doesn't miss

    Would be interested to know if anyone has some better ideas.
  • DelrayneDelrayne Member Posts: 457 ✭✭✭
    maybe if I understood java better I could be of minute service...but even then I could only offer you like a debug here or there :( Wish I could do stuff like this.

  • JorachimJorachim Member Posts: 83 ✭✭✭
    Kyrock, are you attempting to come up with the best cure commands to send for a set of affs?
    Someone powerful says, "Its broken. No more pulling the guillotine."
  • DelrayneDelrayne Member Posts: 457 ✭✭✭
    If so this all just made a little bit more sense, still only a little bit :(

  • KyrockKyrock Member Posts: 35 ✭✭
    yeah. I made my main healing object hold an array of healingMethod objects. The healingMethod objects have a heals property with a string list of all type of affs it heals, a logic method that's called to check if it is available for use, and a remedy method that changes appropriate variables and sends commands to imp. They also have an on and off method to register and unregister themselves from the main healing object. This way I can add in things besides the standard focus, tree, and purge healing methods with only a little bit of coding. So, if I want rage programmed in, I just create a rage healingMethod and it links in and is ready to go. The problem that arises though, is the healing object has to know that order matters and that's what's been taking me so long in creating this system.
  • JorachimJorachim Member Posts: 83 ✭✭✭
    What I did was:

    * Make a table with key names being cures we can send, setting their values to 0.
    * Go through all afflictions, and add 1 to each one that can cure that affliction
    * Sort the cures by count and priority, in case there are some with the same count
    * Starting with the smallest count, work your way down. Every time you send a cure, deduct 1 from the other cures that can cure it. If a cure is at 0, don't send it.
    Someone powerful says, "Its broken. No more pulling the guillotine."
    KyrockIniarOrm
  • DelrayneDelrayne Member Posts: 457 ✭✭✭
    That's actually pretty brilliant, yet simple.

  • KyrockKyrock Member Posts: 35 ✭✭
    what's your criteria for priority? let's say you have 4 affliction and three cures.
    C1: a1,a2
    C2: a2,a3
    C3: a3,a4

    if a1 is on top of my queue it's better to go c3, c2, and then c1 to give me a better chance to get it. So knowing what each cure set is able to cure at the time is needed to also make a decision. The first thing I'm finding is does a particular curing path produce misses and then, of the paths that don't, which one will give me the highest probability of curing a particular affliction.

    The way you propose can also deduct a cure set down to zero without certainty that all the afflictions have been cured. Example
    C3: a1,a2
    C2:a1,a3
    C1:a2,a4
    if c1 and c2 are called before, they have a chance of curing a3 and a4 and c3 would still be at 0...which is why I have been trying to use probability.

    C1: a1,a2,a3
    C2: a1,a2,a3
    C3: a1,a2

    target: a1
    Event A: C1 cures a1 or a2, P(a1 or a2) = 2/3
    Event B: C2 cures a1 or a2, P(a1 or a2) = 2/3

    so if the path I'm checking is C1,C2,C3 I would want to check for a miss
    since a1 and a2 are in c3 I want to check the probability of a1 and a2 occurring.
    P(A and B) = P(B|A) * P(A) = 1/2 * 2/3 = 1/3. Since it's not 0 we know this path can miss and we can continue to check for other paths that don't miss and then find that path with the highest probability of curing a particular affliction.


    Sarciossis
  • KyrockKyrock Member Posts: 35 ✭✭
    Since there were people that attempted to help, figure I should post my finished code.


    (...)
    probable: function probable (path,elements){
            this.miss = false;
            this.outcomes = [];
            this.getOutcomes(path,elements,0);
            this.dataExtract(path,elements);
        }
    };
    Utilities.probable.prototype = {
        getOutcomes: function getOutcomes(path,pElements,step) {
            //if at the end of the path we have the resulting outcome of taking this path.
            if (step == path.length) {
                this.outcomes.push(pElements);
            } else {
                var tempElements;
                var missBool = true;
                for (var i = 0;i < path[step].length;i++) {
                    //if path[step][i] in pElements modify it and recurse
                    for (var j = 0;j < pElements.length;j++) {
                        tempElements = pElements.concat();
                        if (path[step][i] == pElements[j]) {
                            tempElements.splice(j,1);
                            missBool = false;
                            this.getOutcomes(path,tempElements,step + 1);
                        }
                    }
                }
                if (missBool) {
                    this.miss = true;
                    this.outcomes.push(pElements);
                }
            }
        },
        dataExtract: function dataExtract(path,pElements) {
            function addElement(element,self) {
                if (!self[element]) {
                    self[element] = 1;
                } else {
                    self[element] += 1;
                }
            }
            for (var i = 0;i < this.outcomes.length;i++) {
                //get probability of each element being cured.
                for (var j = 0;j < pElements.length;j++) {
                    for (var k = 0;k < this.outcomes[i].length;k++) {
                        if (this.outcomes[i][k] == pElements[j]) {
                            addElement(pElements[j],this);
                        }
                    }
                }
            }
            //calculate probability of each element being cured.
            for (var c = 0;c < pElements.length;c++) {
                if (pElements[c] in this) {
                    this[pElements[c]] = (this.outcomes.length - this[pElements[c]]) / this.outcomes.length;
                } else {
                    this[pElements[c]] = 0;
                }
            }
        }
    };
    function test() {
        world.Note("<---begin test--->");
        var s = ["a1","a2","a3","a4"];
        var h1 = ["a1","a2","a3","a4"];
        var h2 = ["a1","a2","a3"];
        var h3 = ["a1","a2"];
        var path = [h1,h2,h3];
        var permutations = Utilities.factorial(path.length);
        function posAllowed(pos) {
            pos += 1;
            return Utilities.factorial(pos)/pos;
        }
        var wrkArray = [];
        for (var pc = 0;pc < path.length;pc++) {
            wrkArray.push(pc);
        }
        function currentPath() {
            var tempAry = [];
            for (var i = 0;i < path.length;i++) {
                tempAry.push(path[wrkArray[i]]);
            }
            //world.note("tempAry: " + tempAry.length);
            return tempAry;
        }
        function testing(rAry,rPath) {
            var str = "path: " + rPath[rAry[0]];
            for (var tCount = 1;tCount < rPath.length;tCount++){
                str += ", " + rPath[rAry[tCount]];
            }
            world.note(str);
        }
        function possibleCombinations(iteration, fAry, fPath) {
            if (iteration != 0) {
                var pos;
                for (var pCount = 0;pCount < fPath.length - 1;pCount++) {
                    pos = fPath.length - 1 - pCount;
                    if (iteration % posAllowed(pos) == 0) {
                        var temp;
                        if (fPath.length - pCount == 2) {
                            temp =fAry[pCount];
                            fAry[pCount] = fAry[pCount + 1];
                            fAry[pCount + 1] = temp;
                        } else {                   
                            temp = fAry[pCount];
                            fAry[pCount] += 1;
                            if (fAry[pCount] >= fPath.length) {
                                var fCount = 0,increment = 0;
                                while (fCount < pCount) {
                                    if (fAry[fCount] == increment) {
                                        increment++;
                                        fCount = 0;
                                    }
                                    fCount++;
                                }
                                fAry[pCount] = increment;
                            }
                            //search for pointer with the same value.
                            var sCount = 0;
                            var sBool = false;
                            while (sCount < fAry.length && sBool == false) {
                                if (fAry[sCount] == fAry[pCount] && sCount != pCount) {
                                    if (sCount < pCount) {
                                        fAry[pCount] += 1;
                                        sCount = 0;
                                    } else {
                                        fAry[sCount] = temp;
                                        sBool = true;
                                    }
                                } else {
                                    sCount++;
                                }
                            }
                        }
                        return;
                    }
                }
            }
        }
        var possibilities = [];
        for (var c = 0;c < permutations;c++) {
            possibleCombinations(c,wrkArray,path);
            possibilities.push(new Utilities.probable(currentPath(),s));
            for (var e in possibilities[c]) {
                if (typeof possibilities[c][e] != "object" && typeof possibilities[c][e] != "function") {
                    world.Note(e + ": " + possibilities[c][e]);
                }
            }
            //world.Note(currentPath().toString());
           
            /*if (!pathCheck(wrkArray,path)) {
                testing(wrkArray,path);
                world.Note ("is a path that doesn't miss");
                c = permutations;
            }*/
        }
        world.Note("possibilities: " + possibilities.length);
        world.Note("<-----end test------>");
    }

    output:
    H:372 M:430 eb>
    <---begin test--->
    miss: true
    a3: 0.6
    a4: 0.4
    a2: 0.9
    a1: 0.9
    miss: false
    a4: 0.5
    a3: 0.75
    a2: 0.875
    a1: 0.875
    miss: false
    a4: 0.5
    a3: 0.75
    a2: 0.875
    a1: 0.875
    miss: true
    a3: 0.6
    a4: 0.4
    a2: 0.9
    a1: 0.9
    miss: false
    a4: 0.5
    a3: 0.75
    a2: 0.875
    a1: 0.875
    miss: false
    a4: 0.5
    a3: 0.75
    a2: 0.875
    a1: 0.875
    possibilities: 6
    <-----end test------>

  • KyrockKyrock Member Posts: 35 ✭✭
    gotta say this is going to be handy for when I make my affliction tracker
    Jorachim
  • TraynTrayn Member Posts: 1

    Anybody have one for mushclient for fishing?

  • SelthisSelthis Member Posts: 524 ✭✭✭✭✭
    A friend of mine is unable to use the forums but uses MUSH.  Does anyone have a caravan runner written up with simple instructions for how to use it?
  • DeniDeni Member Posts: 7
    edited April 2013
    So, I have a couple of questions that are likely to be trivially easy.
    One, if I'm making highlights, is there a way to put a marker that will match any word and still highlight the line? e.g. making it highlight both "Alex highlights his line" and "Marcus highlights his line"?
    And, when designating things to be highlighted (by selecting it and going to "Highlight Word") is there a way to get it not to look like this in the triggers thereafter?
    image

  • DeniDeni Member Posts: 7
    Can't seem to edit my post, but just to clarify, I know that it can be edited to be normal in the triggers afterward. I'd like it if I didn't have to do that in the first place though!
«1
Sign In or Register to comment.