Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - quixadhal

Pages: 1 2 [3] 4
31
Code Vault / perl lpc
« on: May 27, 2012, 04:05:11 AM »
You had to look, didn't you?

Nooooo, silly wabbit.  This isn't an LPC interpreter written in perl... or at least, it's only a very tiny bit of one. *smile*

This is, instead, a few useful utilities for those of you (no one) that have been begging for a way to talk to I3 from perl.  It's not YET an actual I3 client, but it is the first few steps needed to start thinking about one.

Code: [Select]
#!/usr/bin/perl -w

use strict;
use English;
use Data::Dumper;
use JSON;

sub json_to_lpc {
    my $thing = shift;

    return undef if !defined $thing;
    #JSON and LPC are very similar, in fact to convert from
    #one to the other, all we REALLY need to do (for purposes
    #of using mudmode sockets and LPC data types) is convert
    #{ pairs to ([ pairs, and [ pairs to ({ pairs, avoiding
    #anything inside double-quoted strings.

    my $result = "";
    my $nested_mappings = 0;
    my $nested_arrays = 0;
    my $inside_quotes = 0;
    my $is_backslash = 0;
    my $is_unicode = 0;
    my $unicode = '';

    foreach my $ch (split //, $thing) {
        if( $inside_quotes ) {
            if( $is_backslash ) {
                if( $is_unicode ) {
                    if( length $unicode < 4 ) {
                        $unicode .= $ch;
                    } else {
                        if( $unicode eq '0000' ) {
                            # This is what the JSON encoder does with NUL bytes, but
                            # LPC wants \0, so we need to catch and convert it.
                            $result .= "\\0";
                        } else {
                            # We could add a few other recognized things here,
                            # or just punt and pretend we saw nothing, or
                            # just leave the escape sequence in here and let
                            # the LPC thing deal with it.
                            #$result .= "\\u$unicode";
                        }
                        $unicode = '';
                        $is_unicode = 0;
                        $is_backslash = 0;

                        # This is, of course, the next character NOT part of the sequence.
                        $result .= $ch;
                    }
                } else {
                    if( $ch eq 'u' ) {
                        $is_unicode = 1;
                        $unicode = '';
                    } else {
                        $is_backslash = 0;
                        $result .= "\\$ch";
                    }
                }
            } else {

                if( $ch eq '\\' ) {
                    $is_backslash = 1;
                } elsif( $ch eq '"' ) {
                    $inside_quotes = 0;
                    $result .= $ch;
                } else {
                    $result .= $ch;
                }
            }
        } else {
            if( $ch eq '{' ) {
                $nested_mappings++;
                $result .= '([';
            } elsif( $ch eq '[' ) {
                $nested_arrays++;
                $result .= '({';
            } elsif( $ch eq '"' ) {
                $inside_quotes = 1;
                $result .= $ch;
            } elsif( $ch eq ']' ) {
                $nested_arrays--;
                $result .= '})';
            } elsif( $ch eq '}' ) {
                $nested_mappings--;
                $result .= '])';
            } else {
                $result .= $ch;
            }
        }
    }
    return $result;
}

sub lpc_to_json {
    my $thing = shift;

    return undef if !defined $thing;
    #JSON and LPC are very similar, in fact to convert from
    #one to the other, all we REALLY need to do (for purposes
    #of using mudmode sockets and LPC data types) is convert
    #{ pairs to ([ pairs, and [ pairs to ({ pairs, avoiding
    #anything inside double-quoted strings.

    my $result = "";
    my $nested_arrays = 0;
    my $nested_mappings = 0;
    my $inside_quotes = 0;
    my $is_backslash = 0;
    my $got_paren = 0;
    my $got_brace = 0;
    my $got_bracket = 0;

    foreach my $ch (split //, $thing) {
        if( $inside_quotes ) {
            if( $is_backslash ) {
                if( $ch eq '0' ) {
                    # JSON wants NUL bytes in unicode esaped form...
                    $is_backslash = 0;
                    $result .= "u0000";
                } else {

                    $is_backslash = 0;
                    $result .= $ch;
                }
            } else {
                if( $ch eq '\\' ) {
                    $is_backslash = 1;
                } elsif( $ch eq '"' ) {
                    $inside_quotes = 0;
                }
                $result .= $ch;
            }
        } elsif( $got_paren ) {
            if( $ch eq '{' ) {
                $nested_arrays++;
                $result .= '[';
            } elsif( $ch eq '[' ) {
                $nested_mappings++;
                $result .= '{';
            } else {
                $result .= $ch;
            }
            $got_paren = 0;
        } elsif( $got_bracket ) {
            if( $ch eq ')' ) {
                $nested_mappings--;
                $result .= '}';
            } else {
                $result .= $ch;
            }
            $got_bracket = 0;
        } elsif( $got_brace ) {
            if( $ch eq ')' ) {
                $nested_arrays--;
                $result .= ']';
            } else {
                $result .= $ch;
            }
            $got_brace = 0;
        } else {
            if( $ch eq '(' ) {
                $got_paren = 1;
            } elsif( $ch eq '"' ) {
                $inside_quotes = 1;
                $result .= $ch;
            } elsif( $ch eq ']' ) {
                $got_bracket = 1;
            } elsif( $ch eq '}' ) {
                $got_brace = 1;
            } else {
                $result .= $ch;
            }
        }
    }
    return $result;
}


# The specs for "mudmode" sockets are not really well documented, or

# rather... the documentation is not easy to find... but the basic idea
# is you take a valid LPC data structure and prepend a 4-byte length field
# (which I will *ASSUME* is in network byte order!), and then append a
# NUL byte.

# One presumes NUL bytes within the data structure have already
# been escaped, although it is unclear if any given LPC driver
# actually allows such things to exist anyways.

sub lpc_to_mudmode {
    my $thing = shift;

    return undef if !defined $thing;
    my $len = length $thing;
    my $result = pack('N', $len) . $thing . "\0";
    return $result;
}

sub mudmode_to_lpc {
    my $thing = shift;

    return undef if !defined $thing;
    my $expected_len = unpack('N', $thing);
    my $result = substr($thing, 4, -1);
    return $result;
}

# These are just wrappers to make going between socket data and
# perl hashes a one step conversion.

sub to_mudmode {
    my $thing = shift;

    return undef if !defined $thing;
    return lpc_to_mudmode(json_to_lpc(encode_json($thing)));
}

sub mudmode_to {
    my $thing = shift;

    return undef if !defined $thing;
    return decode_json(lpc_to_json(mudmode_to_lpc($thing)));
}

# Could probably use better test data...

my $test_obj = { "hello" => [ 23, -7, "b{\0oo\nfoo", { "blah" => 17.3 } ] };
my $json_serial = encode_json $test_obj;
my $json_obj = decode_json $json_serial;
my $lpc_convert = json_to_lpc($json_serial);
my $json_convert = lpc_to_json($lpc_convert);
my $stage_two = decode_json $json_convert;

my $mudmode = lpc_to_mudmode($lpc_convert);
my $mm_lpc = mudmode_to_lpc($mudmode);
my $stage_three = decode_json(lpc_to_json($mm_lpc));

my $round_trip = mudmode_to(to_mudmode($test_obj));

print "JSON Serialization:         $json_serial\n";
print "JSON Deserialization:       " . Dumper($json_obj) . "\n";
print "json_to_lpc:                $lpc_convert\n";
print "lpc_to_json:                $json_convert\n";
print "Stage 2 Deserialization:    " . Dumper($stage_two) . "\n";
print "Stage 3 Deserialization:    " . Dumper($stage_three) . "\n";
print "Round Trip Deserialization: " . Dumper($round_trip) . "\n";

32
Code Vault / dumb math stuff to find a heading to a point.
« on: March 29, 2012, 09:47:15 AM »
Probably not super-useful, but I needed to have something to show me the distance and heading from origin to some coordinate.  This is 2D only, feel free to expand it to 3D if you like math.

Distance is easy... distance = sqrt(x*x + y*y);

For the heading (typical compass, 0..360 degrees, with 0 being north)

I put this in /secure/sefun/math.c -- but wherever works. :)

