Mortal Builder System
Snippet Posted Wednesday, October 4th @ 03:50:31 PM, by Brandon Brown in the Players dept.
Subliminal writes, "If you've ever been annoyed at Builders abusing the fact that they are God and not building anything. Well with this code you'll be able to give them the power to build and nothing else! " This is a really innovative piece of code.. a great idea that was well-written. Definitely worth a look.
(replace /T with tabs)

If you've ever been annoyed at Builders abusing the fact that they are
God and not building anything. Well with this code you'll be able to give
them the power to build and nothing else! This allows Mortal's to build
but puts in safety measures to stop them abusing it. This means that they
got to work to get the power they want. It's a pretty simple system, but i
haven't seen on the web and thought a lot of people could use it.
(you can also use my zdelete.txt snippet to get rid of unfinished zones easily)

*NB*

* PLEASE READ THROUGH ALL THE NOTES HERE AND AT THE BOTTOM OF THIS SNIPPET

* Obviously you need OLC for this

* In this system, if the builder doesn't build, just delete them. But if
  they complete their zone and you want to make them Immortal, just advance
  them and use set to remove the "builder" flag.

* Advise players to make new characters to be mortal builders, as
  you must delete them if they don't complete their zone, otherwise
  firstly they have new commands and secondly (even if u fix the commands)
  they could use mortal building as an excuse to "load" eq and then ask
  to stop building and get put back to normal with the new eq.

* Also you might have code yourself which would cause a "leek" in
  the enclosure system. Any code you have added to circlemud which
  moves the player may need to a check to make sure mortal builders
  can't escape and give away free eq etc..


Disclaimer: I'm am not responsible for this code, please backup your
            entire mud before going ahead with this. This doesn't need
            a pfile wipe or anything though.


Open structs.h
~~~~~~~~~~~~~~

/* Player flags: used by char_data.char_specials.act */
#define PLR_KILLER	(1 << 0)   /* Player is a player-killer		*/
#define PLR_THIEF	(1 << 1)   /* Player is a player-thief		*/
#define PLR_FROZEN	(1 << 2)   /* Player is frozen			*/
#define PLR_DONTSET     (1 << 3)   /* Don't EVER set (ISNPC bit)	*/
#define PLR_WRITING	(1 << 4)   /* Player writing (board/mail/olc)	*/
#define PLR_MAILING	(1 << 5)   /* Player is writing mail		*/
#define PLR_CRASH	(1 << 6)   /* Player needs to be crash-saved	*/
#define PLR_SITEOK	(1 << 7)   /* Player has been site-cleared	*/
#define PLR_NOSHOUT	(1 << 8)   /* Player not allowed to shout/goss	*/
#define PLR_NOTITLE	(1 << 9)   /* Player not allowed to set title	*/
#define PLR_DELETED	(1 << 10)  /* Player deleted - space reusable	*/
#define PLR_LOADROOM	(1 << 11)  /* Player uses nonstandard loadroom	*/
#define PLR_NOWIZLIST	(1 << 12)  /* Player shouldn't be on wizlist	*/
#define PLR_NODELETE	(1 << 13)  /* Player shouldn't be deleted	*/
#define PLR_INVSTART	(1 << 14)  /* Player should enter game wizinvis	*/
#define PLR_CRYO	(1 << 15)  /* Player is cryo-saved (purge prog)	*/
+#define PLR_MBUILDER    (1 << 16)


Open constants.c
~~~~~~~~~~~~~~~~

/* strings corresponding to ordinals/bitvectors in structs.h ***********/


/* (Note: strings for class definitions in class.c instead of here) */


+/* Mortal Builder Commands */
+const char *mb_cmds[] =
+{
+  "diceroll",
+  "dig",
+  "goto",
+  "load",
+  "medit",
+  "mlist",
+  "olc",
+  "oedit",
+  "olist",
+  "purge",
+  "redit",
+  "rlist",
+  "sedit",
+  "zedit",
+  "zreset",
+  "\n"
+};



Further down:


