Parity's "Coding for the Coderless" Class
Functions:
add(),
and(),
cat(),
center(),
div(),
first(),
force(),
get(),
get_eval(),
gt(),
gte(),
hasflag(),
idle(),
ifelse(),
isdbref(),
isnum(),
iter(),
lit(),
ljust(),
loc(),
lt(),
lwho(),
match(),
mod(),
mudname(),
mul(),
name(),
num(),
objeval(),
or(),
parent(),
parse(),
pmatch(),
rand(),
repeat(),
rest(),
rjust(),
room(),
setq(),
sub(),
switch(),
time(),
type(),
u(),
v(),
words().
Compatibility:
TinyMUSH.
MUSHCode for Parity's "Coding for the Coderless" Class
©2004 Parity@OGR. You may copy and redistribute this document provided that it remains complete, with credits intact, and is used only for non-profit purposes.
******
Coding for the Coderless
Attendees:
Fyrn | Indi | Iuz | Jayanti | Lady Rosalynne | Odin | Parity | Sabbath | Siobhan | Trek | Virgo | Whirlaway
Parity says, "Good morning, class. I'm going to ask you all to keep the off-topic chatter to a minimum from this point on, and, yes, I want you to raise your hand when you have a question - ie, any -short- pose indicating you want to speak."
Odin enters the room through the double doors, which swing closed behind it.
Odin has arrived.
Parity says, "Okay, this class is particularly focused on the needs of someone without much prior experience in coding just about everything on a MUSH."
Parity says, "The first thing I'm going to say, is -"
Jayanti enters the room through the double doors, which swing closed behind it.
Jayanti has arrived.
Parity says, "-Don't- write your own +finger, +who, etc, even though I'm using such things as examples. It's a waste of time. There's the sandbox globals project, and if you don't like that system, there's other free code available on the web."
Parity says, "However, you're going to need to understand them. So. I'd like everyone to look at (exa) player commands."
Player Commands(#3474V)
Type: THING Flags: VISUAL
Owner: Parity Key: Parity(#384PXcF) Pennies: 1
Zone: *NOTHING*
Parent: Player Functions(#3472)
Powers:
Created: Tue Aug 03 12:38:29.487797 2004
Modified: Wed Aug 11 18:59:38.809211 2004
PLAYER-CMD: $+player *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{'[name(%q0)]' is the player identified by '%0'.},{'%0' is not a player.})]
FINGER-CMD: $+finger *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{ [center(<%b[name(%q0)]%b>,76,-)]%rName: [name(%q0)]%rSex: [switch(get(%q0/sex),M*,Male,F*,Female,Other)]%rIdle: [idle(%q0)] seconds%r[repeat(-,76)] },{'%0' is not a player.})]
WHO-CMD: $+who:@pemit %#=[setq(0,objeval(%#,lwho()))][center(%b[mudname()]%b,76,-)][iter(%q0,%r[ljust(name(##),15)][rjust(u(idle-fn,idle(##)),5)][repeat(.,20)][rjust(switch(loc(##),#-1,Unfindable,name(loc(##))),36,.)])]%r[center(%b[words(%q0)]%bPlayers,76,-)]
FLOATING-LOCK: [or(hasflag(%#,floating),hasflag(%#,wizard))]
UseLock: FLOATING-LOCK/1
Contents:
Player Functions(#3472)
No exits.
Home: Parity's Circuitry Room(#1071RJ)
Location: Lecture Room(#14RJs)
Parity says, "The first attribute on there is 'player-cmd', which is a typical $-command. I believe you all know what $-commands are, if not, now would be a good time to wave panickedly."
Indi fulfulls her destiny, and raises her hand.
Fulfills*
Parity okays, "Briefly, a $-command is an attribute on an object that specifies a command. In this case, the first part of the attribute's value, '$+player *:' says 'The command I define is '+player' followed by a space and one argument'. Does that help Indi, or did you have more of a question?
Indi says, "Answered. =)"
Parity says, "Everyone should, right now, '@set me=floating'."
Parity says, "We'll get to the why of that later, but I locked this object so that that's what you need to do. :)"
Parity says, "Now, you can '+player parity' and get one thing, and '+player flyingpurplepeopleeater' and get another."
Parity says, "Not so exciting, I know."
Parity says, "But, almost every command you make will need to figure out that the target is or is not a valid player, and we use some helpful techniques along the way. The first thing is the command, of course, is '@pemit %#='"
Parity says, "%# is the player (or other object) who -invoked the command-."
Parity says, "OKay. More interesting is setq() ... how many people here know setq()?"
Indi does not.
Siobhan shakes her head.
Trek says, "I know /of/ it... :P"
Parity says, "setq() is how you store values temporarily, so you can use them repeatedly."
Jayanti does not either.
Parity says, "This is particularly useful for, say, calculating 'hours' because you don't want to type a complicated expression every time. So, if you type, 'setq(0,foobar)', then further along in the attribute you type '', '' will be replaced with 'foobar'."
Fyrn says, "Sweet!"
Parity erms.
Parity missed an escape there.
Trek thinks someone forgot to use escape characters. :P
Parity says, "This is particularly useful for, say, calculating 'hours' because you don't want to type a complicated expression every time. So, if you type, 'setq(0,foobar)', then further along in the attribute you type '%q0', '%q0' will be replaced with 'foobar'."
Indi says, "That's cool."
Jayanti raises her hand.
Parity also lost the hours expression, 'setq(0,div(<seconds>,3600))' ... %q0 for hours.
Parity says, "Yes, Jayanti?"
Jayanti says, "nevermind :) That was the question."
Parity ahs.
Parity says, "I changed my example halfway. ):"
Parity says, "Anyway. . is the value of the first argument in a command."
Parity says, "In the case of +player it's everything after '+player'. (Technically, everything after the space after +player)."
Parity says, "So if you type '+player this sentence is false' then will be 'this sentence is false'."
Parity says, "num(*this sentence is false), of course, will return #-1, because there's no such player."
Siobhan says, "And num searches for the dbref# of a player, right?"
Siobhan says, "Oops."
Parity says, "num() returns a dbref of an object... * means check for players & aliases, as opposed to checking for things-near-the-evaluating-object."
Fyrn sighs and leaves.
Parity says, "So, num(*siobhan) will return siobhan's dbref."
Trek raises a metaphorical hand.
Parity says, "While we're in the same room with her, so will num(siobhan) - but globals are usually in the Master Room, nowhere near the player-in-question."
Parity says, "So ... setq(0,num(*%0)) ... store in q0 the dbref of the player named whatever-was-stored in %0 - which came from the person typing '+player parity' or whatever."
Parity says, "Everybody with me so far?"
Indi is. =)
Siobhan nodnods.
Jayanti thinks she is ;)
Virgo says, "Sort of."
Trek ayups.
Parity says, "Anybody feeling a little lost may want to try 'think num(trek)', 'think num(flattenedtuba)', 'think num(sparks)', and 'think num(*sparks)' ..."
Virgo shakes her head and raises her hand.
Parity says, "So, %q0 is now either '#-1' or a dbref of a player, and the next part is where q-values become happy happening things."
Parity nods, "Yes virgo?"
Virgo says, "Is the comma in the setq bit just something like an 'and', as in an addition to? A list?"
Siobhan also puts up her hand after Virgo.
Parity ohs, "In a function, the comma separates arguments. setq() takes two arguments, one before the comma, one after. switch(), which we're comming up on, takes as many arguments as you can throw at it, all seperated by commas."
Parity says, "Yes, Siobhan."
Parity says, "You can follow up if you need to Virgo."
Siobhan says, "So I understand that '%q0' is temporary... it's just set temporarily while that command is being executed? It doesn't actually store it physically on an object?"
Parity says, "Right."
Siobhan says, "Gotcha. :)"
Parity says, "The way I'd say it, being technical, is exists during the current evaluation."
Indi raises a hand.
Parity says, "Yes, Indi?"
Indi says, "Oh, never mind. I reread what you said. Now I get it. =)"
Virgo says, "Sorry, dog distraction. I'm not sure I understand the term argument in relation to this."
Parity says, "Arguments are the values 'given to' a function or command."
Virgo nods. "Okay, got it."
Parity says, "In a command, they're the things after the command name. In a function, they're the things inside the parens ()."
Parity says, "So, going into the next segment, we enter a switch() function and make our q work for us. We want to know, first, that we got a valid dbref, and second, that we got a player."
Parity says, "So, 'switch(and(isdbref(%q0),match(type(%q0),player)), ... )' is what I'm talking about."
Parity says, " and() just returns 1 if -both- things are true (which in computer term means a non-zero number); isdbref() returns 1 if the argument is a valid dbref."
Parity says, "match is a bit tricky, but in this case, we're using it as a case-insensitive 'are these strings equal'."
Parity says, "The actual value of type(*parity) would be 'PLAYER'"
Parity says, "So you can think that we're asking, 'Are isdbref(num(*Parity)) AND match(type(num(*Parity),PLAYER) both true?'"
Parity says, "Having asked that, switch() lets us make a decision based on the answer."
Parity says, "switch() is your friend. ;) switch() is a lot like ifelse(), if that helps."
Parity says, "In this case, it's -exactly- like ifelse()."
Jayanti hehs. Uhhh *hand*
Parity says, "However, switch() can do a whole -bunch- of if's at once if you need to, and exists on every codebase I know."
Parity says, "Yes Jayanti?"
Jayanti says, "Well, may be jumping the gun here, but what are the differences between switch() and @switch?"
Parity says, "switch() is a function, and @switch is a command."
Indi raises a hand.
Parity says, "So, you can either, '@pemit %#=switch(condition,1,true,false)' -or- '@switch condition=1,@pemit %#=true,@pemit %#=false'"
Jayanti nods. ok
Parity says, "Generally speaking, switch() is preferable, but there are exceptions - ie, '@switch <condition>=1,@remit %#=Something happens.,@pemit %#=You can't do that!'"
Parity says, "Now you're using two different commands in that example, hence, @switch."
Jayanti says, "cool"
Parity says, "Yes, Indi?"
Indi says, "The differences between a command and a function are, basically, commands are automatic and simple whereas functions can include a number of commands? Like, the difference between buying peanut butter and making it?"
Indi says, "It's the little things that mess me up."
Parity ponders this one for a moment.
Parity says, "A command is something you can type, and have it do something. '+who' is a command. '@emit' is a command."
Parity says, "A function is something that replaces itself with another string."
Parity says, "That used to be 100% true, and for now we'll pretend it is. ;)"
Virgo holds up her hand for after Indi's question is answered.
Parity says, "So, a command can do anything. Create objects, destroy them, cause the database to be backed up..."
Indi likes to use comparisons. "So, commands are like opening a door when functions are like.. the stuff inside the handle (like locks) that are interchangeable and make it work?"
Parity says, "A function can only replace itself with a string. Okay, setq() has a 'side effect' of setting %q0... but it's mostly true."
Trek inserts a remark, if that's okay?
Parity says, "Sure, Trek."
Parity doesn't have a good comparison ready to hand...
Parity says, "If I make one up on the spot, I'd say functions are like laws of nature and commands are like actions in the world, but I can also poke big holes in that anology. :)"
Trek says, "Functions replace themselves with strings--putting commands inside of them doesn't work, hence why there's an @switch."
Parity ahs, "Good point."
Parity says, "Functions go inside commands, -never- the other way around."
Indi nods, "I think I got it."
Trek says, "Indi's analogy actually seems pretty good to me, but I'm no more than an acolyte with MUSHcode. :P"
Parity says, "It is technically possible to reverse that, but I encourage all good mushdieties to disable the force() function, as it is an abberation of nature and a security hole. ;)"
Parity says, "Here's a point... you can 'say' any function."
Parity says, "like, 'say time()' for example."
Parity says, "Commands cannot be said, they have to be 'done' ... they're the first thing you type if you enter them directly."
Parity says, "Virgo, still have a question?"
Indi says, "Ah, gotcha. That helped cement it. =)"
Virgo says, "With switch(), do the last two arguments always have to be the true and false parameter?"
Parity moves forward in any case, although we may have more questions forthcoming, there it is... , "So, switch() here, briefly, works like, 'switch(something,checkthis,dothis,checkthat,dothat,defaultaction)'
Parity says, "So the -last- argument is the 'false' parameter."
Parity says, "However, you can have - and this will actually show a last argument that is 'true' - and often we see this - switch(rand(3),0,nothing,1,snake-eyes,2,a winner!)"
Parity says, "SO this says, 'if 0, then 'nothing', if '1', then 'snake-eyes', if 2 then 'a-winner' ... since we've covered every possibility, we don't need an 'else' or 'false' condition."
Jayanti grins. Uhh, question.
Parity nods, "Yes, Jayanti?"
Jayanti says, "That breaks down to (pick a random number from 0-3, blah blah blah, if it is 2 or 3 it is a winner?"
Parity says, "Sorry, no, pick a number from 0 to 2."
Parity says, "To get what you describe, we want,"
Parity says, "... switch(rand(4),0,nothing,1,snake-eyes,a winner!)"
Parity says, "rand() returns a number between zero and the argument minus one."
Jayanti says, "Ok...little confusing, cleared up now ;)"
Parity says, "And the rand(4) example goes back to using an 'else' at the end. 'if 0 ... if 1 ... else ...'"
Jayanti nods. Got it.
Parity says, "Anymore questions? It's okay. switch() is -important-."
Siobhan -thinks- she's got it.
Parity says, "A lot of these things I brush over. You can look up num(), rand(), whatever, in the help files. switch() and setq() are tricky. ;)"
Virgo raises her hand... again.
Jayanti noddles. Was just confused as to whether it was a default on switch after 2 or if it ended there ;)
Parity says, "Yes, Virgo?"
Virgo says, "Okay, how does it know if the argument is for a true or false?"
Parity mmms. "switch() doesn't care about true or false, really. It cares about 'does this match'.
Parity says, "It happens that the boolean (meaning 'returns true or false') functions return '0' or '1'."
Parity says, "So, we can switch(somethingboolean(),1,this is a true case,0,this is a false case)"
Parity says, "Does that answer the question, or did you mean something else?"
Virgo says, "Oh, so you need the 0 and 1 in there for it to differentiate?"
Parity nods.
Virgo says, "Gotcha."
Parity says, "ifelse(somethingboolean(),true case,false case) ... switch(somethingboolean(),1,true case,0,false case) ..."
Parity says, "Although, I'd encourage you to write it, 'switch(somethingboolean(),1,true case,false case)' ... subtle difference there being I'm using a default instead of explicitly checking for zero."
Parity says, "Generally speaking, you want all your failures to fall into the 'default' cases so that unexpected errors get handled."
Virgo nodnods. "Makes sense."
Parity nods. "OKay."
Parity says, "So, in our example, we have, for the '1' case, "'Coding for the Coderless' is the player identified by ''.""
Parity says, "I don't think the string itself is anything exciting, though I will mention I almost always use name() rather than values passed in as arguments... it ensures you get the capitalization the player with the name uses."
Parity says, "The default case is even more dull, only printing out what was passed in."
Parity says, "More interesting, is that wrapped it in {}..."
Parity says, "This is utterly unnecessary, but also harmless, and a good habit."
Parity says, "I shall now do the obnoxious teachery thing of asking the class, ahem, 'Can anyone tell me why?'"
Siobhan shakes her head.
Whirlaway can guess?
Parity says, "Yes, Whirlaway?"
Whirlaway says, "Because if what you want to print out has commas, it confuses the switch()? I always get my switch()es wrong and have to go back and escape my commas."
Jayanti raises her hand :)
Indi raises her hand.
Parity nods! "Three cheers for Whirlaway. ;) If I changed it to output like: 'Whirlaway,' a player identified by 'whirlaway'. ... then we'd have a problem. {} will group stuff as a single string so this doesn't happen. Also useful in @switch.
Parity says, "Yes, Jayanti?"
Jayanti says, "ers and was lagged I think. didn't see Whirlaway's answer until I had typed :) Came up in scroll."
Parity ahs. "Okay. ;)"
Parity says, "Indi?"
Indi says, "When you guys keep talking about 'escaping' your commas, uh, what does that mean?"
Parity says, "It means prefixing them with a % or a \"
Indi says, "Which makes them..?"
Parity says, "It makes them no longer have special significance."
Parity says, "You may have noticed that you can't say % ..."
Parity says, "You have to say %% to say % ..."
Indi nods. "Got it."
Parity says, "That's the idea of escaping. '%' has special meaning, but by putting another in front of it we 'cancel' the special meaning. Similarly, %[ just about everywhere."
Parity says, "Commas don't -normally- need escaping, not just to talk, but they do in functions."
Siobhan puts up her hand.
Parity says, "Yes, Siobhan?"
Siobhan says, "So, if you want the function (through the command) to spit out a string, you'd put the curly brackets in, right? Thereby negating the need to use next to special characters?"
Parity says, "Mmm... the curly braces {} only help with commas. [] and % would still have their effect."
Siobhan says, "Okay. That makes sense. :)"
Parity says, "If you truly want -everything- to be treated literally, you can (hopefully, on most codebases) use lit()."
Parity says, "I consider lit() to new to trust, but then, I consider ifelse() to new to trust... ;)"
Siobhan nods. :)
Parity says, "So, if you're not planning on running on a tinymush 2.x or a tinymux 1.x, you're probably safe. I'm not as up with penn versions."
Parity says, "Penn's versions aren't so dramatic since it's got a pretty normal free-software-project continuous-tweaking life."
Whirlaway says, "Penn 1.7.4 has lit()"
Parity nods, "Thanks W.
Parity says, "Okay, that leaves unanalyzed only the []..."
Parity says, "The square brackets are used to force a command evaluation in the midst of a string."
Parity says, "So, they're somewhat computationally expensive, and for that reason among others - like squishing spaces - you want to be careful not to use more than you need, but to use all that you need."
Parity says, "Technically, I used one more than I need."
Parity says, "Immediately after the equals sign, a function would be expected, so I don't have to specially signal evaluation for setq()."
Jayanti *hand up*
Parity says, "It's pretty much true that whenever you -begin an argument- you can have a function there, that's where functions are expected. Anywhere else, you need to signal that you have a function."
Parity says, "Yes Jayanti?"
Jayanti says, "can you show the command again? There are several in the scrollback and I'm not seeing the one with brackets. :)"
Parity is referring to the whole command, "One moment."
Parity says, "$+player *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{'[name(%q0)]' is the player identified by '%0'.},{'%0' is not a player.})]"
Indi shivers. Scary.
Jayanti says, "ohh cool. I totally missed that one :)"
Parity says, "That's the whole command on the 'player commands' object."
Parity says, "You can 'exa player commands/player-cmd' any time you like."
Jayanti says, "oh, sorry sorry"
Parity says, "sokay. Gets it into the log for Sio. :)"
Siobhan grins.
Parity says, "Okay. So, I didn't -have- to wrap setq() because it was at the beginning. I -did- have to wrap switch() because it followed setq and was part of the same single-string argument to @pemit."
Parity says, "With those around the switch() the player would literally see, 'switch' and a bunch of other stuff after it."
Sabbath enters the room through the double doors, which swing closed behind her.
Sabbath has arrived.
Parity says, "Generally speaking, if your command does that to you unexpectedly, you didn't match up your parentheses () or square brackets [] somewhere."
Parity says the command once more to put it on your screens.
Parity says, "$+player *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{'[name(%q0)]' is the player identified by '%0'.},{'%0' is not a player.})]"
Parity says, "Now I think we've pretty much torn this poor piece of code to shreds, but just in case, are there any remaining questions?"
Indi says, "Explain it all again? (Just kidding)."
Parity chuckles, and summarizes quickly, anyway, to get back to the big picture, "When some types '+player <something>', look up the num() of <something>, store in q0. Check q0 for being a dbref and for being a player. Switch on the boolean result of that check. If it -is- a valid player dbref, then print out a message saying so (with name()), otherwise print out an informative error message.
Parity says, "The -reason- for this as our first example, is this is what we call 'boilerplate' code."
Parity says, "You'll have a thousand commands that look an awful lot like this but vary in the details that they @pemit."
Parity says, "But when you have a +background command or a +charsheet command, the first thing you're going to look for is, 'is this argument a valid player?'"
Parity whews. "Okay. I'm going to take five minutes or so break. ;)
Whirlaway raises a hand.
Parity says, "Ah, Whirlaway?"
Parity answers question before break. ;)
Whirlaway says, "I've been using pmatch() to check if something's a valid player. Is using isdbref() and match(type(),player) better?"
Parity says, "It depends on what you want, and how portable you want to be. For your own mu*s code, portability may not be an issue if you love your codebase."
Lady Rosalynne unidles jsut in time for the break she sees. <grin>
Parity says, "However, I don't like the partial-matching, personally... it's too often the cause of mistakes. ;)"
Parity says, "But since it's hardcoded into page and that's the -worst- place for it... well, putting the same partial matching everywhere else might be fine, especially if you love it for being able to, say, match rosalynne when referring to lady rosalynne."
Parity says, "Of course, some mu*bases are supporting multiple aliases now. I prefer strict-matching and multiple-aliases, but when as diety of your own mu* you can do what -you- prefer. ;)"
Parity says, "Okay, feel free to exa the other attributes on 'player commands'."
Parity says, "We'll not be going through those in such excrutiating detail, of course. ;)"
Parity is going to take that few minutes break now. Will be back.
Parity says, "Okay."
Parity says, "A brief word more about setq(), btw. You can have q's from 0-9. setq(1,something) will mean now evaluates to 'something', and so on."
Parity says, "It's sort of obvious to me that that would be the case, but then, I've been working with setq() for years. ;)"
Parity says, "Now. Finger-cmd..."
Parity says, "$+finger *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{ [center(<%b[name(%q0)]%b>,76,-)]%rName: [name(%q0)]%rSex: [switch(get(%q0/sex),M*,Male,F*,Female,Other)]%rIdle: [idle(%q0)] seconds%r[repeat(-,76)] },{'%0' is not a player.})]"
Parity says, "That's the value of the finger-cmd attribute. Similarly to the other one, but the '1' case in the switch has gotten more convoluted."
Parity says, "There's not a lot to say about this one that we didn't say about the other, it's really just a way of showing how changing only the switch() turns a stupid-example into an almost-useful function."
Parity says, "It does have a 'nested' switch, which is to say, a switch inside of another switch. You can do that. :)"
Parity says, "It does -not- check people's &info, &mu-addy, etc., because, as an ordinary player, I can't see those, and so my object can't either."
Parity says, "Now, when you, as a wizard on your own world write a finger you can grab all kinds of attributes, but you need to remember, for your -object- to have that power it must be set 'inherit'."
Parity says, "If you don't do that, your command will fail when an ordinary player runs it."
Parity says, "It also means, of course, to be careful with any code you put on an object set inherit."
Parity thinks that's really about it, unless there's questions?
Siobhan is good. :)
Indi doesn't have any, no.
Parity okays.
Parity says, ""$+who:@pemit %#=[setq(0,objeval(%#,lwho()))][center(%b[mudname()]%b,76,-)][iter(%q0,%r[ljust(name(##),15)][rjust(u(idle-fn,idle(##)),5)][repeat(.,20)][rjust(switch(loc(##),#-1,Unfindable,name(loc(##))),36,.)])]%r[center(%b[words(%q0)]%bPlayers,76,-)]"
Parity says, "Now we get more excitement. ;)"
Parity says, "Kind of silly on a player object, but i stuck objeval() in here anyway."
Parity says, "objeval() evaluates an expression (a function, a string with or without substitutions, etc.) from the point of view of the first argument."
Parity says, "In this case, the invoking player."
Parity says, "So, objeval(%#,lwho()) will get the list of players logged in, -as the invoker- of +who would see it. Meaning, specifically, they don't see dark wizards."
Parity says, "So, objeval() is basically useful when you want to limit powers in one part of a command, but have wizard powers in another part of the command (like getting various attributes, &position or &race or whatever.)"
Parity says, "lwho() is the classic example, but loc() is also a common one, since wizards can ignore 'unfindable' flags but players can't."
Parity says, "Any questions on objeval?"
Parity didn't objeval() around loc() in this example, but should have, and would on a real one.
Siobhan has no questions.
Jayanti either.
Indi nopes.
Parity says, "OKay. More formatting commands, and then, 'iter()' .."
Parity says, "iter() is the most basic and common loop in mushcoding."
Parity says, "In this case, we set %q0 to a list of player dbrefs, seperated by spaces, because that's what lwho() returns."
Parity says, "So, iter(%q0,##) would simply print out that list."
Parity says, "And iter(%q0,name(##)) would print out a list of names, seperated by spaces, that belong to the dbrefs in that list."
Parity says, "We went a little further than that here. ;)"
Parity says, "If you can see through the maze of parentheses and find where the iter() begins, you can see, it's a series of items, most referring to ## in some way. name(##), u(idle-fn,idle(##)), loc(##)..."
Parity says, "Each 'run' of the loop replaces ## with a different dbref."
Parity says, "So, each time we get a line with name, idle time, and either the location or the word unfindable (see the switch -inside- the iter.)"
Parity says, "When looking at stuff like this, it helps to try to trim away the excess, either mentally by looking for the 'key' pieces, or physically, by putting it in your favorite text editor and moving it around, especially putting more spaces in so you can see the pieces."
Parity personally, writes everything in emacs, and then uploads it to the mu*.
Parity says, "When I'm confused by code, I put it in an editor, match up the big chunks blocked of inside of and put them on separate lines, stick spaces or tabs in... and so on."
Parity says, "Of course, then you have to put it back together... but, if you end up doing it a lot, there's a tool out there called 'molitor's mush formatter' (and unformatter) which spaces things out and crunches them together."
Parity says, "I don't use it, but many excellent codewizards out there rely on it daily."
Parity says, "OKay, the u() we'll get to in a moment... any questions on iter()?"
Sabbath shakes her head.
Siobhan is good, she thinks.
Lady Rosalynne raises her hand.
Parity says, "Yes, Lady R?"
Lady Rosalynne says, "Any thing against using parse()? I know iter can do some things that parse cannot, but if both are available, is there a perf?"
Parity says, "Nothing wrong with parse at all."
Parity says, "I actually changed this code -from- parse ;)"
Lady Rosalynne says, "so, interchangeable?"
Parity says, "I just think iter() is an easier mnemonic."
Parity nods.
Parity says, "Pretty much."
Lady Rosalynne nods and thanks.
Parity thinks for a moment, "I'd vaguely recommend iter() over parse() in that I see iter() in -lots- of code out there and hardly ever parse().
Parity says, "So if one were to vanish from the codebases, I know where I'd put my money."
Lady Rosalynne nods.
Parity says, "But, generally, codebases only grow, so that's not likely."
Parity says, "Okay. If we evaluate 'parent(player commands)' we get a dbref like #3472."
Parity says, "If you exa #3472, you'll see on it an attribute called 'idle-fn'."
Player Functions(#3472V)
Type: THING Flags: VISUAL
Owner: Parity Key: *UNLOCKED* Pennies: 1
Zone: *NOTHING*
Powers:
Created: Thu Aug 05 13:00:01.461707 2004
Modified: Thu Aug 05 13:00:54.677242 2004
IDLE-FN: [ifelse(lt(%0,86400),ifelse(lt(%0,3600),ifelse(lt(%0,60),%0s,div(%0,60)m),div(%0,3600) h),div(%0,86400)d)]
No exits.
Home: Parity's Circuitry Room(#1071RJ)
Location: Player Commands(#3474V)
Jayanti shakes her head
Parity says, "no? Oh."
Parity sets it visual!
Parity says, "Sorry!"
Jayanti says, "yay!"
Parity says, "Okay, so. Here's another piece of ancient code of mine. Hm."
Parity says, "s"
Parity says, "First, I have it wrapped in unnecessary ... []"
Parity says, "Then after extolling switch() it's got an ifelse() ... I don't know what I was thinking back then. :)"
Parity says, "Anyway. When we say, back in who-cmd, 'u(idle-fn,idle(##))', what happens - aside from getting the number of seconds a player has been idle - is that the mu* looks for an attribute 'idle-fn' on the current object."
Parity says, "Failing to find it, it looks for such an attribute on the parent."
Parity says, "Then, basically, it acts as if the contents of that attribute were in the place of u(idle-fn) ..."
Parity says, "However, we called idle-fn with an -argument- ..."
Jayanti has a kinda off topic kinda on topic question
Parity says, "That argument becomes '%0' when the contents of idle-fn are evaluated. Similarly, more arguments would become %1, %2 and so on, the same as in $-commands."
Parity says, "Yes, Jayanti?"
Jayanti says, "If it looks on the object first for something and doesnt find it, then on the parent...but finds something that wants to store information or modify information on "me"--where does it modify/store?"
Parity erms. "Don't do that. :)"
Jayanti laughs. Ok
Parity tries to remember, "I went through this upon a time... it was a pain."
Parity says, "you won't want to do that anyway."
Jayanti grins. I'm such a pain. OK :) will accept that answer
Parity says, "When you're creating global system, you want your commands on one object, your functions on another, and your data somewhere else."
Parity says, "Either on a data-object, which I'm fond of, or on a player, which has a lot of good points too."
Jayanti nods
Parity says, "For stuff you create as a normal player to carry on your person, you'll probably not have parents involved anyawy."
Parity says, "The reason for shoving all the functions off onto a parent, is that when your command-object lives in the master room, every time a player types a command, every attribute on every object in the master room is checked..."
Parity says, "Well, until a match is found, of course. But it eats cpu time to check 300 functions..."
Parity says, "A command object in your own inventory has the same issue, of course, but on such a small scale that it's not relevant. And you probably don't have 300 functions on it, you probably have 3. ;)"
Parity okays. "So, back to topic, u() basically evaluates the contents of an attribute, with argument substitution, effectively letting you create your own functions."
Parity says, "And, btw, u() and friend v() are basically like get_eval(me/...) and get(me/...)."
Parity ponders.
Iuz says, "+ritual/eesha"
Parity blinks.
Sabbath has wondered about that.
Iuz says, "Whups :)."
Whirlaway says, "WTF?"
Parity ahems. "Anyway."
Iuz says, "Code command from another MU*. Sorry, been idling to catch this class in my backscroll."
Parity says, "That brings us to floating-lock."
Parity says, "This is the reason I made you all set yourself floating. ;)"
Parity says, "[or(hasflag(%#,floating),hasflag(%#,wizard))]"
Parity says, "Unlike the functions, the are actually necessary here. On some codebases. And don't hurt on others."
Sabbath says, "We had to be set floating?"
Parity says, "So, there they are."
Parity says, "In order to invoke the commands. ;)"
Parity says, "If you @set me=floating, you can use +player and the local-to-this-room +finger and +who."
Jayanti says, "ohhh"
Parity says, "Of course, siobhan was exempt from needing to set floating."
Parity says, "Not that I would have copied a check for royalty-or-wizard and modified it or anything."
Sabbath ahhs.
Parity says, "But now that I think about it... ;) If you wanted to have a bunch of uber-cool-staff-commands, you could put them all on an object like this. Create attribute that evaluates to 1 for people who should have access to staff commands, with a variety of flag checks and boolean functions... and then @lock it up."
Parity says, "In this case, '@lock/uselock player commands=floating-lock/1'"
Sabbath idles for a bit.
Parity says, "Which basically means, 'only evaluate commands on me when floating-lock evaluates to 1'."
Parity says, "It could as easily be floating-lock/yessireebob ..."
Parity says, "But then you'd have to write switches that return yessireebob and people would look at you funny."
Jayanti grins
Parity doesn't know why the syntax is that way. "If I'd been in charge, you'd pass function-locks that evaluate to 1 and fail those that evaluate to zero. But, the way it -is- written, you have to specify the 'passing' return value.
Parity mumbles.
Parity says, "Lessee."
Parity says, "I brought with me for show and tell..."
Parity coughs.
Parity says, "Anyway. 'MoneyCode' is an actual, if not yet complete, softcode system I'm working on."
Parity says, "If you 'l moneycode' you will see I've stuffed inside it, 'moneyfunc' and 'moneydata'."
MoneyCode(#3590V)
Type: THING Flags: VISUAL
Owner: Parity Key: Parity(#384PXcF) Pennies: 1
Zone: *NOTHING*
Parent: MoneyFunc(#3589V)
Powers:
Created: Wed Aug 11 12:34:29.946883 2004
Modified: Wed Aug 11 12:37:13.76777 2004
DATA: #3591
MONEY-OTHER-CMD: $+money *:@switch hasflag(%#,wizard)=1,{ @pemit %#=[setq(0,num(*%0))][name(%q0)] has [u(money-format-fn,u(money-fn,add(%q0,0)))]. },{ @pemit %#=Huh?%b%b(Type "help" for help.) }
PAY-CMD: $+pay *=*:@switch/first [setq(0,num(*%0))][and(isdbref(%q0),match(type(%q0),player))][setq(2,switch(rest(%1),gold,10,dubloons,10,dubloon,10,silver,1,silvers,1,moon,1,moons,1,0))][setq(1,mul(first(%1),%q2))][and(isnum(%q1),gte(u(money-fn,%#),%q1))][gt(%q2,0)]=0??,{ @pemit %#=I don't know who you mean. },??0,{ @pemit %#=I don't understand that amount. },?0?,{ @pemit %#=You don't have that much money! },111,{ &money-%q0-amt [v(data)]=add(u(money-fn,%q0),%q1) ; &money-%#-amt [v(data)]=sub(u(money-fn,%#),%q1) ; @pemit %#=You give [name(%q0)] [u(money-format-fn,%q1)].; @pemit %q0=%n gives you [u(money-format-fn,%q1)].; &money-%#-log [v(data)]=cat(get(v(data)/money-%#-log),|%q0 %q1) }
MONEY-GIVE-CMD: $+money/give *=*:@switch/first [setq(0,num(*%0))][and(isdbref(%q0),match(type(%q0),player))][setq(2,switch(rest(%1),gold,10,dubloons,10,dubloon,10,silver,1,silvers,1,moon,1,moons,1,0))][setq(1,mul(first(%1),%q2))][and(isnum(%q1),gte(u(money-fn,%#),%q1))][gt(%q2,0)]=0??,{ @pemit %#=I don't know who you mean. },??0,{ @pemit %#=I don't understand that amount. },?0?,{ @pemit %#=You don't have that much money! },111,{ &money-%q0-amt [v(data)]=add(u(money-fn,%q0),%q1) ; &money-%#-amt [v(data)]=sub(u(money-fn,%#),%q1) ; @pemit %#=You give [name(%q0)] [u(money-format-fn,%q1)].; @pemit %q0=%n gives you [u(money-format-fn,%q1)].; &money-%#-log [v(data)]=cat(get(v(data)/money-%#-log),|%q0 %q1) }
MONEY-CMD: $+money:@pemit %#=You have [u(money-format-fn,u(money-fn,%#))].
MONEY-SET-CMD: $+money/set *=*:@switch/first [hasflag(%#,floating)][setq(0,num(*%0))][and(isdbref(%q0),match(type(%q0),player))]=0?,@pemit %#=You're not authorized to set anyone's money.,?0,@pemit %#=I don't know who you mean.,&money-%q0-amt [v(data)]=%1
Contents:
MoneyFunc(#3589V)
MoneyData(#3591V)
No exits.
Home: Parity's Circuitry Room(#1071RJ)
Location: Lecture Room(#14RJs)
Parity says, "In light of our earlier discussion, you might quickly guess that moneycode's parent is moneyfunc."
MoneyFunc(#3589V)
Type: THING Flags: VISUAL
Owner: Parity Key: *UNLOCKED* Pennies: 1
Zone: *NOTHING*
Powers:
Created: Wed Aug 11 12:34:26.396479 2004
Modified: Thu Aug 12 09:25:20.06567 2004
MONEY-FORMAT-FN: [switch(%0,0,no money,switch(div(%0,10),0,,div(%0,10) Crown[switch(div(%0,10),1,,s)][switch(mod(%0,10),0,,%band%b)]))][switch(mod(%0,10),0,,1,1 Noble,mod(%0,10) Nobles)]
MONEY-FN: get(v(data)/money-%0-amt)
No exits.
Home: Parity's Circuitry Room(#1071RJ)
Location: MoneyCode(#3590V)
Parity says, "Now, the 'real' version of this code lives in a text file, and between each attribute theres an '@@' or three with text after it. '@@' is the 'comment' command so when I send my file to mush, my comments don't do anything."
Parity says, "If I had to actually work with just the object as it is here, I'd probably go mad... err, though some might say that's already happened. However."
Parity says, "The deal with the moneycode is, it uses a number of common conventions, so when you grab myrddin's bbs or such off the net you may see this."
Jayanti raises her hand
Parity says, "IIRC, keran's weather has a completely convoluted setup involving a special room for most of the code to live in, but it needs a parent room anyway. ;)"
Parity says, "Yes, Jayanti?"
Jayanti says, "You mean the fn. stuff that denotes it as a function, or that it has a function that is used so prevalently in the object that it deserves a reference function?"
******
Coding for the Coderless
Attendees:
Fyrn | Indi | Iuz | Jayanti | Lady Rosalynne | Odin | Parity | Sabbath | Siobhan | Trek | Virgo | Whirlaway
Parity says, "Good morning, class. I'm going to ask you all to keep the off-topic chatter to a minimum from this point on, and, yes, I want you to raise your hand when you have a question - ie, any -short- pose indicating you want to speak."
Odin enters the room through the double doors, which swing closed behind it.
Odin has arrived.
Parity says, "Okay, this class is particularly focused on the needs of someone without much prior experience in coding just about everything on a MUSH."
Parity says, "The first thing I'm going to say, is -"
Jayanti enters the room through the double doors, which swing closed behind it.
Jayanti has arrived.
Parity says, "-Don't- write your own +finger, +who, etc, even though I'm using such things as examples. It's a waste of time. There's the sandbox globals project, and if you don't like that system, there's other free code available on the web."
Parity says, "However, you're going to need to understand them. So. I'd like everyone to look at (exa) player commands."
Player Commands(#3474V)
Type: THING Flags: VISUAL
Owner: Parity Key: Parity(#384PXcF) Pennies: 1
Zone: *NOTHING*
Parent: Player Functions(#3472)
Powers:
Created: Tue Aug 03 12:38:29.487797 2004
Modified: Wed Aug 11 18:59:38.809211 2004
PLAYER-CMD: $+player *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{'[name(%q0)]' is the player identified by '%0'.},{'%0' is not a player.})]
FINGER-CMD: $+finger *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{ [center(<%b[name(%q0)]%b>,76,-)]%rName: [name(%q0)]%rSex: [switch(get(%q0/sex),M*,Male,F*,Female,Other)]%rIdle: [idle(%q0)] seconds%r[repeat(-,76)] },{'%0' is not a player.})]
WHO-CMD: $+who:@pemit %#=[setq(0,objeval(%#,lwho()))][center(%b[mudname()]%b,76,-)][iter(%q0,%r[ljust(name(##),15)][rjust(u(idle-fn,idle(##)),5)][repeat(.,20)][rjust(switch(loc(##),#-1,Unfindable,name(loc(##))),36,.)])]%r[center(%b[words(%q0)]%bPlayers,76,-)]
FLOATING-LOCK: [or(hasflag(%#,floating),hasflag(%#,wizard))]
UseLock: FLOATING-LOCK/1
Contents:
Player Functions(#3472)
No exits.
Home: Parity's Circuitry Room(#1071RJ)
Location: Lecture Room(#14RJs)
Parity says, "The first attribute on there is 'player-cmd', which is a typical $-command. I believe you all know what $-commands are, if not, now would be a good time to wave panickedly."
Indi fulfulls her destiny, and raises her hand.
Fulfills*
Parity okays, "Briefly, a $-command is an attribute on an object that specifies a command. In this case, the first part of the attribute's value, '$+player *:' says 'The command I define is '+player' followed by a space and one argument'. Does that help Indi, or did you have more of a question?
Indi says, "Answered. =)"
Parity says, "Everyone should, right now, '@set me=floating'."
Parity says, "We'll get to the why of that later, but I locked this object so that that's what you need to do. :)"
Parity says, "Now, you can '+player parity' and get one thing, and '+player flyingpurplepeopleeater' and get another."
Parity says, "Not so exciting, I know."
Parity says, "But, almost every command you make will need to figure out that the target is or is not a valid player, and we use some helpful techniques along the way. The first thing is the command, of course, is '@pemit %#='"
Parity says, "%# is the player (or other object) who -invoked the command-."
Parity says, "OKay. More interesting is setq() ... how many people here know setq()?"
Indi does not.
Siobhan shakes her head.
Trek says, "I know /of/ it... :P"
Parity says, "setq() is how you store values temporarily, so you can use them repeatedly."
Jayanti does not either.
Parity says, "This is particularly useful for, say, calculating 'hours' because you don't want to type a complicated expression every time. So, if you type, 'setq(0,foobar)', then further along in the attribute you type '', '' will be replaced with 'foobar'."
Fyrn says, "Sweet!"
Parity erms.
Parity missed an escape there.
Trek thinks someone forgot to use escape characters. :P
Parity says, "This is particularly useful for, say, calculating 'hours' because you don't want to type a complicated expression every time. So, if you type, 'setq(0,foobar)', then further along in the attribute you type '%q0', '%q0' will be replaced with 'foobar'."
Indi says, "That's cool."
Jayanti raises her hand.
Parity also lost the hours expression, 'setq(0,div(<seconds>,3600))' ... %q0 for hours.
Parity says, "Yes, Jayanti?"
Jayanti says, "nevermind :) That was the question."
Parity ahs.
Parity says, "I changed my example halfway. ):"
Parity says, "Anyway. . is the value of the first argument in a command."
Parity says, "In the case of +player it's everything after '+player'. (Technically, everything after the space after +player)."
Parity says, "So if you type '+player this sentence is false' then will be 'this sentence is false'."
Parity says, "num(*this sentence is false), of course, will return #-1, because there's no such player."
Siobhan says, "And num searches for the dbref# of a player, right?"
Siobhan says, "Oops."
Parity says, "num() returns a dbref of an object... * means check for players & aliases, as opposed to checking for things-near-the-evaluating-object."
Fyrn sighs and leaves.
Parity says, "So, num(*siobhan) will return siobhan's dbref."
Trek raises a metaphorical hand.
Parity says, "While we're in the same room with her, so will num(siobhan) - but globals are usually in the Master Room, nowhere near the player-in-question."
Parity says, "So ... setq(0,num(*%0)) ... store in q0 the dbref of the player named whatever-was-stored in %0 - which came from the person typing '+player parity' or whatever."
Parity says, "Everybody with me so far?"
Indi is. =)
Siobhan nodnods.
Jayanti thinks she is ;)
Virgo says, "Sort of."
Trek ayups.
Parity says, "Anybody feeling a little lost may want to try 'think num(trek)', 'think num(flattenedtuba)', 'think num(sparks)', and 'think num(*sparks)' ..."
Virgo shakes her head and raises her hand.
Parity says, "So, %q0 is now either '#-1' or a dbref of a player, and the next part is where q-values become happy happening things."
Parity nods, "Yes virgo?"
Virgo says, "Is the comma in the setq bit just something like an 'and', as in an addition to? A list?"
Siobhan also puts up her hand after Virgo.
Parity ohs, "In a function, the comma separates arguments. setq() takes two arguments, one before the comma, one after. switch(), which we're comming up on, takes as many arguments as you can throw at it, all seperated by commas."
Parity says, "Yes, Siobhan."
Parity says, "You can follow up if you need to Virgo."
Siobhan says, "So I understand that '%q0' is temporary... it's just set temporarily while that command is being executed? It doesn't actually store it physically on an object?"
Parity says, "Right."
Siobhan says, "Gotcha. :)"
Parity says, "The way I'd say it, being technical, is exists during the current evaluation."
Indi raises a hand.
Parity says, "Yes, Indi?"
Indi says, "Oh, never mind. I reread what you said. Now I get it. =)"
Virgo says, "Sorry, dog distraction. I'm not sure I understand the term argument in relation to this."
Parity says, "Arguments are the values 'given to' a function or command."
Virgo nods. "Okay, got it."
Parity says, "In a command, they're the things after the command name. In a function, they're the things inside the parens ()."
Parity says, "So, going into the next segment, we enter a switch() function and make our q work for us. We want to know, first, that we got a valid dbref, and second, that we got a player."
Parity says, "So, 'switch(and(isdbref(%q0),match(type(%q0),player)), ... )' is what I'm talking about."
Parity says, " and() just returns 1 if -both- things are true (which in computer term means a non-zero number); isdbref() returns 1 if the argument is a valid dbref."
Parity says, "match is a bit tricky, but in this case, we're using it as a case-insensitive 'are these strings equal'."
Parity says, "The actual value of type(*parity) would be 'PLAYER'"
Parity says, "So you can think that we're asking, 'Are isdbref(num(*Parity)) AND match(type(num(*Parity),PLAYER) both true?'"
Parity says, "Having asked that, switch() lets us make a decision based on the answer."
Parity says, "switch() is your friend. ;) switch() is a lot like ifelse(), if that helps."
Parity says, "In this case, it's -exactly- like ifelse()."
Jayanti hehs. Uhhh *hand*
Parity says, "However, switch() can do a whole -bunch- of if's at once if you need to, and exists on every codebase I know."
Parity says, "Yes Jayanti?"
Jayanti says, "Well, may be jumping the gun here, but what are the differences between switch() and @switch?"
Parity says, "switch() is a function, and @switch is a command."
Indi raises a hand.
Parity says, "So, you can either, '@pemit %#=switch(condition,1,true,false)' -or- '@switch condition=1,@pemit %#=true,@pemit %#=false'"
Jayanti nods. ok
Parity says, "Generally speaking, switch() is preferable, but there are exceptions - ie, '@switch <condition>=1,@remit %#=Something happens.,@pemit %#=You can't do that!'"
Parity says, "Now you're using two different commands in that example, hence, @switch."
Jayanti says, "cool"
Parity says, "Yes, Indi?"
Indi says, "The differences between a command and a function are, basically, commands are automatic and simple whereas functions can include a number of commands? Like, the difference between buying peanut butter and making it?"
Indi says, "It's the little things that mess me up."
Parity ponders this one for a moment.
Parity says, "A command is something you can type, and have it do something. '+who' is a command. '@emit' is a command."
Parity says, "A function is something that replaces itself with another string."
Parity says, "That used to be 100% true, and for now we'll pretend it is. ;)"
Virgo holds up her hand for after Indi's question is answered.
Parity says, "So, a command can do anything. Create objects, destroy them, cause the database to be backed up..."
Indi likes to use comparisons. "So, commands are like opening a door when functions are like.. the stuff inside the handle (like locks) that are interchangeable and make it work?"
Parity says, "A function can only replace itself with a string. Okay, setq() has a 'side effect' of setting %q0... but it's mostly true."
Trek inserts a remark, if that's okay?
Parity says, "Sure, Trek."
Parity doesn't have a good comparison ready to hand...
Parity says, "If I make one up on the spot, I'd say functions are like laws of nature and commands are like actions in the world, but I can also poke big holes in that anology. :)"
Trek says, "Functions replace themselves with strings--putting commands inside of them doesn't work, hence why there's an @switch."
Parity ahs, "Good point."
Parity says, "Functions go inside commands, -never- the other way around."
Indi nods, "I think I got it."
Trek says, "Indi's analogy actually seems pretty good to me, but I'm no more than an acolyte with MUSHcode. :P"
Parity says, "It is technically possible to reverse that, but I encourage all good mushdieties to disable the force() function, as it is an abberation of nature and a security hole. ;)"
Parity says, "Here's a point... you can 'say' any function."
Parity says, "like, 'say time()' for example."
Parity says, "Commands cannot be said, they have to be 'done' ... they're the first thing you type if you enter them directly."
Parity says, "Virgo, still have a question?"
Indi says, "Ah, gotcha. That helped cement it. =)"
Virgo says, "With switch(), do the last two arguments always have to be the true and false parameter?"
Parity moves forward in any case, although we may have more questions forthcoming, there it is... , "So, switch() here, briefly, works like, 'switch(something,checkthis,dothis,checkthat,dothat,defaultaction)'
Parity says, "So the -last- argument is the 'false' parameter."
Parity says, "However, you can have - and this will actually show a last argument that is 'true' - and often we see this - switch(rand(3),0,nothing,1,snake-eyes,2,a winner!)"
Parity says, "SO this says, 'if 0, then 'nothing', if '1', then 'snake-eyes', if 2 then 'a-winner' ... since we've covered every possibility, we don't need an 'else' or 'false' condition."
Jayanti grins. Uhh, question.
Parity nods, "Yes, Jayanti?"
Jayanti says, "That breaks down to (pick a random number from 0-3, blah blah blah, if it is 2 or 3 it is a winner?"
Parity says, "Sorry, no, pick a number from 0 to 2."
Parity says, "To get what you describe, we want,"
Parity says, "... switch(rand(4),0,nothing,1,snake-eyes,a winner!)"
Parity says, "rand() returns a number between zero and the argument minus one."
Jayanti says, "Ok...little confusing, cleared up now ;)"
Parity says, "And the rand(4) example goes back to using an 'else' at the end. 'if 0 ... if 1 ... else ...'"
Jayanti nods. Got it.
Parity says, "Anymore questions? It's okay. switch() is -important-."
Siobhan -thinks- she's got it.
Parity says, "A lot of these things I brush over. You can look up num(), rand(), whatever, in the help files. switch() and setq() are tricky. ;)"
Virgo raises her hand... again.
Jayanti noddles. Was just confused as to whether it was a default on switch after 2 or if it ended there ;)
Parity says, "Yes, Virgo?"
Virgo says, "Okay, how does it know if the argument is for a true or false?"
Parity mmms. "switch() doesn't care about true or false, really. It cares about 'does this match'.
Parity says, "It happens that the boolean (meaning 'returns true or false') functions return '0' or '1'."
Parity says, "So, we can switch(somethingboolean(),1,this is a true case,0,this is a false case)"
Parity says, "Does that answer the question, or did you mean something else?"
Virgo says, "Oh, so you need the 0 and 1 in there for it to differentiate?"
Parity nods.
Virgo says, "Gotcha."
Parity says, "ifelse(somethingboolean(),true case,false case) ... switch(somethingboolean(),1,true case,0,false case) ..."
Parity says, "Although, I'd encourage you to write it, 'switch(somethingboolean(),1,true case,false case)' ... subtle difference there being I'm using a default instead of explicitly checking for zero."
Parity says, "Generally speaking, you want all your failures to fall into the 'default' cases so that unexpected errors get handled."
Virgo nodnods. "Makes sense."
Parity nods. "OKay."
Parity says, "So, in our example, we have, for the '1' case, "'Coding for the Coderless' is the player identified by ''.""
Parity says, "I don't think the string itself is anything exciting, though I will mention I almost always use name() rather than values passed in as arguments... it ensures you get the capitalization the player with the name uses."
Parity says, "The default case is even more dull, only printing out what was passed in."
Parity says, "More interesting, is that wrapped it in {}..."
Parity says, "This is utterly unnecessary, but also harmless, and a good habit."
Parity says, "I shall now do the obnoxious teachery thing of asking the class, ahem, 'Can anyone tell me why?'"
Siobhan shakes her head.
Whirlaway can guess?
Parity says, "Yes, Whirlaway?"
Whirlaway says, "Because if what you want to print out has commas, it confuses the switch()? I always get my switch()es wrong and have to go back and escape my commas."
Jayanti raises her hand :)
Indi raises her hand.
Parity nods! "Three cheers for Whirlaway. ;) If I changed it to output like: 'Whirlaway,' a player identified by 'whirlaway'. ... then we'd have a problem. {} will group stuff as a single string so this doesn't happen. Also useful in @switch.
Parity says, "Yes, Jayanti?"
Jayanti says, "ers and was lagged I think. didn't see Whirlaway's answer until I had typed :) Came up in scroll."
Parity ahs. "Okay. ;)"
Parity says, "Indi?"
Indi says, "When you guys keep talking about 'escaping' your commas, uh, what does that mean?"
Parity says, "It means prefixing them with a % or a \"
Indi says, "Which makes them..?"
Parity says, "It makes them no longer have special significance."
Parity says, "You may have noticed that you can't say % ..."
Parity says, "You have to say %% to say % ..."
Indi nods. "Got it."
Parity says, "That's the idea of escaping. '%' has special meaning, but by putting another in front of it we 'cancel' the special meaning. Similarly, %[ just about everywhere."
Parity says, "Commas don't -normally- need escaping, not just to talk, but they do in functions."
Siobhan puts up her hand.
Parity says, "Yes, Siobhan?"
Siobhan says, "So, if you want the function (through the command) to spit out a string, you'd put the curly brackets in, right? Thereby negating the need to use next to special characters?"
Parity says, "Mmm... the curly braces {} only help with commas. [] and % would still have their effect."
Siobhan says, "Okay. That makes sense. :)"
Parity says, "If you truly want -everything- to be treated literally, you can (hopefully, on most codebases) use lit()."
Parity says, "I consider lit() to new to trust, but then, I consider ifelse() to new to trust... ;)"
Siobhan nods. :)
Parity says, "So, if you're not planning on running on a tinymush 2.x or a tinymux 1.x, you're probably safe. I'm not as up with penn versions."
Parity says, "Penn's versions aren't so dramatic since it's got a pretty normal free-software-project continuous-tweaking life."
Whirlaway says, "Penn 1.7.4 has lit()"
Parity nods, "Thanks W.
Parity says, "Okay, that leaves unanalyzed only the []..."
Parity says, "The square brackets are used to force a command evaluation in the midst of a string."
Parity says, "So, they're somewhat computationally expensive, and for that reason among others - like squishing spaces - you want to be careful not to use more than you need, but to use all that you need."
Parity says, "Technically, I used one more than I need."
Parity says, "Immediately after the equals sign, a function would be expected, so I don't have to specially signal evaluation for setq()."
Jayanti *hand up*
Parity says, "It's pretty much true that whenever you -begin an argument- you can have a function there, that's where functions are expected. Anywhere else, you need to signal that you have a function."
Parity says, "Yes Jayanti?"
Jayanti says, "can you show the command again? There are several in the scrollback and I'm not seeing the one with brackets. :)"
Parity is referring to the whole command, "One moment."
Parity says, "$+player *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{'[name(%q0)]' is the player identified by '%0'.},{'%0' is not a player.})]"
Indi shivers. Scary.
Jayanti says, "ohh cool. I totally missed that one :)"
Parity says, "That's the whole command on the 'player commands' object."
Parity says, "You can 'exa player commands/player-cmd' any time you like."
Jayanti says, "oh, sorry sorry"
Parity says, "sokay. Gets it into the log for Sio. :)"
Siobhan grins.
Parity says, "Okay. So, I didn't -have- to wrap setq() because it was at the beginning. I -did- have to wrap switch() because it followed setq and was part of the same single-string argument to @pemit."
Parity says, "With those around the switch() the player would literally see, 'switch' and a bunch of other stuff after it."
Sabbath enters the room through the double doors, which swing closed behind her.
Sabbath has arrived.
Parity says, "Generally speaking, if your command does that to you unexpectedly, you didn't match up your parentheses () or square brackets [] somewhere."
Parity says the command once more to put it on your screens.
Parity says, "$+player *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{'[name(%q0)]' is the player identified by '%0'.},{'%0' is not a player.})]"
Parity says, "Now I think we've pretty much torn this poor piece of code to shreds, but just in case, are there any remaining questions?"
Indi says, "Explain it all again? (Just kidding)."
Parity chuckles, and summarizes quickly, anyway, to get back to the big picture, "When some types '+player <something>', look up the num() of <something>, store in q0. Check q0 for being a dbref and for being a player. Switch on the boolean result of that check. If it -is- a valid player dbref, then print out a message saying so (with name()), otherwise print out an informative error message.
Parity says, "The -reason- for this as our first example, is this is what we call 'boilerplate' code."
Parity says, "You'll have a thousand commands that look an awful lot like this but vary in the details that they @pemit."
Parity says, "But when you have a +background command or a +charsheet command, the first thing you're going to look for is, 'is this argument a valid player?'"
Parity whews. "Okay. I'm going to take five minutes or so break. ;)
Whirlaway raises a hand.
Parity says, "Ah, Whirlaway?"
Parity answers question before break. ;)
Whirlaway says, "I've been using pmatch() to check if something's a valid player. Is using isdbref() and match(type(),player) better?"
Parity says, "It depends on what you want, and how portable you want to be. For your own mu*s code, portability may not be an issue if you love your codebase."
Lady Rosalynne unidles jsut in time for the break she sees. <grin>
Parity says, "However, I don't like the partial-matching, personally... it's too often the cause of mistakes. ;)"
Parity says, "But since it's hardcoded into page and that's the -worst- place for it... well, putting the same partial matching everywhere else might be fine, especially if you love it for being able to, say, match rosalynne when referring to lady rosalynne."
Parity says, "Of course, some mu*bases are supporting multiple aliases now. I prefer strict-matching and multiple-aliases, but when as diety of your own mu* you can do what -you- prefer. ;)"
Parity says, "Okay, feel free to exa the other attributes on 'player commands'."
Parity says, "We'll not be going through those in such excrutiating detail, of course. ;)"
Parity is going to take that few minutes break now. Will be back.
Parity says, "Okay."
Parity says, "A brief word more about setq(), btw. You can have q's from 0-9. setq(1,something) will mean now evaluates to 'something', and so on."
Parity says, "It's sort of obvious to me that that would be the case, but then, I've been working with setq() for years. ;)"
Parity says, "Now. Finger-cmd..."
Parity says, "$+finger *:@pemit %#=[setq(0,num(*%0))][switch(and(isdbref(%q0),match(type(%q0),player)),1,{ [center(<%b[name(%q0)]%b>,76,-)]%rName: [name(%q0)]%rSex: [switch(get(%q0/sex),M*,Male,F*,Female,Other)]%rIdle: [idle(%q0)] seconds%r[repeat(-,76)] },{'%0' is not a player.})]"
Parity says, "That's the value of the finger-cmd attribute. Similarly to the other one, but the '1' case in the switch has gotten more convoluted."
Parity says, "There's not a lot to say about this one that we didn't say about the other, it's really just a way of showing how changing only the switch() turns a stupid-example into an almost-useful function."
Parity says, "It does have a 'nested' switch, which is to say, a switch inside of another switch. You can do that. :)"
Parity says, "It does -not- check people's &info, &mu-addy, etc., because, as an ordinary player, I can't see those, and so my object can't either."
Parity says, "Now, when you, as a wizard on your own world write a finger you can grab all kinds of attributes, but you need to remember, for your -object- to have that power it must be set 'inherit'."
Parity says, "If you don't do that, your command will fail when an ordinary player runs it."
Parity says, "It also means, of course, to be careful with any code you put on an object set inherit."
Parity thinks that's really about it, unless there's questions?
Siobhan is good. :)
Indi doesn't have any, no.
Parity okays.
Parity says, ""$+who:@pemit %#=[setq(0,objeval(%#,lwho()))][center(%b[mudname()]%b,76,-)][iter(%q0,%r[ljust(name(##),15)][rjust(u(idle-fn,idle(##)),5)][repeat(.,20)][rjust(switch(loc(##),#-1,Unfindable,name(loc(##))),36,.)])]%r[center(%b[words(%q0)]%bPlayers,76,-)]"
Parity says, "Now we get more excitement. ;)"
Parity says, "Kind of silly on a player object, but i stuck objeval() in here anyway."
Parity says, "objeval() evaluates an expression (a function, a string with or without substitutions, etc.) from the point of view of the first argument."
Parity says, "In this case, the invoking player."
Parity says, "So, objeval(%#,lwho()) will get the list of players logged in, -as the invoker- of +who would see it. Meaning, specifically, they don't see dark wizards."
Parity says, "So, objeval() is basically useful when you want to limit powers in one part of a command, but have wizard powers in another part of the command (like getting various attributes, &position or &race or whatever.)"
Parity says, "lwho() is the classic example, but loc() is also a common one, since wizards can ignore 'unfindable' flags but players can't."
Parity says, "Any questions on objeval?"
Parity didn't objeval() around loc() in this example, but should have, and would on a real one.
Siobhan has no questions.
Jayanti either.
Indi nopes.
Parity says, "OKay. More formatting commands, and then, 'iter()' .."
Parity says, "iter() is the most basic and common loop in mushcoding."
Parity says, "In this case, we set %q0 to a list of player dbrefs, seperated by spaces, because that's what lwho() returns."
Parity says, "So, iter(%q0,##) would simply print out that list."
Parity says, "And iter(%q0,name(##)) would print out a list of names, seperated by spaces, that belong to the dbrefs in that list."
Parity says, "We went a little further than that here. ;)"
Parity says, "If you can see through the maze of parentheses and find where the iter() begins, you can see, it's a series of items, most referring to ## in some way. name(##), u(idle-fn,idle(##)), loc(##)..."
Parity says, "Each 'run' of the loop replaces ## with a different dbref."
Parity says, "So, each time we get a line with name, idle time, and either the location or the word unfindable (see the switch -inside- the iter.)"
Parity says, "When looking at stuff like this, it helps to try to trim away the excess, either mentally by looking for the 'key' pieces, or physically, by putting it in your favorite text editor and moving it around, especially putting more spaces in so you can see the pieces."
Parity personally, writes everything in emacs, and then uploads it to the mu*.
Parity says, "When I'm confused by code, I put it in an editor, match up the big chunks blocked of inside of and put them on separate lines, stick spaces or tabs in... and so on."
Parity says, "Of course, then you have to put it back together... but, if you end up doing it a lot, there's a tool out there called 'molitor's mush formatter' (and unformatter) which spaces things out and crunches them together."
Parity says, "I don't use it, but many excellent codewizards out there rely on it daily."
Parity says, "OKay, the u() we'll get to in a moment... any questions on iter()?"
Sabbath shakes her head.
Siobhan is good, she thinks.
Lady Rosalynne raises her hand.
Parity says, "Yes, Lady R?"
Lady Rosalynne says, "Any thing against using parse()? I know iter can do some things that parse cannot, but if both are available, is there a perf?"
Parity says, "Nothing wrong with parse at all."
Parity says, "I actually changed this code -from- parse ;)"
Lady Rosalynne says, "so, interchangeable?"
Parity says, "I just think iter() is an easier mnemonic."
Parity nods.
Parity says, "Pretty much."
Lady Rosalynne nods and thanks.
Parity thinks for a moment, "I'd vaguely recommend iter() over parse() in that I see iter() in -lots- of code out there and hardly ever parse().
Parity says, "So if one were to vanish from the codebases, I know where I'd put my money."
Lady Rosalynne nods.
Parity says, "But, generally, codebases only grow, so that's not likely."
Parity says, "Okay. If we evaluate 'parent(player commands)' we get a dbref like #3472."
Parity says, "If you exa #3472, you'll see on it an attribute called 'idle-fn'."
Player Functions(#3472V)
Type: THING Flags: VISUAL
Owner: Parity Key: *UNLOCKED* Pennies: 1
Zone: *NOTHING*
Powers:
Created: Thu Aug 05 13:00:01.461707 2004
Modified: Thu Aug 05 13:00:54.677242 2004
IDLE-FN: [ifelse(lt(%0,86400),ifelse(lt(%0,3600),ifelse(lt(%0,60),%0s,div(%0,60)m),div(%0,3600) h),div(%0,86400)d)]
No exits.
Home: Parity's Circuitry Room(#1071RJ)
Location: Player Commands(#3474V)
Jayanti shakes her head
Parity says, "no? Oh."
Parity sets it visual!
Parity says, "Sorry!"
Jayanti says, "yay!"
Parity says, "Okay, so. Here's another piece of ancient code of mine. Hm."
Parity says, "s"
Parity says, "First, I have it wrapped in unnecessary ... []"
Parity says, "Then after extolling switch() it's got an ifelse() ... I don't know what I was thinking back then. :)"
Parity says, "Anyway. When we say, back in who-cmd, 'u(idle-fn,idle(##))', what happens - aside from getting the number of seconds a player has been idle - is that the mu* looks for an attribute 'idle-fn' on the current object."
Parity says, "Failing to find it, it looks for such an attribute on the parent."
Parity says, "Then, basically, it acts as if the contents of that attribute were in the place of u(idle-fn) ..."
Parity says, "However, we called idle-fn with an -argument- ..."
Jayanti has a kinda off topic kinda on topic question
Parity says, "That argument becomes '%0' when the contents of idle-fn are evaluated. Similarly, more arguments would become %1, %2 and so on, the same as in $-commands."
Parity says, "Yes, Jayanti?"
Jayanti says, "If it looks on the object first for something and doesnt find it, then on the parent...but finds something that wants to store information or modify information on "me"--where does it modify/store?"
Parity erms. "Don't do that. :)"
Jayanti laughs. Ok
Parity tries to remember, "I went through this upon a time... it was a pain."
Parity says, "you won't want to do that anyway."
Jayanti grins. I'm such a pain. OK :) will accept that answer
Parity says, "When you're creating global system, you want your commands on one object, your functions on another, and your data somewhere else."
Parity says, "Either on a data-object, which I'm fond of, or on a player, which has a lot of good points too."
Jayanti nods
Parity says, "For stuff you create as a normal player to carry on your person, you'll probably not have parents involved anyawy."
Parity says, "The reason for shoving all the functions off onto a parent, is that when your command-object lives in the master room, every time a player types a command, every attribute on every object in the master room is checked..."
Parity says, "Well, until a match is found, of course. But it eats cpu time to check 300 functions..."
Parity says, "A command object in your own inventory has the same issue, of course, but on such a small scale that it's not relevant. And you probably don't have 300 functions on it, you probably have 3. ;)"
Parity okays. "So, back to topic, u() basically evaluates the contents of an attribute, with argument substitution, effectively letting you create your own functions."
Parity says, "And, btw, u() and friend v() are basically like get_eval(me/...) and get(me/...)."
Parity ponders.
Iuz says, "+ritual/eesha"
Parity blinks.
Sabbath has wondered about that.
Iuz says, "Whups :)."
Whirlaway says, "WTF?"
Parity ahems. "Anyway."
Iuz says, "Code command from another MU*. Sorry, been idling to catch this class in my backscroll."
Parity says, "That brings us to floating-lock."
Parity says, "This is the reason I made you all set yourself floating. ;)"
Parity says, "[or(hasflag(%#,floating),hasflag(%#,wizard))]"
Parity says, "Unlike the functions, the are actually necessary here. On some codebases. And don't hurt on others."
Sabbath says, "We had to be set floating?"
Parity says, "So, there they are."
Parity says, "In order to invoke the commands. ;)"
Parity says, "If you @set me=floating, you can use +player and the local-to-this-room +finger and +who."
Jayanti says, "ohhh"
Parity says, "Of course, siobhan was exempt from needing to set floating."
Parity says, "Not that I would have copied a check for royalty-or-wizard and modified it or anything."
Sabbath ahhs.
Parity says, "But now that I think about it... ;) If you wanted to have a bunch of uber-cool-staff-commands, you could put them all on an object like this. Create attribute that evaluates to 1 for people who should have access to staff commands, with a variety of flag checks and boolean functions... and then @lock it up."
Parity says, "In this case, '@lock/uselock player commands=floating-lock/1'"
Sabbath idles for a bit.
Parity says, "Which basically means, 'only evaluate commands on me when floating-lock evaluates to 1'."
Parity says, "It could as easily be floating-lock/yessireebob ..."
Parity says, "But then you'd have to write switches that return yessireebob and people would look at you funny."
Jayanti grins
Parity doesn't know why the syntax is that way. "If I'd been in charge, you'd pass function-locks that evaluate to 1 and fail those that evaluate to zero. But, the way it -is- written, you have to specify the 'passing' return value.
Parity mumbles.
Parity says, "Lessee."
Parity says, "I brought with me for show and tell..."
Parity coughs.
Parity says, "Anyway. 'MoneyCode' is an actual, if not yet complete, softcode system I'm working on."
Parity says, "If you 'l moneycode' you will see I've stuffed inside it, 'moneyfunc' and 'moneydata'."
MoneyCode(#3590V)
Type: THING Flags: VISUAL
Owner: Parity Key: Parity(#384PXcF) Pennies: 1
Zone: *NOTHING*
Parent: MoneyFunc(#3589V)
Powers:
Created: Wed Aug 11 12:34:29.946883 2004
Modified: Wed Aug 11 12:37:13.76777 2004
DATA: #3591
MONEY-OTHER-CMD: $+money *:@switch hasflag(%#,wizard)=1,{ @pemit %#=[setq(0,num(*%0))][name(%q0)] has [u(money-format-fn,u(money-fn,add(%q0,0)))]. },{ @pemit %#=Huh?%b%b(Type "help" for help.) }
PAY-CMD: $+pay *=*:@switch/first [setq(0,num(*%0))][and(isdbref(%q0),match(type(%q0),player))][setq(2,switch(rest(%1),gold,10,dubloons,10,dubloon,10,silver,1,silvers,1,moon,1,moons,1,0))][setq(1,mul(first(%1),%q2))][and(isnum(%q1),gte(u(money-fn,%#),%q1))][gt(%q2,0)]=0??,{ @pemit %#=I don't know who you mean. },??0,{ @pemit %#=I don't understand that amount. },?0?,{ @pemit %#=You don't have that much money! },111,{ &money-%q0-amt [v(data)]=add(u(money-fn,%q0),%q1) ; &money-%#-amt [v(data)]=sub(u(money-fn,%#),%q1) ; @pemit %#=You give [name(%q0)] [u(money-format-fn,%q1)].; @pemit %q0=%n gives you [u(money-format-fn,%q1)].; &money-%#-log [v(data)]=cat(get(v(data)/money-%#-log),|%q0 %q1) }
MONEY-GIVE-CMD: $+money/give *=*:@switch/first [setq(0,num(*%0))][and(isdbref(%q0),match(type(%q0),player))][setq(2,switch(rest(%1),gold,10,dubloons,10,dubloon,10,silver,1,silvers,1,moon,1,moons,1,0))][setq(1,mul(first(%1),%q2))][and(isnum(%q1),gte(u(money-fn,%#),%q1))][gt(%q2,0)]=0??,{ @pemit %#=I don't know who you mean. },??0,{ @pemit %#=I don't understand that amount. },?0?,{ @pemit %#=You don't have that much money! },111,{ &money-%q0-amt [v(data)]=add(u(money-fn,%q0),%q1) ; &money-%#-amt [v(data)]=sub(u(money-fn,%#),%q1) ; @pemit %#=You give [name(%q0)] [u(money-format-fn,%q1)].; @pemit %q0=%n gives you [u(money-format-fn,%q1)].; &money-%#-log [v(data)]=cat(get(v(data)/money-%#-log),|%q0 %q1) }
MONEY-CMD: $+money:@pemit %#=You have [u(money-format-fn,u(money-fn,%#))].
MONEY-SET-CMD: $+money/set *=*:@switch/first [hasflag(%#,floating)][setq(0,num(*%0))][and(isdbref(%q0),match(type(%q0),player))]=0?,@pemit %#=You're not authorized to set anyone's money.,?0,@pemit %#=I don't know who you mean.,&money-%q0-amt [v(data)]=%1
Contents:
MoneyFunc(#3589V)
MoneyData(#3591V)
No exits.
Home: Parity's Circuitry Room(#1071RJ)
Location: Lecture Room(#14RJs)
Parity says, "In light of our earlier discussion, you might quickly guess that moneycode's parent is moneyfunc."
MoneyFunc(#3589V)
Type: THING Flags: VISUAL
Owner: Parity Key: *UNLOCKED* Pennies: 1
Zone: *NOTHING*
Powers:
Created: Wed Aug 11 12:34:26.396479 2004
Modified: Thu Aug 12 09:25:20.06567 2004
MONEY-FORMAT-FN: [switch(%0,0,no money,switch(div(%0,10),0,,div(%0,10) Crown[switch(div(%0,10),1,,s)][switch(mod(%0,10),0,,%band%b)]))][switch(mod(%0,10),0,,1,1 Noble,mod(%0,10) Nobles)]
MONEY-FN: get(v(data)/money-%0-amt)
No exits.
Home: Parity's Circuitry Room(#1071RJ)
Location: MoneyCode(#3590V)
Parity says, "Now, the 'real' version of this code lives in a text file, and between each attribute theres an '@@' or three with text after it. '@@' is the 'comment' command so when I send my file to mush, my comments don't do anything."
Parity says, "If I had to actually work with just the object as it is here, I'd probably go mad... err, though some might say that's already happened. However."
Parity says, "The deal with the moneycode is, it uses a number of common conventions, so when you grab myrddin's bbs or such off the net you may see this."
Jayanti raises her hand
Parity says, "IIRC, keran's weather has a completely convoluted setup involving a special room for most of the code to live in, but it needs a parent room anyway. ;)"
Parity says, "Yes, Jayanti?"
Jayanti says, "You mean the fn. stuff that denotes it as a function, or that it has a function that is used so prevalently in the object that it deserves a reference function?"