Code: [Select]
float atan2( float x, float y ) {
    if( y == 0.0)
        if( x >= 0.0 )
            return 0.0;
        else
            return 3.14159;

    return 2.0 * atan((sqrt(x*x + y*y) - x) / y);
}

float heading( float x, float y ) {
    float val;

    if( y == 0.0 )
        if( x >= 0.0 )
            return 90.0;
        else
            return 270.0;

    val = atan2(x,y) * 180.0 / 3.14159;

    if(val > 90.0)
        return 450.0 - val;
    else if(val > 0.0)
        return 90.0 - val;
    else if(val < -90.0)
        return (0.0 - val) + 90.0;
    else
        return 90.0 - val;
}

33
Lima Lounge / Unofficial, unauthorized, unwarranted github release
« on: March 15, 2012, 05:40:18 PM »
Hey guys,

Since I've recently been playing with github and dead souls, I figured I'd go dig out my old archive of the lima mudlib (which is much smaller) and give that the same treatement.

So, I've put up a git repository of the lima mudlib, from the oldest official release I could find (0.9r1) up through the last release (1.0b5), Cratylus's modifications to bring it into the FluffOS era (fluffos_v1), and then I updated the driver to the current 2.23 version with a few tweaks to add default values for the new symbols it wants (fluffos_v2).

Use, abuse, whatever... you can download a zip or tarball via github itself, or browse the tree, or clone the repository using git.  However you like.

34
Design Lab / LPC shell?
« on: January 01, 2012, 06:17:46 AM »
Ok, Happy New Year folks. :)

Instead of being asleep and drunk, as I should be... I find myself awake and thinking about an old idea I tossed around a few years ago... the inside-out MUD server.

The short version is this... most MUD servers spend a LOT of their time and code trying to mimic systems that are already well established and in place, at least on the unix platform.  The login/account system, the shell environment and all the user input processing and command execution that entails, the terminal handling system... instead of making the mud server do all that, why not let the OS do it, the way it already does for regular logins?

IE:  Why not write a custom shell which talks to the MUD server directly, and replaces /bin/bash (or whatever)?

The benefits have already been discussed elsewhere, and I think the security issues are manageable.  The question is, does anyone have a good idea of what would work well for such a thing?

I considered modifying bash, but anyone who's looked at GNU code knows what a nightmare that would be.  I also considered using perl/python/etc to write a shell myself, and that's certainly an option... but then there's PIKE.

Does anyone actually use PIKE?  It would be a bonus if you had a login shell that could understand LPC right there as your scripting language, but not essential.

Currently, iPython seems like a good place to start, but I'm open to suggestions.

To be clear, the concept is to have a login shell that works properly with full terminal support -- just like bash -- but also connects to your MUD server to handle events.  So when the orc walks into the room, you want the game server to push that event to your shell, and have it do the display and redraw your prompts/etc as needed.  When you type 'kill orc', it should execute a "kill" command which would ultimately send the kill command to the server and print the results.

If such a concept worked, you'd essentially decouple the display system and much of the user-input parsing from the game server and move them into the individual login shells... giving you better performance (multi-threading) and much cleaner server code.

Please discuss. :)

35
Code Vault / sefun strip_raw_ansi()
« on: November 12, 2011, 10:05:40 PM »
This is something I added to the strip_colors() sefun, to handle weirdoes who add raw ANSI sequences to their I3 traffic.

Code: [Select]
string strip_raw_ansi(string str) {
    mixed stuff;
    string ret = "";

    stuff = pcre_assoc( str, ({ "(\e[[][0-9]+m)", "(\e[[][0-9]+;[0-9]+m)" }), ({ 1, 2 }), 0);
    for(int i = 0; i < sizeof(stuff[0]); i++) {
        if(!stuff[1][i])
            ret += stuff[0][i];
    }
    return ret;
}

36
Dead Souls Support / Strange behavior in 3.2
« on: March 15, 2011, 06:20:59 PM »
Hmmmmm, so I recently upgraded to DS 3.2 from DS 3.0.  I installed the new game and then ported over a small handful of changes from my old game, which had been running stable for about 16 weeks.  Now, I seem to have a few issues, and am not quite sure where to look first.

The first issue I noticed was that after recreating my immortal and then restarting the driver after the expected shutdown, the first time I log in, I am NOT an admin and can't run commands such as "ls".  Exiting via "quit" and logging back in seems to fix this.  I wouldn't think anything of it, except it seems to happen EVERY time the driver restarts...

And that leads me to issue #2.  The driver crashed with the following trace:

Code: [Select]
******** FATAL ERROR: couldn't find object  in obj_table
FluffOS driver attempting to exit gracefully.
(current object was /secure/sefun/sefun)
--- trace ---
Object: /secure/daemon/instances, Program: /secure/daemon/instances.c
   in heart_beat() at /secure/daemon/instances.c:677
Object: /secure/daemon/instances, Program: /secure/daemon/instances.c
   in CheckConnections() at /secure/daemon/instances.c:637
Object: /secure/sefun/sefun, Program: /secure/sefun/sefun.c
   in socket_names() at /secure/sefun/sockets.c:25
'          CATCH' in '/secure/sefun/sefun.c' ('/  secure/sefun/sefun') /secure/sefun/sockets.c:25
--- end trace ---
crash() in master called successfully.  Aborting.

The matching entry from /log/crashes:

Code: [Select]
Bloodlines crashed Tue Mar 15 17:27:20 2011 with error couldn't find object  in obj_table.

0:OBJ(/secure/sefun/sefun), file: /secure/sefun/sefun.c, fun: get_stack, origin: simul
1:OBJ(/secure/daemon/master), file: /secure/daemon/master.c, fun: crash, origin: driver
2:OBJ(/secure/sefun/sefun), file: /secure/sefun/sefun.c, fun: CATCH, origin: simul
3:OBJ(/secure/sefun/sefun), file: /secure/sefun/sefun.c, fun: socket_names, origin: simul
4:OBJ(/secure/daemon/instances), file: /secure/daemon/instances.c, fun: CheckConnections, origin: local
5:OBJ(/secure/daemon/instances), file: /secure/daemon/instances.c, fun: heart_beat, origin: driver
({ OBJ(/secure/sefun/sefun), OBJ(/secure/daemon/instances) })

Since, AFAIK, I'm not using instances and haven't messed with anything around these files, with the one exception of adding a single function to the bottom of the strings part of the sefun set, I'm at a bit of a loss to know where to start looking for roaches.

Any ideas?  Anyone else run into anything like this before?

37
Didn't see a thread already, so here's a spot where I can toss the occasional bug fix or improvement (in MY eyes) to the DS mudlib. :)

First up is a one-liner for the help command.  It just replaces the hard-coded "2000" character breakpoint for passing things to the pager with a more sensible "screen size - 2 lines".  There are quite a few legacy places where things are hardcoded with assumptions like this (80x25 screen size), but this is the first I found while adding my local changes to my git repository of DS 3.2.

Code: [Select]
bloodlines@brezhnev:~/lib$ git diff cmds/common/help.c
diff --git a/lib/cmds/common/help.c b/lib/cmds/common/help.c
index 639c2aa..b7064bf 100755
--- a/lib/cmds/common/help.c
+++ b/lib/cmds/common/help.c
@@ -50,7 +50,8 @@ mixed cmd(string arg) {
         }
     }
     help = center(mud_name()+" System Help", screen[0]) + tmp;
-    if(sizeof(help) < 2000)    help = wrap(help, screen[0]);
+    if(sizeof(help) < screen[0] * (screen[1] - 2))
+        help = wrap(help, screen[0]);
     who->eventPage(explode(help, "\n"), MSG_HELP);
     return 1;
 }

38
Dead Souls Support / colorize bug?
« on: February 02, 2011, 03:45:55 AM »
Hey guys,

Could one of you check something for me?  I found a bug on my copy of DS, but I've bashed the terminal handling around quite a bit, so it may be the way I've rearranged stuff (and thus only MY problem).

Try "admin|colorize YiIIIPPPpE"

For me, the I's and P's don't show up.  I tracked it down to an artifact of the way Pinkfish codes are parsed (in terminal_color(), basically by exploding on %^ and then matching names).

