Caged Birds Don’t Sing

One of the very first bits of advice I was given on my BYOND page was a snarky remark based off of a recent advice post which basically said, “If you announce what you’re working on, you’re going to be robbed of the motivation to do it.”

I scoffed at that on the grounds that I couldn’t see that as being all that concrete. However, as of late, motivation flagging, I’m thinking perhaps there’s something to it after all. In taking it seriously, the brain cogs started turning, I decided that it probably has to do with the idea that caged birds shouldn’t sing.

Continue reading

Learning BYOND #11: The Power Of Modular Programming

Though I think of it as being a couple weeks off, this is in mostly counting minor dabbling: the actual amount of time I spent away from hardcore BYOND development is more like a month.  I’ve spent the pretty much the entire weekend (in which I had four days) hammering BYOND, and I think I’ve finally caught up with my lost knowledge.  This, and more.

I’ve picked up and dusted off my old Learning BYOND series for a special installment about the power of modular programming.

Continue reading

Crunch Time: The end of the Learning BYOND series

So ends my ‘Learning BYOND” series (though I’ll probably go back and edit those entries – for brevity, if nothing else). Ten days of “Learning BYOND” is probably enough to say that I’m past learning it, and am now simply using it.

What does use of BYOND produce? If the title is to believed, it allows you to Build Your Own Net Dream. Does BYOND live up to its name? Well, it definitely cuts down the toil of creating an online game tremendously, and I’m very much in debt to Dantom for providing it: it made building my online game accessible. Yet, I’m finding that a game is only as good as you’re willing to put the effort into.

In the end, BYOND is a canvas and brush to wield with whatever skill you’re capable – not a spigot that need only be twist to realize your dream game. (This hardly surprises the realists among us.)

Two weeks after starting, I’m staring down the barrel of a school semester 3 days from now without a completed game to show for it. That’s fine – I can continue using BYOND to further refine my Own Net Dream during the school semester — I’ve only a half-time schedule. I’ve little doubt that I’ll be able to produce something playable within a month soon.

Besides… I’ve always thought it interesting when I read a game credit (such as at the end of Quest for Glory 3) that says, “we hope you had as much fun playing our game as we had making it.” Sure enough, right now, it seems that making games is more fun for me than playing them. Thanks, continuous crappy quality of games leading to burnout. (Or is that a chicken and the egg scenario where burnout makes good games seem crappy?) If nothing else, when I’m building my own game and feel the balance is off, I’m able to fix it myself: that kind of freedom is awesome.

As for details on the particular game I’m making now, I’m hesitant to show my cards early. It’s not that I’m worried people are going to steal my idea — if you could do this and do it better than me, that’d save me a lot of work! It’s just that if I start talking about my game before people play it my words become hype. Hype kills games: I’d rather players judge it for themselves.

In future entries, I might drop a few hints by writing a few pieces of fiction that take place within the game universe. This would handily double as good background material.

Learning BYOND, Day 9: Purposeful Toil

With the focus placed on my Graphical User Interface from Day 8, I’ve pretty much created the game. The GUI is the game, after all. At least that’s what I quoted yesterday… but, I have to concur from personal experience that once you’ve got the basics of the GUI ironed out, the game itself materializes.

My GUI will have three separate play modes. A sensible first-time BYOND Dream Maker user would develop one game, but I’m a fickle gamer, I apparently want my first game to be three games in one. (This is to say nothing for the dynamic content focus.) The specifics (such as balancing the individual pieces) have yet to be worked out, but I now know enough to build the basic skeleton I’ll be using and tweaking to project completion. I wouldn’t have been able to do so without knowing both the BYOND 4.0 skin features and the screen objects discussed in yesterday’s blog entry.

Whether it’s my over-ambition or simply a sign of inexperience, it’s been difficult to get my code synced up right. I’ve tried putting an entire design on paper, but I’m afraid I can’t visualize the underlying mechanics well enough. Instead, I’ve been somewhat forced to build piece by piece, creating individual aspects of the game and seeing how well they stand before moving on to the next.

Perhaps this is the way all newbies start out, but the consequence is having to rebuild or re-arrange my code when previous implementations fail, to the point where it seems I’m no closer to my final product now than I was a few days ago. It’s a bit discouraging, but I shoulder on knowing a few things:

