07 Jan, 2009, BleaS wrote in the 21st comment:
Votes: 0
quixadhal said:
Once we've done the C++ conversion, I'd like to take almost ALL of the hard-coded things in tables.c (for example) and load that data from a set of files. Anything done that way should be managed by OLC in some form.

The only caveat is that a certain amount of care will have to be done when removing elements from those lists. For example, if you choose to remove the warrior class from the class table, you have to check to ensure that either no NPC's or players are warriors and forbid the deletion, or ensure that there's a fallback class which all former players/NPC's will become.

That kind of thing is easier to manage in C++, because you aren't as likely to be using array indexes directly. It might even be the case that you don't actually delete the elements immediately, but flag them for deletion on the next startup.

We'll certainly appreciate the help! Right now, we're still at a point where things are in flux quite a bit, but eventually we'll need people to help with lots of the non-code aspects of the driver. In particular, I'm hoping to eventually retire all the "stock" ROM areas and create new ones that do a better job of teaching both players and builders how things work, and also make it clear that this isn't a "download and play" game system, but one where you can and should build your own world.

There's been talk of a ROM area respository, and ideally I'd like to make it easy to import areas if you really do just want to cherry-pick pieces, but that's a ways down the road I think.


I would certainly build areas if needed, or anything else I could offer. I do hope to get my hands on the code too though because one of the reasons I want to see an updated codebase is for my own personal edification. I have coded in the past and can code, I simply am not at the level that would likely be required for something like a MUD. As an example of what I can code, I took the CircleMUD base that I downloaded, searched up how the tells worked in it and created a tell_self function which operated much the same as the tell function except that it sent just one tell, to you, instead of giving the message of "You can't send a tell to yourself" or sending "You tell <your name> 'blah" and "<Your name> tells you 'blah'". It required finding that function, understanding it enough to edit it into a new function, and changing the is_a_tell function from a strict boolean function to one that returned a character instead for three levels of data 'y' (normal tell) 'n' (can't send tell, maybe sleeping, whatever) 's' (tell to yourself).

However, at the same time, I couldn't figure out how to get the reply function to work with it so that you could reply to yourself if you were the last person to send yourself a tell. There were simply things in the function I didn't understand.

But I do look forward to helping in any non-code aspect because, at heart, I'm a designer. I like to think like an end-user, etc… often I can be a coder's nightmare because I will suggest a lot of things and keep them busy. But I'm not leading the project so all you have to do is say "No." and you seem like the person that would be able to do that. I'd love to help with the code in any way I can, but I don't think I'll be much help there.

As for the areas, I love your thinking. I tried one of the other current codebases suggested in the other thread, it was an update on Circle I think. Either way, I looked to the site of the project and read a thread by one of the people leading it in which he stated that there was no way to really remove the stock areas without possibly messing some of the codebase up and that a user should just unlink those areas. While that might work, the areas are still there in the game when they shouldn't be. It seems very inefficient, and spells like teleport or vanish (that my MUD has, I don't know about this one) that use random rooms for results could possibly end up with a problem where they send someone to an area not linked to the rest of the MUD.

I have lots of ideas already, but I'm holding off to see where it is at first. I don't want to repeat or parrot things that are already in it or already in the works. Hopefully I can log in to the next roundtable.

Edit:

One idea which seems relevant in some ways to the current discussion is this:

Perhaps there could be a normal color setting which would be equatable to the current "complete" color setting of many MUDS which is a full ansi color setting. Then there would also be a "rich" color setting which can be set by users with better mud clients which supports a larger range of colors that those clients can read (via MXP?) so they could experience oranges and browns and a lot of other standard colors.
07 Jan, 2009, quixadhal wrote in the 22nd comment:
Votes: 0
kaervos said:
Alright, I like where you are headed with this. For the sake of immediate progress, I'm going to ignore what may come down the road and focus on chat channels, as I have been. Do you have a problem with the following:

in merc.h
/*
* Channel types.
*/
#define CHAN_GOSSIP "gossip"
#define CHAN_AUCTION "auction"
#define CHAN_QUESTION "question"
#define CHAN_ANSWER "answer"
#define CHAN_QUOTE "quote"
#define CHAN_GRATS "grats"
#define CHAN_WIZ "immtalk"
#define CHAN_SHOUT "shout"
#define CHAN_TELL "tell"
#define CHAN_REPLY "reply"
#define CHAN_SAY "say"
#define CHAN_GROUP "gtell"
#define CHAN_CLAN "clan"
#define CHAN_YELL "yell"