I've mentioned the issue before.  You can't generate a red RED without some kind of padding... %^RED%^RED%^RESET%^ should logically yield the word RED, but instead it generates nothing because the way things are parsed allows %^BOLD%^UNDERLINE%^RED%^ to work.

This bug shows up to bite you when using colorize(), because it splits the string up into characters, and adds random color codes around each one.  Because someone added in HTML to the Pinkfish language, %^I%^ and %^P%^ are recognized as valid tokens, and get translated to empty strings if your terminal type is not HTML.

Normally, not an issue.. unless you were trying to print a colored I or P.

Where this might bite someone a bit harder is if they tried to use I as a symbol for a graphical map or a title screen, or even an ANSI picture in a book or scroll.

So, my question is... does anyone actually use the pinkfish HTML tokens?  If not, the band-aid solution is to remove the HTML stuff entirely or change the tokens to PARAGRAPH and similar.

The "proper" solution would be to "fix" the Pinkfish system to require full delimiting of tokens.  %^BOLD%^%^RED%^ would work, but the sloppy %^BOLD%^RED%^ would not.  I'll toss the idea out again, but you guys hate change so I don't expect it to get any more traction than last time. :)

39
Code Vault / DS Intermud log mungerer thingy
« on: December 28, 2010, 03:22:50 AM »
Hey guys,

Finally got this to the point that it works "well enough" for my taste.  It's not meant to take away from David's work over at MudWorld (which is a real I3 log system), but rather to show how to access the stuff that's already there in your very own DS 3.0+ mudlib.

Wot?

Well, it provides a fancypants HTML view (default), which uses colors for channel and speaker names, and wraps links in href's so you can click on them.  If you click on a speaker name, it filters by that speaker only.  If you click a channel name, same thing.  Right now, the page size is by parameter only, so if you want more or less than 25 entries, go poke at it.  I didn't feel like adding a text field form thing.

But wait!  There's more!  With your $0.00, you also get a plain text view, suitably formatted to 120 columns and ready to be.... ummmm.... viewed as text!  Just add the fm=text parameter.

Order now and you also get an RSS view, at NO ADDITIONAL CHARGE!  That's right... you can view the I3 logs on your favorite RSS reader, which should at least display stuff, even if it looks ugly.  Hey, I tested it on my Logitech G510 keyboard.

Yeah, but what's the catch?

Well, yes... there's ALWAYS a catch.  In this case, you have to apply a tiny patch to your channel logging code, because the format DS saves them in is really ugly and hard to parse because of spaces being allowed in mud names AND emote format being stupid.

Ok, actually, it may not be quite a tiny patch... my chat.c has changed radically from the 3.0 vanilla version I started with, but... it's simple enough. :)

Open up /lib/secure/daemon/chat.c in your favorite editor
Skip down to "eventSendChannel"
Add a variable somewhere up at the top for a string array:
    string *whobits;

Then down near the bottom:
Code: [Select]
    whobits = explode(who, "@");
    if(sizeof(whobits) < 2) {
        if(sizeof(whobits) < 1) {
            whobits += ({ "Someone" });
        }
        whobits += ({ mud_name() });
    }
    who = implode(whobits, "@");
    LogIt(timestamp()+"\t"+ch+"\t"+who+"\t"+pmsg+"\n", "/secure/log/allchan.log", ch);

That *SHOULD* be all you need to do.  The DS log system will happily rotate the file for you as it grows.  It's in /secure, since it may also contain admin stuff and other local channels.  If you don't want those, filter them out yourself. :)

40
Here's the story.  I was writing a filter to allow one to see what the poor souls on IMC2 see when they get URL's with color codes embedded in them.  Why?  I was curious.  Anyways, the idea was that I would run a string through imc_to_pinkfish, and then escape the pinkfish codes so you could print it out.

Code: [Select]
eval return replace_string(IMC2_D->imc2_to_pinkfish("http://foo.com/~broken"), "%^", "%%^^");
Result = "http://foo.com/%^BLUE%%^B_RED%^oken"

Not quite what I expected.  I expected to see:

Code: [Select]
Result = "http://foo.com/%^BLUE%^roken"
So, poking around, I found the issue is in my sefun replace_strings(), which calls replace_string() using the key/values of a mapping to do mass replacements, as you'd want to do in a terminal color manager, for example. :)

The problem is that some of the replacements look like additional codes.

So, ~broken gets converted to %^BLUE%^roken, but then the ^r is recognized as another IMC color code and gets replaced by %^B_RED%^, so you now have %^BLUE%^%^B_RED%^oken.  ^o is not a valid IMC color code, so it stops there.

So, here are the code snippets that are involved....

Code: [Select]
    string imc2_to_pinkfish(string str){
        str = replace_strings( str, imc_pinkfish );
        return str;
    }

and imc_pinkfish is a mapping that has stuff like:

Code: [Select]
static private mapping imc_pinkfish = ([
...
            "^r"                     : "%^B_RED%^",
...
            "~b"                     : "%^BLUE%^",
...
]);

Ok so far, replace_strings() is an sefun:

Code: [Select]
string replace_strings(string str, mapping m) {
    int i;
    string *k = keys(m);
    string *v = values(m);

    for(i = 0; i < sizeof(k); i++) {
        str = replace_string(str, k[i], v[i]);
    }
    return str;
}

and our good friend, replace_string is, of course, an efun in FluffOS.

So, can anyone suggest a nice way to still accomplish this without having the newly replaced values re-interpreted?  If replace_string() told me the offsets it was at when the last replacement happened, I could chop the string and feed only the unprocessed part back in, building it as we go.

I realize I could do it in two passes, by perverting the pinkfish codes to some non-overlapping symbols and then back, but that's both ugly and makes it possible to stomp on other things.  *shrug*

Anyhoo... 5am approaches, so I give up for now. :)

41
Intermud / Antique DikuMUD I3 code
« on: September 30, 2010, 06:14:25 AM »
So, partly for amusement and partly because I'm tired of the stupid IMC color codes screwing up URL's, I decided to try and revive the old I3 code for Smaug that worked years ago, but was dropped when MudBytes picked up the IMC2 torch.

It appears to connect and talk to *i4 ok.  I can connect and get a mudlist with no problems.  However, I don't ever get any channel listings.

Looking at the spec, when you send the startup-req-3 packet, the server *might* deign to send you a chanlist-reply packet, telling you about channels you didn't know about.

So, I predict one of two possible reasons for this error.  One -- *i4 never sent me a chanlist-reply packet, and so either I'm in error with the startup packet, or I'm just unworthy.  Two -- *i4 did send me a packet with the entire channel listing, and it managed to overflow the DikuMUD "MAX_STRING_LENGTH" buffer limit, which silently dropped it on the floor.

Cratylus?  Any chance you could check on your end to see if you sent me a gigantic packet that I dropped?  I'll try to paw through the socket code on this end and add some more debugging code.

As usual, no hurry, and thanks!

42
Intermud / dalet no like me no more?
« on: August 09, 2010, 12:30:35 AM »
Hey Crat,

If you're bored, see if you can tell what I'm doing differently now than I was a few days ago before my server's hard drive melted?

I restored a backup and my old trusty Diku is back up and running, but for whatever reason it doesn't want to reconnect to dalet.  I have no clue why, since it's the exact same configuration data that was working 3 days ago.

The only error I get in the logs is:

Code: [Select]
<: 1100809.012336.935 - INFO - (imc.c;imclog,275)
 : IMC: Invalid authentication response received from 1281331416!!
<: 1100809.012336.935 - INFO - (imc.c;imclog,275)
 : IMC: Data received: *@Firefly_Devmud 1281331416 dalet!*dalet is-alive *@WileyMUD

I could probably shove more debug code into place, but at this point I'm wondering if dalet forgot me and no longer likes whatever stuff I'm shoveling at it for passwords?

No hurry, and thanks!

43
Intermud / Filtered channels?
« on: June 09, 2010, 05:11:11 AM »
Ok, so since certain folks decided to abuse my nice url expander, because they are childish little minions who'd rather tear down than build up, I figured I'd take Crat's advice and try to set up a filtered channel of my own. :)