First, learning BYOND coding is an excellent self-improvement mechanism. Second, the code I create will be doing the work for me once it’s done properly (it’ll be a joy once I can stop coding and start world-building). Third, as I get better at using BYOND, the difficulty of putting together more content like this should lessen – design and coding are learned through practice like any other applied skill.

Finally, whether or not my games are ever popular or if I ever get paid for making them, this is essentially the birth of a game designer. Perhaps a game designer whose games only entertain himself, but a game designer nonetheless.

Well, enough slacking on today’s blog entry. Back to the grindstone.

Learning BYOND, Day 8: Is The Game

It’s hot and it’s a Saturday, but I don’t care. I’ve only got another 9 days until the school semester starts. Plus, I’ve developed a relatively good design in my head, now it’s time to see it through. Back to work, slacker.

Today, the Graphical User Interface was on the agenda. A reoccurring theme I picked up many time from “Game Design: Secrets of the Sages” (merely a compilation of developer quotes and pictures, but not without some insights): “The GUI is the game.” The saying means that what the user plays is actually the graphical user interface and therefore literally is the game. No wonder some consider it the hardest part of making a game.

I’ve learned about three powerful elements that I’m looking into right now.

  1. The newly introduced (as of BYOND 4.0) skin creator.

    This is a really nice suite that lets you set up your GUI configuration however you like. It’s a graphical interface creator not unlike one I’ve already been introduced to when using Visual Basic.

    It seems pretty complicated, but a good tutorial on that can be found here: Making skins in BYOND 4.0: A Lesson

    BYOND’s 4.0 GUI customization is both extensive and remarkably user-friendly, but I’ve still got to figure out how the code interfaces with the GUI elements added. It seems as though all you really need to do is manipulate them via their tags using the “winset” procedure. Could it really be so easy?

  2. Menu ItemsI figured this one out on my own. After opening up the same file where the macros and menus, and windows are defined (the .dmf file), go into the “menu” menu. There, it’s quite easy to add additional commands by recognizing the format is the standard column>>command format that’s likely at the top of your browser as you read it. In the “command” section is simply a verb that’s passed to the parser. So, define that “verb” on your client object just like any other verb and the functionality will go through.
  3. Objects assigned to the client.screen list.In a way, the “screen” variable on the client object is similar to the “image” variable (the same I discussed at length at Day 7) in that it is a list of things that are continually displayed to the user on the client level. (Meaning other users won’t see what this user is seeing.)

    However, it differs considerably in that what’s being displayed are interaction-capable, atom-style objects. This is really cool because you can define all sorts of interactive verbs on objects, while images can’t be clicked at all (though I’m sure an imitator could be jury-rigged).

    Assigning fully manipulatable objects to be used is actually remarkably easy. I recommend this simple tutorial on the BYOND developers section. It’s quite basic and does not cover more complicated tricks, such as adding mouse interaction by defining the MouseDrag() and Click() functions on the objects you’re adding to the screen, but if you’ve been using BYOND for awhile those things are self-evident.

The skin editor is undeniably more powerful, but the client.screen object list is still a valuable tool for adding things such as on-map controls. I’ll be learning them both. As for pull-down menus, it’s hard to say what use I’ll get out of that — it doesn’t seem very immersive for a RPG-like game.

After learning these methods, I can pretty much make any point-and-click windows-based interface I can imagine (at least so long as I don’t mind that the core of the game is a 2d tile-based one… and actually, I think I prefer it). However, just because BYOND makes it easy to create and display half-dozen panes at once doesn’t mean I should. My years of game-playing experience tells me that a very simple interface is much easier for the user to handle. Perhaps the difference between a good designer and a bad one is just how much complication you can get across in a user-friendly manner.

Learning BYOND, Day 7: All About Image

Seriously, today really was all about the image for me… the BYOND image object and how it is used, that is. It turned out to be a rather long and agonizing day: I wish I had known now what I did when I started. Sit back, read, and enjoy the butter without the churning I did today.

The image object refers to an image that is not actually part of the game world, but rather is a custom image specifically made to be drawn on the screen of any specifically specified users’ client.  Such objects have many potential applications, such presenting a custom GUI or applying special effects beyond what the world engine is normally capable.

The official instructions on images is quite short. It’s not mentioned at all in the client chapter and (as we’re about to discover) that’s a major omission. The Dream Maker help mechanic and BYOND developer community are the best reference I’m aware of for image objects.

