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.
<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.
^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.
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.
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.
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.
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..
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
In addition, you might want to consider abstracting all that out into a single function. Having a list of functions you call in every alias does not scale well (for instance, 2 weeks from now you're going to add a "pullArrowCheck" for incendiary. You now either have to put that somewhere unintuitive like your check mount function (this is what you'll do because its easier, its also a mistake and you'll hate yourself a year from now), or you have to add it to every alias that have your various checks. You have a few common approaches to this:
- You can define a table of functions, then have a preCommands function that is called in your aliases that just iterates over that table and calls each one in turn. - You can have a preCommands function that just calls a bunch of functions one after the other. This is fine though less flexible, not allowing you to trivially dynamically add/remove checks at runtime. Its quite possibly the simplest way and the benefit of a single abstraction like this is that you can rewrite that function later without actually having to change anything else.
Something else to consider is if you want to handle commands in this way. This might not seem important now but its a pretty key thing to decide, given you're not in a location with great ping. A linear list of functions that you call that then send commands does prohibit you from using ifeqbal/queueing/separators trivially. If you do want to use these you can: - Rather than sending the commands push them to a table, then have your own send function that joins those commands by your separator and dispatches them to whatever method you want to use (be that a standard send, a queue eqbal, an ifeqbal, etc). or - You can have your functions return strings and just append them. I see a lot of people do this and advise against it. It is inflexible and doesn't allow for clean lookups for if you're using a command already, etc. It also requires you to handle your separators yourself, and you'll inevitably miss one somewhere and then have to track down where you forgot to insert one. A join is just better in this case.
I'd go with something like this:
function prepare(command) append command to action table end
function exampleTrueassessCheckYouShouldNeverDoBecausePreTrueassessOnEveryActionWillKillYou(target) prepare("trueassess " .. target) end
function preCommands(target) reset action table to empty foreach check in checks check(target) end end
function dispatch(prefix) command = join(action table, your separator) send(prefix .. " " .. command) end
function spearStab(target, toxin) prepare("spear stab " .. target .. " " .. toxin) end
function yourSpearStabThing(target) preCommands(target) spearStab(target, "probably chiltran because chiltran is awesome") dispatch("queue eqbal") end
That's all very rough, but is how I would do things if looking for a good place to get started. Ideally you want to spend less time coding and more time playing the game, so having something that let's you throw attacks together quickly is ideal. Even if you do go with just a standard send and forget about queueing etc, I recommend writing your own wrapper around your client's built in send function. This is because down the line there's a good chance you'll want to double up commands or something like that when afflicted with stupidity etc.
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
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.
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
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
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
Comments
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.
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.
repeat time action to do the action every at that interval. repeat to stop and start it. You might want to add echoes.
Just trying to figure this whole defenses-on-queue thing.
Also, found this interesting tidbit while looking up the history of Lua:
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?
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.
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--
^(\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)
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.
alias ss
where:
and:
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..
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.
- You can define a table of functions, then have a preCommands function that is called in your aliases that just iterates over that table and calls each one in turn.
- You can have a preCommands function that just calls a bunch of functions one after the other. This is fine though less flexible, not allowing you to trivially dynamically add/remove checks at runtime. Its quite possibly the simplest way and the benefit of a single abstraction like this is that you can rewrite that function later without actually having to change anything else.
Something else to consider is if you want to handle commands in this way. This might not seem important now but its a pretty key thing to decide, given you're not in a location with great ping. A linear list of functions that you call that then send commands does prohibit you from using ifeqbal/queueing/separators trivially. If you do want to use these you can:
- Rather than sending the commands push them to a table, then have your own send function that joins those commands by your separator and dispatches them to whatever method you want to use (be that a standard send, a queue eqbal, an ifeqbal, etc).
or
- You can have your functions return strings and just append them. I see a lot of people do this and advise against it. It is inflexible and doesn't allow for clean lookups for if you're using a command already, etc. It also requires you to handle your separators yourself, and you'll inevitably miss one somewhere and then have to track down where you forgot to insert one. A join is just better in this case.
I'd go with something like this:
function prepare(command)
append command to action table
end
function exampleTrueassessCheckYouShouldNeverDoBecausePreTrueassessOnEveryActionWillKillYou(target)
prepare("trueassess " .. target)
end
function preCommands(target)
reset action table to empty
foreach check in checks
check(target)
end
end
function dispatch(prefix)
command = join(action table, your separator)
send(prefix .. " " .. command)
end
function spearStab(target, toxin)
prepare("spear stab " .. target .. " " .. toxin)
end
function yourSpearStabThing(target)
preCommands(target)
spearStab(target, "probably chiltran because chiltran is awesome")
dispatch("queue eqbal")
end
That's all very rough, but is how I would do things if looking for a good place to get started. Ideally you want to spend less time coding and more time playing the game, so having something that let's you throw attacks together quickly is ideal. Even if you do go with just a standard send and forget about queueing etc, I recommend writing your own wrapper around your client's built in send function. This is because down the line there's a good chance you'll want to double up commands or something like that when afflicted with stupidity etc.
/ramble
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.
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?
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.
Otherwise, this is helping a lot to highlight the names I want, thank you!
I have a pretty basic function, with a pretty basic schema.
And
When I try to run the function, the DB SQL debug looks like this:
But there is no value being saved to last_seen, either using the provided db:fetch command or visible using an offline db viewer.
Like a daydream.. or a fever
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:
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?
Like a daydream.. or a fever
So basically, I had to fix the timestamp using this code:
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.
Like a daydream.. or a fever