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) *************************************************************************