The brevity of the help is probably because image objects are actually pretty easy to use… provided you stick to one image object reference variable at a time: However, I wasn’t content with that: I wanted to do a whole image list at a time. There lay madness.

Finally, I figured out the one thing they don’t flat out tell you (unless you very carefully read the BYOND dream maker help in the “image var (client)” section):

“The key to displaying images is a specially handled client object list. The “client.images” variable is directly called by the hardcode every update to display any and all image objects involved for that client.”

Edit (Sept 8th, 08): Originally, I wrote this Blog entry with an understanding that client.images was very arbitrarily handled for a list.  This is because, in my code dabbling, it exhibited unusual behavior.  Trying to call image.len (to get the length of the image list) did not work, nor did using a “for variable in images” call.

Zac pointed out in the comments that actually you can do this without trouble, leading me to wonder if perhaps I was stumping myself with a simple typo or perhaps trying to call client.images without the proper references from another procedure.

What remains below are the few truths I know to be true and unusual about the client.images list.

  1. Images must be passed to the client.images variable one at a time.

    If I try to use the << operator to pass a list of images to the client, it handles it like a string and spams “/list” to the user’s screen.

    If I try to use the images.Add() operator to pass a list of images, nothing happens.  The image list is not added and there’s no explained reason why, it just doesn’t work.

    Fortunately, it’s not too hard to simply break down any list of images you have an add them one at a time to client images. That was ultimately the solution that ended a day of misery and woe for me.

  2. You cannot delete the client.images object.

    If you try, you get a “bad del” error.  This must be because the client (not the client object but the user’s actual client program) relies too much on the client.images variable to allow it to be cleared and reference to null.

    Instead, what you must do is delete each image from the client.images list manually.  If you want to clear out the whole thing, you can (contrary to my earlier beliefs) perform a simple loop like this:

    for (var/deleteThisImage in images)
    del deleteThisImage

    And it will work.  However, if you want to delete a specific image from that list of images, you need to be able to find it first, and that can be really hard to do if you have no reference variable to that image.  Thus, maintaining reference variables (or even lists of reference variables) is a good idea.

    The requirement to keep a reference to added images strikes me as an unfriendly feature for BYOND designers: Never should there be a point you’ve added something that impacts the user which you can’t take away. Still, I suppose I can appreciate the logic: if the BYOND game designer did their job right, and kept a reference to every image they’ve added, this should never happen in the first place. It may not be as user friendly, but it’s the more powerful implementation, and I can appreciate that.


Progress Check

Speaking of using BYOND Dream Maker, here we are, one week later, and I’m still working out the foundations of my extravagant game world.

That’s okay, I recall I read somewhere that Richard Garriott himself said that’s the best way to go about it: build what you want the engine to do first, then worry about the story/game (I forget which). Richard Garriott (a.k.a. Lord British) practically invented the tile-based engine, the first 8 Ultima games were presented in tile-based engines built from the ground up, so (like em’ or hate em’ for a certain clean slate’s WoW imitation) I think Garriott’s advice can be trusted on this matter!

Besides, I’m not really on day 7. Looking back to day 6, I created the system that handles all the moves done by the game pieces on a one turn per second system yesterday, and that was the closest thing I did to genuine progress. All days before that, I was mostly learning BYOND… am still learning BYOND judging by today’s entry. If I already knew how to program BYOND from the start as well as I do now, I’d probably be polishing a finished prototype by now. Rather than let that discourage me, I should chalk it up to a sign of how much I’ve learned since then.

By Design

While I have been busy learning BYOND lately, that’s no excuse to not have a design document. Design documents need little working knowledge of the BYOND engine or DM code, all the game designer really needs to know is that BYOND is a real-time, tile-based engine with implicit multiplayer support (so you should factor in there will be some network lag between moves that is, fortunately, handled automatically). It’s only after a design document is done that one need take off their designer hat and wear the coder hat. (Granted, each coder hat needs has a code design section, but you need to start knowing what you’re planning on doing.)

At this point in my own BYOND project, it’s clearer than ever that I need a target to shoot for. Because I’m lacking the kind of forethought a design doc exists for, my efforts to develop a game are very unfocused. For example, I created an action queue handler, yes. However, I haven’t thought through what kind of actions need to be handled, and so now I’m encountering a problem of what happens when a creature is interrupted and needs to stop moving and start defending itself.