This is the mythical "mode 2" channel.  From reading the docs, it looks like you simply create an I3 channel of this mode and it becomes a public channel, but with a catch.  Anything sent to that channel is first forwarded to the mud that owns it (seperate message type), and that mud then has to send it back to the router as approved for it to go out.

Essentially, this allows you to make a channel anyone can watch, but only certain users/muds/etc can write to it.  Problem solved?

Almost.  I implemented what appears (to me) a handler to deal with these auth request packets (chan-filter-req), but it never gets triggered.  I went down to the network room in ds to watch the packets go out, and it LOOKED ok, so I reloaded intermud.c to see if I could spot the channel list.  I forgot I was on *wpr because of *i4's downtime the other day, and IT seemed to show my channel as mode 1!

I redid the chancreate on *i4, and it shows up as mode 2, but still no filter requests come back.

Sooooo, time for me to get some sleep, but if Crat or someone else with I3 router knowhow could help me figure out what's going on, I'd appreciate it.  No hurry. :)

Here's /daemon/services/filter.c
Code: [Select]
#include <daemons.h>
#include <message_class.h>

void eventReceiveFilterRequest(mixed *packet) {
    // The actual payload to be filtered is in packet[7]
    // ({
    //     (string)   "chan-filter-req",
    //     (int)      5,
    //     (string)   originator_mudname,     // the router
    //     (string)   0,
    //     (string)   target_mudname,         // the owner/host mud
    //     (string)   0,
    //     (string)   channel_name,
    //     (mixed *)  packet_to_filter,
    // })
    //
    // Where packet_to_filter is a channel-m, channel-e or channel-t packet.

    PING_D->SetOK();
    tn("eventReceiveFilterRequest: "+identify(packet),"green");
    if( file_name(previous_object()) != INTERMUD_D ) return;

    if( packet[4] != mud_name() ) return;
    // We only want to respond to packets that were sent to us for filtering.

    if( packet[7][0] != "channel-m" ) return;
    // Further, we only want regular messages, no emotes!

    if( packet[7][2] != mud_name() ) return;
    // And we only want to deal with packets which came from someone here!


    // ({
    //     (string)   "chan-filter-reply",
    //     (int)      5,
    //     (string)   originator_mudname,    // The channel host/owner mudname
    //     (string)   0,
    //     (string)   target_mudname,        // the router
    //     (string)   0,
    //     (string)   channel_name,
    //     (mixed *)  filtered_packet,
    // })

    INTERMUD_D->eventWrite(({ "chan-filter-reply", 5, mud_name(), 0, packet[2],
                    0, packet[6], packet[7] }));
}

and the change to intermud.c, in eventRead():
Code: [Select]
        case "chan-filter-req":
            tn("chan-filter-req: "+identify(packet),"green");
            SERVICES_D->eventReceiveFilterRequest(packet);
            break;
        case "chan-filter-reply":
            tn("chan-filter-reply: "+identify(packet), "red");
            break;

44
Code Vault / Chatter colours for DS
« on: January 15, 2010, 04:02:20 AM »
Hey guys,

This might still have a bug or two lurking in it, but it *seems* to be working ok, so I thought I'd share and see if anyone could suggest improvements.

This is a modification to /secure/daemon/chat.c, which adds fixed colours to the speakers' names as they show up on various chat channels.  To me, this makes it easier to follow who said what in a conversation, since the same named person will always end up with the same colour tag.



The main API is just getWhoColor(), which returns a string with the colour code assigned to that name.  Names are forced to lower-case and are unique to the first '@' sign (if any), so Quixadhal@WileyMUD and Quixadhal@Bloodlines both map to "quixadhal", and thus both get the same colour value.

Colours are assigned by making a call to getWhoColor(name), at which point either the assigned colour is returned, or a new one is assigned.  They are assigned in the order encountered in the private array chat_colors, which can be modified at any point.  The code simply keeps a counter of how many have been assigned in total, and then uses that modulo sizeof(chat_colors) to pick the next one.

Because I figured someone would want to hand-set the colours of one or more people, there is a setWhoColor() function which forcibly sets someone to be the token passed.  This is just a string, so if you want to make them FLASH or have *** in front of their name, you can.  It checks that they exist to prevent adding typos to the saved chatters list.

There is also a routine to return the mapping as an inversion, where the colour tokens themselves are the keys, and the names are an array of values.  This is mapWhoColor(), which is used by showWhoColor() to present a write()'able string to provide output like the screenshot above.

The actual mapping is saved in /secure/save/chat.o.

I changed the default chat layout to keep the channel name on the left edge, followed by the speaker's name, and then the text.  If you prefer the default DS method, I'm sure you can easily change it back, as the old version is left as a comment.

So, here's the file... hopefully I can paste it without mangling it too much....  a patch is also included below:

[code]/*    /daemon/chat.c
 *    from the Dead Souls Mudlib
 *    daemon to handle all mud chat channels
 *    created by Descartes of Borg 931220
 *
 *    IMC2 support added by Shadyman 2007-Sep-24
 *    Feelings support added by Shadyman 2007-Sep-24
 *    "mapping tags" added by Shadyman 2007-Sep-24
 */

#ifndef LOG_REMOTE_CHANS
#define LOG_REMOTE_CHANS 0
#endif

#ifndef LOG_LOCAL_CHANS
#define LOG_LOCAL_CHANS 1
#endif

#ifndef CHANNEL_PIPES
#define  CHANNEL_PIPES 0
#endif

#include <lib.h>
#include <save.h>
#include <pov.h>
#include <daemons.h>
#include <origin.h>
#include <message_class.h>
#include "include/chat.h"

inherit LIB_DAEMON;

mapping chatters = ([]);
int chat_counter = 0;
static private array chat_colors = ({
            "%^RED%^",
            "%^GREEN%^",
            "%^ORANGE%^",
            "%^BLUE%^",
            "%^MAGENTA%^",
            "%^CYAN%^",
            "%^DARKGREY%^",
            "%^LIGHTRED%^",
            "%^LIGHTGREEN%^",
            "%^YELLOW%^",
            "%^LIGHTBLUE%^",
            "%^PINK%^",
            "%^LIGHTCYAN%^",
            "%^WHITE%^",

            "%^B_RED%^%^WHITE%^",
            "%^B_GREEN%^%^WHITE%^",
            "%^B_BLUE%^%^WHITE%^",
            "%^B_MAGENTA%^%^WHITE%^",

            "%^B_RED%^%^YELLOW%^",
            "%^B_GREEN%^%^YELLOW%^",
            "%^B_BLUE%^%^YELLOW%^",
            "%^B_MAGENTA%^%^YELLOW%^",

            "%^B_RED%^%^BLACK%^",
            "%^B_GREEN%^%^BLACK%^",
            "%^B_MAGENTA%^%^BLACK%^",
            "%^B_CYAN%^%^BLACK%^",
            "%^B_YELLOW%^%^BLACK%^",
            "%^B_WHITE%^%^BLACK%^",

            "%^B_CYAN%^%^BLUE%^",
            "%^B_YELLOW%^%^BLUE%^",
            "%^B_WHITE%^%^BLUE%^",

            "%^B_YELLOW%^%^GREEN%^",
            "%^B_WHITE%^%^GREEN%^",
        });

static string SaveFile;

static string suspect,site,chan;
static private mapping Channels;
static private mapping chanlast;

static private string *local_chans = ({});
static private string *remote_chans = ({});
static string *syschans = ({});

static private mapping localchans = ([
        //I3 Channels
        "imud_code": "intercre",
        "imud_gossip": "intergossip",
        "ie_flibcode": "foundation",
        "dead_test4": "ds_test",
        "dead_souls": "ds",

        //IMC2 Channels
        "Server02:igame": "i2game",
        "Server02:inews": "i2news",
        ]);

static private mapping remotechans = ([
        //I3 Channels
        "intercre": "imud_code",
        "intergossip": "imud_gossip",
        "foundation": "ie_flibcode",
        "dutch": "dutch",
        "ds_test": "dead_test4",
        "ds": "dead_souls",

        //IMC2 Channels
        "i2game" : "Server02:igame",
        "i2news" : "Server02:inews",
        ]);

