ZS - Just another RP gamemode

Update notice 2:
Although it was frozen, I continued developing a bit and the very basics are almost complete. Ignore the update notice.

Update notice:
This project has been released/quit - the code, documentation and a few words are a bit down.


Today, I’d like to talk a bit about ZS, a gamemode I started developing a few months back. I wanted to have a RP gamemode that I know inside out, that was easily adjustable (for clients and the server), easily maintainable, documented, generic to some extent (i.e. fitting for all possible RP modes and themes, not just one), extendable, does not rely on networked variables and all in all uses as less space or traffic as possible while still being able to offer an open RP environment that does not rely too much on the script. This introduction is a bit sober, including the screens. It’s all using the Derma default skin and therefore it’s not really impressing at all - however, design is one of the last things I will do, if ever. For me, functionality is way more important. Also, it’s very technical because that’s more interesting in my humble opinion. However, if you skip this wall of text, you will find a shorter list of features along a list of things that I are not going to be in ZS as well as a list of things that are planned - and at the very end, I could need a bit of help.

It was written completely from scratch and did not have another script as target. That means, at no point I wanted to replace a certain script or have its functionality completely. However, I can say that it was somewhat inspired from TacoScript, 1 and 2.

One of the most important things was the open environment. In my opinion, a script should guide and support players in their RP experience, not restrict them. In addition, GMod RP is always heavily text based - there might be animations, guns and all in all a three dimensional world but in the end, the important stuff happens in a chatbox.

Therefore, the chat was one of the first things that was completed and one of the most advanced. ZS uses a system called OLM for chat messages. OLM splits up too long messages into several chunks to send them. In addition, OLM is heavily customizable on the client side: Every chat message type (so called MessageFilters) is shared between server and client, allowing them to define the type of a message using a simple char (and therefore restricting the amount of possible filters to 255 - but then again, who’s going to use about 255 different types of chat). On the client side, these tables can easily be modified to adjust the feel-and-look: For the basics, the color for the name and the chat message as well as the font can be defined and changed on-runtime (although they are not saved, there are plans for a options GUI that allow to change these values easily). For advanced users (and the script itself), it’s possible to define a lua function per filter which "refines” the incoming messages. For example, this function prefixes all YELL messages with "[YELL] " - but it’s not restricted to that. Changing names, text, re-structuring the way it is displayed and more is possible using that little function.