I’m wearing the wrong hat to move this project forward: I really need to force myself to take a break from coding. As much as I apparently enjoy it given how easy the BYOND engine makes it to produce results, I’m at the point where I don’t know what result I’m trying to produce. It’s time to do some brainstorming and designing.

(Granted, if I was making a simple game, I could eyeball it. A simple overall design document could be easily generated in my head and that would work fine. However, after 25 years of gaming, I’m far from being a simple gamer at heart.)

Learning BYOND, Day 6: Open Heart Surgery

I’m probably going to go back and severely edit those “Learning BYOND” entires. Right now they’re a somewhat rambling collection that probably contain a number of inadvertent lies said out of code-newbie innocence. I’m not sure anyone finds those entries particularly interesting… at the very least, I should throw in some helpful diagrams!

Diagrams like so.

Diagrams like so. Funny enough, knowing how to answer the Pythagorean Theorem is actually quite useful for aspiring BYOND users (although the get_dist() function performs much the same way).


Oh well, this entry will be somewhat more interesting, I hope. Today, I talk about what goes into coding a force that drives a virtual universe.


The heart of my game is the actionqueue procedure. This is activated when the world first boots up and stays running for the duration. Every second, it cycles through a list of designated “alive” mobs and checks the action queue on each. Each mob in the game can only execute one action per turn. In this way, BYOND’s flexible engine has been shaped into a simulated turn-based roleplaying game engine.

Controlling the use of the actionqueue is tricky because (thanks to the sleep() proc within it) it is waiting while other procedures are occurring at the same time. To protect against the conflicts that may occur, the actionqueue only performs the first action in the queue. No other procedure should manipulate that first action. Otherwise, if the timing is just right (or just wrong) then something’s going to break. If something needs to be inserted before that first action, the actionqueue procedure is the one to handle this.

The actionqueue procedure must be very efficient. I’ve tested that my computer can run about 50,000 lines per second. If I have 50 objects and the ActionQueue wants to go through 1000 lines each, it’ll bog down the server. If, on the other hand, each object only processes 10 lines then I can support up to 5000 idling objects. (Give or take — this is a bit of a shot in the dark.) If the server’s lagging, there will be a visible hitch every second when the actionqueue goes through its list.

Sorry Q-Bot, Ive made my own.

Sorry Q-Bot, I've made my own.


How many “living” objects will I need? It’s hard to say. Though my plan is not set in stone, currently I want to do an epic 1000×1000 2d tile-based world. That’s huge – traveling at one second per square, it’ll take about 16 1/2 minutes to cross the length of it. (I’ll probably add quicker means to travel.)

However, on such a large map, will there will always be something fairly meaningful going on with the players will be in the thick of it? This brings us to the central point: a huge world is pointless in game mechanic terms. Where the player is is not half as important as what I give them to do.

With the implementation of the actionqueue, I’ve harnessed BYOND’s flexible event model into a powerful virtual heart that drives my ideal game. In the coming days, I’ll have to design and implement the virtual soul that engages the player. It’s a pretty tall order – hopefully my 25 years of playing games will grant some insight there.

Learning BYOND, Day 5: Vital Misconceptions

Edit: This has once again been modified both because of correcting my own earlier ignorance and thanks to Zac’s helpful comments.

Yesterday was good practice to get familiar with coding in the environment. Today, I largely took my advice from yesterday and did a whole lot of RTFM. I went from chapter 7 to 14 in the DM guide (skipping the chapter on save files for now) taking hours to read and understand it. It has not been a fruitless endeavor, as I came away with quite a few nifty new commands and understanding.