Looks good, although I'd probably combine the question and answer channels into a single "help" channel, perhaps with both do_question and do_answer interfaces that dump into the same channel.
08 Jan, 2009, ghasatta wrote in the 23rd comment:
Votes: 0
I'm going to attempt to comment on several things from this thread in one post: Kaervos' original suggestion, Quixadhal's discussion of the roadmap/architecture, and some finer points of the implementation that seems to be moving forward for channels. They are all sort of in the same vein.

First - Channels. I think Kaervos' idea is a good one. Having input channels will make it much easier to manage client output and customize the formatting for different mediums and preferences. I want to give some feedback to make this idea even stronger. I am concerned that, as initially described, the implementation runs the risk of being monolithic and hard to manage. To start, I think that it will be necessary to separate out game logic (such as in game languages) from the nuts and bolts of channels. Also, why not run with the idea of filters? I would suggest that rather than focusing on channel structures, you define messages (i.e. events) that carry a bunch of properties, and then run each message through a series of filters. Each filter can decide if and how to modify a message. So, player preferences (such as color enabled, disabled, etc), languages, and message formatting can be represented as filters that modify a message depending on the details of the message (channel, language, etc). This is basically an event system. I will hold off on describing any implementation details for now so we can focus on discussing the merits of this approach first.

And yes, I am aware that Quix has said most of this already but perhaps not quite the same way I have put it ;)

Second -

quixadhal said:
Once we're using C++ features, they can be kept in a std::map for fast lookups,[…]
(emphasis mine) For new code, why not now? Especially if there is a clear benefit up front and not much to be gained by waiting.

Third -

kaervos said:
For the sake of immediate progress, I'm going to ignore what may come down the road and focus on chat channels, as I have been.[…]Defining the channel types as strings allows using the CHAN_ defines to be used to in the channel_lookup function.
The future is now my friend. I think it would be in the best interest of the project if we tried to plan this out a little bit. Text keys sound good. But why hardcode all the other properties of each channel? I strongly suggest/request/beg/plead that we don't introduce more macro values or magic constants if we can avoid it. I realize this is not 100% attainable given the way this is hardcoded, but I think this will become spaghetti-fied very quickly once additional 'channels' are defined. My suggestion would be to hardcode the keys but load all other properties from db. Pleeeeeaaaaaase.

-Ghasatta
08 Jan, 2009, tphegley wrote in the 24th comment:
Votes: 0
I will admit that I just like to sit and read what you guys are doing, but I get the feeling that you are creating more work by 'tearing down code to fix code' when you could just take socket mud or whatever and create fresh a mud that exactly fits the needs that you want a mud to have. You can add all the customization into it without having to first tear something out.

So I guess my question is, why are you gutting rom to build it back up rather then build a new codebase that will have all the things that you want in it done by your team and not someone else?
08 Jan, 2009, quixadhal wrote in the 25th comment:
Votes: 0
ghasatta said:
And yes, I am aware that Quix has said most of this already but perhaps not quite the same way I have put it ;)


Never hurts to have someone translate from my version of reality to what the rest of the universe might understand. :)

ghasatta said:
quixadhal said:
Once we're using C++ features, they can be kept in a std::map for fast lookups,[…]
(emphasis mine) For new code, why not now? Especially if there is a clear benefit up front and not much to be gained by waiting.


No real reason. :)

I think we've pretty much established that adding OLC to Ice is probably the last work that'll be done on that side, other than bug fixes that easily translate between the two.

I'm currently working on integrating the ban code, and so far so good. I'm trying to get rid of a few more of the internal char * buffers, just because I hate them and want them to die a horrible, painful, death… errrr… ummm… :)

I have a handful of routines to add in for C++ string utilities, case insensitive compare (still can't believe they didn't include one in std::string), a format routine that works like sprintf, but uses dynamic buffer sizes.

ghasatta said:
kaervos said:
For the sake of immediate progress, I'm going to ignore what may come down the road and focus on chat channels, as I have been.[…]Defining the channel types as strings allows using the CHAN_ defines to be used to in the channel_lookup function.
The future is now my friend. I think it would be in the best interest of the project if we tried to plan this out a little bit. Text keys sound good. But why hardcode all the other properties of each channel? I strongly suggest/request/beg/plead that we don't introduce more macro values or magic constants if we can avoid it. I realize this is not 100% attainable given the way this is hardcoded, but I think this will become spaghetti-fied very quickly once additional 'channels' are defined. My suggestion would be to hardcode the keys but load all other properties from db. Pleeeeeaaaaaase.

