Skip to content

Mudlet Scripting

1121314151618»

Comments

  • edited July 2017
    Don't really feel like belabouring the point since people might be on a non-current mudlet.  So for those who aren't:
    function toboolean(value)
       if (value==true) then
          -- why are you feeding bools to something named toboolean?
          return true
       elseif (value==false) then
          -- why are you feeding bools to something named toboolean?
          return false
       elseif (tonumber(value)~=nil) then
          if (tonumber(value)>0) then
             return true
          else
             return false
          end
       else
          return false
       end
    end
    

    It was a bit confusing to me we have tostring and tonumber but not toboolean.  It would have been one of the first things I'd've added with booleans when they added a boolean type.

    [edit]: Pet peeve: WSIWYG editors that ... aren't at all what you see is what you get.

    image
  • edited July 2017
    I prefer this, personally.
    <div>function toBoolean(s)	
    <span style="background-color: transparent; color: inherit; font-size: inherit;">   </span><span style="background-color: transparent; color: inherit; font-size: inherit; font-family: "lucida grande", "Lucida Sans Unicode", tahoma, sans-serif;">local st = (type(s) == "string" and string.lower(s) or s)
    </span><span style="background-color: transparent; color: inherit; font-size: inherit; font-family: "lucida grande", "Lucida Sans Unicode", tahoma, sans-serif;">   if type(st) == "number" and st >= 1 then st = "1" end
    </span><span style="background-color: transparent; color: inherit; font-size: inherit; font-family: "lucida grande", "Lucida Sans Unicode", tahoma, sans-serif;">   if st == true or st == "true" or st == "on" or st == "1" or st == "yes" or st == "yep" or st == "y" then
    </span><span style="background-color: transparent; color: inherit; font-size: inherit; font-family: "lucida grande", "Lucida Sans Unicode", tahoma, sans-serif;">      return true
    </span><span style="background-color: transparent; color: inherit; font-size: inherit; font-family: "lucida grande", "Lucida Sans Unicode", tahoma, sans-serif;">   else
    </span><span style="background-color: transparent; color: inherit; font-size: inherit; font-family: "lucida grande", "Lucida Sans Unicode", tahoma, sans-serif;">      return false
    </span><span style="background-color: transparent; color: inherit; font-size: inherit; font-family: "lucida grande", "Lucida Sans Unicode", tahoma, sans-serif;">   end
    </span><span style="background-color: transparent; color: inherit; font-size: inherit; font-family: "lucida grande", "Lucida Sans Unicode", tahoma, sans-serif;">end</span></div>
    If a number greater than (or equal to) 1 is given, then it returns true. If what you pass under toBoolean(whatever) is true, "true" or anything really that's a 'positive answer' then it will return true. Anything else and it'll return false. I can parse pretty much everything my system uses through it, and it'll work perfectly.

    image
  • I don't have a toBoolean function in my system at all... there's a reason it's not in Lua's stdlib! Here's how Svof captures balance: https://github.com/svof/svof/blob/master/raw-svo.controllers.lua#L1248
  • ^repeat(?:| (\d+) (.*))$
    
    
    repeatTheThing = function()
    
    if repeater.active then
    repeater.timer = tempTimer(repeater.time,[[send(repeater.action) repeatTheThing()]])
    end
    
    end
    
    if not repeater then repeater = {} end
    if not repeater.active then repeater.active = false end
    
    if matches[2] then
    
     repeater.time = tonumber(matches[2])
     repeater.action = matches[3]
    end
     
    if not repeater.active then
      send(repeater.action)
      repeater.timer = tempTimer(repeater.time,[[send(repeater.action) repeatTheThing()]])
    	repeater.active = true
    else
      repeater.timer = nil
    	repeater.active = false
    end
    

    repeat time action to do the action every at that interval. repeat to stop and start it. You might want to add echoes.
  • Could I get someone to point me in the direction of a defenses manager, or is there one that I am somehow missing?

    Just trying to figure this whole defenses-on-queue thing.
  • Vadi said:
    I don't have a toBoolean function in my system at all... there's a reason it's not in Lua's stdlib! Here's how Svof captures balance: https://github.com/svof/svof/blob/master/raw-svo.controllers.lua#L1248
    The actual reason is probably "they only recently actually added a boolean type and didn't add the support functions like that in when they did."
    image
  • That might be true too!

    Also, found this interesting tidbit while looking up the history of Lua:

    It turned out that Bret Mogilefsky was the lead programmer on Grim Fandango, the main adventure game LucasArts released in 1997. In another message he told us that "A TREMENDOUS amount of this game is written in Lua" (his emphasis). This first use of Lua in a game attracted the attention of many game developers around the world to the language.



  • edited October 2017
    Do not know if this question has been answered before. I am trying to track purge blood and focus. Both of these sometimes cure afflictions with 3P cure messages. I need a way to have a trigger activate one piece of code if the following line is a 3P cure which I think is easy, just use a chain of length 1 on the general message and code in the two or three 3P cure messages. What I do need help with is finding a way to have a piece of code trigger only if there is no 3P affliction message after it. How can I do that?

    Edit: Can I do something like: Write a multiline AND trigger like this:
    Line 1) ^A look of extreme focus crosses the face of (\w+).$
    Line 2) ^(.*)$

    And then make each 3P affliction message an if conditional, so if none of them are met than the other piece of code for non-3P messages fires?
  • 3p triggers can be tracked directly using the 3p message in a single line trigger. You can then do something like 
    Line 1) ^A look of extreme focus crosses the face of (\w+).$  Perl Regex
    Line 2) return isPrompt() Lua Function
    This trigger only fires if the line immediately after the cure is your prompt, meaning that 3p Triggers don't fire it's curing.
  • edited October 2017
    Ryc said:
    3p triggers can be tracked directly using the 3p message in a single line trigger. You can then do something like 
    Line 1) ^A look of extreme focus crosses the face of (\w+).$  Perl Regex
    Line 2) return isPrompt() Lua Function
    This trigger only fires if the line immediately after the cure is your prompt, meaning that 3p Triggers don't fire it's curing.
    Thanks so much for that, seriously. When I get bored at work I like to think about the changes I want to make to my system and the rewrite I want to do, and the problem I was running in to was figuring a way to work around having to remove 2 affs because of the 3ps. The changes I was going to make were to be a little more efficient at non 3ps. This idea will help complete the idea. 
  • I think that did it for me, thank @Ryc. My code should look like this, correct?
    Trigger for non-3p cured:
    Line 1) ^A look of extreme focus crosses the face of (\w+).$ --Perl Regex-- 
    Line 2) return isPrompt() --Lua Function-

    Trigger for 3p cured - in this case, Stupidity
    Line 1) ^A look of extreme focus crosses the face of (\w+). (\w+)'s expression no longer looks so vacant. --Perl Regex--



  • The 3p trigger would look like 
    ^(\w+)'s expression no longer looks so vacant\.$ Perl Regex
    There's no need for the focus line, or really any curetype line for a 3p cure, just trigger off of the 3p message itself. (the exception being if you want to track what the last of each curetype cured is)
  • I wouldn't say there's no need at all, it can rule out illusions and the like, but the last time I saw someone use illusions in combat was a couple IRL years ago.  That said you can get by without it.
    image
  • DimitriDimitri Somewhere cold
    I'm not sure how you could implement this, but for some lulz on your end.

    http://doom.wikia.com/wiki/Status_bar_face_hysteresis

    Seems like the doomguy status faces could be useful as a visual representation of how you're doing. Or at least entertaining.
  • Howdy guys, I'm trying to start all over again and was trying to implement some checks along the way.. I've ended up with something like..
     
    alias ss
    mountCheck()
    spearCheck()
    send("spear stab "..target)

    where:
    function mountCheck()
    if gmcp.Char.Vitals.mount == "XXXX" then
    send()
    else send("mount XXXX")
    end
    end

    and:
    function spearCheck()
    if (gmcp.Char.Vitals.leftwield == "XXXX") and (gmcp.Char.Vitals.rightwield == "XXXX") then 
    send()
    else send("quickdraw spear shield")
    end
    end

    My problem is, this works if I'm dismounted and not holding my spear... but otherwise it just stops in the functions called.. how do I get it to proceeed through to the next section?  I f -think- the issue is the send() inside the functions, but I'm not sure what I should put there instead..
  • That would be the only thing I see being weird. Just change your equal tos (==) to to not equal tos (~=) so one would look like this:

    if gmcp.Char.Vitals.mount ~= x then
      send("mount "..x)
    end

    Excuse if it's not perfect I typed from my phone, but you get the drift.
  • The problem is you're trying to use the function Send() when it requires an input. Such as Send("say hi") etc. So you're getting an error from the missing string which is why the function is stopping. I'm not sure why you felt like you needed to use send at all. Just removing the send and leaving that part of the if statement blank would have done the same thing such as

    function mountCheck()
       if gmcp.Char.Vitals.mount == "XXXX" then 
       else send("mount XXXX")
       end
    end


  • Do what @Aodan suggested. You don't need an else statement for every if, and it's better to negate in the original condition.
  • OwynOwyn US
    edited December 2017
    If you didn't have some sort of wrapper, now's a good time to start updating your systems. The way actions are queued is going to change soon to where you can stack action queues natively. This queue update also means that if you're spamming an alias that's using queue eqbal, you're now making a legit list of actions instead of just one. Friendly reminder.
  • Leading on from Owyn's comment, a better way to handle that kind of thing is to pass a function rather than a prefix. I tried to avoid that in the example above because that can confuse a lot of people who aren't used to first class functions, but something like:

    function queueEqbal(command)
        send("queue eqbal clear" .. your separator .. "queue eqbal " .. command)
    end

    function rawSend(command)
        send(command)
    end

    function ifeqbal(command)
        send("ifeqbal " .. command)
    end

    function dispatch(sendMethod)
        command = join(action table, your separator)
        sendMethod(command)
    end

    then you can do like:

    dispatch(queueEqbal)
    dispatch(rawSend)
    dispatch(ifeqbal)

    Etc. This is objectively  better, but its also more complicated if you're not comfortable with how functions work. It does let you weather major gameside changes like queueing rewrites etc without significant problems, however. Of course, you can achieve similar behaviour using a prefix style with something like:

    dispatch("queue eqbal clear " .. your separator .. "queue eqbal")

    However, this limits what you can do and is also fragile. At this point you're starting to make the system do something outside of the obvious and are having to compose strings as arguments to get the behaviour you want. This isn't ideal. Some people like to pass a string to their dispatch equivalent then lookup the correct function from a separate table. This does work, but is almost always because they went with a prefix approach initially then didn't want to rewrite major sections of their aliases to conform to a more function based approach. Perfectly valid, regardless.

    But basically, do what you're comfortable with. I tend to recommend a prefix approach to people who are just learning, because it works and has less abstraction from what you already understand (game mechanics). The function approach is better, overall, though.
  • Great example of using functions as first class variables 
  • Is there any nice way to highlight player's names in room description?

    Under here is my view of the room description, but if I wanted to change the colour of Rav's name, how can I do that? Any neat ideas?

  • You can just make a trigger with their name, set it to substring and set the highlight colours how you want it highlighted.

    Don't really need to do anything too complex. (names are just for example purposes)


  • @Lachlan why am I in 4th place?
  • Lachlan said:
    You can just make a trigger with their name, set it to substring and set the highlight colours how you want it highlighted.

    Don't really need to do anything too complex. (names are just for example purposes)



    If you want it to match the name every time it appears in the line, check that "match all" checkbox.
    Like what we're doing? Why not take a second to vote? Vote for Imperian at http://www.imperian.com/vote
  • Eoghan said:
    Lachlan said:
    You can just make a trigger with their name, set it to substring and set the highlight colours how you want it highlighted.

    Don't really need to do anything too complex. (names are just for example purposes)



    If you want it to match the name every time it appears in the line, check that "match all" checkbox.
    Is there a way for me to remove those names in trigger, otherwise than opening the trigger and then delete the name from there? I was wondering if I could do an alias that could remove the name OR alias that could add them?

    Otherwise, this is helping a lot to highlight the names I want, thank you!
  • Does anyone know if the db:Timestamp function in the database wrapper works?

    I have a pretty basic function, with a pretty basic schema.
    
    function player_info_database_update_last_seen(name)
      name = string.title(name)
    
      db:set(player_info.players.last_seen, db:Timestamp("CURRENT_TIMESTAMP"), db:eq(player_info.players.name, name))
    end
    And
    
    db:create("playerinfo", {
      players = {
        name = "",
        profession = "",
        city = "",
        towne = "",
        guild = "",
        race = "", 
        statpack = "", 
        level = 0,
        player_kills = 0,
        deaths = 0,
        last_seen = db:Timestamp("CURRENT_TIMESTAMP"),
        _unique = {"name"},
        _violations = "FAIL"
      },
    })
    
    player_info = db:get_database("playerinfo")

    When I try to run the function, the DB SQL debug looks like this:
    UPDATE OR FAIL players SET "last_seen" = datetime('CURRENT_TIMESTAMP', 'unixepoch') WHERE "name" == 
    'Jarrhn'  

    But there is no value being saved to last_seen, either using the provided db:fetch command or visible using an offline db viewer.
    You grabbed my hand and we fell into it
    Like a daydream.. or a fever
  • Okay, updates:

    I took out the db:set for the current timestamp and created a brand new player record for a newbie that hasn't logged in since forever. I allowed to do its thing automatically, and the schema successfully added the timestamp table as expected:
      last_seen = {
        _timestamp = 1581609582
      },

    But now nothing I seem to do from here forward changes it. Trying to manually set it using the db:Timestamp function breaks it again. So I successfully have a 'first_seen' variable, but does anyone know if there's a way to properly update it?
    You grabbed my hand and we fell into it
    Like a daydream.. or a fever
  • Oh hey it works.

    So basically, I had to fix the timestamp using this code:
      local time = math.floor(getEpoch())
      
      -- player table
      local player_table = db:fetch(player_info.players, db:eq(player_info.players.name, name))[1]
      player_table.last_seen = db:Timestamp(time)
      
      display(player_table)
      db:update(player_info.players, player_table)
    It seems like the 'CURRENT_TIMESTAMP' argument doesn't work outside of the schema, but you can manually update the timestamp field like anything else.

    Just in case anyone runs across this via Google or whatever.
    You grabbed my hand and we fell into it
    Like a daydream.. or a fever
Sign In or Register to comment.