Talk about “enough knowledge to be dangerous” — apparently much of my coding yesterday was done under massively false pretenses. Here’s a few things off the top of my head that I was doing very wrong:

  1. I didn’t really know how to declare new objects into existence.

    Instead, I was declaring my objects in the game world (dynamically at runtime as opposed to with the map editor) largely by cutting and pasting what I saw and getting lucky.

    This much the manual will tell you: New() is the universal constructor (translation: it’s the procedure that runs on the object immediately after it is created). I used it before to set up the default variables and whatnot on an object. The new() proc with a lowercase n is what actually bridges the gap from using var (to declare a variable reference to an object type) to actually creating the object.

    Without using new(), one tends to have their procedures crash a lot from attempting to do things with null-assigned reference variables: You might have declared a variable that points to that type of object, but you haven’t actually created the object yet!

    Of course, having dabbled with C++ and Java in the past, I’m no stranger to the idea of there being a difference between a prototype and the actual object. What stumped me were little things called “atoms” and why not passing a location to them stopped new() from working. Suddenly, new() was an alien command to me, it wasn’t working like new from other programming languages.

    It turns out that the trick is that atoms, being areas, turfs, mobs, and (in-game) objects, have a tendency to need a place in the game world to exist. Therefore, they take (as the first argument to new) a location in which they are placed. Without passing this location, BYOND’s dream maker tends to break.

    Likely this is because the involved New() constructor requires that the object be placed in a virtual world location to function right. If I try to use a mob’s Step_Dir() procedure and it’s not actually on the map, it’s not going to know what to do. If, in the New() constructor itself, I have some code that wants to check the mob’s location variable, and that location variable is set to null because it’s not actually placed anywhere, that’s going to cause problems.

    Thus the problem with new() and atoms is actually pretty understandable. The location is merely an important argument without which the atom objects largely don’t know what to do. However, it’s tough to grok for the first time BYOND user.

    Another tricky thing about new() is the format. It scans weirdly to the eyes of a code dabbler from elsewhere. In Java, declaring an object looks like this: “Point originOne = new Point(23, 94);” In BYOND, it’s a bit different. The following statements actually do the same thing:


    var/obj/robot/myRobot = new/obj/robot(loc)
    Implicitly declares a reference variable, then implicitly creates an object of the same type and assigns it to the reference.

    var/obj/robot/myRobot = new /obj/robot(loc)
    You can put a space after new if you want. This makes no difference to the compiler but clarifies for us (the dumb coders) that what we’re actually doing here is “new typedef(argument)”. (More on that in a moment)

    var/obj/robot/MyRobot = new(loc)
    Without the type and/or location specified, new() automatically adapts to the left side. The location is still needed to place it on the map.

    new/obj/robot(loc)
    Actually, this does not do the same thing, at least not exactly. (An explanation follows.)


    That last one is particularly tricky (and in more than one way).

    In other coding languages, initializing an object without a variable is a bit like marking a part of your memory as a useless black hole with junk in it you can’t use. The compilers generally won’t allow it. It’s okay in BYOND because what we’re defining here is an atom, and it lives in the virtual world so long as we pass a location in which it is created. Because it exists in the virtual world, it can be referenced and (hopefully) eventually removed and garbage collected from the world, avoiding the useless black hole problem.

    The overall problem I have with most of these examples is the typedef argument. This is visible in examples 1, 2, and 4 above when we say “new/obj/robot().” Compare that to my Java example above and you can see we’ve suddenly got a whole bunch of junk between “new” and “robot()” I’m not used to. What we’re seeing is actually new/typedef(). Typedef is explicitly defines the type. As you can see in example 3, that’s not necessary, but an explicit definition at least settles the mind we’re creating the right kind of object.

  2. Having an unclear idea how objects were created, I also had no idea how to delete them.

    BYOND deletes objects in a rather novel, simplified way. In other languages, the deconstructor – which is what Del() is in BYOND – will take some arguments and so it looks just like New(). In BYOND, there is no argument.

    Consequently, you don’t call Del() with del(), you call Del() with simply del – without the parentheses. Want to get rid of that object in the world? del object – not del object(arguments).

    Trickier yet, Del() Is a finicky proc to override. According to the manual, section 7.2.2 says you need to add ..() at the end of the deconstructor to resume the parent process if you’re using it, otherwise, the item may not be deleted properly.

    (I’m not sure how true that still is. Section 7.2.2 of the manual also says that the contents of an object or world will be dumped to its location when it is deleted… I tested this and it did not. In the addendum page this is confirmed.)

  3. I was using the atom object Click() (and other events/verbs) the hard way when I could have been using their callers on the client object.The client object actually triggers these procedures on the other objects through their own versions. However, this necessitates having an additional arg for the Client: the object being manipulated.

    My mistake was defining the Click() directly on the tile or object every time. If you’ve been following this for awhile, you may have noticed I was wondering how I could go about passing waypoints. Through manipulation of the clientside.Click(), this is much easier.

