ABITS and QBITS: Written by Scion for the Rogue Winds
This code is freely distributable so long as the headers
and credits remain intact. I'd appreciate an email from
you if you decide to use it, but it is by no means necessary.
-- Scion <keeler@teleport.com>

Most people hate readme files, so I'll just go quickly
through how to install it on a Smaug. If you have trouble
installing it on another codebase, good luck. I don't currently
work on any code other than the Rogue Winds, although I'd be
happy to try and help most times.

This readme assumes you have some basic knowlege of C. Please
do not email me asking about where to paste the code in this file
into your mud... it should be fairly obvious if you read the rest
of the code around it. -- Scion

WHAT THE HECK ARE ABITS AND QBITS?

The problem with mob programs is generally that they cannot store
any information on a character. They can see many aspects of a
character, such as race, class, level, marriage status on some
muds, and many other things. Some can even use mset on players to
change them based on the results of the program. However, it is
very difficult to achieve something as simple as a mob recognizing
that a player is returning to a room instead of entering for the
first time. Abits are little bits of information a mob prog can use
to store information on a character or on itself to keep a record
of information important to the mob. It is best explained with
examples.

Say for instance a mob asks a player to retrieve an important
spell book. The mob can ask the player a question, such as "Will
you help me find my book, $n?" If the player says a sentence with
the word "yes" in it, the mob sets a bit on the player and sends
him on his way. When the player discovers that the book is on a
very difficult mob and returns empty handed, the mob greets him by
asking if he's found the book, because he sees the player still
has the bit he set earlier. Without the abit, the mob would never
have been able to remember the player, and would give the reward
to anyone who brought the book back. In this case, only the player
who actually offered to help can return the book. If someone else
brings it back, the mob can react differently.. surprised that
someone brought it back without being told that it was missing, he
might be suspicious and believe the player to be a thief...? :)

As you can see, abits and qbits can be quite useful for making
in-depth interactive mobs.

The difference between an abit and a qbit is simple. An abit goes
away when a player leaves the game, because it doesn't save. Abits
can also be set on mobs. Qbits, on the other hand, cannot be set
on mobs, but do save even after a player quits. Therefore, a player
might not be able to complete a particular quest more than once,
because the qbit would stay set until it is removed by an immortal
or a mob.

HOW TO INSTALL ABITS AND QBITS:

1) Add bits.c to your src directory and to your Makefile. Smaug
makefiles have two lists of files, one with the .o files and the
other with the .c files. It needs to be in both.

2) Add the new command entries to tables.c. The new commands are:

do_abit
do_qbit
do_showabit
do_showqbit
do_setabit
do_setqbit
do_mpaset
do_mpqset

If you have never added a new command to Smaug before, tables.c has
two lines for each command. Do a grep or similar search function to
find where you should put them. It's generally a good idea to put them
in alphabetical order, because one part needs them to be alphabetical,
and it just makes them that much easier to find later on.

3) Add the following code to mud_prog.c. These won't be too useful
on their own unless you've got the smaug mudprogs on your mud. They're
the ifchecks a mob can use to find out if a player or another mob has
an abit or a qbit set on them.

/* This is about line 913 in my mud_prog.c, just above the check for
numfighting */

/* abits and qbits */
if ( !str_cmp(chck, "hasabit") ) {
	int number;
	
	if ( is_number(rval) ) {
		number = atoi(rval);

		if (get_abit(chkchar, number) == NULL)
			return mprog_veval(0, opr, 1, mob);
		else
			return mprog_veval(1, opr, 1, mob);
	}
	progbug("hasabit: bad abit number", mob);
	return BERR;
}

/* abits and qbits */
if ( !str_cmp(chck, "hasqbit") ) {
	int number;
		
	if ( is_number(rval) ) {
		number = atoi(rval);

		if (get_qbit(chkchar, number) == NULL)
			return mprog_veval(0, opr, 1, mob);
		else
			return mprog_veval(1, opr, 1, mob);
	}
	progbug("hasqbit: bad qbit number", mob);
	return BERR;
}

/* That's it! */

4) Add a bit into do_whois to show bits on whois. If you don't want
players to be able to see what bits they have, or don't have a whois
command, you can skip this step.

/* This is just before the "immortal data" in my do_whois */
if (victim->first_abit) {
	BIT_DATA *bit;

	for (bit = victim->first_abit; bit; bit = bit->next) {
		if (strlen(bit->desc) > 3)
			pager_printf(ch, "%s\r\n", bit->desc);
	}
}

if (victim->pcdata->first_qbit) {
	BIT_DATA *bit;

for (bit = victim->pcdata->first_qbit; bit; bit = bit->next) {
	if (strlen(bit->desc) > 3)
		pager_printf(ch, "%s\r\n", bit->desc);
	}
}

/* That's it! */

5) Define a "bit" by adding its struct to mud.h.

/* Mine's just above morph structs, but it can theoretically go 
anywhere near the top. */