static private mapping tags = ([
        "intermud"    : "%^B_BLACK%^WHITE%^",
        "muds"        : "%^B_BLACK%^WHITE%^",
        "connections" : "%^B_BLACK%^BOLD%^WHITE%^",
        "death"       : "%^BOLD%^RED%^",
        "cre"         : "%^BOLD%^GREEN%^",
        "admin"       : "%^BOLD%^MAGENTA%^",
        "newbie"      : "%^BOLD%^B_YELLOW%^",
        "gossip"      : "%^BOLD%^B_BLUE%^",

        "ds"          : "%^YELLOW%^",
        "dchat"    :"%^CYAN%^",
        "intergossip" : "%^GREEN%^",
        "intercre"    : "%^ORANGE%^",

        "ibuild"      : "%^B_RED%^%^YELLOW%^",
        "ichat"       : "%^B_RED%^%^GREEN%^",
        "pchat"       : "%^B_RED%^%^BOLD%^GREEN%^",
        "i2game"      : "%^B_BLUE%^",
        "i2chat"      : "%^B_GREEN%^",
        "i3chat"      : "%^B_RED%^",
        "i2code"      : "%^B_YELLOW%^%^RED%^",
        "i2news"      : "%^B_YELLOW%^%^BLUE%^",
        "imudnews"    : "%^B_YELLOW%^%^CYAN%^",
        "irc"         : "%^B_BLUE%^%^GREEN%^",
        "ifree"         : "%^B_BLUE%^%^GREEN%^",

        "default"     : "%^BOLD%^BLUE%^",
        "default-IMC2" : "%^BOLD%^WHITE%^%^B_BLUE%^",
        ]);

static void Setup(){
    remote_chans = ({});
    local_chans = ({"newbie","cre","gossip","admin","error", "intermud",
            "death", "connections", "muds" });
    syschans = ({ "intermud", "death", "connections", "muds" });

    local_chans += CLASSES_D->GetClasses();

    if(find_object(INTERMUD_D)){
        if(arrayp(INTERMUD_D->GetChannels()))
            remote_chans += distinct_array(INTERMUD_D->GetChannels());
    }
    if(find_object(IMC2_D)){
        if(arrayp(IMC2_D->GetChanList()))
            remote_chans += distinct_array(IMC2_D->GetChanList());
    }

    foreach(string foo in remote_chans){
        if(member_array(foo, local_chans) != -1){
            remote_chans -= ({ foo });
        }
        if(!strsrch(foo, "Server")){
            int i, x;
            string local, remote;
            i = sscanf(foo, "Server0%d:%s", x, local);
            if(i == 2 && !localchans[foo]){
                localchans[foo] = local;
                remotechans[local] = foo;
            }
        }
    }
    remote_chans = distinct_array(remote_chans);
}

static void create() {
    object pl;
    string *tmp_arr = ({});
    daemon::create();
    SetNoClean(1);
    Channels = ([]);

    SaveFile = save_file(SAVE_CHAT);
    if(unguarded((: file_exists(SaveFile) :))){
        RestoreObject(SaveFile);
    }
    SaveObject(SaveFile);

    call_out("Setup", 10);

    foreach(string kanal in local_chans + syschans){
        if( !Channels[kanal] ) Channels[kanal] = ({});
    }
    foreach(pl in users()) {
        string *chans;
        string channel;

        if( pl && !(chans = pl->GetChannels()) ) continue;
        foreach(channel in chans) {
            if( !Channels[channel] ) Channels[channel] = ({});
            Channels[channel] = distinct_array(Channels[channel] + ({ pl }));
        }
    }
    foreach( string channel in local_chans ){
        tmp_arr += ({ channel + "emote" });
        tmp_arr += ({ channel + ":" });
    }

    local_chans += tmp_arr;
}

string *AddRemoteChannel(mixed chan){
    string *ret = copy(remote_chans);
    if(base_name(previous_object()) != INTERMUD_D) return ret;
    if(stringp(chan)) chan = ({ chan });
    if(!arrayp(chan)) return ret;
    foreach(string element in chan){
        if(member_array(element, local_chans) != -1){
            chan -= ({ element });
        }
    }
    return copy(remote_chans = distinct_array(remote_chans += chan));
}

string *RemoveRemoteChannel(mixed chan){
    string *ret = copy(remote_chans);
    if(base_name(previous_object()) != INTERMUD_D) return ret;
    if(stringp(chan)) chan = ({ chan });
    if(!arrayp(chan)) return ret;
    foreach(string element in chan){
        if(member_array(element, local_chans) != -1){
            chan -= ({ element });
        }
    }
    return copy(remote_chans = distinct_array(remote_chans -= chan));
}

varargs string *GetRemoteChannels(int localized){
    mixed *ret = ({});
    if(!localized) return copy(remote_chans);
    foreach(string chan in remote_chans){
        ret += ({ GetLocalChannel(chan) });
    }
    return ret;
}

string decolor(string str){
    string s1 = "", s2, s3, test;
    int tmp = 2;
    if(sscanf(str,"%s<%s>%s",s1,s2,s3) != 3)
        tmp = sscanf(str,"<%s>%s",s2,s3);
    if(tmp != 2) return str;
    else {
        test = s1+"<"+s2+">%^RESET%^"+strip_colours(s3);
        return test;
    }
}

varargs int CanListen(object who, string canal){
    if(!RESTRICTED_INTERMUD) return 1;
    if(canal && member_array(canal, local_chans) != -1) return 1;
    else return imud_privp(who);
}

varargs int CanTalk(object who, string canal){
    if(!RESTRICTED_INTERMUD) return 1;
    if(canal && member_array(canal, local_chans) != -1) return 1;
    else return imud_privp(who);
}

string *eventRegisterMember(string *chans) {
    string *tmp;
    object ob;
    string channel;

    if( !living(ob = previous_object()) ) return ({});
    tmp = ({});
    foreach(channel in chans) {
        /* just check out for secure channels */
        switch(channel) {
            case "admin":
                if( !archp(ob) ) break;
            case "cre": case "intercre": case "intergossip":
                if( !creatorp(ob) ) break;
            default:
            if( !Channels[channel]) Channels[channel] = ({});
            Channels[channel] = distinct_array(Channels[channel] + ({ ob }));
            tmp += ({ channel });
        }
    }
    return tmp;
}

string *eventRemoveMember(string *chans) {
    object ob;
    string channel;

    if( !living(ob = previous_object()) ) return({});
    foreach(channel in chans) {
        if( !Channels[channel] ) continue;
        else Channels[channel] -= ({ ob });
        if( !sizeof(Channels[channel]) ) map_delete(Channels, channel);
    }
    return chans;
}

int cmdLast(string feep){

    if(!chanlast||!Channels[feep]||member_array(this_player(), Channels[feep])==-1){

        this_player()->eventPrint("You are not subscribed to that channel.", MSG_ERROR);
        return 1;
    }
    if(!sizeof(chanlast[feep]))
    {
        this_player()->eventPrint("That channel has no backlog.", MSG_ERROR);
        return 1;
    }
    if(!CanListen(this_player(),feep)){
        write("You lack privileges to that channel.");
        return 1;
    }
    this_player()->eventPrint(implode(chanlast[feep], "\n"));
    return 1;
}

static int LogIt(string what, string where, string canale){
    if( (member_array(canale,local_chans) != -1 && LOG_LOCAL_CHANS) ||
            ( member_array(GetRemoteChannel(canale),remote_chans) != -1 && LOG_REMOTE_CHANS) ){
        unguarded( (: write_file($(where), $(what)) :) );
        return 1;
    }
    else return 0;
}