Those are some of the more obvious blunders, I’m sure I’ll discover more in time: Such is learning.

I spent most of the day with my nose in the book. I’ll probably spent the rest of it and most of tomorrow trying to bring these new practices into fruition so that I’ll remember them.

However, first thing’s first. It’s time to draw up a proper design document. Such a document is vital for prototyping all the major objects in the game and how they will interact. I’ve found that the speed in which a project can be put together is increased a hundredfold with such a document.

It’s the difference between assembling a house with blueprint versus assembling a house by propping up poles and seeing which ones stay vertical long enough for you to tack on a ceiling. You might get there eventually anyway but a blueprint provides a clearer sense of purpose and a product which doesn’t look like it’s going to fall over if the wind blows too hard.

(As much as I’d like to give you Learning BYOND readers a respite from all these run-on entries, I probably won’t detail my master plan much: an aspiring game designer has to keep his cards close to his chest to surprise his future gamers.)

Learning BYOND, Day 4: Early Vestiges Of Awesome

Am I really only on day 4? The human brain is a remarkable device – that which seems hopelessly impossible to understand yesterday is implicitly understood and being done today. Where is the tangible difference? In the individual’s perspective, it is as though a part of reality was completely redefined, and yet there’s no artifacts to be found to mark the change.

I didn’t keep a running tab of everything I figured out today, so there will be no categorized list of minor newbie tips. Sorry, I was just having too much fun. However, I can remember a few interesting things that happened in my coding exploits today that might prove enlightening.

Bloat

As I wrote yesterday, I’m just comfortable enough writing code now to be dangerous. Consequently, I’ve been coding pretty comfortably. When you type 100 WPM, that stuff adds up pretty quick. Looking at the directory now, my code is up to about 41 kilobytes (over 40000 keystrokes) of raw text now. My code probably more than doubled in size this day alone.

I’ve broken off parts of my source code into other source files named after the particularly meaty object or global procedure definitions I moved there. That’s a good practice to adapt in order to quickly leap to the code you want to access. BYOND handles all the code file inclusions automatically: if it’s checked on the left of the dream maker’s file list, it’ll be compiled and accessible. (Of course, it’d be a bad idea to split an object or procedure in mid-definition since you can’t be sure in which order those files will be assembled.)

All this bloat is just that: Little (if any) of the code I wrote today is permanent. In fact, I’ll probably regret my amateur code later and want to completely re-write it when practice brings with it new standards of coding elegance. Oh well, such is the business of programming. At least, that’s the kind attitude a fledging programmer needs to not regret another day of his life down the bit bucket. (Oh well, how else would I have spent that time? Spamming a forum mostly filled with people half my age, probably.)

Hints of reward

With size, my code is also growing more capable. All those happy little digital souls living in my program now have brand new arms and legs with which they run amok all about my virtual world, gnashing and tearing, raping and pillaging. I do hope to teach them subtlety some day, but I can only code an ideal virtual world one line at a time.

As of today, my little robot mobs can now have special items I created – “robot interfaces” – installed into them by player characters who are carrying these interfaces. Each robot interface carries verbs that allow the players who can see them to control the robot they are installed in. So far, only two interfaces work: “follow me” and “wait,” but the basic framework is in place to allow players to install and use as many as I feel like creating. In a way, my coding more robotic interfaces would be not unlike a fantasy RPG developer coding more magic spells for wizards to cast.

The interfaces work via a rather crude hack where anyone in the world can use the verbs attached to them. That would simply not do – anyone could hack your robots and use them against you – however I’ve yet to figure out BYOND sufficiently to configure a better ‘set src’ setting to allow an item in another mob’s inventory to be accessible by the player.

For the time being, access can be controlled by who is capable of viewing the items in that robot’s inventory. The only way you can see the robot’s inventory is to see the robot’s inventory panel. Though it feels sloppy to not rely on the standard “set src” verb restriction, it works. It’s almost a very clever workaround, as the verb-enabled objects merge together on the robot’s inventory list to form a dynamic right-click menu.

Another bit of progress today is making some rudimentary use of clicking the mouse in the game via the Click() procedure that can be redefined on any visible object that’s placable in the game world. One elegant-feeling trick is to hook up the mouse click procedure to swap of the client.statobj variable. This enables players to see the stat panels of something else – just be sure to have coded the neccessary access restrictions in place to prevent the statobj from being assigned to anything you don’t want the players to view. A Click() procedure is also good to put on usable items to call a default verb that activates when the item is clicked on.