-Ghasatta


This might not be a bad time to consider establishing an API for a handful of functions and look into integrating dlsym support?

For example, all normal user commands are prefixed with do_, as in do_tell(), do_kill() and so forth. If we setup a protocol such as do_() functions being mortal game commands, cast_() being spells or skills, wiz_() being immortal commands, and chan_() being channels… we could then combine that with data files to allow the interpreter to look in the right places for various commands.

Right now, do_tell() is a hard-coded command for the interpreter, but it could work by having the interpreter parse "tell" as a verb, and then look through the do_() set, the chan_() set, the wiz_() set, etc. until if finds a match or hits the bottom and fails.
08 Jan, 2009, quixadhal wrote in the 26th comment:
Votes: 0
tphegley said:
I will admit that I just like to sit and read what you guys are doing, but I get the feeling that you are creating more work by 'tearing down code to fix code' when you could just take socket mud or whatever and create fresh a mud that exactly fits the needs that you want a mud to have. You can add all the customization into it without having to first tear something out.

So I guess my question is, why are you gutting rom to build it back up rather then build a new codebase that will have all the things that you want in it done by your team and not someone else?


Don't think I haven't considered it. In fact, I'd be more inclined to abandon C entirely and write a ROM-compatible driver in python, ruby, or lua. However, doing such a thing that wouldn't be bound by the ROM/Diku license is not trivial, since you have to figure out how all the code works and then rewrite it without USING that code as a reference. I don't currently understand how it works well enough to pull that off. And, I would hate to spend the effort to write a python driver that's still bound by the Diku license.

Of course, if we wanted to simply incorporate ROM code into SocketMUD and place that merger under the ROM license, that's a possibility. SocketMUD is public domain (not GPL), so it's possible. It is still, quite a bit of work though.
08 Jan, 2009, tphegley wrote in the 27th comment:
Votes: 0
Thanks for the info, but I have one more question and then I'll stop with the 'why' stuff. Sorry for being a debbie downer…haha. I'm just wondering here.

Why did you pick ROM over say smaugfuss that already has a lot of what you want to do? You could then in turn make it backwards compatible with ROM (areas, pfiles) and then when they load are saved into the new smaugfuss format.
08 Jan, 2009, Kayle wrote in the 28th comment:
Votes: 0
tphegley said:
Why did you pick ROM over say smaugfuss that already has a lot of what you want to do? You could then in turn make it backwards compatible with ROM (areas, pfiles) and then when they load are saved into the new smaugfuss format.


The goal was to give ROM it's own version that is fixed up like SmaugFUSS is.
08 Jan, 2009, quixadhal wrote in the 29th comment:
Votes: 0
*grin* No worries!

As for why ROM? Well, the folks who kickstarted this little project really liked the way ROM works, and were a bit disgruntled by the fact that Smaug and Circle both had active communities who were fixing up and enhancing their respective codebases, but nobody had championed ROM. I kindof fell into it because I've done a lot of the bug fixing/cleanup work for a few other projects, none of which involved ROM in any way. :stare:

My own MUD is from the dark ages of Diku Gamma, and I'm far more familiar with Smaug, but I liked the idea of bring ROM up to date and maybe pushing it ahead a ways. Who knows? Maybe someday it will even be quasi modular? Baby steps first. :)
08 Jan, 2009, tphegley wrote in the 30th comment:
Votes: 0
Ah, Sounds like a plan you got there. Thanks for answering my questions…heh. It will be good to have more support from the major codebase contributors (smaug, circle, and now ROM) More ways to be different.
08 Jan, 2009, ghasatta wrote in the 31st comment:
Votes: 0
quix said:
I'm trying to get rid of a few more of the internal char * buffers, just because I hate them and want them to die a horrible, painful, death… errrr… ummm… :)

I have a handful of routines to add in for C++ string utilities, case insensitive compare (still can't believe they didn't include one in std::string), a format routine that works like sprintf, but uses dynamic buffer sizes.
I took a if-it-aint-broke-dont-fix-it approach to the use of char[] buffers within functions. Or rather, I turned a blind eye to them to avoid getting sucked in. I think case insensitive comparison could be useful, but I would say it's probably better to use stringstreams rather than sprintf-for-strings.

