MAJOR: 3.63 Pre-Release: Cedit Toggle for prot system, new skill, updated documentation, and more.

This commit is contained in:
Vatiken 2012-03-31 17:03:54 +00:00
parent 5c317f6863
commit 24018d145b
24 changed files with 854 additions and 38 deletions

View file

@ -35,9 +35,23 @@ export (QQ's a zone into a tarball)
Xlist (mlist, olist, rlist, zlist, slist, tlist, qlist)
(lots of major bugfixes too)
@
[Mar 31 2012] - Vatiken
improve: updated some of the documents.
feature: added the 'whirlwind' skill as a event/list template
feature: protocol system now can be deactivated thru cedit
improve: 256 to ANSI conversions changed to reflect the new colouring scheme
feature: added blink, underline, bold, reverse and '@' to the protocol system
[Mar 25 2012] - Vatiken
feature: whois now lists protocol informations when used by an immortal
improve: proc_colors() has been removed, and tbaMUD has been made backwards compatible for
systems still using '@' symbols for colour.
feature: added underline, bold, reverse, and flashing text to the protocol system.
bug: Fixed a glitch within protocol.h that had defines differing from similar tbaMUD defines.
feature: added oset() to allow modification of individual objects through commands or dg_scripts.
improve: Adjusted protocolinput() and processinput() to be more efficient.
bug: Fixed major leak in the history system
[Feb 12 2012] - Vatiken
bug: do_score, changed level 30 to LVL_IMMORT
idea: Mortals can't see immortals levels
bug: the NOHASSLE flag allows imms to carry unlimited weight
idea: dexterity now affects whether a character gets the first hit
idea: advance to immortal now sets hunger/thirst to -1

547
doc/ProtocolSystem.txt Normal file
View file

@ -0,0 +1,547 @@
/******************************************************************************
Protocol snippet by KaVir. Released into the Public Domain in February 2011.
Version 6: 16-Nov-2011. The changes are listed at the end of this file.
******************************************************************************/
There are no licence conditions or restrictions to worry about. So feel free
to copy whatever you need, or just use it as a reference if you prefer.
This was originally just supposed to be an MSDP snippet, but I got a little
carried away and ended up adding several other features as well. Thanks go to
Donky for inspiring me to start playing with protocols, and to Scandum for
creating the specifications for MSDP and MSSP (and also for introducing me to
XTerm 256 colours). I'd also like to thank Tijer and Squiggle for testing the
snippet and providing me with feedback, and to Bryantos for porting the snippet
to a couple of other codebases, and pointing out a missing statement in the
installation instructions. Tyche drew my attention to the problem of broken
packets, while the MSSP table was updated in version 5 following feedback from
Rarva.Riendf on MudBytes. Version 6 contains a minor bugfix and clarification
for using MCCP based on feedback from Jindrak.
I've included instructions for adding the snippet to Diku/Merc, as it was first
tested on Tijer's GodWars mud, but the snippet itself is codebase-neutral and
should be fairly easy to use for any mud written in C. It should take around
5-10 minutes to install in most muds, as long as you know where the hooks need
to go (see the appropriate INSTALL file for details).
The goal was to produce something that's easy to add and easy to use. It's not
exactly optimised for performance, but it shouldn't cause any problems, and the
REPORTABLE option makes MSDP fairly light on bandwidth.
In order to make the snippet as easy as possible to add, I made it greedy. If
you were using other protocols, they'll just stop working, as the snippet will
eat all the negotiation sequences. Fixing this is a pretty simple job though,
you just need to call your code from within the snippet's negotiation functions.
/******************************************************************************
So what does it do?
******************************************************************************/
The snippet offers the following features:
Out-of-band communication between mud and client: Clients can choose either
MSDP or ATCP to transmit data to and from the mud. This is done invisibly,
allowing you to update energy bars, icons, maps, etc, without anything being
displayed in the text window. These are the same protocols I used for the
MUSHclient and Mudlet GUIs described on my blog: http://godwars2.blogspot.com
Extended colours: Allows you to embed XTerm 256 colours in strings (including
help files, room descriptions, etc). Automatically downgrades to the best-fit
ANSI colour for clients that don't support extended colours.
Client detection: Allows you to view the name (and version when available) of
the clients used by each of your players, see which protocols they support, and
track the current size of their screen.
Clickable links: Allows you to embed clickable MXP links in strings (including
help files, room descriptions, etc). Automatically strips links before sending
them to clients that don't support MXP.
Unicode support: Allows you to embed unicode characters within regular ASCII
strings, and provide an alternative ASCII sequence that will be automatically
substituted for clients that don't support UTF-8.
MSSP: Provides information about your mud to crawlers. This is currently only
used by sites such as MudBytes and MudStats, but could in theory be used for
automatically generating and updating entire mud lists.
Sound support: Provides an extremely simple mechanism for sending sounds via
MSDP or ATCP, with an automatic fallback for clients that only support MSP.
You will need to provide your own soundpack of course!
/******************************************************************************
How do I add the snippet to my mud?
******************************************************************************/
1. Follow the installation instructions in the INSTALL.TXT file.
2. Edit MUD_NAME in protocol.h, replacing "Unknown MUD" with your mud name.
3. Make sure the first section of protocol.c uses the correct headers and
functions for your mud.
/******************************************************************************
How do I add a new MSDP variable?
******************************************************************************/
In protocol.h, add your new variable to the variable_t enum.
In protocol.c, add your new variable to the VariableNameTable[]. This needs
to be in the same order as the enum (you'll get a runtime warning if it isn't).
Add a call to either MSDPSetString() or MSDPSetNumber() whenever the variable
might change. If the variable could be changed in multiple places, you can
just add the call to msdp_update() instead.
/******************************************************************************
I need to send my MSDP variable immediately, not once per second!
******************************************************************************/
You can call MSDPUpdate() after setting your variables, and it will immediately
send them all to the player. If you only want to flush a single variable, you
can use MSDPFlush() instead - however, as with MSDPUpdate(), it will only send
variables that are reportable and have changed.
/******************************************************************************
The MSDP_GOLD variable reports a negative number!
******************************************************************************/
The snippet uses ints, which are usually 32 bits. If you're using 64 bit long
long ints for certain things (such as gold), then you should either store them
in MSDP string variables, or change the snippet to use long long ints.
Note that this won't effect your character, it's only the MSDP variable that
overflows. It will give inaccurate information on your GUI, but players won't
actually lose any gold, so don't panic!
/******************************************************************************
The snippet is revealing my vnums! Those are supposed to be top secret!
******************************************************************************/
I'm not quite sure why people are so protective about revealing vnums, but many
are. If you don't want to reveal them then you could have MSDP_ROOM_VNUM only
update for imms, or even remove it entirely. However if you wish to support
the automappers that many major clients offer, you really need to provide your
players with some way to uniquely identify their current room, and vnums are
the easiest way of doing it.
If you don't want people mapping certain areas (such as mazes), then just send
a vnum of '0' when in those areas. You'll need a flag for this if you don't
have one already.
/******************************************************************************
My mud previously supported MCCP, but it's stopped working!
******************************************************************************/
The snippet intercepts and extracts all negotiation requests. You will need to
edit protocol.h and uncomment USING_MCCP, then update the CompressStart() and
CompressEnd() functions in protocol.c to call whatever functions you normally
use for starting and ending compression.
If you don't yet support MCCP and wish to, there are snippets available. Jobo
has some on his website here: http://www.dystopiamud.dk/snippets.php
MCCP increases the memory and CPU usage of your mud, but also gives significant
bandwidth savings. The exact savings will vary, but you can generally expect
your bandwidth to be reduced to about 20% of its previous amount.
Please note that MCCP1 is obsolete, and should not be used. All references to
MCCP throughout this snippet refer to MCCP2 (telnet option 86).
If you also support copyover/hotreboot, please read the next section as well.
/******************************************************************************
All the protocol information vanishes after I do a copyover/hotreboot!
******************************************************************************/
Some muds use an exec() function to replace the current process with a new one,
effectively rebooting the mud without shutting it down. The problem with this
is that the client can't detect it, and because clients need to protect against
negotiation loops they may end up ignoring your attempts to renegotiate.
Therefore in order to store the data across reboots, you need to save it when
you do the copyover, and then load it again afterwards.
The snippet offers CopyoverSet() and CopyoverGet() functions to make this a
bit easier. When writing descriptors to the temporary file in your copyover
code, add an extra "%s" to each row and copy the string from CopyoverGet() into
it. Then when you load the file again after the copyover, pass the string back
into CopyoverSet(), and it'll restore the settings.
Note that this won't save the client name and version. It's recommend that you
instead save these in the player file (this means you can grep through player
files to collect client usage statistics, which can be quite useful).
If you do start saving things in the player file, once again be particularly
careful about the malloc/str_dup free/free_string thing. If you mix them you
may end up with some nasty bugs that are hard to track down. As I mentioned
earlier, it's well worth going through the snippet and making sure it uses
the same functions as the rest of your mud.
Note also that CopyoverSet() calls CompressStart(), while CopyoverGet() calls
CompressEnd(). So if you're using both copyover and MCCP, you shouldn't need
to manually switch compression off and back on when doing a copyover, it should
be done for you automatically.
/******************************************************************************
None of the official ATCP variables work!
******************************************************************************/
This snippet primarily uses MSDP for transmitting data. Unfortunately not all
clients support MSDP, so I offer an alternative - you can use ATCP instead,
with the MSDP variables treated as if they were a custom ATCP package.
This is really just a workaround. The muds that originally used ATCP are now
migrating over to GMCP, so I'm just "borrowing" their old telnet option. My
workaround doesn't break the ATCP specification (because the MSDP variables all
go into their own package), but neither does it implement the official options.
If you actually want full ATCP, I'd suggest implementing GMCP instead.
/******************************************************************************
Why don't you support GMCP/ZMP/102/etc?
******************************************************************************/
Because the original intent of this snippet was to add MSDP support. I got a
bit carried away, and ended up adding various other features that I felt could
improve the user interface, but the main focus of the snippet is still MSDP.
/******************************************************************************
How do I view/modify information about the clients my players are using?
******************************************************************************/
All of the data is stored in the protocol structure, it can be read and changed
just like any other data. For example ScreenWidth and ScreenHeight are simple
integers, while client name and version are MSDP strings. You can view the
full list of options in the protocol.h file.
An IMPORTANT word of warning though:
Although I've added a small section at the top of protocol.c to make it easier
to integrate into Diku/Merc derivatives, the snippet is designed to be codebase
independent. It has its own functions and its own types, and in particular it
uses the standard C malloc() and free() functions for strings.
If you use this in a Diku you're probably using str_dup() and free_string() for
strings. Well whatever you do, do NOT mix and match. If you allocate memory
with str_dup() you MUST free it with free_string() - and if you allocate it
with malloc(), you MUST free it with free().
In fact you should probably go through the snippet and change it to use the
same functions as the rest of your mud for allocating and freeing memory.
Update the types as well, and use your own equivalent of MatchString(), etc.
/******************************************************************************
How do I use sound?
******************************************************************************/
Place a call to SoundSend() in your code. You should do this before sending
the associated message, because when sending an MSP trigger there is no newline
(you could in theory add one to the SoundSend() function, but then the user
would see a blank line every time they received a sound).
The client can enable sound through ATCP/MSDP by setting SOUND to 1. If the
client supports ATCP or MSDP, then these will be used to send out-of-band sound
triggers to the client, which can then be played using a plugin or script.
For other clients, you will need to provide a command for switching sound on
and off. If the bSound variable in the protocol structure is set to true, and
the client doesn't support ATCP or MSDP, then the snippet will send an old
MSP-style in-band sound trigger.
If a client is using MSP sound triggers, then any text sequences of "!!SOUND("
sent to them will be instead be displayed as "!?SOUND(", so that players can't
trigger sounds through chats, tells, etc.
/******************************************************************************
How do I update the MSSP fields?
******************************************************************************/
Edit protocol.c and do a text search for "MSSPTable". Remove the comments from
around the variables you wish to use, and fill in the fields according the MSSP
specification, which you can read here: http://tintin.sourceforge.net/mssp/
The "NAME" should already be defined if you've edited MUD_NAME in protocol.h,
while PLAYERS and UPTIME will be calculated for you automatically.
/******************************************************************************
How do I use extended colour?
******************************************************************************/
The special character used to indicate the start of a colour sequence is '\t'
(i.e., a tab, or ASCII character 9). This makes it easy to include in help
files (as you can literally press the tab key) as well as strings (where you
can use "\t" instead). However players can't send tabs (on most muds at
least), so this stops them from sending colour codes to each other.
The predefined colours are:
n: no colour (switches colour off)
r: dark red R: bright red
g: dark green G: bright green
b: dark blue B: bright blue
y: dark yellow Y: bright yellow
m: dark magenta M: bright magenta
c: dark cyan C: bright cyan
w: dark white W: bright white
o: dark orange O: bright orange
/* Vatiken Additions */
p: dark pink P: bright pink
+: bold -: blink
_: underline =: reverse
*: The '@' Symbol 1: Primary Colour
2: Secondary Colour 3: Tertiary Colour
So for example "This is \tOorange\tn." will colour the word "orange". You can
add more colours by updating the switch statement in ProtocolOutput(), and if
you're using your own colour code, it can use extended colours in the same way.
It's also possible to explicitly specify an RGB value, by including a four
character colour sequence within square brackets, eg:
This is a \t[F010]very dark green foreground\tn.
Or:
This is a \t[B210]dark brown background\tn.
The first character is either 'F' for foreground or 'B' for background. The
next three characters are the RGB (red/green/blue) values, each of which must
be a digit in the range 0 (very dark) to 5 (very light).
Finally, it's also possible to retrieve the colour code directly by calling the
ColourRGB() function. This uses a static buffer, so make sure you copy the
result after each call, don't do a sprintf() with multiple ColourRGB() calls.
Note that sending extended colours to a terminal that doesn't support them can
have some very strange results. The snippet therefore automatically downgrades
to the best-fit ANSI colour for users that don't support extended colours.
Because there is no official way to detect support for extended colours, the
snippet tries to work it out indirectly, erring on the side of caution. If the
b256Support variable in the protocol structure is set to "eSOMETIMES", that
means some versions of this client are known to support extended colour - you
will need to ask the user, and then set eMSDP_XTERM_256_COLORS to 1 (or they
can do this themselves through MSDP/ATCP).
/******************************************************************************
How do I use unicode characters?
******************************************************************************/
Unicode characters can be displayed in a similar way to colour, using square
brackets to provide both a unicode value and an ASCII substitute. For example:
\t[U9814/Rook]
The above will draw a rook (the chess piece - unicode value 9814) if the client
supports UTF-8, otherwise it'll display the text "Rook".
As with extended colour, support for UTF-8 is detected automatically - in this
case using the CHARSET telnet option. However it's not possible to detect if
their font includes that particular character, or even if they're actually
using a unicode font at all, so some care will need to be taken.
A free unicode font that I've found good is Fixedsys Excelsior, which you can
download from here: http://www.fixedsysexcelsior.com/
Also of interest: http://en.wikipedia.org/wiki/List_of_Unicode_characters
/******************************************************************************
How do I use clickable MXP links?
******************************************************************************/
You can add MXP tags in the same way as colour and unicode. The easiest and
safest way to do this is via the ( and ) bracket options. For example:
From here, you can walk \t(north\t).
This will turn the word "north" into a clickable link - you can click on it to
execute the "north" command.
However it's also possible to include more explicit MXP tags, like this:
The baker offers to sell you a \t<send href="buy pie">pie\t</send>.
As with the extended colour, MXP tags will be automatically removed if the user
doesn't support MXP - but it's very important you remember to close the tags.
In theory you could also use other MXP options, such as graphics and sound, but
be aware that MXP is implemented very inconsistently across clients - you'd be
better off using MSDP instead. If you do play with other MXP options, the
pMXPVersion variable in the protocol structure will tell you which version of
MXP the client is using, and you can use MXPSendTag() with the "<SUPPORT>" tag
to find out exactly which options they support. You can also embed another
tag within strings to indicate which version of MXP is required:
\t[X1.0]Special MXP data
In the above example, "\t[X1.0]" temporarily blocks MXP if the client is using
a version of MXP below 1.0. The block only applies to the next MXP tag, after
that it is automatically cleared.
It's worth noting that MXP also supports 24-bit colour, which you may want to
investigate. Personally I've found that 256 colours are more than enough.
/******************************************************************************
How do I use the Mudlet autoinstaller for my custom GUI?
******************************************************************************/
Uncomment MUDLET_PACKAGE at the top of protocol.h, and replace the URL with the
one for your Mudlet package. This should be a zip file containing one script
(an XML file) and a folder containing whatever graphics and/or sound your GUI
uses. You may wish to rename the file from ".zip" to ".mpackage" to make it
clear it's a Mudlet package, although this isn't strictly necessary.
If you update your GUI you will also need to update the version number so that
Mudlet knows it needs to download a newer version. The "1" before the package
name represents the version number, so simply increment it by 1.
/******************************************************************************
Your snippet thinks my client doesn't support X, but actually it does!
******************************************************************************/
I've covered what I could, but some of these things (particularly XTerm 256
colour) are difficult to detect, so there will be clients that I've missed.
If you're a developer on a mud that uses this snippet, it should be fairly easy
to add new clients to the list - but you should also add some in-game commands
allowing players to manually switch the various options on and off.
If you're a client developer, you could add MSDP to your client and use the
configurable variables to switch on XTerm 256 colour, UTF-8, etc.
/******************************************************************************
My hosting service uses mudcheck.pl, and it keeps killing my mud!
******************************************************************************/
The mudcheck script checks the first line it receives after connecting, which
is now a negotiation sequence. You need to send a newline (or whatever the
script is checking for) first.
Add another Write() to the ProtocolNegotiate() function:
void ProtocolNegotiate( descriptor_t *apDescriptor )
{
static const char DoTTYPE [] = { (char)IAC, (char)DO, TELOPT_TTYPE, '\0' };
Write(apDescriptor, "\n"); /* <--- Add this line */
Write(apDescriptor, DoTTYPE);
}
/******************************************************************************
I already added an older version, what do I need to change to update?
******************************************************************************/
Ideally you should diff the old protocol.h and protocol.c against the new ones
to see exactly what has changed. At the very least, have a brief look to give
yourself a general idea. You should also make a backup of your old stuff.
At the top of your protocol.c is a section with mud-specific stuff, you will
almost certainly have changed the #include, the Write() and the ReportBug(),
so make sure you copy them across to the new protocol.c file.
In the MSSPTable[] in your old protocol.c file, copy everything between here:
/* Generic */
{ "CRAWL DELAY", "-1" },
And here:
{ NULL, NULL } /* This must always be last. */
Then paste it into the new protocol.c file. Do the same in protocol.h:
#define MUD_NAME "Unknown MUD"
typedef struct descriptor_data descriptor_t;
Make sure the above is updated to be the same as your old protocol.h file.
Take a look in the appropriate INSTALL file and see how the MSDP_AFFECTS and
MSDP_ROOM_EXITS now use tables. It is recommended that you do the same, but
don't forget to update your MUSHclient plugin and/or Mudlet script as well!
Some muds internally modify or strip out characters with ASCII values of 3, 4,
5 and/or 6. If your mud does this, you will need to change it before you can
use the MSDP tables and arrays.
As the protocol_t structure has changed, it's essential that you do a clean
make after updating to the latest version.
/******************************************************************************
What's new in this version?
******************************************************************************/
As people use the snippet, occasional problems are revealed and reported, and I
resolve them for the next version. Furthermore, the specifications for some of
the protocols (particularly MSDP) change over time, and the snippet needs to be
updated to remain compliant. The following summary describes each version:
Version 2 (13-Jun-2011)
* Added support for broken packets.
* Resolved a cyclic TTYPE issue that caused Windows telnet to freeze.
* Added the new MSSP variables.
Version 3 (28-Aug-2011)
* Added an AllocString() wrapper function, as strdup() isn't standard C.
* Added support for the new MSDP tables and arrays.
* Added support for the new UNREPORT and RESET MSDP commands.
* Added a new REPORTED_VARIABLES list, as described in the latest MSDP spec.
* Renamed VARIABLES to SENDABLE_VARIABLES as described in the latest MDSP spec.
* Cleaned up the code, adding consts and fixing -ansi and -pedantic warnings.
* Added support for the new Mudlet GUI autoinstaller.
* Added an MCCP flag to make integration with the snippet easier.
* Updated CopyoverGet() and CopyoverSet() to include TTYPE, MCCP and CHARSET.
* Added an MSDPFlush() function for variables that need to be sent immediately.
* ProtocolOutput() now lets you send tabs.
* The snippet now recognises that DecafMUD supports 256 colours.
* Updated the TBA instructions with a fix for strfrmt().
* Updated the installation instructions to use MSDP tables.
Version 4 (31-Aug-2011)
* Quick fix to AllocString().
Version 5 (12-Oct-2011)
* Added symbolic constants for MSDP_TABLE_OPEN/CLOSE and MSDP_ARRAY_OPEN/CLOSE.
* MSDPSetArray() was using table values rather than the array values. Fixed.
* Added MSDPSendList(), used for the MSDP LIST command.
* Doubled MAX_VARIABLE_LENGTH for the list variables.
* Some of the LISTs had no separators between values when using ATCP. Fixed.
* The MSSP table now uses function pointers, making it easier to update.
* Added support for both variants of MXP negotiation.
Version 6 (16-Nov-2011)
* Removed a stray semicolon at the end of an 'if' statement.
* Made it easier to add MCCP support.
* Made several minor updates to the installation instructions.
* Added an INSTALL_ROM.TXT.