varargs int eventAddLast(string feep, string str, string pchan, string pmsg, string pwho)
{
    string plainmsg;
    string Chan=feep;
    if(!chanlast)
        chanlast=([]);
    if(!sizeof(chanlast[Chan]))
        chanlast[Chan] = ({});
    if(sizeof(chanlast[Chan]) == 50)
        chanlast[Chan] = chanlast[Chan][1..sizeof(chanlast[Chan])];
    chanlast[Chan] += ({ str });
    Chan = GetLocalChannel(Chan);

    if (Chan == "death") return 1;

    //Log in either SQL or file
#ifdef MYSQL
    if (MYSQL_D->sql_request("INSERT INTO LOG_CHAT (Channel,Who,What) VALUES (\'"+ escape(pchan) +"\',\'" + escape(pwho) + "\',\'" + escape(pmsg) + "\')") == 0) {
        true();
    }
#endif
    Chan = GetLocalChannel(Chan);
    if(!pchan || pchan == "") pchan = "foo";
    plainmsg = "bar";
    if(pchan) plainmsg = "<" + pchan + "> ";
    if(pmsg) plainmsg += pmsg;
    if(pwho && pwho !="") plainmsg = pwho+" "+plainmsg;
    if(pchan && pchan != "admin"){
        LogIt("["+timestamp()+"] "+plainmsg+"\n", "/log/chan/"+Chan, Chan);
    }
    else {
        LogIt("["+timestamp()+"] "+plainmsg+"\n", "/secure/log/"+Chan, Chan);
    }
    return 1;
}

int cmdChannel(string verb, string str){
    string msg, name, rc, target, targetkey, target_msg, emote_cmd, remains;
    string *exploded;
    mixed array msg_data;
    object ob = 0;
    int i, emote, forcedemote;

    if(grepp(verb,"|")){
        string foo, bar;

        if(CHANNEL_PIPES){
            if(grepp(verb,"|morse")){
                str = morse(str);
                verb = replace_string(verb,"|morse","");
            }

            if(grepp(verb,"|colorize")){
                str = dbz_colors(str);
                verb = replace_string(verb,"|colorize","");
            }

            if(grepp(verb,"|annoy")){
                str = dbz_colors(str,2);
                verb = replace_string(verb,"|annoy","");
            }
            if(grepp(verb,"|file")){
                if(!file_exists(str) || !(str = read_file(str))){
                    write("Can't read that file.");
                    return 0;
                }
                verb = replace_string(verb,"|file","");
            }
        }

        if(sscanf(verb, "%s|%s", foo, bar) == 2) verb = foo;
    }

    if(grepp(verb, ":")){
        string *tmpv = explode(verb, ":");
        if(!sizeof(tmpv)) tmpv = ({"newbie"});
        verb = tmpv[0]+"emote";
        if(sizeof(tmpv) > 1) str = implode(tmpv[1..], ":") + str;
    }

    if(grepp(verb, ";")){
        string *tmpv = explode(verb, ";");
        if(!sizeof(tmpv)) tmpv = ({"newbie"});
        verb = tmpv[0]+"forcedemote";
        if(sizeof(tmpv) > 1) str = implode(tmpv[1..], ";") + str;
    }

    if(sizeof(str) > 2){
        if((str[0..0] == ":" || str[0..0] == ";") &&
                alphap(str[1..1]) && str[2..2] != " "){
            if(str[0..0] == ";" && !grepp(verb,"forcedemote"))
                verb = replace_string(verb,"emote","") + "forcedemote";
            else if(str[0..0] == ":" && !grepp(verb,"emote")) verb += "emote";
            str = str[1..];
        }
    }

    //******LIST******
    //allow "list <chan>" to list users listening
    if( verb == "list" ) {
        string *who;
        string ch, mud;

        if( !str ) return 0;

        //Find the remote listing for a channel on a specific mud
        if( sscanf(str, "%s@%s", ch, mud) == 2 ) {
            mud = trim(mud);
            if(!alphap(last(mud,1))) mud = truncate(mud,1);

            if( !Channels[ch] ) return 0;

            if( member_array(this_player(), Channels[ch]) == -1 ) return 0;

            if( ch == (ch = GetRemoteChannel(ch)) ) {
                if(!creatorp(this_player())){
                    write("Remote channel information is not available to players.");
                    return 1;
                }
            }

            if( !(mud = INTERMUD_D->GetMudName(mud)) ) {
                this_player()->eventPrint(mud_name() + " is not aware of "+
                        "such a place.", MSG_ERROR);
                return 1;
            }

            if(!CanTalk(this_player(),verb)) {
                write("You lack privileges to that channel.");
                return 1;
            }
            SERVICES_D->eventSendChannelWhoRequest(ch, mud);
            this_player()->eventPrint("Remote listing request sent.",
                    MSG_SYSTEM);
            return 1;
        }
        else ch = str;

        //If no such channel, or not a part of that channel, then no list.
        if( !Channels[ch] ) return 0;
        if( member_array(this_player(), Channels[str]) == -1 ) return 0;

        //Build and print the list of listeners
        who = GetChannelList(str);
        msg = "Online: " + implode(who, "   ");
        this_player()->eventPrint(msg, MSG_SYSTEM);
        return 1;
    }
    //******END LIST******


    //All emotes will fall into this IF structure and get tagged
    //as emote = 1 or forcedemote = 1

    //If it's a verb+emote, de-emote the verb, and mark as an emote
    if(grepp(verb, "emote")) {
        //Get the real channel
        if(grepp(verb, "forcedemote")){
            verb = replace_string(verb,"forcedemote","");   
            forcedemote = 1;
        }
        else verb = replace_string(verb,"emote","");
        emote = 1;
    }

    if(!strsrch(str,"^encode")) str = morse("(encoded):  "+str[7..]);

    if(find_object(INTERMUD_D) && !sizeof(remote_chans))
        remote_chans = distinct_array(INTERMUD_D->GetChannels());

    if(member_array(GetRemoteChannel(verb), remote_chans) == -1 &&
            member_array(verb, local_chans) == -1) local_chans += ({ verb });


    //******Access Checks
    //No talking if you're not allowed.
    if ( !CanTalk(this_player(),verb) ) {
        write("You lack privileges to that channel.");
        return 1;
    }

    //Toggle channel blocking
    if ( emote == 1 && ( !str || str == "" ) ) {
        this_player()->SetBlocked(verb + "emote");
        return 1;
    } else if ( !str || str == "" ) {
        this_player()->SetBlocked(verb);
        return 1;
    }

    //Syschans aren't for chatting on, only listening
    if ( member_array(verb, syschans) != -1 ) {
        write("This is not a channel for chatting.");
        return 1;
    }

    //If gagged, you can't talk on channels
    if ( this_player()->GetGagged(verb) ) {
        write("You have gag mode enabled. Type: 'gag off' to talk on channels.");
        return 1;
    }

    //Channel doesn't exist, probably an emote typo
    if(!Channels[verb]) return 0;

    //If not part of the channel, no chatting
    if( member_array(this_player(), Channels[verb]) == -1 ) return 0;

    //If blocked, allow no chatting
    if( this_player()->GetBlocked(verb) ) {
        if( this_player()->GetBlocked("all") ) {
            this_player()->eventPrint("You cannot chat while totally blocked.",
                    MSG_ERROR);
            return 1;
        }
        this_player()->eventPrint("Turn this channel on to talk on it.", MSG_ERROR);
        return 1;
    }
    //******End Access Checks


    //If there's no channel matching now, then it's a typo or wasn't meant for this file to pick up.
    if( !Channels[verb] ) return 0;

    //Find the remote channel's name, based on the local, pretty name
    rc = GetRemoteChannel(verb);

    //Check emotes
    if (emote == 1) {
        exploded = explode(str, " "); //BOOM!!! We have an array of words.
        if (sizeof(exploded) <= 1) {
            emote_cmd = str;
            remains = 0;
        } else {
            emote_cmd = exploded[0];
            remains = implode(exploded[1..]," ");
        }

        //***********************************
        //Find a target for targetted emotes.
        //***********************************

        if( !remains ) { //If no arguments and just one word
            msg_data = SOUL_D->GetChannelEmote(emote_cmd, ""); //Search for a feeling that matches
        } else { //If there is an argument to the emote,
            if( ob = find_living(target = convert_name(remains)) ) {  //If there is a living target
                msg_data = SOUL_D->GetChannelEmote(emote_cmd, "LIV");
                //If it's not there, get the emote's LVS text.
                //if (!msg_data)
                //   msg_data = SOUL_D->GetChannelEmote(emote_cmd, "LVS", remains);
            } else if( strsrch(target, "@") == -1 ) { //If no living target
                string array words = explode(remains, " ");
                target = "";
                for(i=0; i<sizeof(words); i++) {
                    target += lower_case(words);
                    if( ob = find_living(target) ) {
                        if( i < sizeof(words)-1 ) {
                            remains = implode(words[(i+1)..], " ");
                        } else {
                            remains = 0;
                        }
                        //If it's not there, get the emote's LVS STR text.
                        if (!msg_data)
                            msg_data = SOUL_D->GetChannelEmote(emote_cmd, "LVS STR", remains);
                        break;
                    }
                }

                if( !ob ) {
                    msg_data = SOUL_D->GetChannelEmote(emote_cmd, "STR", remains);
                    target = 0;
                }

            } else {
                string array words;

                //Find any @'s in the remains.. Should be User@Mud
                i = strsrch(remains, "@", -1);

                //If there's not enough room for a proper name@mud, just do it as a string
                if ( i >= strlen(remains)-1 ) {
                    msg_data = SOUL_D->GetChannelEmote(emote_cmd, "STR", remains);
                    target = 0;
                } else { //Otherwise, call mud and find user
                    string mud,temp;

                    words = explode(remains[(i+1)..], " ");
                    target = remains[0..i];
                    remains = "";
                    while(sizeof(words)) {
                        temp = implode(words, " ");
                        temp = trim(temp);
                        if(!alphap(last(temp,1))) temp = truncate(temp,1);
                        mud = INTERMUD_D->GetMudName(lower_case(temp));
                        if (!mud) mud = IMC2_D->find_mud(lower_case(temp));
                        if( mud ) {
                            target += mud;
                            break;
                        }
                        if( remains == "" ) remains = words[<1];
                        else remains = words[<1] + " " + remains;
                        words = words[0..<2];
                    }

                    //If we couldn't find the mud,
                    if ( !mud ) {
                        msg_data = SOUL_D->GetChannelEmote(emote_cmd, "STR", remains);
                        target = 0;
                    } else {
                        if ( trim(remains) == "" ) {
                            msg_data = SOUL_D->GetChannelEmote(emote_cmd, "LIV");
                        } else {
                            msg_data = SOUL_D->GetChannelEmote(emote_cmd, "LIV STR", remains);
                        }
                    }
                }
            }
        } //Done finding target

        //***********************************
        //Find the target's proper name and target the message at him/her.
        //***********************************

        if ( msg_data ) { //There's a target
            string sgen = this_player()->GetGender();
            string tgen = 0;

            if ( ob ) { //If a local user
                target = ob->GetName();
                tgen = ob->GetGender();
            } else if ( target ) { //If a mud user
                string user, mud;

                sscanf(target, "%s@%s", user, mud);
                targetkey = target;
                tgen = SERVICES_D->GetRemoteGender(user, mud);
                target = SERVICES_D->GetRemoteDisplayName(user, mud);
                if( !target ) target = capitalize(targetkey);
            }

            //Calculate the viewpoint for 3rd parties
            str = create_message(POV_OBSERVER, msg_data[0][0],
                    msg_data[0][1], "$N", sgen, "$O", tgen,
                    msg_data[1]);

            //If it's targetted, calculate the message for the target
            if ( target ) {
                target_msg = create_message(POV_TARGET, msg_data[0][0],
                        msg_data[0][1], "$N", sgen,
                        "$O", tgen, msg_data[1]);
                target_msg = replace_string(target_msg, "$O's", "your");   
            }
        } else { //There's no target. Spurt it out like the user put it in.
            //Forced emotes only allow real emotes, not custom ones.
            if (forcedemote == 1) {
                if ( member_array( emote_cmd,SOUL_D->GetEmotes() ) > -1 ) {
                    write("Invalid syntax. See %^CYAN%^help "+emote_cmd+"%^RESET%^ for a list of usages.");
                    return 1;
                } else {
                    write("No such feeling. See %^CYAN%^help feelings%^RESET%^ for a list of feelings.");
                    return 1;
                }
            } else {
                str = "$N " + str;
                target = 0;
            }
        }
    }


    //If admin or cre channels, Capitalize a person's real name, because admins can be physically hidden
    if( verb == "admin" || verb == "cre" ) {
        if( !(name = this_player()->GetCapName()) )
            name = capitalize(this_player()->GetKeyName());
    }
    else name = this_player()->GetName();

    //Add the "Name" $N to the string
    if(!grepp(str,"$N") && emote) str = "$N "+str;

    //Send locally
    eventSendChannel(name, verb, str, emote, target, target_msg);

    //If it's a remote channel, send it remotely.
    if(member_array(GetRemoteChannel(verb), remote_chans) != -1
            && member_array(verb, local_chans) == -1){
        if (rc[0..5] == "Server") { //It's an IMC2 channel
            if(IMC2_D->getonline() != 1){
                return 1;
            }
            name = replace_string(name, " ", "");
            if( ob ) {
                IMC2_D->channel_out(name, rc, replace_string(replace_string(str,"$N ",""),"$O",target), emote);
            } else if ( targetkey ) {
                IMC2_D->channel_out(name, rc, replace_string(replace_string(str,"$N ",""),"$O",targetkey), emote);
            } else {
                IMC2_D->channel_out(name, rc, replace_string(str,"$N ",""), emote);
            }
        } else { //It's an I3 channel
            if( ob ) {
                SERVICES_D->eventSendChannel(name, rc, str, emote, convert_name(target), target_msg);
            } else {
                SERVICES_D->eventSendChannel(name, rc, str, emote, convert_name(targetkey), target_msg);;
            }
        }
    }
    return 1;
}