Trouble Ahead: Finding The Way

Considering the difficulty I’m having with figuring out a way players can input waypoints, I might just settle for the “follow me” and “wait” robot interfaces along with a third that orders the robot to go to somewhere easily in view. Players could tow around their robots and deploy them that way, and the game will be completely playable.

That’s a cop out, however. Next on the agenda will be creating a much better way to handle waypoint travel. Part of the reason why is because I wasted about 3-4 hours trying to paint my player character’s assigned waypoints with the image() procedure. Because my current waypoint system is so kludgey, that turned out to be several times harder than it should have been.

(It might have helped if I had some previous experience with BYOND’s Image object handling – I’ve got the theory down, but there’s a remarkable difference between understanding the theory and having the experience of actually doing.)

The much-maligned short path to knowledge: RTFM

If I wasn’t having so much fun playing with my code today, I might have taken a better look at the DM Guide PDF. I’m only up to about chapter 7 now, having skimmed ahead for occasional things as I need it. Reading through my printed out PDF file and defacing it with a pencil seems to produce excellent rules in fostering better understanding. If I actually read it from cover to cover this way, it would probably be the shortest path to neigh complete understanding of the BYOND coding environment.

Alternately, I should probably consider getting my hands on some more example code. Seeing the way things are written by experienced BYOND programmers may prove enlightening, at least once I know enough about the why of it to understand why the code turned out elegant the way it was done.

Learning BYOND, Day 3: Armed and Dangerous

Today, I found that my brushing up on the fundamentals helped quite a bit. BYOND’s differences from the programming languages I’m comfortable with are beginning to melt away. I’m able to define classes of objects and place them intelligently in the game, as well as allow players to pick up and drop things. Some interesting things learned today include:

  1. Defining the name of an object enables the right-click menu interaction with verbs. This only seems to work if the verb’s access is set to a list of things (src in *list*) and not a single user (src = *specific user*).
  2. The interpreter won’t ask you which one you mean if you’re activating the same verb on identical objects. This caused me no end of confusion when I couldn’t figure out why it kept grabbing the nearest one (when access was set to “src in *list*”) or the sequentially first one (when access was set to “src = *specific user*”) without asking me which I want.
  3. When referring to turfs, think of them as containing the mobs and objects in them, and as though the turf literally is the location of the mob. Thus, if Mob is standing in Turf, Mob.loc equals Turf, *not* Mob.loc Equals Turf.loc. (I would guess this works the same way for items in a player inventory: item.loc Equals player, not item.loc Equals player.loc.)
  4. A good spot to initialize global variables is on the world’s New() procedure. Seems self-evident enough now, but prior to this I wasn’t sure the world even had a New() procedure. (This refers to initialization, the definition should be done at the root of the code.)
  5. I found out about “image” objects which, as far as I can tell, are completely missing from the guide. The details using them are still beyond me, but discovering this object is great news. Prior to this, I had the problem that everything displayed to a users’ client would actually be a part of the game world. Now, a custom GUI seems possible.

By the end of the day, I figured out a way to allow users to materialize new objects into their inventories or onto the game world. This is a major part of my game design, which involves a Mercenaries-like capacity to call in equipment and reinforcements in battle.

The players are now armed and dangerous — at least, able to pick up things and use them. They aren’t the only ones: now that I have these basics under my control, I know just enough to be dangerous to my fledging virtual world. Consequently, designing the working model on paper is becoming more important than before.

My current immediate technical challenges to overcome:

  1. Find better way to present the user with a selectable list of objects to be summoned.

    I could do so with just a bunch of separate verbs, but that’s sloppy. I could do so with an image overlay… this would probably be the best choice – but also one of the more technically challenging.

  2. Find a way for the player to cue way points to be executed by certain the mobs in the game.

    This core functionality would be useful both to set a balanced speed on players’ avatars – by default they run around as quickly as the players can hammer the keys and their connection allows and that’s unbalanced – and also for vital mob automation. At my disposal is some pre-created movement procedures, but they do not implicitly have waypoints built in… I think.

If I can get those two things out of the way, the biggest technical hurdles (besides the interface) are out of the way, and I can get down to actual game mechanic implementation.