View file

@ -2,12 +2,117 @@
************************************************************************
* File: events.doc *
* *
* Usage: An explanation of how to use mud events *
* Written by Joseph Arnusch (Vatiken) (Joseph.Arnusch@gmail.com) *
*
* Usage: An explanation of how to use events *
* *
* Written by Eric Green (ejg3@cornell.edu) *
************************************************************************
*/
Vatiken's MUD event system
--------------------------
Table of Contents
-----------------
1. Purpose
2. Functions Related to MUD Events
3. Steps to Create a New MUD Event
4. Differences between the two systems
1. PURPOSE
I scribed a "MUD" event system using the "Death Gate Event" system already
in place to allow for increased ease, and maintainability for both rookie
and experienced programmers.
2. FUNCTIONS RELATED TO MUD EVENTS
a) See EVENTFUNC() in the Death Gate Events documentation below
b) void init_events(void)
"init_events()" creates the global events list and is the allocated location
for placing any global events, these may include things like AI, Weather,
and Combat.
c) struct mud_event_data * char_has_mud_event(struct char_data * ch, event_id iId)
"char_has_mud_event()" returns an event in the characters event list that matches
the supplied "event_id", or NULL if none exists.
d) NEW_EVENT(event_id, struct, var, time)
"NEW_EVENT" creates a new event of the "event_id" type, with the supplied structure
(ch, desc, object, etc..), any addtional "var"s, and is set to activate in
this amount of "time".
e) struct mud_event_list[]
The mud_event_list[] is an array of all the events you've designed into your MUD.
The reason for this excessive step is primarily for organization and troubleshooting,
and it takes a mere couple seconds to add to mud_events.c.
3. STEPS TO CREATE A NEW MUD EVENT
a) Add the new event_id to enum list in mud_events.h
typedef enum {
eNULL,
ePROTOCOLS, /* The Protocol Detection Event */
eWHIRLWIND, /* The Whirlwind Attack */
eNEWEVENT /* A NEW EVENT */
} event_id;
b) Create the event
EVENTFUNC(new_event)
{
struct char_data *ch, *tch;
struct mud_event_data *pMudEvent;
struct list_data *room_list;
int count;
/* This is just a dummy check, but we'll do it anyway */
if (event_obj == NULL)
return 0;
...
return 0;
}
c) Add the event_id data to mud_event_list[]
struct mud_event_list mud_event_index[] = {
{ "Null" , NULL , -1 }, /* eNULL */
{ "Protocol" , get_protocols , EVENT_DESC }, /* ePROTOCOLS */
{ "Whirlwind" , event_whirlwind, EVENT_CHAR } /* eWHIRLWIND */
{ "A New Event" , new_event , EVENT_CHAR } /* eNEWEVENT */
};
d) Place a call for the new event
if (variableX > variableY)
NEW_EVENT(eNEWEVENT, ch, NULL, 60 * PASSES_PER_SEC);
e) Sit back and enjoy your event triggering in 60 seconds.
4. DIFFERENCES BETWEEN THE TWO SYSTEMS
The biggest differences between the two systems is that the MUD Event System
employs certain functions to make it more "dummy proof" without limiting
functionality.
For example:
a) all memory allocated for a MUD event will be freed when the event
is no longer in use.
b) the mud_event_index[] can/will log when events are called, allowing for an
easy way to debug any problems.
c) the mud_event structure allows for easy handling of memory that shouldn't
be freed with the event like the character him/herself.
d) when a character leaves the game, all mud_events will be cleared without
manually having to place checks in free_char().
The "MUD Event" system should be adequate for 99% of all events that a developer
may be interested in creating, and still allows access the dg_event event system
for anything requiring more complicated procedures.
========================================================================
Death Gate Events
@ -195,7 +300,3 @@ Tips for creating events:
o Any place a game object is extracted from the game, any events it points to
should be canceled and its pointer to the events set to NULL.