/* PLR_x */
const char *player_bits[] = {
  "KILLER",
  "THIEF",
  "FROZEN",
  "DONTSET",
  "WRITING",
  "MAILING",
  "CSH",
  "SITEOK",
  "NOSHOUT",
  "NOTITLE",
  "DELETED",
  "LOADRM",
  "!WIZL",
  "!DEL",
  "INVST",
  "CRYO",
+  "MBUILDER",
  "\n"
};



Open constants.h
~~~~~~~~~~~~~~~~

extern const char *circlemud_version;
extern const char *dirs[];
+extern const char *mb_cmds[];



Open utils.h
~~~~~~~~~~~~
#define GET_ALIASES(ch)		CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->aliases))
#define GET_LAST_TELL(ch)	CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->last_tell))
+
+#define ENCLOSED(ch, room)      (PLR_FLAGGED(ch, PLR_MBUILDER) && \
+                                ((ch)->player_specials->saved.olc_zone) != (world[room].number / 100))

#define GET_SKILL(ch, i)	CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.skills[i]))
#define SET_SKILL(ch, i, pct)	do { CHECK_PLAYER_SPECIAL((ch), (ch)->player_specials->saved.skills[i]) = pct; } while(0)

 
If you have George Greer's Auction system open auction.c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ACMD(do_bid)
{
  long bid;

  /* NPC's can not bid or auction if charmed */
  if (ch->master && AFF_FLAGGED(ch, AFF_CHARM))
    return;

+  if (PLR_FLAGGED(ch, PLR_MBUILDER)) {
+    send_to_char("Mortal Builders can't bid!\r\n", ch);
+    return;
+  }


Further down:


ACMD(do_auction)
{
  struct obj_data *obj;
  struct char_data *seller;

  /* NPC's can not bid or auction if charmed */
  if (ch->master && AFF_FLAGGED(ch, AFF_CHARM))
    return;

+  if (PLR_FLAGGED(ch, PLR_MBUILDER)) {
+    send_to_char("Mortal Builders can't bid!\r\n", ch);
+    return;
+  }



Open act.movement.c
~~~~~~~~~~~~~~~~~~~

In "do_simple_move":

  /* move points needed is avg. move loss for src and destination sect type */
  need_movement = (movement_loss[SECT(ch->in_room)] +
		   movement_loss[SECT(EXIT(ch, dir)->to_room)]) / 2;

  if (GET_MOVE(ch) < need_movement && !IS_NPC(ch)) {
    if (need_specials_check && ch->master)
      send_to_char("You are too exhausted to follow.\r\n", ch);
    else
      send_to_char("You are too exhausted.\r\n", ch);

    return (0);
  }
+  if (ENCLOSED(ch, EXIT(ch, dir)->to_room)) {
+   send_to_char("Sorry, Mortal Builders can't leave their zone.\r\n", ch);
+   return(0);
+  }
  if (ROOM_FLAGGED(ch->in_room, ROOM_ATRIUM)) {
    if (!House_can_enter(ch, GET_ROOM_VNUM(EXIT(ch, dir)->to_room))) {
      send_to_char("That's private property -- no trespassing!\r\n", ch);
      return (0);
    }
  }
  if (ROOM_FLAGGED(EXIT(ch, dir)->to_room, ROOM_TUNNEL) &&
      num_pc_in_room(&(world[EXIT(ch, dir)->to_room])) > 1) {
    send_to_char("There isn't enough room there for more than one person!\r\n", ch);
    return (0);
  }


Open act.wizard.c
~~~~~~~~~~~~~~~~~

ACMD(do_last);
ACMD(do_force);
ACMD(do_wiznet);
ACMD(do_zreset);
ACMD(do_wizutil);
void print_zone_to_buf(char *bufptr, zone_rnum zone);
ACMD(do_show);
ACMD(do_set);
+ACMD(do_addbuilder);


In "find_target_room":

  /* a location has been found -- if you're < GRGOD, check restrictions. */
  if (GET_LEVEL(ch) < LVL_GRGOD) {
    if (ROOM_FLAGGED(location, ROOM_GODROOM)) {
      send_to_char("You are not holy enough to use that room!\r\n", ch);
      return (NOWHERE);
    }
    if (ROOM_FLAGGED(location, ROOM_PRIVATE) &&
	world[location].people && world[location].people->next_in_room) {
      send_to_char("There's a private conversation going on in that room.\r\n", ch);
      return (NOWHERE);
    }
    if (ROOM_FLAGGED(location, ROOM_HOUSE) &&
	!House_can_enter(ch, GET_ROOM_VNUM(location))) {
      send_to_char("That's private property -- no trespassing!\r\n", ch);
      return (NOWHERE);
    }
+    if (ENCLOSED(ch, location)) {
+      send_to_char("Sorry, Mortal Builders cannot leave their zone.\r\n", ch);
+      return (NOWHERE);
+    }
  }
  return (location);
}


Further down in "do_set":


   { "deleted", 	LVL_IMPL, 	PC, 	BINARY },
   { "class",		LVL_GRGOD, 	BOTH, 	MISC },
   { "noadlist",        LVL_GOD,        PC,     BINARY },  /* 40 */
   { "quest",		LVL_GOD, 	PC, 	BINARY },
   { "loadroom", 	LVL_GRGOD, 	PC, 	MISC },
   { "color",		LVL_GOD, 	PC, 	BINARY },
   { "idnum",		LVL_IMPL, 	PC, 	NUMBER },
   { "passwd",		LVL_IMPL, 	PC, 	MISC },    /* 45 */
   { "nodelete", 	LVL_GOD, 	PC, 	BINARY },
   { "sex", 		LVL_GRGOD, 	BOTH, 	MISC },
   { "age",		LVL_GRGOD,	BOTH,	NUMBER },
   { "height",		LVL_GOD,	BOTH,	NUMBER },
   { "weight",		LVL_GOD,	BOTH,	NUMBER },  /* 50 */
   { "olc",		LVL_IMPL,	PC,	NUMBER },
+   { "builder",         LVL_IMPL,       PC,     BINARY },


Further down:


  case 49:	/* Blame/Thank Rick Glover. :) */
    GET_HEIGHT(vict) = value;
    affect_total(vict);
    break;

  case 50:
    GET_WEIGHT(vict) = value;
    affect_total(vict);
    break;

  case 51:
    GET_OLC_ZONE(vict) = value;
    break;

+  case 52:
+    SET_OR_REMOVE(PLR_FLAGS(vict), PLR_MBUILDER);
+    break;



At the end of the file:


+ACMD(do_addbuilder)
+{
+  struct char_data *vict;
+  room_rnum location;
+  int i, number, j = 0;
+
+  two_arguments(argument, buf, buf2);
+
+  if (!*buf) {
+   send_to_char("Who do you want to make a Mortal builder?\r\n", ch);
+   return;
+  }
+  if (!*buf2) {
+   send_to_char("What about the zone! they can't build on thin air!\r\n", ch);
+   return;
+  }
+  if (!(vict = get_char_vis(ch, buf, FIND_CHAR_WORLD))) {
+   send_to_char("No such player.\r\n", ch);
+   return;
+  }
+  if (GET_LEVEL(vict) >= LVL_IMMORT) {
+   send_to_char("They wouldn't be a Mortal builder if they were Immortal now would they?\r\n", ch);
+   return;
+  }
+  if (IS_NPC(vict)) {
+   send_to_char("A Mob!", ch);
+   return;
+  }
+
+  number = atoi(buf2);
+
+  for (i = 0; i <= top_of_zone_table; i++) {
+    if (zone_table[i].number == number) {
+      j = TRUE;
+    }
+  }
+  if (((location = real_room(number * 100)) < 0) && j) {
+   send_to_char("Sorry, that zone has no start room, i.e. the 00 room.\r\n", ch);
+   return;
+  }
+  if (!j) {
+   send_to_char("Sorry, there ain't a zone with that number.\r\n", ch);
+   return;
+  }
+
+  /* okay, i think thats it, all checks done */
+  SET_BIT(PRF_FLAGS(vict), PRF_NOHASSLE);
+  SET_BIT(PRF_FLAGS(vict), PRF_ROOMFLAGS);
+  SET_BIT(PRF_FLAGS(vict), PRF_HOLYLIGHT);
+  SET_BIT(PRF_FLAGS(vict), PRF_COLOR_2);
+  SET_BIT(PRF_FLAGS(vict), PRF_COLOR_1);
+  SET_BIT(PRF_FLAGS(vict), PRF_LOG2);
+  SET_BIT(PRF_FLAGS(vict), PRF_LOG1);
+  SET_BIT(PLR_FLAGS(vict), PLR_MBUILDER);
+  GET_COND(vict, THIRST) = -1;
+  GET_COND(vict, FULL) = -1;
+  GET_OLC_ZONE(vict) = number;
+  sprintf(buf, "(GC) %s has been made a Mortal Builder", GET_NAME(vict));
+  mudlog(buf, BRF, LVL_GOD, TRUE);
+  send_to_char("Mortal Builder Created and Enclosed. Please ask them to quit and come back on.\r\n", ch);
+  return;
+}


Open spell_parser.c
~~~~~~~~~~~~~~~~~~~

ACMD(do_cast)
{
  struct char_data *tch = NULL;
  struct obj_data *tobj = NULL;
  char *s, *t;
  int mana, spellnum, i, target = 0;

  if (IS_NPC(ch))
    return;

+  if (PLR_FLAGGED(ch, PLR_MBUILDER)) {
+   send_to_char("Sorry, Mortal Builders cannot use spells, it's just easier this way.\r\n", ch);
+   return;
+  }

  /* get: blank, spell name, target name */
  s = strtok(argument, "'");



Open interpreter.c
~~~~~~~~~~~~~~~~~~

extern struct index_data *mob_index;
extern struct index_data *obj_index;
extern struct room_data *world;
+extern const char *mb_cmds[];

/* external functions */
void echo_on(struct descriptor_data *d);
void echo_off(struct descriptor_data *d);
void do_start(struct char_data *ch);


Further down:


/* prototypes for all do_x functions. */
ACMD(do_action);
+ACMD(do_addbuilder);


Further down:


  { "moan"     , POS_RESTING , do_action   , 0, 0 },
+  { "mortbuild", POS_DEAD    , do_addbuilder, LVL_GRGOD, 0 },
  { "motd"     , POS_DEAD    , do_gen_ps   , 0, SCMD_MOTD },



Further down:

const char *reserved[] =
{
  "a",
  "an",
  "self",
  "me",
  "all",
  "room",
  "someone",
  "something",
  "\n"
};


+/* (mb_cmds[] is in constants.c) */
+int is_mb_cmd(const char *command)
+{
+ int i;
+
+  for (i = 0; *mb_cmds[i] != '\n'; i++) {
+    if (!str_cmp(mb_cmds[i], command))
+     return(1);
+  }
+  return(0);
+}


Further down:

  /* otherwise, find the command */
  for (length = strlen(arg), cmd = 0; *cmd_info[cmd].command != '\n'; cmd++)
    if (!strncmp(cmd_info[cmd].command, arg, length))
-      if (GET_LEVEL(ch) >= cmd_info[cmd].minimum_level)
+      if ((GET_LEVEL(ch) >= cmd_info[cmd].minimum_level) || (PLR_FLAGGED(ch, PLR_MBUILDER) && is_mb_cmd(cmd_info[cmd].command)))
	break;



Further down:

      /*
       * We have to place the character in a room before equipping them
       * or equip_char() will gripe about the person in NOWHERE.
       */
      if ((load_room = GET_LOADROOM(d->character)) != NOWHERE)
	load_room = real_room(load_room);

      /* If char was saved with NOWHERE, or real_room above failed... */
      if (load_room == NOWHERE) {
	if (GET_LEVEL(d->character) >= LVL_IMMORT)
	  load_room = r_immort_start_room;
	else
	  load_room = r_mortal_start_room;
      }

+      if (PLR_FLAGGED(d->character, PLR_MBUILDER))
+        load_room = real_room((GET_OLC_ZONE(d->character) * 100));

      if (PLR_FLAGGED(d->character, PLR_FROZEN))
	load_room = r_frozen_start_room;

      send_to_char(WELC_MESSG, d->character);
      d->character->next = character_list;
      character_list = d->character;
      char_to_room(d->character, load_room);
      load_result = Crash_load(d->character);
      save_char(d->character, NOWHERE);



Thats it's, i'm sure someone will point out a better way to do it.
But that happens with all code, but it works for me. To make changes
to the commands that mortal builders can use, just change the:

mb_cmds[] in constants.c, just add the name of the command.

And here are the steps to creating a Mortal Builder:

1. Create the zone.
2. Using "redit" create the first room (00).
3. Using "zedit" name the zone.
4. Save the changes.
5. Use "mortbuild" to assign the builder to the zone.
6. Ask them to quit and come back on.
7. Sit back and watch them build :)

You might want to let your GR_GODs know as i've made it so they
can make mortal builders, if a mortal builder logs on and something
has happened to their zone (e.g. it wasn't saved) the the mud will crash
everytime they log on, it can be a bitch, especially when they don't
realize they're the reason the mud is crashing. See mortal builders
are enclosed in their zone, therefore they start in it when they log
on, if it ain't there the mud crashes.

btw i've used this code in both CircleMUD3bpl15 and CircleMUD3bpl17
and have had no problems.

*************************************************************************

If you use this code please email me and let me know. I'd appreciated it.

Subliminal
m_gally@hotmail.com

Head Coder/Implementor of "STFMUD: The Second Coming".

http://www.stfmud.com/
(you can find my other snippets there)

*************************************************************************


<< FTP Uploads 2000/10/01 | Reply | Threaded | Vampires creating Vampires [by Subliminal] >>

 


Related Links
  CircleMUD
Subliminal
Related Articles
More by bbrown
 
 

Quick Links
 
The CircleMUD FAQ
The CircleMUD home page
Alex's Snippets
Wintermute Snippets
CircleMUD Bug Reporting or Help
CircleMUD List Archives
CircleMUD Resources
Death Gate's Scripts
(Author of C conversion)
Sammy's code site
Erwin S. Andreasen's page
(Author of mudFTP and other goodies)
Death's Gate Scripting site
Help for CircleMUD in Windows
The OasisOLC Maintenance Effort
George's Random Stuff
Imaginary Realities
MUD Dictionary
 
 


Eh?
by Craig Cooney (perfect_circle@angelfire.com) on Monday, November 6th @ 10:52:35 PM
http://
Why not just give your lowest lvl of immorts
just the redit, sedit, oedit, and medit commands?
Without zedit or load they wouldn't be able to actually put anything into the game that could be abused, not to mention it would be a way of enforcing one of your 'Head Builders' actually QC everything in a new zone and don't just sit on their asses. Removing the ability to use mortal skills/spells makes sense, as would making them unable to attack mobs so they can't tank for mortals. But, why code all this when when the same effect could be acheived by more careful selection of god commands?
[ Reply to this comment ]

Re: Eh?
by Lars (lars@fryed.net) on Thursday, November 16th @ 07:05:31 PM
http://telnet://fryed.net:4000
I worked with this system, and actually made a decent mortal builder level. I raised the total number of levels to 100, giving mortal builders 101, and immorts 102-105. I set a couple of spares in structs.h for old_hitpoints, old_exp, and old_level, when I addbuilder {name} {zone}, it increases their hitpoints, restricts them to only the zone their building in, and set their level to 101. When I remove builder, it returns the builder to the exact state they were in before they started building. With LVL_BUILDER, you can allow access to some immortal commands, but put restricts on them as so they aren't restoring other players, and messing with other people zones. While you could accomplish that by setting their level as immortal, you wouldn't be able to restrict their movement, (goto any zone, finished or not in the mud), or deny certain commands or switches of commands as easily as this.

Lars
[ Reply to this comment ]