quix said:
This might not be a bad time to consider establishing an API for a handful of functions and look into integrating dlsym support?

For example, all normal user commands are prefixed with do_, as in do_tell(), do_kill() and so forth. If we setup a protocol such as do_() functions being mortal game commands, cast_() being spells or skills, wiz_() being immortal commands, and chan_() being channels… we could then combine that with data files to allow the interpreter to look in the right places for various commands.

Right now, do_tell() is a hard-coded command for the interpreter, but it could work by having the interpreter parse "tell" as a verb, and then look through the do_() set, the chan_() set, the wiz_() set, etc. until if finds a match or hits the bottom and fails.
I like the concept but I think dlsym might be going a little, well, low-level. I think if you had a list of interpreter function pointers, you could iterate through them when trying to handle input. Each function would be able to decide whether to handle the command or not (at a basic level, based on a match with the right verb. At a more complex level, based on number of arguments, character state, etc). You could even have multiple layers of interpreters that get added / subtracted from characters depending on their state, privileges, etc. Different modules could then register their commands and we could avoid a big spaghetti-fied mess! hooray!
09 Jan, 2009, quixadhal wrote in the 32nd comment:
Votes: 0
ghasatta said:
I would say it's probably better to use stringstreams rather than sprintf-for-strings.

String streams are OK for some things, but they're no substitute for the kind of format control that sprintf provides. For some things it doesn't matter, but for screen output where lining up columns by character is important, sprintf provides much tighter control. Of course, if there's a method in the string stream library that works without 5 levels of annoyance, do tell! :)

ghasatta said:
I like the concept but I think dlsym might be going a little, well, low-level. I think if you had a list of interpreter function pointers, you could iterate through them when trying to handle input. Each function would be able to decide whether to handle the command or not (at a basic level, based on a match with the right verb. At a more complex level, based on number of arguments, character state, etc). You could even have multiple layers of interpreters that get added / subtracted from characters depending on their state, privileges, etc. Different modules could then register their commands and we could avoid a big spaghetti-fied mess! hooray!


Yes, but if you don't use dlsym, you can't handle a command table that can grow without mucking with hard-coded arrays in the interpreter. I'm not suggesting using it to allow on-the-fly addition of code (although that IS possible), but rather not having to declare a table with function pointers that you have to maintain. AFKMUD did this, and I believe SmaugFUSS also has it.
09 Jan, 2009, ghasatta wrote in the 33rd comment:
Votes: 0
Quote
Of course, if there's a method in the string stream library that works without 5 levels of annoyance, do tell! :)
There's actually a pretty cool example right in the Mudbytes code repository - the TableGenerator library. http://www.mudbytes.net/index.php?a=file...

That notwithstanding, any level of precision possible with printf is also possible with an ostringstream, I suppose 5 levels of annoyance is subjective. The most complicated sprintf call I could find in RaM at the moment is this:

sprintf( buf, "%-20s %-14s %5d %4d %6d %4d %5d\r\n"…)
Granted you would have about 4 insertion operators for each variable in the string. I personally don't consider that to be that big of a deal, but others might.
std::ostringstream out;
out << setw(20) << left << text1 << " " <<
<< setw(14) << left << text2 << " " <<
<< setw(5) << int1 << " " <<
…etc.
I can see how that would get a bit tedious, but maybe only 1 or 2 levels of annoyance. Before anyone complains that the ostringstream version increases code size, know that the sprintf code I snipped above takes up exactly the same number of lines, since each arg supplied is on its own line (for readability presumably).

My preferred solution would be to use something like the TableGenerator library. No accounting for taste I suppose.
09 Jan, 2009, quixadhal wrote in the 34th comment:
Votes: 0
ghasatta said:
std::ostringstream out;
out << setw(20) << left << text1 << " " <<
<< setw(14) << left << text2 << " " <<
<< setw(5) << int1 << " " <<
…etc.


That makes my skin crawl.

How ugly would the stream version of sprintf(foo, "%-9.3f %08.10d %-5.5s\r\n", a, b, c); be?

That's, print a floating point number, left justified, with 9 digits of space, 3 of which are after the decimal; print an integer with leading zeros that will take at least 8 digits of space, but at most 10; and print a left justified string taking at most 5 spaces, and truncating if it would be longer.