Binary file not shown.

View file

@ -1,6 +1,6 @@
T B A M U D
D E V E L O P M E N T P O R T
3 . 6 3
Based on CircleMUD,
Created by Jeremy Elson

View file

@ -185,7 +185,7 @@ ACMD(do_kick);
ACMD(do_kill);
ACMD(do_order);
ACMD(do_rescue);
ACMD(do_whirlwind);
/*****************************************************************************
* Begin Functions and defines for act.other.c

View file

@ -2441,7 +2441,7 @@ ACMD(do_whois)
if (!got_from_file && victim->desc != NULL && GET_LEVEL(ch) >= LVL_GOD) {
protocol_t * prot = victim->desc->pProtocol;
send_to_char(ch, "Client: %s\r\n", prot->pVariables[eMSDP_CLIENT_ID]->pValueString);
send_to_char(ch, "Color: %s\r\n", prot->pVariables[eMSDP_XTERM_256_COLORS] ? "Xterm" : (prot->pVariables[eMSDP_ANSI_COLORS] ? "Ansi" : "None"));
send_to_char(ch, "Color: %s\r\n", prot->pVariables[eMSDP_XTERM_256_COLORS]->ValueInt ? "Xterm" : (prot->pVariables[eMSDP_ANSI_COLORS]->ValueInt ? "Ansi" : "None"));
send_to_char(ch, "MXP: %s\r\n", prot->bMXP ? "Yes" : "No");
send_to_char(ch, "Charset: %s\r\n", prot->bCHARSET ? "Yes" : "No");
send_to_char(ch, "MSP: %s\r\n", prot->bMSP ? "Yes" : "No");

View file

@ -19,6 +19,7 @@
#include "spells.h"
#include "act.h"
#include "fight.h"
#include "mud_event.h"
ACMD(do_assist)
{
@ -390,6 +391,98 @@ ACMD(do_rescue)
WAIT_STATE(vict, 2 * PULSE_VIOLENCE);
}
EVENTFUNC(event_whirlwind)
{
struct char_data *ch, *tch;
struct mud_event_data *pMudEvent;
struct list_data *room_list;
int count;
/* This is just a dummy check, but we'll do it anyway */
if (event_obj == NULL)
return 0;
/* For the sake of simplicity, we will place the event data in easily
* referenced pointers */
pMudEvent = (struct mud_event_data *) event_obj;
ch = (struct char_data *) pMudEvent->pStruct;
/* When using a list, we have to make sure to allocate the list as it
* uses dynamic memory */
room_list = create_list();
/* We search through the "next_in_room", and grab all NPCs and add them
* to our list */
for (tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room)
if (IS_NPC(tch))
add_to_list(tch, room_list);
/* If our list is empty or has "0" entries, we free it from memory and
* close off our event */
if (room_list->iSize == 0) {
free_list(room_list);
send_to_char(ch, "There is no one in the room to whirlwind!\r\n");
return 0;
}
/* We spit out some ugly colour, making use of the new colour options,
* to let the player know they are performing their whirlwind strike */
send_to_char(ch, "\t[f313]You deliver a vicious \t[f014]\t[b451]WHIRLWIND!!!\tn\r\n");
/* Lets grab some a random NPC from the list, and hit() them up */
for (count = dice(1, 4); count > 0; count--) {
tch = random_from_list(room_list);
hit(ch, tch, TYPE_UNDEFINED);
}
/* Now that our attack is done, let's free out list */
free_list(room_list);
/* The "return" of the event function is the time until the event is called
* again. If we return 0, then the event is freed and removed from the list, but
* any other numerical response will be the delay until the next call */
if (GET_SKILL(ch, SKILL_WHIRLWIND) < rand_number(1, 101)) {
send_to_char(ch, "You stop spinning.\r\n");
return 0;
} else
return 1.5 * PASSES_PER_SEC;
}
/* The "Whirlwind" skill is designed to provide a basic understanding of the
* mud event and list systems. This is in NO WAY a balanced skill. */
ACMD(do_whirlwind)
{
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_WHIRLWIND)) {
send_to_char(ch, "You have no idea how.\r\n");
return;
}
if (GET_POS(ch) < POS_FIGHTING) {
send_to_char(ch, "You must be on your feet to perform a whirlwind.\r\n");
return;
}
/* First thing we do is check to make sure the character is not in the middle
* of a whirl wind attack.
*
* "char_had_mud_event() will sift through the character's event list to see if
* an event of type "eWHIRLWIND" currently exists. */
if (char_has_mud_event(ch, eWHIRLWIND)) {
send_to_char(ch, "You are already attempting that!\r\n");
return;
}
send_to_char(ch, "You begin to spin rapidly in circles.\r\n");
act("$N begins to rapidly spin in a circle!", FALSE, ch, 0, 0, TO_ROOM);
/* NEW_EVENT() will add a new mud event to the event list of the character.
* This function below adds a new event of "eWHIRLWIND", to "ch", and passes "NULL" as
* additional data. The event will be called in "3 * PASSES_PER_SEC" or 3 seconds */
NEW_EVENT(eWHIRLWIND, ch, NULL, 3 * PASSES_PER_SEC);
WAIT_STATE(ch, PULSE_VIOLENCE * 3);
}
ACMD(do_kick)
{
char arg[MAX_INPUT_LENGTH];

View file

@ -134,6 +134,8 @@ static void cedit_setup(struct descriptor_data *d)
OLC_CONFIG(d)->operation.nameserver_is_slow = CONFIG_NS_IS_SLOW;
OLC_CONFIG(d)->operation.medit_advanced = CONFIG_MEDIT_ADVANCED;
OLC_CONFIG(d)->operation.ibt_autosave = CONFIG_IBT_AUTOSAVE;
OLC_CONFIG(d)->operation.protocol_negotiation = CONFIG_PROTOCOL_NEGOTIATION;
/* Autowiz */
OLC_CONFIG(d)->autowiz.use_autowiz = CONFIG_USE_AUTOWIZ;
OLC_CONFIG(d)->autowiz.min_wizlist_lev = CONFIG_MIN_WIZLIST_LEV;
@ -233,6 +235,8 @@ static void cedit_save_internally(struct descriptor_data *d)
CONFIG_OLC_SAVE = OLC_CONFIG(d)->operation.auto_save_olc;
CONFIG_MEDIT_ADVANCED = OLC_CONFIG(d)->operation.medit_advanced;
CONFIG_IBT_AUTOSAVE = OLC_CONFIG(d)->operation.ibt_autosave;
CONFIG_PROTOCOL_NEGOTIATION = OLC_CONFIG(d)->operation.protocol_negotiation;
/* Autowiz */
CONFIG_USE_AUTOWIZ = OLC_CONFIG(d)->autowiz.use_autowiz;
CONFIG_MIN_WIZLIST_LEV = OLC_CONFIG(d)->autowiz.min_wizlist_lev;
@ -542,6 +546,9 @@ int save_config( IDXTYPE nowhere )
"min_wizlist_lev = %d\n\n",
CONFIG_MIN_WIZLIST_LEV);
fprintf(fl, "* If yes, enable the protocol negotiation system?\n"
"protocol_negotiation = %d\n\n",
CONFIG_PROTOCOL_NEGOTIATION);
fclose(fl);
@ -727,6 +734,7 @@ static void cedit_disp_operation_options(struct descriptor_data *d)
"%sN%s) Start Message : \r\n%s%s\r\n"
"%sO%s) Medit Stats Menu : %s%s\r\n"
"%sP%s) Autosave bugs when resolved from commandline : %s%s\r\n"
"%sR%s) Enable Protocol Negotiation : %s%s\r\n"
"%sQ%s) Exit To The Main Menu\r\n"
"Enter your choice : ",
grn, nrm, cyn, OLC_CONFIG(d)->operation.DFLT_PORT,
@ -745,6 +753,7 @@ static void cedit_disp_operation_options(struct descriptor_data *d)
grn, nrm, cyn, OLC_CONFIG(d)->operation.START_MESSG ? OLC_CONFIG(d)->operation.START_MESSG : "<None>",
grn, nrm, cyn, OLC_CONFIG(d)->operation.medit_advanced ? "Advanced" : "Standard",
grn, nrm, cyn, OLC_CONFIG(d)->operation.ibt_autosave ? "Yes" : "No",
grn, nrm, cyn, OLC_CONFIG(d)->operation.protocol_negotiation ? "Yes" : "No",
grn, nrm
);
@ -1218,6 +1227,11 @@ void cedit_parse(struct descriptor_data *d, char *arg)
TOGGLE_VAR(OLC_CONFIG(d)->operation.ibt_autosave);
break;
case 'r':
case 'R':
TOGGLE_VAR(OLC_CONFIG(d)->operation.protocol_negotiation);
break;
case 'q':
case 'Q':
cedit_disp_menu(d);