typedef struct bit_data BIT_DATA;

#define MAX_xBITS 32000

/* abit and qbit struct */
struct bit_data {
	int number;
	char desc[MAX_STRING_LENGTH];

	BIT_DATA *next;
	BIT_DATA *prev;
};

BIT_DATA *first_abit;
BIT_DATA *first_qbit;
BIT_DATA *last_abit;
BIT_DATA *last_qbit;

/* That's it! */

6) Declare the do_functions in mud.h. Find the long list of DECLARE_DO_FUN
thingies and add this wherever you want inside it:

DECLARE_DO_FUN(do_abit);
DECLARE_DO_FUN(do_qbit);
DECLARE_DO_FUN(do_showabit);
DECLARE_DO_FUN(do_showqbit);
DECLARE_DO_FUN(do_setabit);
DECLARE_DO_FUN(do_setqbit);
DECLARE_DO_FUN(do_mpaset);
DECLARE_DO_FUN(do_mpqset);

7) Add elements to char_data and pc_data. Mobs only get abits because they
do not save, and players get both, but qbits go in pc_data and abits go in
char_data. All the code in bits.c knows about this slight difference.

Add this to char_data:

BIT_DATA *first_abit;
BIT_DATA *last_abit;

Add this to pc_data:

BIT_DATA *first_qbit;
BIT_DATA *last_qbit;

8) Add the function prototypes from bits.c near the end of mud.h. Try grepping
through for a comment with "handler.c" in it, and follow that as a model for
"bits.c".

/* bits.c */
BIT_DATA *find_abit(int number);
BIT_DATA *find_qbit(int number);
BIT_DATA *get_abit(CHAR_DATA *ch, int number);
BIT_DATA *get_qbit(CHAR_DATA *ch, int number);
void load_bits(void);
void save_bits(void);
void set_abit(CHAR_DATA *ch, int number);
void set_qbit(CHAR_DATA *ch, int number);
void remove_abit(CHAR_DATA *ch, int number);
void remove_qbit(CHAR_DATA *ch, int number);
void do_showabit(CHAR_DATA *ch, char *argument);
void do_showqbit(CHAR_DATA *ch, char *argument);

/* That's it! */

9) Finally, make qbits on players save and load in their pfiles.
At the end of fwrite_char in save.c, just before the fwrite(fpout, "End\n\n");
put the following loop:

if (ch->pcdata->first_qbit) {
	BIT_DATA *bit;

	for (bit = ch->pcdata->first_qbit; bit; bit = bit->next)
		fprintf(fp, "Qbit	%d %s~\n", bit->number, bit->desc);
}

...and inside fread_char, add a case 'Q':

case 'Q':
	if (!strcmp(word, "Qbit")) {
		BIT_DATA *bit;
		BIT_DATA *desc;

		CREATE(bit, BIT_DATA, 1);

		bit->number = fread_number(fp);
		if ((desc = find_qbit(bit->number))==NULL)
			strcpy(bit->desc, fread_string(fp));
		else {
			strcpy(bit->desc, desc->desc);
			fread_string(fp);
		}

		LINK(bit, ch->pcdata->first_qbit, ch->pcdata->last_qbit, next, prev);
		fMatch = TRUE;
	}
	break;

/* That's it! */

10) Add a call to load_bits() inside db.c to make it reload the bits after a reboot.
There are a lot of other similar looking things, just stick this in at the end of
the list:

log_string("Loading bits");
load_bits();

/* That's it! */

11) Now save all the files and do a make clean.

12) Type make to recompile, and restart your mud once it's finished. You'll need
to use cedit to add the new commands inside the game.

To create a new abit or qbit, use the setabit and setqbit commands:
setabit <number> <description>
setqbit <number> <description>

The range for numbers is from 0 to 32000, and is defined as MAX_xBITS
just above the struct in mud.h. To raise or lower it, change the #define
and recompile your mud.

To see what bits exist, use the showabit and showqbit commands.
showabit <number>   /* Show the abit at <number> */
showqbit <number>   /* Show the qbit at <number> */
showabit all        /* List all abits */
showqbit all        /* List all qbits */

To set abits or qbits on characters manually, or see which ones characters have on
them, use the abit and qbit commands:
abit <victim> [number]
qbit <victim> [number]

Without an argument, they'll list the bits, with an argument, they'll toggle the bit
on or off.

Mob progs can use mpaset and mpqset to toggle bits on or off:
mpaset <victim> <number>
mpqset <victim> <number>

Mob progs can also use the hasabit and hasqbit ifchecks to check the
state of a bit on a character. Example:

if hasabit($n) == 3100
say Welcome back, $n.
else
say You're new around here, aren't you, $n?
mpaset $n 3100
endif

They can also check for a bit being turned off. Example:

if hasqbit($n) != 8546
say Haven't you completed your quest yet, $n?
else
say Congratulations, $n! You've completed the quest!
endif