What's So Hard About Ruby?
-
@arkandel Heh, right?
For comparison, here's the same function (more or less - there's not a 100% mapping) in the Ares ruby framework. It's still complex, but at least it's readable.
https://github.com/AresMUSH/aresmush/blob/master/plugins/fs3combat/helpers/actions_helper.rb#L392
And because it's a modern framework, I can have unit tests to make sure each piece works right.
-
@faraday said in What's So Hard About Ruby?:
I'm not saying Lisp (or MUSHCode for that matter) is a bad language. They have their niche uses.
It's probably fine to call MUSHCode a bad language for modern use. It made sense for the purpose it was designed, when everyone was using telnet and there was no such thing as IDE's and source control and feeding the game code line by line was just the way you did things.
I don't think it makes any sense in a world where we have so many powerful IDE's and flexible frameworks to work with.
That said, one thing that's easy to do in MUSH and hard to do without MUSHCode is scripting unique objects. I haven't tried it in Ares but I know in Evennia it's non-trivial to make something like a ball you can throw at people or a magic 8 ball or whatever.
-
@groth said in What's So Hard About Ruby?:
It's probably fine to call MUSHCode a bad language for modern use.
If your constraints are that you need to be able to edit complex systems live in-game through a MU client, I doubt you could do much better than MUCode. People are still doing that so I consider that a modern use. YMMV though obviously. Bad or not, it's a pain to code in.
@groth said in What's So Hard About Ruby?:
That said, one thing that's easy to do in MUSH and hard to do without MUSHCode is scripting unique objects. I haven't tried it in Ares but I know in Evennia it's non-trivial to make something like a ball you can throw at people or a magic 8 ball or whatever.
I mean, it depends on what you want the thing to do.
class MagicEightBallCmd include CommandHandler def check_has_ball return "You don't have a magic 8-ball!" if false return nil end def handle message = "" case rand(3) when 0 message = "A" when 1 message = "B" else message = "D" end client.emit "You shake the magic eight-ball. It says: #{message}" end end
What's different about Ares is that it's designed for global systems, not local code. Why? Because I personally feel that local code is archaic and rarely-used on the kind of narrative-focused MUs that Ares is made for, and also local code doesn't mesh well with web portal play, which Ares is also made for.
So if you want your 8ball command to be a global available to anyone on-demand, it's easy. If you want to limit it, you need to put a bit more thought into how exactly that's going to work and update the
check_has_ball
method accordingly. Is it a full-blown economy and inventory tracking system, a "has_eight_ball" flag that's set by staff, something that only works in Joe's Bar, or what? -
Maybe I just don't have the brain for modern coding languages then. Because I found it frustrating to the point of despair.
-
@cobalt said in What's So Hard About Ruby?:
Maybe I just don't have the brain for modern coding languages then. Because I found it frustrating to the point of despair.
The frustrating part I find with any modern language is learning the quirks of any given library or framework. They all have subtle differences that can trip you up until you get used to them.
I would recommend starting with something small and manageable or modding some pre existing project. Tinkering with an ares game or arx gives plenty of opportunity for small projects.
-
@groth Yeah, I did that. I even went through the tutorials on ares central, both the one for coding the notes stuff and links to getting started with Ruby. Then when it came time to do my own project I could not, for the life of me, wrap my head around how to do it.
I wanted to code a widget that would flip the area a room was at from "simulated weather" to "space", to simulate turning a viewport off and on. And I couldn't, for the life of me, figure out how to get/set the area.
Other people have thrived with Ares and Ruby, so obviously the language isn't the problem. The problem is me.
Possibly because I learnt softcode before real code.
-
If it makes you feel better, I haven't quite figured that out either.
The actual coding of Ruby I can do.
But I've read the AresCentral tutorials about three dozen times, and right around the time we get into YAML and coding plugins -- something just does not line up.
I cannot for the life of me figure out how the YAML files get structured into character sheet data, or how to represent ranges in YAML files, or even, really, how to create a command that appends data onto old data, like a list of aspirations that can be /added and /completed.
I feel like all the information is there, or should be there, or there should be some way to figure it out. But the 'putting it all into practice' part, to me, feels like 'Alright, now that you know the times tables, let's talk about polynomial equations'.
Like -- it feels there are missing steps in there, somewhere, and that I should be able to piece it together. But for the life of me I have not been able to so far.
-
@derp Right, exactly, I feel like I missed some very obvious important step somewhere that everyone else can see and understand but I am just blind to it.
I might try again now that I am being treated for ADD (kinda), but like... Waves hands in space. It feels like there's some missing link that my brain just cannot click onto.
-
The problem is likely just the different paradigm and your brain thinking the MUSH way. Rooms, objects, characters etc are not set up the same way so whenever you try to approach a problem the same way you did MUSH code it doesn't work.
Unfortunately there's probably no easier way then learning the new pattern step by step until you're used to it. With Ares at least Faraday did a great work with the documentation.
-
Yeah, exactly.
Like, I know that I'm not completely inept at this, I managed to code a functional polyhedral die roller from scratch complete with pretty output templates and everything.
And yet, when we get to updating character objects in the database and how to structure them -- it really feels like there's a missing link, somewhere.
Like, it has to be there because a billion other people have made it work, it seems. But for whatever reason, it's like 'here is a YAML file and here is how to create and update a field on the character object and here is how to create Cortex...'
And still, I'm left going -- ok so if I wanted to do 'Strength has a range of values from 1 to 5 in integers' -- how do I do that?
If I do set Strength = 5 how do I tell the game that the 5 is an integer and not a string?
How do I tell it that Strength = Duck is an invalid value in the YAML?
There are so many questions.
-
@Cobalt @Derp I don't think there's anything wrong with you or that you're missing anything in particular.
Ares is massive. Thousands of files. Tens of thousands of lines of code. A website. A database. Two different programming languages (more if you count the templating languages and YAML and CSS).
It's a lot.
The thing is - MUSHcode was a lot too. I remember printing out the function help files back in the '90s and being all: OMG this is overwhelming. I learned it piece by piece, starting out with some dumb little notepad object or something and working up slowly. We've just all had so many years to build up familiarity with it, and probably have forgotten how hard it was to get started.
Another confounding factor is that in Ares, most of the stuff you need is already built. So all that remains is the hard stuff - chargen, magic, and other massive systems. Nobody's starting with their own custom +finger because that's already done for you. And even if you did want to customize it, you have to first decipher what's already been made. So you go from getting your feet wet in the tutorials to jumping right into the deep end. It's hard.
But none of that has anything to do with the language itself.
-
@derp said in What's So Hard About Ruby?:
And still, I'm left going -- ok so if I wanted to do 'Strength has a range of values from 1 to 5 in integers' -- how do I do that?
If I do set Strength = 5 how do I tell the game that the 5 is an integer and not a string?
How do I tell it that Strength = Duck is an invalid value in the YAML?These are great questions for the Ares forums or discord, and there are lots of different ways to do it, but this might help. (I'm winging it, so please don't expect this to actually work right as written)
class AttributeSetCmdHandler include CommandHandler # Place to store our ability name and rating attr_accessor :ability, :rating # This makes sure you gave both an ability and rating def required_args [ self.ability, self.rating ] end # This cracks apart our `set Strength=5` into its pieces. # The ability is trimmed and titlecased. # The rating is interpreted as a number. If it's not a number string it becomes 0. def parse_args args = cmd.parse_args(ArgParser.arg1_equals_arg2) self.ability = titltecase_arg(args.arg1) self.rating = integer_arg(args.arg2) end def handle # Read our list of attributes and max rating from the YAML config. valid_attrs = Global.read_config("yoursystem", "attributes") max_rating = Global.read_config("yoursystem", "max_attr_rating") if (self.rating < 0 || self.rating > max_rating) client.emit_failure "Invalid rating." return end if (!valid_attrs.include?(self.ability)) client.emit_failure "Not a valid ability." return end # update the database. attributes is probably a name:value # hash, so there's a little extra fussing you have to do. abilities = enactor.yoursystem_attributes abilities[self.ability] = self.rating enactor.update(yoursystem_attributes: abilities) client.emit_success "You set your #{self.ability} to #{self.rating}." end end
-
@cobalt said in What's So Hard About Ruby?:
I wanted to code a widget that would flip the area a room was at from "simulated weather" to "space", to simulate turning a viewport off and on. And I couldn't, for the life of me, figure out how to get/set the area.
Sorry for the triple post but wanted to answer the pieces separately.
# Set your current room to the space area space_area = Area.named("Space") enactor.room.update(area: space_area)
Changing it back gets a bit trickier because you might have to create a temporary storage for "the area it used to be in" or something. Kinda depends how you want it to work.
Regardless, this is not something I would have expected to be super intuitive looking at the 2,000 or so lines of code in the 'rooms' module, so you shouldn't feel bad for not being able to just figure it out at a glance. I'm always happy to help point folks in the right direction though.
-
@groth said in What's So Hard About Ruby?:
I haven't tried it in Ares but I know in Evennia it's non-trivial to make something like a ball you can throw at people or a magic 8 ball or whatever.
I don't think doing that would be too difficult in Evennia either. I kinda structured this off some furniture code I wrote a long time ago on a pet project, but I'm really rusty with both Evennia and python at the moment so it's just a broad-strokes sketch and not meant to work out of the box and probably not the best way to do it!
from evennia import DefaultObject, CmdSet, default_cmds import random class EightBall(DefaultObject): "A simple 8-ball" def at_init(self): self.ndb.fortunes = self.ndb.fortunes or ["1","2","3","4","5","6","7","8"] def at_object_creation(self): # add the commands associated with the 8-ball to each instance self.cmdset.add("typeclasses.eightball.BallCmdSet", permanent=True) def fortune(self): # return a random selection from our fortunes. I don't think this return is an # issue but if it were you might need to change how this is done. selection = random.choice(self.ndb.fortunes) return selection class CmdShake(default_cmds.MuxCommand): """ Usage: shake <object> This command allows a character to read their fortune in an 8-ball. """ key = "shake" arg_regex = r"\s.+" # require a space-separated argument, i.e. 'ball' locks = "cmd:all()" def parse(self): self.target = self.args.strip() def func(self): caller = self.caller target = caller.search(self.target) if not target: #yield an error if the target cannot be found caller.msg(f"Can't find {self.target}.") return elif not isinstance(target, EightBall): # ensure the command is being used on a valid target caller.msg("Shaking that would be rude!") return else: # provide a fortune to the caller caller.location.msg_contents(f"{caller.key} shakes {target.key} and studies it closely.") fortune = target.fortune() caller.msg(f"Through {target.key}'s murky glass, you can read: {fortune}.") return class BallCmdSet(CmdSet): """ Base command set for 8-ball objects. """ key = "BallCmdSet" def at_cmdset_creation(self): self.add(CmdShake())
You could modify and complicate that in a host of ways, like having the main class have hundreds of fortunes and just pack a selection of 8 into each object (and be saved instead of being nbd), and so on, but it's a scaffold.
A huge challenge with an engine like Evennia, and from what faraday has been saying with Ares, is that a lot of its power comes from the fact that it has all kinds of hooks and tools distinct from the language it uses packed in everywhere. So even a simple idea ends up involving a lot of wrestling to learn how to get it to fit into the pattern of the engine, and that's really hard at first.
On the head subject of the thread, I think Ruby is pretty straightforward and no more difficult than Python or another alternative. My only experience with it was a mandatory semester of programming-for-non-programmers in college and I had no head for code but I suffered through it kinda well, and that's a point in the language's favor in a big way. The biggest hurdle to making any project a reality, imo, is bridging the gap from understanding the basics of a language (if you're approaching from a new-coder perspective) to understanding how to leverage whatever tools the engine you're using has to offer, and that's going to happen regardless of the language and regardless of the engine.