View file

@ -1634,6 +1634,7 @@ void init_spell_levels(void)
spell_level(SKILL_RESCUE, CLASS_WARRIOR, 3);
spell_level(SKILL_TRACK, CLASS_WARRIOR, 9);
spell_level(SKILL_BASH, CLASS_WARRIOR, 12);
spell_level(SKILL_WHIRLWIND, CLASS_WARRIOR, 12);
}
/* This is the exp given to implementors -- it must always be greater than the

View file

@ -1443,7 +1443,7 @@ static void init_descriptor (struct descriptor_data *newd, int desc)
*newd->output = '\0';
newd->bufptr = 0;
newd->has_prompt = 1; /* prompt is part of greetings */
STATE(newd) = CON_GET_PROTOCOL;
STATE(newd) = CONFIG_PROTOCOL_NEGOTIATION ? CON_GET_PROTOCOL : CON_GET_NAME;
CREATE(newd->history, char *, HISTORY_SIZE);
if (++last_desc == 1000)
last_desc = 1;
@ -1457,6 +1457,7 @@ static int new_descriptor(socket_t s)
{
socket_t desc;
int sockets_connected = 0;
int greetsize;
socklen_t i;
struct descriptor_data *newd;
struct sockaddr_in peer;
@ -1521,13 +1522,16 @@ static int new_descriptor(socket_t s)
newd->next = descriptor_list;
descriptor_list = newd;
/* Attach Event */
attach_mud_event(new_mud_event(ePROTOCOLS, newd, NULL), 1.5 * PASSES_PER_SEC);
/* KaVir's plugin*/
write_to_output(newd, "Attempting to Detect Client, Please Wait...\r\n");
ProtocolNegotiate(newd);
if (CONFIG_PROTOCOL_NEGOTIATION) {
/* Attach Event */
NEW_EVENT(ePROTOCOLS, newd, NULL, 1.5 * PASSES_PER_SEC);
/* KaVir's plugin*/
write_to_output(newd, "Attempting to Detect Client, Please Wait...\r\n");
ProtocolNegotiate(newd);
} else {
greetsize = strlen(GREETINGS);
write_to_output(newd, "%s", ProtocolOutput(newd, GREETINGS, &greetsize));
}
return (0);
}