// Sets a particular user to be a particular color.
int setWhoColor(string who, string color) {
    string shortwho;

    shortwho = lower_case(explode(who, "@")[0]);
    if (member_array(shortwho,keys(chatters)) >= 0) {
        chatters[shortwho] = color;
        SaveObject(SaveFile);
        return 1;
    }
    return 0;
}

// Figure out what color to make this guy.
string getWhoColor(string who) {
    string color, shortwho;

    shortwho = lower_case(explode(who, "@")[0]);
    if (member_array(shortwho,keys(chatters)) >= 0) {
        color = chatters[shortwho];
    } else {
        color = chat_colors[chat_counter % sizeof(chat_colors)];
        chatters[shortwho] = color;
        chat_counter++;
        SaveObject(SaveFile);
    }
    return color;
}

// Show who is mapped to a particular color.
mapping mapWhoColor() {
    int i;
    array k, v;
    mapping m;
    k = keys(chatters);
    v = values(chatters);
    m = ([]);

    for(i = 0; i < sizeof(k); i++) {
        m[v] = undefinedp(m[v]) ? ({ k }) : m[v] + ({ k });
    }

    return m;
}

string showWhoColor() {
    int i;
    mapping m;
    string s = "";
    array k;
    int t = 0;

    m= mapWhoColor();
    k = sort_array(keys(m), 1);
    for(i = 0; i < sizeof(k); i++) {
        string nk = replace_string(k, "%^", "");
        int c = sizeof(m[k]);
        s += sprintf("(%4d) %-20s: %s%s%s\n", c, nk, k, implode(sort_array(m[k], 1), ", "), "%^RESET%^");
        t += c;
    }
    s += sprintf("(%4d) Total\n", t);

    return s;
}