The chatbox itself supports tabs. However, these tabs are not hardcoded - it’s possible to add, remove or change tabs on runtime. However, you can define what message should be delivered into what box. In addition, the chat has a target channel display, i.e. it shows what channel you are talking right now (as an example, writing "/y " will change the target to "Yell”, erasing the chat message. Upon sending, the "/y " is attached again so the server can understand it). This applies for all commands and aliases that are defined as well as private messages (/pm), which is using the ZS command target system to show you directly if your PM will hit somebody or not. Also, it has an input history - you are able to browse between earlier sent messages using the up and down key. Using a bit of lua, it’s possible to add additional aliases for each of those types - for example, it’s possible that "!” on the beginning of a line is interpreted as a YELL message automatically using one function call (ZS.AddAlias(’!’, ZS.MessageFilters.YELL)).

ZS also provides a logging tool for chats which allows logging the chats completely into the database including the time, the sender, the receivers, the message and what kind of message it was. Therefore, it’s possible to completely re-construct the chat for a person (within a certain timeframe). This will later be used in a complaint form - players will be able to give admins the permissions to view their RP log within a certain timeframe that they can choose. For example, I can choose to provide 30 minutes of my log and every admin that can view complaint forms can see these 30 minutes as well. Directly from the database, no screenshots required, no way of manipulating them (there is really no reason anybody should mess around with the ZS database outside of ZS, with exceptions being ZS.web)
If you ever played World of Warcraft, the chat is pretty much like that - except that you can’t drag tabs around to form new chats and there isn’t a settings GUI right now. But it’s already planned.

As database, ZS relies on MySQL. However, I’ve written a wrapper for it - the script itself will never call any mysql.* function directly. In addition, this wrapper handles escaping and "threaded queries”. Threaded queries are queries that are sent but do not return immediately. Instead, ZS queues them and executes them one after another. As soon as the first query’s results are available, the (previously given) callback is called with the result as argument. Like timers, these callbacks can have a variety of other passed arguments. After the callback was executed, the next query in the queue is executed and history repeats itself. These queries are not "blocking” the server and should be used whenever possible. However, I’ll be honest: Most of the queries ZS uses do not rely on this technique because it can get really annoying with callbacks after callbacks. However, this might change in the future.

Another more dynamical thing in ZS is the flag system. There are two different flags: One per-player (bound to SteamID), one per-character. Also, it’s not possible to set complete flag strings. Instead, you can only set or unset a single flag at a time. This is supposed to avoid setting the wrong flag or an invalid flag string. However, both have the same functionality, they are stored in a lua table and can have various callbacks. These callbacks are either event based (upon connecting/selecting a character, upon any spawn, upon getting the flag set or unset) or permission based (can X set the flag for Y, can X unset the flag for Y). Additionally, flags have at least two letters, of which the first is uppercase and all following are lowercase. This allows grouping of flags - for example, all administrative flags are within "A” - developer is "Ad”, super admin is "As” and basic admin is a simple "Ab”. Flags are also required to have an unique name which identifies themselves in the script. For example, to check if somebody is a developer, you can use ply:IsDeveloper. This string is also sent upon (un-)setting a flag so you know what flag was just (un-)set.

However, for some things, flags are just too strict or too inaccurate. For example, prop limits or ragdoll limits. ZS introduces player and character variables for that. There are three different "levels” of them: The ones that are saved directly in the characters or players table (and therefore require a table change), the ones that are saved in characterVariables or playerVariables and do not require a change, but generate some overhead when used with common variables, and the ones that are only existing on runtime. Each of them can be defined using one function. After that, set and get functions for these variables are available. ZS handles the storing completely independent, it doesn’t matter what kind of variable it is, you call the function, ZS stores it. If you want to change the type later, you are not required to rewrite the script (but of course need to re-structure the database). All in all, it’s possible to store additional player or character data in an easy accessible way.

Speaking of storing things, let’s talk about inventories. ZS uses grid-inventories. A grid is a table with a predefined width and a certain height. Items also have a width and a height. Unlike some other scripts however, ZS does not have one giant grid per character but more, smaller grids. For example, each character starts with two grids (think of them as the right and the left pocket), each 2x2. This isn’t enough to carry a weapon anywhere else but in your hands. And while this restricts roleplay to a certain amount, it’s more important that players cannot run around as walking armories. However, if you wish to, you can modify it easily to have just one giant grid - ZS won’t care how many inventories you define. However, due to database storage things, you can only define up to 255 different inventory templates. But who is going to define more than 255 different inventories anyway?

However, let’s come back to items: Items that are placed in a grid block that spot in the grid, therefore disallowing other items to take this space. To avoid having unpleasant gaps in the inventory that are unusable, they can be rotated by 90°. In addition, certain items can add additional grids, for example could a backpack give you an additional, unique 3x3 grid (unique as in "It’s not possible to stack 140 backpacks to have a mega inventory”). This does not solve all problems with grid inventories, but it’s the best implementation of an inventory that I could think of with the least disadvantages.
And back to items again: Items are lua tables/objects that can be attached to an entity. This allows items to remember their state even when they are dropped and picked up again. Also, they are serialized upon saving them into the database and deserialized once they are loaded again. Therefore - assuming the item was coded properly - nothing can get lost.

Items are also always behaving like SENTs in certain aspects. For example, items can always communicate with players and vice versa. ZS broadcasts messages not only to players but also to items, giving them the opportunity to parse the message. This could, for example, allow in a wire that broadcasts whatever it hears directly to your PDA or whatever. Or they could react to certain chat input, for example giving simple responses upon simple questions (having a lamp that insults you whenever you yell? No problem!) This does not only apply to items but any entity that has the callback for chat messages. This will be useful in dynamic mapping.

To make life a bit easier for coders, ZS contains so called wizards. They are more or less the same as you know them from installation programs - page-by-page applications. Wizards validate the input given and can therefore already tell if an input will be rejected by whatever processes it. So far, the only wizard used is within the character creation where it sends its data to the server at the end. They are a bit boring to describe but allow to easily creating forms to gather data from an user. For example for the character creation, a feedback form, a complaint form, anything that requires a bit more input.

Animation-wise, it’s a bit boring: ZS is using pre-defined tables that contain the sequence name or an array of sequence names (in which case a random one is picked). This doesn’t allow us to play animations that are not defined in the original models, but it’s enough I suppose. After all, I still stick to the idea that GMod RP is more a text RP than a graphical one - it would just be dessert and there are more important things to focus on right now.

"Dynamic maps” is a term I made up at some point. Basically, it means that you can re-shape the map at runtime to make it more fitting to your community needs. This does not mean reshaping it in the real sense; it is restricted, more or less, to entities. Dynamic mapping is a lua script that is executed upon map change and removes or changes existing entities or adds new ones. An example for dynamic maps could be that you add buttons to open certain doors (which can be spawned again by the script). It is not implemented yet, however, I made some thoughts about it and probably already wrote an essay in my internal forum about that.

Kind of behind the scenes, but a pretty nice feature: Custom CVars. That sounds a bit odd, and perhaps it is. Basically, it’s an API that allows developers to add client console vars and access their values easily as well as assuring that they are in-range for whatever cause might serve. For example, until the chat configuration is implemented completely, the chat behavior (when tabs fade, how long they take for that, when lines fade, how many lines are saved in the history) is saved in various cvars that are all prefixed with zs_ and are accessible using a simple function. In this case, ZS assures that the numbers are always greater or equal to zero and less than a reasonable time.

The last point on the technical part is ZS.web. ZS.web is a collection of Perl scripts that can be used to give users web access to some things, for example lists of users that just play, played in the last X minutes, list of administrators, users with a certain flag, chatlogs and more. For chatlogs, I could imagine that it’s possible to have a Steam OpenID login to access more sensible parts. However, the web and the script itself will be kept differently, meaning that it will be necessary to configure ZS.web on its own. Of course it’s possible to access the database with any script in any language you wish, it’s not restricted to Perl. However, the example code I will provide will be in Perl.

Okay, that’s it for the talk-a-lot part. Although it might sound like it’s not much, I think it is. However, without seeing it in action, it’s a bit hard to describe it. For now, let’s just say that I really put a lot of thinking into everything I made - and basically, I’ve written whole essays about certain features before I even began implementing them. Now, the more easy-to-read part with a few lists describing things that are already implemented and things that need to be implemented… soon.

Features to date:

[li]A stable database wrapper that could be used with almost any SQL compliant database system, including less important queries and escaping. Per default powered by MySQL which allows external scripts easy access - for example web access, dynamic generated user-, admin- or playerlists[/li][li]Player and character variables, allowing easy storing and accessing of dynamical data per player or character.[/li][li]Wizards as an UI element to get valid data from users in a simple and fast way with the option of being easily extendible[/li][li]Behind the scenes: A response system that allows ZS to give users response to their actions, i.e. if they succeeded or not, and why not.[/li][li]Character creation using a wizard, character selection using a selection screen[/li][li]Characters having a name, two (optional) titles, optional age and a optional rather long character description.[/li][li]Looking at something (a player, a prop, an item, anything that has a scripted callback for that) will provide additional information (name, description) using a system that produces as less traffic as possible[/li][li]Behind the scenes: A so called cooldown system helps to keep cooldowns between two actions (for example selecting a character, creating a character, looking at something) on client and server synced, therefore avoiding unnecessary traffic by clients asking if they could do something[/li][li]Restricted toolgun and spawning of non-props[/li][li]Configurable prop- and ragdoll limits as player variables that can be per-player[/li][li]Behind the scenes: A stable chat system that can transmit chat messages of any length, however configurable-wise capped at 500 characters.[/li][li]A customizable chat interface that allows to define the look-and-feel of each type of chat line (say, whisper, yell, emotes, etc.) and a chat box that has fully configurable tabs, allowing users to set in what tab they want to receive what message[/li][li]Behind the scenes: Chatlogs that can be used to completely reconstruct the chat of a player or character[/li][li]Behind the scenes: An easy-to-access API that allows developers to add and control custom client cvars to change ZS’ behavior and look on the client[/li][li]Animation tables for the NPC models that should persist GMod updates and can be extended easily to add more models, including ones with different animation sets.[/li][li]Easily scriptable items (~ same effort as SWEPs) that can interact with characters through chat and keep their state upon being dropped or stored in the database. In addition, items can be derived from other items (therefore inheriting their attributes and functions).[/li][li]Grid-based inventories, as many per character as you want, as well as having a panel to view all of them at once, including drag-and-drop of items from one inventory to another and rotating items.[/li][li]The whole UI scales according to your resolution within predefined borders (target resolutions are 800x600 up to 1920x1080).[/li][li]A command targeting system allowing easily to find players using “RPName”, “>Steamname” or “#UserID”. This is shared and works pretty much everywhere, for example in PMs and all console commands. In case of PMs, it can give players feedback if the recipient can be found by the script, therefore avoiding to have to send messages again because of an invalid receiver.[/li][li]A pretty simple-to-use ITEM editor that allows to create or edit nasty stuff regarding items. Loads and writes directly lua that can be copypasted into the item definition.[/li][li]Behind the scenes: Various log and debugging functions on client and server help to debug code and spot errors easily (assuming they are used wisely)[/li][li]Behind the scenes: Various pre-defined API functions to handle common stuff, for example functions for admin commands that include target finding or argument count validation.[/li][li]Behind the scenes: Documented source code and a Wiki that explains the important mechanisms.[/li][/ul]

Features that are planned (and thought of) but not implemented:

[li]Special animations, i.e. knocking, throwing[/li][li]Dynamical mapping[/li][li]Option menus for the custom cvars, chat settings, flags and other related stuff[/li][li]A few performance tweaks (including getting rid of datastream wherever possible)[/li][li]A SWEP base[/li][li]A global chat interface ("radio API”) to allow entities to communicate over long distances over pre-defined open or secure (“encrypted”/“closed”) channels.[/li][li]Item crafting, item qualities and dynamic item spawns for low-quality items (perhaps put in a different modification)[/li][li]A simple-to-use API for chat commands on client and server (‘triggers’), allowing for example third party scripts to easily embed themselves into the chat[/li][li]Wearable items[/li][li]Several, different menus (AMX-like and some kind of ringmenu) that allow interaction with the server (e.g. votings) or the world (e.g. Use-menus)[/li][/ul]

Things that ZS will most likely not have:

[li]Jobs or anything like that. I want it to be an open RP environment where nobody is restricted to whatever he was voted right now or whatever hat he is wearing.[/li][li]An economy. If you want to have an economy within ZS, there might be a branch that adds that (extending the item tables, adding a character variable, a few user messages), but there won’t be anything economy like in the main core. ZS aims to be generic, not restricting, and it’s easier to add features than to remove them. Although there was some thinking regarding item shops (SNPCs, SENTs), item crafting and item spawns that would provide probably lots of passive.[/li][li]Some specific RP theme. Again, there might be example branches provided by me or somebody else later that show how to adapt ZS to various RP situations, but that won’t happen in the first few releases.[/li][li]Most likely any kind of stat system. It’s possible that some things (for example item crafting, is it ever to be implemented) is using something similar (for example, a techtree) but stats itself like “speed”, “health”, “strength”, “agility” won’t be implemented. All characters are the same, script-wise (this can change due to having certain items equipped, for example a vest)[/li][/ul]

A few screenshots
Keep in mind that the graphical design was not a point of ZS until now. ZS uses extended Derma skins to style itself and various fonts (although they all look the same, right now). Additionally, every UI element is created using ZS.UI.Create, which then involves various hooks for it - it’s possible to do small last-minute changes to elements before they are finally set and displayed.
All screenshots were captured on 1024x768. I’ll just link them with a short description instead of embedding them directly.

[li]A page of the character creation wizard. Invalid fields are highlighted, which is this kind of cyan in the default derma. This validation is done on client and server, of course.[/li][li]Character selection screen. Not much to say here - pretty simple.[/li][li]A bit of the chat while holding a bukkit (the first and pretty much only item so far).[/li][li]A bukkit reacting to the chat. A very simple reaction, it just does some conspiracy talk upon saying “bukkit”. The first line, the yelling from before, has already faded out.[/li][li]The item editor. It’s kept pretty simple but does the majority of the annoying job - the preview model position.[/li][li]And the last picture, the inventory. The inventories are templates (i.e. they have to be defined and are shared). Each inventory template has a width, height, a name, an ID and relative offset (relative to the panel’s complete width, the best thing that came in my mind regarding the scaling UI so far).[/li][/ul]

Why I am posting this at this stage:
The plan has been and still is to develop ZS alone until its first release (under the MIT license). There are various reasons for me to do this. Also, I am not looking for any kind of testers. What I need is some advice regarding some strange behaviors in GMod that I encountered and that I need help with. In addition, it’s always good to have a few more opinions about certain things.

For example, there are various unclear things. Should there be item crafting? In what way (like TF2, like Minecraft)? Can players disassemble items? Do they require tools to do that? What about stats? There are many open, but at the moment not important questions. As soon as I encounter a serious one that needs to be cleared ASAP I’ll post it.
I’m not sure if I was able to give a picture of the mode so far. Like I said, it isn’t going to be a precious designed thing. I aim at clean, maintainable code, not being pretty for a week.

This… Actually sounds pretty great.
I don’t know who you are or what previous Lua experience you have, but this seems hard to make, especially by yourself.
But, based on the screenshots this looks pretty damn awesome already. I like the inventory (although it’s clearly unfinished), it reminds me a bit of the inventory Epidemic used.

Also, I have to give you some credit for writing this post. It’s very well written and explains your gamemode perfectly, although it looks kind of boring with just a wall of text.


About my lua experience, well, it’s not that much. I started lua somewhere at the end of last year with a few chat extensions for TacoScript (i.e. introducing several language features, scriptable aliases, chat history, new tabs, and breaking too long lines into smaller ones). However, I’ve been programming for quite a while now, mainly C++ and Perl. It’s some work, that’s true, but if you have a solid concept, it’s not that hard. After all, the hardest thing when programming something is always to find the right approach - and in every feature I’ve implemented so far (or announced to implement it), I thought a bit about an approach and I think I found a good one.

And yes, I’m sorry about the wall. I tend to do that rather often. Also, I’m not really a designer, graphical-wise. And because of that, the default ZS skin won’t look very pretty (default Derma-ish). However, it’s also part of the design to keep everything as simple as possible, even the design. However, I feel like it’s nothing special and therefore not really worth being shown.

Also, something I forgot to post, is the kind of menu that is used by the player to access several things. A while back, I built something that is similar to the AMX menus (the voice menus in TF2, commonly used in vote menus in other source games). However, to give users a choice, I’ll have another implementation of the menus as well, I haven’t decided what yet but it is most likely something like in Sims (a ring menu) or a simple list where items are under each other and can be selected using the mouse. The AMX menu is using slot1-slot0 bindings to achieve that (and imho, it’s more practical). The AMX menus will most likely be used for votes (that can be issued by admins) whereas the other system(s) will be used for interaction menus.

Also, I’ve started documenting some of the main features already (so far chat messages, chatlogs and the custom cvar system). The (read only) wiki will most likely be split in two parts; one for the developers and one for the players. I’ll first write a bunch of articles for developers, trying to keep it simple (i.e. not explaining precisely HOW it does it) yet it will be a bit technical, so some lua experience will be required. I’m not aiming to make ZS a clicki-go RP mode, but a easily modifiable one (assuming you have some lua practice and know how to read a documentation). However, all important information should be ingame available as well.

However, the priority number one right now (and kind of a cliffhanger because I like to finish one thing after another) is to find a way to fix this panel bug. I’m at my wits’ end. I’m going to try some create-a-new-panel-upon-dragging stuff, but I’m not too sure if that’s the way to go. The GUI drives me insane. Repeatedly.

This sounds very interesting, and very ambitious. If you can get this done, i’ll be very impressed. And happy, this sounds like something I’d use.

Okay, worked around GMod another time (and found out that MakePopup forces the panel to be on top - hooray for SetVisible-EnableScreenClicker combo). Also, item moving around and saving is completely done.

From that point of view, inventory and item management is working so far as expected. Next thing on the list are the ingame menus.

Oh, I forgot something. I knew it. Currently, the item thing is “laggy”: The client re-sets the item to its original position once the “Move that item, please” request is sent, therefore, the item “hops” back to the original position until the server sends the “Hey, move that item” command. So, more or less, I need a clever prediction system to avoid these “lags”.

It seems as if the SQL schema has some flaws. On UNIX systems, check that the tables are named properly (chatlogReceivers instead of chatlogreceivers, characterVariables etc.). Also, the key for chatlogReceivers is called receiverId instead of receiver.

10’986 lines later, the first release. This is by no means a working (it works as far as it is planned to, with a lot of rpd_ commands) nor a production release - I “abandon” the project. I started coding in C++ again and I just enjoy doing whatever I want the way I want too much - in that way, GMod is too restrictive. Also, I don’t want to debug hours around something that should be working according to the “docs”. Additionally, the Source network protocol is some kind of a mess. And I lost real interest in RP months ago - but it is now, during graduation, that I came to the conclusion to stop it.
However, I’m not keeping what I’ve done so far. Some parts might be kind of messy and there are at least 45 TODOs that need to be done (sometimes), along with some serious stuff regarding items but I think there is some valuable stuff in there that can be used for other projects - for example OLM, the chat box, perhaps ZSMultiline or TSV. The whole code is released under the so called MIT license - feel free to do whatever you want to do with the code or parts of it as long as you give credits. Additionally, but not necessary, give me some feedback on the code or where you are using it. I’m interested to see what people can harvest from… what is left.

I might continue this in the future, but it’s unlikely.

So, here -was- the download (edited it out). I did not release it as a repository as most of the commit messages were either German, English, mixed or non-sense (because some changes are obvious) and therefore, not for the public. I wanted to move to a public git repository once I was done - well, doesn’t happen now.

Included is also the so-far written documentation (zs/docs), it’s written in markdown for Github so it could be a little bit weird to read it plain. The documentation is not complete but as far as I can tell pretty accurate and updated.

If you have questions regarding the code or mechanics feel free to ask.

It saddens me to hear that you’ve decided to abandon this project, sounded like it had a lot of potential.

I’ll take a look at the code later today

And a little update to that. What I released had some flaws (regarding the SQL file) as I can’t simply dump the SQL every time I change something (yaaay case insensitive NTFS). However, I continued developing and included a few more things along with the SWEP base and support for a bit weird animation models (headcrabs/antlions, perhaps even strider). I’ve also experimented a bit with those bonemerging animation systems and think it could be implemented at some point.

So, right, there’s a newer version and ZS itself is “almost” complete. I’m not going to give any ETA but it looks as if there will be at least one stable release that includes the basics for RP. If there’s still anybody interested in it I can expand it further until I’ve implemented everything I mentioned in the starting post. I also intend to create one specific RP mode with ZS, HL2RP. I know it’s overdone and everything but I really want to try to see if I can realize a good HL2RP with an intelligent use of SENTs and script features. One that actually can encourage RP other than “sit in an apartment, do /me(h).”

I am actually pretty interested in this, and hope it is not dead. I was waiting for Castella, Tiramisu is pretty broken right now in terms of doing anything other than the included HL2RP schema, and DarkRP is wayyyyyy over done.

It’s still alive. At the moment, I’m porting Tiramisu’s animation system into ZS, because - honestly, animations can be a horrible waste of time.

Other than that, the SWEP base is more or less done: SWEPs have to be re-coded for ZS (or rather, extended with item and ammo information). You can define as many different ammo types as you want, reloading the weapon is possible as long as you have a fitting ammo object in your inventory that has still ammo in it.

For example, we have zs_pewpew which requires ammo of the type ‘melon’. As long as you have an ammo item in your inventory which isn’t empty and has the type ‘melon’, the weapon will automatically reload itself by draining ammo from that item. It allows trading with ammo and other fancy things as well as infinite different types of ammo.

After I have done that, I’ll do a quick check of the bugs that are still inside and work on the TODOs I placed in the code (about 60 now I think - they are just little things that could be changed at some time or could need investigation). After I’ve done that, I think I’ll need some kind of welcome screen for the MOTD and the event MOTD I mentioned earlier. And then I think I’m good to go for OpenSource and github.

It’s not broken? I haven’t had any issues with it lately.

Also, it’s great that this is still alive, can’t wait for the release.

Void my statement about porting over Tiramisu’s animation system. While it is nice and shiny, I can’t get rid of that “FLEX goes all DURRRP” (read: the facial expression of the player is kind of… messed up, softly spoken) thing and since it happens in Tiramisu too, I doubt it’s a bug in my port.

I’ll branch the attempt in case I want to go back, but I doubt it. I think I’ll just go with the “normal” animation system that tries its best to get the animations working.