I'm not totally against using streams where it makes life easier, but things like that are NOT easier IMO.
09 Jan, 2009, David Haley wrote in the 35th comment:
Votes: 0
Streams' true power comes when dealing with more or less arbitrary types and defining what happens when a given type meets a given stream. Format specifiers only work with POD, and you run into pretty annoying 32 vs 64 bit problems, for example, or having to add stringification functions to all of your objects – which is what you'd do for streams anyhow. Of course, streams aren't perfect (is your stringification the human-readable version, a summary version, or the full shebang version?), but they're not bad. I think you might just not be used to them. I disliked them at first but now they don't bother me at all.
09 Jan, 2009, Tyche wrote in the 36th comment:
Votes: 0
sprintf( buf, "%-20s %-14s %5d %4d %6d %4d %5d\r\n"…)


Using the Boost Format Library and literal printf tranlation…
std::ostringstream out;
out << format("%1$-20s %2$-14s %3$5d %4$4d %5$6d %6$4d %7$5d\r\n"")
% "my" % "format" % 35 % 81 % 71 % 6 % 45 ;


There are other syntax styles one can use.
I kind of like the required argument ordinal positional notations.
09 Jan, 2009, quixadhal wrote in the 37th comment:
Votes: 0
Wandering back into the channel part of the discussion… I had an idear… *grin*

Building on the idea of chat channels as filters, and looking at some of the channel pairings (such as question/answer, tell/reply, etc), it occured to me that sub-channels would be possible.

IE: a channel "private" might have several sub channels (whisper, tell, ask, reply), which all get treated the same way and which one might want to toggle as a set (IE: if AFK, buffer private messages). If we extend channels to be generic messaging, this also groups things like language filters, color/MXP/HTTP format filters, etc.

Anyways… I was also thinking about OO design. Since we're selling this to the Fire branch, there's no real reason it can't be implemented as class objects, and that brought me around to streams.

IF we obtained a socket stream library (I'm sure there must be a zillion of them), and converted the socket handling part of the codebase to create socket stream objects and stuff those into the descriptor structure instead of just a descriptor handle, our channels could also be stream compatible, which would mean they could feed into each other and eventually into the socket itself.

The tricky part here is, is there a way to pass arguments to a stream, other than the data that goes TO the stream? In network terms, Out-Of-Band data? I'm thinking of something like this, which is probably NOT possible:

Quote
target->tell(ch) << "You're a noob!\r\n"


What I'm trying to do is send the message to the tell stream of target, and the ch argument would let tell recognize who sent the message and add the apporpriate language information.

So I guess, I'm not wanting tell to be a stream, but rather a function which returns a stream?

Hmmmm, have to get coffee and ponder a bit more. Anyways, you see the idea. Even if streams won't work for this, I still think writing the channels so they can send their output to other channels is a good idea.
09 Jan, 2009, Tyche wrote in the 38th comment:
Votes: 0
quixadhal said:
The tricky part here is, is there a way to pass arguments to a stream, other than the data that goes TO the stream? In network terms, Out-Of-Band data? I'm thinking of something like this, which is probably NOT possible:

Quote
target->tell(ch) << "You're a noob!\r\n"


What I'm trying to do is send the message to the tell stream of target, and the ch argument would let tell recognize who sent the message and add the apporpriate language information.


Streams store data in IOS. You need to subclass the stream, in order to provide an area to store extra data, like for instance character name. Then you define your own manipulators on the stream.

talkchannelstream out;
out << who(ch) << color(YELLOW) << "You're a noob!" << std::endl;
09 Jan, 2009, BleaS wrote in the 39th comment:
Votes: 0
Should I bring up my idea in the Sunday roundtable then?
09 Jan, 2009, quixadhal wrote in the 40th comment:
Votes: 0
Tyche said:
Streams store data in IOS. You need to subclass the stream, in order to provide an area to store extra data, like for instance character name. Then you define your own manipulators on the stream.

talkchannelstream out;
out << who(ch) << color(YELLOW) << "You're a noob!" << std::endl;


Seems reasonable. Oh, I do have to ask this though…. std::endl. I know what it's supposed to do, but is that really the right thing to use for TELNET? IE: On my OS (linux), std::endl should resolve to "\n". On MS-DOGGIE, it should become "\r\n", which also happens to be the correct ending for TELNET.

I know it's the right choice for console I/O, and for file I/O (presumably it auto-converts on input streams?), but I'm not sure it's correct for TELNET.

Thanks Tyche! I may try to take the format() routine I have and see if I can't make a subclass wrapper for sstream to see how it works.
20.0/47