View file

@ -297,7 +297,6 @@ int min_wizlist_lev = LVL_GOD;
* set to YES. */
int display_closed_doors = YES;
/* Automap and map options */
/* Default is to have automap and map command only enabled for immortals */
int map_option = MAP_IMM_ONLY;
@ -309,3 +308,6 @@ int medit_advanced_stats = YES;
/* Does "bug resolve" autosave ? */
int ibt_autosave = YES;
/* Use the protocol negotiation system */
int protocol_negotiation = YES;

View file

@ -68,6 +68,7 @@ extern const char *START_MESSG;
extern int use_autowiz;
extern int min_wizlist_lev;
extern int display_closed_doors;
extern int protocol_negotiation;
/* Automap and map options */
extern int map_option;
extern int default_map_size;

View file

@ -24,7 +24,7 @@
* @todo cpp_extern isn't needed here (or anywhere) as the extern reserved word
* works correctly with C compilers (at least in my Experience)
* Jeremy Osborne 1/28/2008 */
cpp_extern const char *tbamud_version = "tbaMUD 3.62";
cpp_extern const char *tbamud_version = "tbaMUD 3.63";
/* strings corresponding to ordinals/bitvectors in structs.h */
/* (Note: strings for class definitions in class.c instead of here) */

View file

@ -3761,6 +3761,7 @@ static void load_default_config( void )
CONFIG_TRACK_T_DOORS = track_through_doors;
CONFIG_NO_MORT_TO_IMMORT = no_mort_to_immort;
CONFIG_DISP_CLOSED_DOORS = display_closed_doors;
CONFIG_PROTOCOL_NEGOTIATION = protocol_negotiation;
CONFIG_DIAGONAL_DIRS = diagonal_dirs;
CONFIG_MAP = map_option;
CONFIG_MAP_SIZE = default_map_size;
@ -4005,6 +4006,8 @@ void load_config( void )
case 'p':
if (!str_cmp(tag, "pk_allowed"))
CONFIG_PK_ALLOWED = num;
else if (!str_cmp(tag, "protocol_negotiation"))
CONFIG_PROTOCOL_NEGOTIATION = num;
else if (!str_cmp(tag, "pt_allowed"))
CONFIG_PT_ALLOWED = num;
break;