varargs void eventSendChannel(string who, string ch, string msg, int emote,
        string target, string targmsg) {
    object channeler = find_player(lower_case(who));
    int terminal;
    string prev = base_name(previous_object());
    string pchan,pmsg;
    //string chatlayout = "%s%s %s<%s>%s %s";
    string chatlayout = "%s<%s>%s %s%s:%s %s";
    string emotelayout = "%s<%s>%s %s";
    //string chatlayout = "%s says, %s(%s)%s '%s'";
    //string emotelayout = "%s(%s)%s %s";

    if(prev == INSTANCES_D){
        terminal = 1;
    }
    if(prev == SERVICES_D) terminal = 1;
    if(prev == IMC2_D) terminal = 1;
    if(!terminal){
        string rch = GetRemoteChannel(ch);
        if(member_array(rch, remote_chans) == -1){
            INSTANCES_D->eventSendChannel(who,ch,msg,emote,target,targmsg);
        }
    }

    pchan=ch;
    if(!channeler) channeler = this_player();
    if(!strsrch(msg,"-.--. . -. -.-. --- -.. . -.. -.--.- ---...")) msg = unmorse(msg);
    if(targmsg && !strsrch(targmsg,"-.--. . -. -.-. --- -.. . -.. -.--.- ---..."))
        targmsg = unmorse(targmsg);

    if(this_player() && this_player() != channeler) channeler = this_player();

    if(!strsrch(base_name(previous_object()), "/realms/") ||
            !strsrch(base_name(previous_object()), "/open/")) {
        return 0;
    }

    if(member_array(ch, syschans) != -1) {
        emote = 0;
    }
    if(channeler){
        if(!CanTalk(channeler, ch) && member_array(ch, syschans) == -1){
            return;
        }
    }
    if( file_name(previous_object()) == SERVICES_D ||
            file_name(previous_object()) == IMC2_D) {
        ch = GetLocalChannel(ch);
        if( emote && sizeof(who)) {
            msg = replace_string(msg, "$N", getWhoColor(who) + who + "%^RESET%^");
        }
    }
    else if( origin() != ORIGIN_LOCAL && previous_object() != master() &&
            file_name(previous_object()) != PARTY_D &&
            file_name(previous_object()) != UPDATE_D &&
            file_name(previous_object()) != INSTANCES_D &&
            member_array(ch, syschans) == -1){
        return;
    }
    prev = file_name(previous_object());
    if(!Channels[ch] && prev != SERVICES_D && prev != INSTANCES_D){
        return;
    }
    if( emote ) {
        object *obs;
        object ob;
        string chan_color, tmp;
        //string targetcolor;

        if( target && (ob = find_player(convert_name(target))) ) {
            target = ob->GetName();
        }

        //Colorize emote channels
        if (member_array(lower_case(ch),keys(tags)) >= 0){
            chan_color = tags[lower_case(ch)];
        } else {
            if(member_array(ch, local_chans) < 0 && (prev == IMC2_D ||
                        member_array(ch, (keys(INTERMUD_D->GetChannelList())
                                || ({}))) < 0)){
                chan_color = tags["default-IMC2"]; //Use the default IMC2 entry
            }
            else {
                chan_color = tags["default"]; //Use the default entry
            }
        }

        msg = replace_string(msg, "$N", getWhoColor(who) + who + "%^RESET%^");
        if( target ) {
            // Don't do this, as it can pollute the table with fake entries
            // or if you DO validate them, it'll be a lot of lag for a tiny
            // bit of bling...
           
            //msg = replace_string(msg, "$O", getWhoColor(target) + target + "%^RESET%^");

            msg = replace_string(msg, "$O", target);
            targmsg = replace_string(targmsg, "$N", getWhoColor(who) + who + "%^RESET%^");
            targmsg = capitalize(replace_string(targmsg, "$O", "you"));
        }

        //Put together the channel emote message
        tmp = sprintf(emotelayout, chan_color, ch, "%^RESET%^", msg);

        //Store message in the history list
        eventAddLast(ch, tmp, pchan, msg);

        if(Channels[ch]){
            obs = filter(Channels[ch], (: $1 && !($1->GetBlocked($(ch))) :));
            foreach(object listener in obs) {
                int ignore;
                if(sscanf(who,"%s@%s",suspect,site) < 2) {
                    suspect = who;
                    site = "@"+mud_name();
                }
                else site = "@"+site;
                if( listener == ob ) continue;
                if(sizeof(listener->GetMuffed()))
                    foreach(string jerk in listener->GetMuffed()){
                        if(jerk && lower_case(suspect) == lower_case(jerk)){
                            ignore = 1;
                        }
                        if(jerk && lower_case(site) == lower_case(jerk)){
                            ignore = 1;
                        }
                    }
                if(listener->GetNoChanColors()) tmp = decolor(tmp);
                if(!ignore && CanListen(listener,ch) &&
                        !(listener->GetMuted(ch))){
                    listener->eventPrint(tmp, MSG_CHAN);
                }
                ignore = 0;
            }
            if( member_array(ob, obs) != -1 ) {
                if( ob && !(ob->GetBlocked(ch)) ) {
                    int ignore;
                    tmp = sprintf(emotelayout, chan_color, ch, "%^RESET%^", targmsg);
                    if(sizeof(ob->GetMuffed()))
                        foreach(string jerk in ob->GetMuffed()){
                            if(jerk && lower_case(suspect) == lower_case(jerk)) ignore = 1;
                            if(jerk && lower_case(site) == lower_case(jerk)) ignore = 1;
                        }
                    if(ob->GetNoChanColors()) tmp = decolor(tmp);
                    if(!ignore && CanListen(ob,ch)&& !(ob->GetMuted(ch)))
                        ob->eventPrint(tmp, MSG_CHAN);
                    ignore = 0;
                }
            }
        }
        suspect = "";
        site = "";
    }
    else {
        object *obs;
        string chancolor;

        //Colorize flag
        if (member_array(lower_case(ch),keys(tags)) >= 0) { //If there's an entry for the channel
            chancolor = tags[lower_case(ch)]; //Use it
        } else { //Otherwise
            if(member_array(ch, local_chans) < 0 && (prev == IMC2_D ||
                        member_array(ch, (keys(INTERMUD_D->GetChannelList())
                                || ({}))) < 0)){
                chancolor = tags["default-IMC2"]; //Use the default IMC2 entry
            }
            else {
                chancolor = tags["default"]; //Use the default entry
            }
        }

        pmsg = msg;

        //Put together the channel emote message
        //msg = sprintf(chatlayout, who, chancolor, ch, "%^RESET%^", pmsg);
        msg = sprintf(chatlayout, chancolor, ch, "%^RESET%^", getWhoColor(who), who, "%^RESET%^", pmsg);
        eventAddLast(ch, msg, pchan, pmsg, who);

        if(Channels[ch]) {
            obs = filter(Channels[ch], (: $1 && !($1->GetBlocked($(ch))) :));
            foreach(object ob in obs){
                int ignore;
                if(sscanf(who,"%s@%s",suspect,site) < 2) {
                    suspect = who;
                    site = "@"+mud_name();
                }
                else site = "@"+site;

                if(sizeof(ob->GetMuffed()))
                    foreach(string jerk in ob->GetMuffed()){
                        if(jerk && lower_case(suspect) == lower_case(jerk)) ignore = 1;
                        if(jerk && lower_case(site)

45
Dead Souls Support / FluffOS 2.18 config + DS 3.0
« on: January 05, 2010, 03:43:08 PM »
Not sure exactly if this falls into the DS camp, or the FluffOS camp, or the "You're a moron user" camp. :)

For my own amusement, and to remember more LPC, I decided to extend the terminal daemon in DS to handle XTERM256 and the colour names from X11.  To do so, I simply wrote a perl script to generate the values and output an lpc file containing the mappings.  So far, so good.

When attempting to load this monster, I run into the "Program too large" error, which appears to stem from that silly 16-bit addressing limit, designed in the dark ages of only having 2M of RAM to run your game in.  Fine.  The easy fix seemed to be to enable the USE_32BIT_ADDRESSES option in the config file.

Doing so, results in code which worked fine before to fail.  What I did is this:
Code: [Select]
edit local_options.ds.debug to enable 32-bit addressing
./configure ds.debug
./build.FluffOS develop
make && make install
My reward is this:
Code: [Select]
using config file: ./mudos.cfg
Initializing internal tables....
----------------------------------------------------------------------------
Bloodlines (FluffOS v2.18-ds07) starting up on Linux - Tue Jan  5 16:08:24 2010


******** FATAL ERROR: Stack underflow.

FluffOS driver attempting to exit gracefully.
(current object was /secure/sefun/sefun)
--- trace ---
'  #global_init#' in '/secure/sefun/sefun.c' ('/  secure/sefun/sefun') /secure/sefun/absolute_value.c:7
arguments were ()
--- end trace ---
crash() in master called successfully.  Aborting.
Aborted
That's literally the only bread-crumb I have.

Pages: 1 2 [3] 4