Code Teachers?
-
This is probably a long shot, but I really want to learn to code, and I'm sure I'm not the only one.
I know there's a coding how-to manual, bit it's not for Mux (What I'm using and most familiar with over the years of playing), and it's very out of date.
I'm not looking to have someone come code for me, but I want to know how to do these things.
Anyone out there willing to teach?
-
@Taika There's some decent tutorial logs to get you started on: http://www.mushcode.com/ but the biggest thing for me was just reading through the help on all the various functions but those can get you going.
After that, look at other code, once you know what the functions and replacement bits mean it makes more sense.
-
You should embark on a quest to gain the tutelage of the Great Wizard @Thenomain.
Like all legendary tutors, he will be a cold, heartless master, whose interest is far more focused on leaving behind a legacy worthy of his name. In time, however, he may come to truly care for you as a student.
He doesn't have a beard, though, so it may be a crapshoot.
(He can be a little testy, too. Grr!)
-
One of the big problems with learning mushcode as a beginner is mushcode is a right bastard to read.
Start learning with this http://muxify.musoapbox.net/editor.html and make your life easier.
-
I shall poke him (@Thenomain) verily!
I was also pointed at notepad++. It highlights brackets and such for writing code up, similar looking to how muxify will spread it out.
-
I use atom, myself. I would suggest setting up a server that you can crash to learn to code on. Then install working code and then break it down and figure out why and how it works. That is how I learned. It took me about 3 months to get a working knowledge of code, and I am still learning everytime I hit a wall.
-
Dunno if this helps any but here's something I wrote awhile ago. http://aresmush.com/articles/practical-mush-coding
-
I code everything in notepadd++ it's a very good tool. I should have mentioned it in my first post. Sorry.
-
@Taika
Even for MUX, taking apart code is useful. A good 95% of code is back-and-forth compatible between PennMUSH and TinyMUX (at least things build before the past 3-4 years, maybe). I ended up having to teach myself how to code, because my first MU* I had to fire my coder for sexually harassing female players (we were a VERY open group, people know each others' RL names and genders and such).I took apart code, read the help files, asked questions... taking apart and reverse-engineering is useful, especially doing it in sections. I also find it's helpful to CODE in sections - command references function, function pass/fails to a set of pass/fail functions, and so on.
-
Coding isn't hard, but good coding is.
Things to remember when you mush code. And this applies to all mush flavors (Penn, TinyMush, MUX, Rhost, etc)
- Everything in mush starts as a command. Think of each command as their own separate sandbox. Each command has it's own 'resources'. Each command is executed linearly in a single-thread. Each command is able to have their 'environment' modified by functions. Functions will, with few exceptions, manipulate that command and arguments to that command which brings up. You can chain commands one after the other with a ';'. Each time a command is executed, it pushes onto a command queue stack. If you have a command call a SECOND command. Then you have two levels of command queue stacks. So for example:
@emit 123 -- This is a single queue stack. @emit pushes '123' onto the queue stack and pops it. One level. @switch 1=1,@emit 123 -- This is a DOUBLE stack. @switch compares 1=1, finds that to be 'true' and then pushes '@emit 123' onto the stack. This is a command, so when it pops it from the queue stack it evaluates @emit 123 as the second queue stack.
This is very important, because how things are pushed and pulled from the command queue stack depends on how things evaluate. For example
@wait 0={@emit 123;@emit 456;@emit 789} returns: 123 456 789 However... @wait 0={@emit 123;@switch 1=1,@emit 456;@emit 789} returns: 123 789 456
WAIT... WTF? you're asking yourself. It's actually asking yourself. Well, consider what I said before about evaluation. @switch is an evaluation, then what it calls is ALSO an evaluation. While each @emit itself is an evaluation.
So it was processing that command chain as:
@wait 0 -- One evaluation
@emit 123 -- One evaluation
@emit 456 --One evaluation
@emit 789 -- One evaluation
@switch 1=1 -- One evaluationSo, to put this in perspective:
@wait 0={@emit 123;@switch 1=1,@emit 456;@emit 789} ^^^^1 ^^^^2 ^^^^2 ^^^^3 ^^^^2
1 is evaluated first. The {}'s mean everything inside that is passed to that one argument
2 is evaluated next.
3 is evaluated last.It's all based on how things are pushed and pulled from the command queue.
-
Functions. Functions are not commands. They are used within commands and are intended to manipulate the stateful data of a given command. They tend to be used to manipulate input and output of those commands and format, redirect, or in some way alter what a user enters to what they ultimate see returned. Functions can mimic commands like @set via set() and are called side-effects. They are called side-effect as the function itself doesn't really return anything but in fact acts as an 'aside' for a different purpose. The arguments that the functions use lead up to
-
Arguments. Arguments are called via %0 (or [v(0)]) to %9 (or [v(9)]) through an interpreted parser. By using the v() function, you can access arguments past 9, usually up to 30 by default. So v(10), v(11), and so forth. Penn, MUX, and Rhost have very similar parsers but they do have some small differences in evaluation that can annoy people who are used to one parser or another. MUX and Rhost for example will require additional escapes of backslashes ()'s while Penn tends to nerf ['s and have some significant issues with stacking functions. Each can be worked around, but they can be annoying when you're neck deep in complex code. How evaluation works leads to...
-
Parsing. Parsing is done when you enter text into a command or function. Depending on how many times you call that text and how many times you act upon it, you could, potentially, double, triple or even more a segment of text. Generally, this can lead to all sorts of security risks, since some strings you do NOT want to double parse, as it opens up possibilities to execute code that you may not necessarily want to execute. This leads us to
-
Security. Security in mush is a very hard animal to understand if you're not familiar with the language. If you have a string [add(1,1)] as a literal string, it will be passed as that. However, if it evaluates, it will return '2'. This isn't that big a deal. But let us assume you have [add(1,1)] in an attribute. You have [get(myobj/attribute)]. It evaluates and returns the raw string [add(1,1)] which you want. But you mistakenly use this and evaluate it again, so now you have '2' being passed, which is not what you wanted. This could, potentially, be a nested evaluation that causes unforseen evaluation. So when you code, always test against evaluation. Make sure you are not mistakenly double evaluating anything, and never, ever, just evaluate values that you can not guarantee will have a value you expect. Such as an attribute off a player that they can change. There are functions (like objeval(), secure(), escape(), and so forth) that you can use to lock down and limit evaluation issues, but each one should be a case by case basis on your needs and desires. This leads to how commands and evaluation is chained together by...
-
user defined commands. These are also commonly called $-commands because these start with an identifier of a '$'. They allow globbing wildcards (* and ?) by default, and most modern and current mush codebases allow the optional REGEXP flag to allow regular expression (PCRE -- perl's contribution) matching for the commands. This allows some fairly consistent flexibility in convenience and while an interpreted language will never be faster than a byte compiled or compiled language, hitting hundreds of thousands of evaluations a second isn't too hard a thing to accomplish. Put plainly, the built in interpreted language of mush is powerful, complex, and while a far cry from a mature language, isn't something to just sneer at either. You can store values in various ways that lead us to...
-
Static storage. This tends to be attributes or if you have it configured sql databases or other methods. The common method, however, is attribute storage. This is done through the @set command (short-hand of '&') or using a sideeffect function like set(). These are considered static (or permanent) storage because it is written to the database on consistent physical storage on a physical harddrive. So they will remain during shutdowns, restarts, migrations, etc until you modify or delete it. Static storage can be fetched through the get() function or evaluated and fetched via the u() function. There are a slew of other functions you can use to fetch and evaluate, but are generally based off the theme of get() and u(). get() takes it raw, u() evaluates. You also have the capability of having...
-
Dynamic storage. These tend to be called registers and will last until the command (or command sequence) is completed. Once the command chain is completed, the dynamic storage (registers) are gone. This is handy when you want to store temporary values, function returns, or essentially complex parsing or processing that you wish to recall or re-use later in the command sequence. This not only allows for better readable code, but speeds up processing since a set of complex code doesn't have to be re-processed as you already have the result stashed away into a register. There are a limited number of registers on mushes (generally 36 depending on the codebase), which I find more than sufficient for most needs. Registers are gotten through the %q substitution or r() function. They can be set with the setq() or setr() function. Dynamic storage also leads to...
-
percent substitutions. These are pretty much dynamic and are intended as a 'substitution' value fro when something parses. For example, %n is 'name'. It will be replaced with the name of the executor that evaluates that string. There's a large number of useful substitutions on mushes and you should practice and experiment with how they parse. Registers, dynamic, and static values can be utilized using...
-
Data Objects. Objects can be referenced by name or by dbref#. A dbref# is essentially a unique index assigned to each item in the database. While dbref#'s can be recycled, they will be unique for that item until destroyed (recycled). When you storage attributes, they are stored based on the object.
Now you can put this all together, so without further adoo....
This leads us to some fun examples in putting this all together...
&AN_ATTRIBUTE -- This is an attribute called 'an_attribute' that is a static (permanent) value. &A_STRING - This is an attribute called 'a_string' that is a static (permanent) value. [setq(0,My Value)] -- This stores 'My Value' into a register of '0'. [r(0)] -- return the value of register '0' (you can also use %q0) #12345 -- This is a dbref# specifying an object in the database [get(#12345/a_string)] - fetches the contents of the variable 'a_string' from object #12345 @emit foo -- This is the command '@emit' with the argument 'foo' $mycommand * -- this is a user defined command called 'mycommand' that takes a single argument (the '*') To put this all together: &A_STRING #12345=This is a string &AN_ATTRIBUTE #12345=$mycommand *:@emit %0 [setq(0,get(#12345/a_string))];@emit Register was: [r(0)]
If you typed:
mycommand abc
You would see returned:
abc Register was: This is a string
This is by far not a complete document, but hopefully it'll give you some understanding of the guts and garters of mushing. Some day I should sit down and write a manual, but honestly I'm being bum-gammed with real life and work, so maybe for 2017
-
@Ashen-Shugar I would love an actual manual from you some day Ashen. I keep wanting to ask you to code for me but I know how many games you are tied to and I should do it myself anyways.
One day I will figure out how to get a nicely formatted and complex +sheet command coded, one day.
-
Oh wow. That is a lot of information, thanks @Ashen-Shugar!
I know when I think of code, I have an emd product in mind. I think one of my personal challenges is going to be learning how to break that end result down into small pieces and steps.
Definitely going to look into setting up a tester game where I can run rampant and break toys, now, too!
-
@Taika If you don't have an end product in mind for what a piece of code does, then you're really going nowhere fast
-
@Lithium said in Code Teachers?:
I keep wanting to ask you to code for me but I know how many games you are tied to and I should do it myself anyways.
Well, real life and work has bit me hard, so I am taking a small vacation from mushing for a minimum of a few months to a maximum of a year. Soooo... if you're serious, hit me up toward the end of this year and I'll put you to the top of my free list and see if I can't lend a hand for any mush you want to start up.
Long as you stick to MUSH I can help you. My MOO-fu, MUCK-fu, and Evennia-fu is weak
-
@Ashen-Shugar I only use TinyMUX, I know you love Rhost but, it's what I use
-
@Lithium - Yeah, but if you can't think of how to get to that pretty chart you want to code (what attributes to pull, how to order them, adding commands to set new ones, etc), you won't get far either, I would think?
-
@Taika I don't know, when I code I set out and be like: I need this command, say a dice roller. Then I go through and figure out what the dice roller needs to do for that system, what attributes it needs to pull from (if any) etc. Once I know what it is I am making then I start coding, and I test it. If it doesn't look how I want, I tweak the code, test again, until I get it how I want and working without running into loops and whatnot.
When I am writing a piece of code, say Chargen, as I am writing I will sometimes realize I am being silly and making the code more complicated then it has to be, or inefficient, and end up re-writing it.
I have never once sat down and wrote a perfect line of code that was part of a complex system without it needing editing, tweaks, or even full re-writes upon occasion. I am just not that good so I try not to get hung up on what mistakes I make, or how many times I might need to start from scratch because each time I do, when I get it done and working, I've usually learned a lot.
It's probably different for the psycho-coders like Ashen and Theno and Chime etc.
-
I think the pychocoders think and dream in code :3
-
Code +finger. Code +who. Almost everything Ashen talks about will be addressed in these two commands.
I will help almost anyone who has troubleshooting questions about the four Mushes (Tiny, Mux, Penn, Rhost), but I don't have the kind of office time to be as available as I'd like.
-
I can help out, but much like @Thenomain my time is limited as well.