View file

@ -127,6 +127,8 @@ void event_process(void)
the_event->q_el = queue_enq(event_q, the_event, new_time + pulse);
else
{
if (the_event->isMudEvent && the_event->event_obj != NULL)
free_mud_event((struct mud_event_data *) the_event->event_obj);
/* It is assumed that the_event will already have freed ->event_obj. */
free(the_event);
}

View file

@ -343,6 +343,7 @@ cpp_extern const struct command_info cmd_info[] = {
{ "whois" , "whoi" , POS_DEAD , do_whois , 0, 0 },
{ "whoami" , "whoami" , POS_DEAD , do_gen_ps , 0, SCMD_WHOAMI },
{ "where" , "where" , POS_RESTING , do_where , 1, 0 },
{ "whirlwind", "whirl" , POS_FIGHTING, do_whirlwind, 0, 0 },
{ "whisper" , "whisper" , POS_RESTING , do_spec_comm, 0, SCMD_WHISPER },
{ "wield" , "wie" , POS_RESTING , do_wield , 0, 0 },
{ "withdraw" , "withdraw", POS_STANDING, do_not_here , 1, 0 },
@ -1303,7 +1304,6 @@ EVENTFUNC(get_protocols)
write_to_output(d, GREETINGS, 0);
STATE(d) = CON_GET_NAME;
free_mud_event(pMudEvent);
return 0;
}

View file

@ -18,17 +18,38 @@
/* Global List */
struct list_data * world_events = NULL;
/* The mud_event_index[] is merely a tool for organizing events, and giving
* them a "const char *" name to help in potential debugging */
struct mud_event_list mud_event_index[] = {
{ "Null" , NULL , -1 }, /* eNULL */
{ "Protocol" , get_protocols, EVENT_DESC } /* ePROTOCOLS */
{ "Null" , NULL , -1 }, /* eNULL */
{ "Protocol" , get_protocols , EVENT_DESC }, /* ePROTOCOLS */
{ "Whirlwind" , event_whirlwind, EVENT_CHAR } /* eWHIRLWIND */
};
/* init_events() is the ideal function for starting global events. This
* might be the case if you were to move the contents of heartbeat() into
* the event system */
void init_events(void)
{
/* Allocate Event List */
world_events = create_list();
}
/* event_countdown() is used for events which are to be used as a countdown...
* go figure eh? This could be useful for skills which have an extended cooldown,
* like "lay on hands" once every 24 hours. Simply add an event to the
* mud_event_index[] such as:
* { "Lay on hands" , event_countdown, EVENT_CHAR }
* and then add the event after a successful skill call:
* attach_mud_event(new_mud_event(eLAYONHANDS, ch, NULL), 24 * SECS_PER_MUD_HOUR);
* and then add something like this is your skill function:
* if (char_has_mud_event(ch, eLAYONHANDS)) {
* send_to_char(ch, "You must wait a full 24 hours before re-using this skill.\r\n");
* return;
* }
* The bottom switch() is for any post-event actions, like telling the character they can
* now access their skill again.
*/
EVENTFUNC(event_countdown)
{
struct mud_event_data * pMudEvent;
@ -49,10 +70,13 @@ EVENTFUNC(event_countdown)
break;
}
free_mud_event(pMudEvent);
return 0;
}
/* As of 3.63, there are only global, descriptor, and character events. This
* is due to the potential scope of the necessary debugging if events were
* included with rooms, objects, spells or any other structure type. Adding
* events to these other systems should be just as easy as adding the current
* library was, and should be available in a future release. - Vat */
void attach_mud_event(struct mud_event_data *pMudEvent, long time)
{
struct event * pEvent;
@ -126,6 +150,9 @@ struct mud_event_data * char_has_mud_event(struct char_data * ch, event_id iId)
struct mud_event_data * pMudEvent;
bool found = FALSE;
if (ch->events->iSize == 0)
return NULL;
simple_list(NULL);
while ((pEvent = (struct event *) simple_list(ch->events)) != NULL) {

View file

@ -19,9 +19,12 @@
#define EVENT_DESC 1
#define EVENT_CHAR 2
#define NEW_EVENT(event_id, struct, var, time) (attach_mud_event(new_mud_event(event_id, struct, var), time))
typedef enum {
eNULL,
ePROTOCOLS,
ePROTOCOLS, /* The Protocol Detection Event */
eWHIRLWIND, /* The Whirlwind Attack */
} event_id;
struct mud_event_list {
@ -50,5 +53,6 @@ struct mud_event_data * char_has_mud_event(struct char_data * ch, event_id iId);
/* Events */
EVENTFUNC(event_countdown);
EVENTFUNC(get_protocols);
EVENTFUNC(event_whirlwind);
#endif /* _MUD_EVENT_H_ */

View file

@ -1,9 +1,5 @@
/******************************************************************************
Protocol snippet by KaVir. Released into the Public Domain in February 2011.
This snippet was originally designed to be codebase independent, but has been
modified slightly so that it runs out-of-the-box on Merc derivatives. To use
it for other codebases, just change the code in the "Diku/Merc" section below.
******************************************************************************/
/******************************************************************************
@ -550,13 +546,16 @@ const char *ProtocolOutput( descriptor_t *apDescriptor, const char *apData, int
pCopyFrom = Tab;
break;
case '_':
pCopyFrom = "\x1B[4m"; /* Underline */
pCopyFrom = "\x1B[4m"; /* Underline... if supported */
break;
case '+':
pCopyFrom = "\x1B[1m"; /* Bold */
pCopyFrom = "\x1B[1m"; /* Bold... if supported */
break;
case '-':
pCopyFrom = "\x1B[5m"; /* Blinking??? */
pCopyFrom = "\x1B[5m"; /* Blinking... if supported */
break;
case '=':
pCopyFrom = "\x1B[7m"; /* Reverse... if supported */
break;
case '*':
pCopyFrom = "@"; /* The At Symbol... I don't really like this, but it seems like
@ -2429,9 +2428,9 @@ static const char *GetAnsiColour( bool_t abBackground, int aRed, int aGreen, int
else if ( aRed == aGreen && aRed == aBlue )
return abBackground ? s_BackWhite : aRed >= 4 ? s_BoldWhite : s_DarkWhite;
else if ( aRed > aGreen && aRed > aBlue )
return abBackground ? s_BackRed : aRed >= 3 ? s_BoldRed : s_DarkRed;
return abBackground ? s_BackRed : aRed > 3 ? s_BoldRed : s_DarkRed;
else if ( aRed == aGreen && aRed > aBlue )
return abBackground ? s_BackYellow : aRed >= 3 ? s_BoldYellow : s_DarkYellow;
return abBackground ? s_BackYellow : aRed > 3 ? s_BoldYellow : s_DarkYellow;
else if ( aRed == aBlue && aRed > aGreen )
return abBackground ? s_BackMagenta : aRed >= 3 ? s_BoldMagenta : s_DarkMagenta;
else if ( aGreen > aBlue )

View file

@ -950,5 +950,6 @@ void mag_assign_spells(void)
skillo(SKILL_SNEAK, "sneak");
skillo(SKILL_STEAL, "steal");
skillo(SKILL_TRACK, "track");
skillo(SKILL_WHIRLWIND, "whirlwind");
}

View file

@ -103,11 +103,11 @@
#define SKILL_HIDE 133 /* Reserved Skill[] DO NOT CHANGE */
#define SKILL_KICK 134 /* Reserved Skill[] DO NOT CHANGE */
#define SKILL_PICK_LOCK 135 /* Reserved Skill[] DO NOT CHANGE */
/* Undefined 136 */
#define SKILL_WHIRLWIND 136
#define SKILL_RESCUE 137 /* Reserved Skill[] DO NOT CHANGE */
#define SKILL_SNEAK 138 /* Reserved Skill[] DO NOT CHANGE */
#define SKILL_STEAL 139 /* Reserved Skill[] DO NOT CHANGE */
#define SKILL_TRACK 140 /* Reserved Skill[] DO NOT CHANGE */
#define SKILL_TRACK 140 /* Reserved Skill[] DO NOT CHANGE */
/* New skills may be added here up to MAX_SKILLS (200) */
/* NON-PLAYER AND OBJECT SPELLS AND SKILLS: The practice levels for the spells

View file

@ -22,7 +22,7 @@
* on an older version. You are supposed to compare this with the macro
* TBAMUD_VERSION() in utils.h.
* It is read as Major/Minor/Patchlevel - MMmmPP */
#define _TBAMUD 0x030620
#define _TBAMUD 0x030630
/** If you want equipment to be automatically equipped to the same place
* it was when players rented, set the define below to 1 because
@ -1348,6 +1348,7 @@ struct game_operation
char *START_MESSG; /**< The start msg for new characters. */
int medit_advanced; /**< Does the medit OLC show the advanced stats menu ? */
int ibt_autosave; /**< Does "bug resolve" autosave ? */
int protocol_negotiation; /**< Enable the protocol negotiation system ? */
};
/** The Autowizard options. */

View file

@ -1046,6 +1046,8 @@ do \
#define CONFIG_MEDIT_ADVANCED config_info.operation.medit_advanced
/** Does "bug resolve" autosave ? */
#define CONFIG_IBT_AUTOSAVE config_info.operation.ibt_autosave
/** Use the protocol negotiation system? */
#define CONFIG_PROTOCOL_NEGOTIATION config_info.operation.protocol_negotiation
/* Autowiz */
/** Use autowiz or not? */