diff --git a/changelog b/changelog index eb07df8..936fe83 100644 --- a/changelog +++ b/changelog @@ -2,11 +2,13 @@ TbaMUD is currently being developed by The Builder Academy. If you need any help, find any bugs, or have ideas for improvement please stop by TBA at telnet://tbamud.com:9091 or email rumble@tbamud.com --Rumble @ +[Feb 12 2013] - Vatiken + feature: New group system. + feature: Room events. + bug: Many small bug fixes. [Sep 08 2012] - Rumble added another example to doc/syserr.txt Added a !NPC check to can_take_object. It was spamming a "mob using player data SYSERR". This means mobs do not have a max weight carrying capacity anymore. I think this is a good thing because I've seen people stumped when mob triggers fail due to weight limitations. But it could be unbalancing on some MUDs since pets could then carry unlimited gear. -ht limitations. But it could be unbalancing on some MUDs since pets could then carry unlimited gear. - Uncommented code to prevent crashes when trying to save a deleted object. [Aug 22 2012] - Rumble bug: moved cedit load_config of no_mort_to_immort to its proper place. (thanks Liko) [Aug 12 2012] - Vatiken diff --git a/src/act.comm.c b/src/act.comm.c index c69b5d5..6213e9d 100644 --- a/src/act.comm.c +++ b/src/act.comm.c @@ -73,41 +73,26 @@ ACMD(do_say) ACMD(do_gsay) { - struct char_data *k; - struct follow_type *f; - skip_spaces(&argument); - - if (!AFF_FLAGGED(ch, AFF_GROUP)) { - send_to_char(ch, "But you are not the member of a group!\r\n"); + + if (!GROUP(ch)) { + send_to_char(ch, "But you are not a member of a group!\r\n"); return; } if (!*argument) send_to_char(ch, "Yes, but WHAT do you want to group-say?\r\n"); else { - char buf[MAX_STRING_LENGTH]; - + if (CONFIG_SPECIAL_IN_COMM && legal_communication(argument)) - parse_at(argument); - - if (ch->master) - k = ch->master; - else - k = ch; - - snprintf(buf, sizeof(buf), "$n tells the group, '%s\tn'", argument); - - if (AFF_FLAGGED(k, AFF_GROUP) && (k != ch)) - act(buf, FALSE, ch, 0, k, TO_VICT | TO_SLEEP); - for (f = k->followers; f; f = f->next) - if (AFF_FLAGGED(f->follower, AFF_GROUP) && (f->follower != ch)) - act(buf, FALSE, ch, 0, f->follower, TO_VICT | TO_SLEEP); - + parse_at(argument); + + send_to_group(ch, ch->group, "%s%s%s says, '%s'%s\r\n", CCGRN(ch, C_NRM), CCGRN(ch, C_NRM), GET_NAME(ch), argument, CCNRM(ch, C_NRM)); + if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT)) send_to_char(ch, "%s", CONFIG_OK); else - send_to_char(ch, "You tell the group, '%s\tn'\r\n", argument); - } + send_to_char(ch, "%sYou group-say, '%s'%s\r\n", CCGRN(ch, C_NRM), argument, CCNRM(ch, C_NRM)); + } } static void perform_tell(struct char_data *ch, struct char_data *vict, char *arg) diff --git a/src/act.h b/src/act.h index e2bc341..7ec7f94 100644 --- a/src/act.h +++ b/src/act.h @@ -249,7 +249,6 @@ ACMD(do_sneak); ACMD(do_split); ACMD(do_steal); ACMD(do_title); -ACMD(do_ungroup); ACMD(do_visible); @@ -328,6 +327,7 @@ ACMD(do_plist); ACMD(do_purge); ACMD(do_recent); ACMD(do_restore); +void return_to_char(struct char_data * ch); ACMD(do_return); ACMD(do_saveall); ACMD(do_send); diff --git a/src/act.informative.c b/src/act.informative.c index 1bacadf..6a4c15d 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -309,6 +309,17 @@ static void list_one_char(struct char_data *i, struct char_data *ch) } } + if (GROUP(i)) { + if (GROUP(i) == GROUP(ch)) + send_to_char(ch, "(%s%s%s) ", CBGRN(ch, C_NRM), + GROUP_LEADER(GROUP(i)) == i ? "leader" : "group", + CCNRM(ch, C_NRM)); + else + send_to_char(ch, "(%s%s%s) ", CBRED(ch, C_NRM), + GROUP_LEADER(GROUP(i)) == i ? "leader" : "group", + CCNRM(ch, C_NRM)); + } + if (IS_NPC(i) && i->player.long_descr && GET_POS(i) == GET_DEFAULT_POS(i)) { if (AFF_FLAGGED(i, AFF_INVISIBLE)) send_to_char(ch, "*"); @@ -1201,9 +1212,9 @@ ACMD(do_who) continue; if (showclass && !(showclass & (1 << GET_CLASS(tch)))) continue; - if (showgroup && (!tch->master || !AFF_FLAGGED(tch, AFF_GROUP))) + if (showgroup && !GROUP(tch)) continue; - if (showleader && (!tch->followers || !AFF_FLAGGED(tch, AFF_GROUP))) + if (showleader && (!GROUP(tch) || GROUP_LEADER(GROUP(tch)) != tch)) continue; for (i = 0; *rank[i].disp != '\n'; i++) if (GET_LEVEL(tch) >= rank[i].min_level && GET_LEVEL(tch) <= rank[i].max_level) @@ -1245,9 +1256,9 @@ ACMD(do_who) continue; if (showclass && !(showclass & (1 << GET_CLASS(tch)))) continue; - if (showgroup && (!tch->master || !AFF_FLAGGED(tch, AFF_GROUP))) + if (showgroup && !GROUP(tch)) continue; - if (showleader && (!tch->followers || !AFF_FLAGGED(tch, AFF_GROUP))) + if (showleader && (!GROUP(tch) || GROUP_LEADER(GROUP(tch)) != tch)) continue; if (short_list) { diff --git a/src/act.movement.c b/src/act.movement.c index dca7019..a5a8e1d 100644 --- a/src/act.movement.c +++ b/src/act.movement.c @@ -965,7 +965,7 @@ ACMD(do_follow) } if (ch->master) stop_follower(ch); - REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_GROUP); + add_follower(ch, leader); } } diff --git a/src/act.other.c b/src/act.other.c index d614e39..a579ac0 100644 --- a/src/act.other.c +++ b/src/act.other.c @@ -35,9 +35,8 @@ /* Local defined utility functions */ /* do_group utility functions */ -static int perform_group(struct char_data *ch, struct char_data *vict); static void print_group(struct char_data *ch); - +static void display_group_list(struct char_data * ch); ACMD(do_quit) { @@ -319,185 +318,172 @@ ACMD(do_title) } } -static int perform_group(struct char_data *ch, struct char_data *vict) -{ - if (AFF_FLAGGED(vict, AFF_GROUP) || !CAN_SEE(ch, vict)) - return (0); - - SET_BIT_AR(AFF_FLAGS(vict), AFF_GROUP); - if (ch != vict) - act("$N is now a member of your group.", FALSE, ch, 0, vict, TO_CHAR); - act("You are now a member of $n's group.", FALSE, ch, 0, vict, TO_VICT); - act("$N is now a member of $n's group.", FALSE, ch, 0, vict, TO_NOTVICT); - return (1); -} - static void print_group(struct char_data *ch) { - struct char_data *k; - struct follow_type *f; + struct char_data * k; - if (!AFF_FLAGGED(ch, AFF_GROUP)) - send_to_char(ch, "But you are not the member of a group!\r\n"); - else { - char buf[MAX_STRING_LENGTH]; + send_to_char(ch, "Your group consists of:\r\n"); - send_to_char(ch, "Your group consists of:\r\n"); - - k = (ch->master ? ch->master : ch); - - if (AFF_FLAGGED(k, AFF_GROUP)) { - snprintf(buf, sizeof(buf), " [%3dH %3dM %3dV] [%2d %s] $N (Head of group)", - GET_HIT(k), GET_MANA(k), GET_MOVE(k), GET_LEVEL(k), CLASS_ABBR(k)); - act(buf, FALSE, ch, 0, k, TO_CHAR); - } - - for (f = k->followers; f; f = f->next) { - if (!AFF_FLAGGED(f->follower, AFF_GROUP)) - continue; - - snprintf(buf, sizeof(buf), " [%3dH %3dM %3dV] [%2d %s] $N", GET_HIT(f->follower), - GET_MANA(f->follower), GET_MOVE(f->follower), - GET_LEVEL(f->follower), CLASS_ABBR(f->follower)); - act(buf, FALSE, ch, 0, f->follower, TO_CHAR); - } - } + while ((k = (struct char_data *) simple_list(ch->group->members)) != NULL) + send_to_char(ch, "%-*s: %s[%4d/%-4d]H [%4d/%-4d]M [%4d/%-4d]V%s\r\n", + count_color_chars(GET_NAME(k))+22, GET_NAME(k), + GROUP_LEADER(GROUP(ch)) == k ? CBGRN(ch, C_NRM) : CCGRN(ch, C_NRM), + GET_HIT(k), GET_MAX_HIT(k), + GET_MANA(k), GET_MAX_MANA(k), + GET_MOVE(k), GET_MAX_MOVE(k), + CCNRM(ch, C_NRM)); } +static void display_group_list(struct char_data * ch) +{ + struct group_data * group; + int count = 0; + + if (group_list->iSize) { + send_to_char(ch, "# Group Leader # of Members In Zone\r\n" + "---------------------------------------------------\r\n"); + + while ((group = (struct group_data *) simple_list(group_list)) != NULL) { + if (IS_SET(GROUP_FLAGS(group), GROUP_NPC)) + continue; + if (GROUP_LEADER(group) && !IS_SET(GROUP_FLAGS(group), GROUP_ANON)) + send_to_char(ch, "%-2d) %s%-12s %-2d %s%s\r\n", + ++count, + IS_SET(GROUP_FLAGS(group), GROUP_OPEN) ? CCGRN(ch, C_NRM) : CCRED(ch, C_NRM), + GET_NAME(GROUP_LEADER(group)), group->members->iSize, zone_table[world[IN_ROOM(GROUP_LEADER(group))].zone].name, + CCNRM(ch, C_NRM)); + else + send_to_char(ch, "%-2d) Hidden\r\n", ++count); + + } + } + if (count) + send_to_char(ch, "\r\n" + "%sSeeking Members%s\r\n" + "%sClosed%s\r\n", + CCGRN(ch, C_NRM), CCNRM(ch, C_NRM), + CCRED(ch, C_NRM), CCNRM(ch, C_NRM)); + else + send_to_char(ch, "\r\n" + "Currently no groups formed.\r\n"); +} + +/* Vatiken's Group System: Version 1.1 */ ACMD(do_group) { char buf[MAX_STRING_LENGTH]; struct char_data *vict; - struct follow_type *f; - int found; - one_argument(argument, buf); + argument = one_argument(argument, buf); if (!*buf) { - print_group(ch); + if (GROUP(ch)) + print_group(ch); + else + send_to_char(ch, "You must specify a group option, or type HELP GROUP for more info.\r\n"); return; } - - if (ch->master) { - act("You cannot enroll group members without being head of a group.", - FALSE, ch, 0, 0, TO_CHAR); - return; - } - - if (!str_cmp(buf, "all")) { - perform_group(ch, ch); - for (found = 0, f = ch->followers; f; f = f->next) - found += perform_group(ch, f->follower); - if (!found) - send_to_char(ch, "Everyone following you is already in your group.\r\n"); - return; - } - - if (!(vict = get_char_vis(ch, buf, NULL, FIND_CHAR_ROOM))) - send_to_char(ch, "%s", CONFIG_NOPERSON); - else if ((vict->master != ch) && (vict != ch)) - act("$N must follow you to enter your group.", FALSE, ch, 0, vict, TO_CHAR); - else { - if (!AFF_FLAGGED(vict, AFF_GROUP)) - perform_group(ch, vict); - else { - if (ch != vict) - act("$N is no longer a member of your group.", FALSE, ch, 0, vict, TO_CHAR); - act("You have been kicked out of $n's group!", FALSE, ch, 0, vict, TO_VICT); - act("$N has been kicked out of $n's group!", FALSE, ch, 0, vict, TO_NOTVICT); - REMOVE_BIT_AR(AFF_FLAGS(vict), AFF_GROUP); - } - } -} - -ACMD(do_ungroup) -{ - char buf[MAX_INPUT_LENGTH]; - struct follow_type *f, *next_fol; - struct char_data *tch; - - one_argument(argument, buf); - - if (!*buf) { - if (ch->master || !(AFF_FLAGGED(ch, AFF_GROUP))) { - send_to_char(ch, "But you lead no group!\r\n"); + + if (is_abbrev(buf, "new")) { + if (GROUP(ch)) + send_to_char(ch, "You are already in a group.\r\n"); + else + create_group(ch); + } else if (is_abbrev(buf, "list")) + display_group_list(ch); + else if (is_abbrev(buf, "join")) { + skip_spaces(&argument); + if (!(vict = get_char_vis(ch, argument, NULL, FIND_CHAR_ROOM))) { + send_to_char(ch, "Join who?\r\n"); + return; + } else if (vict == ch) { + send_to_char(ch, "That would be one lonely grouping.\r\n"); + return; + } else if (GROUP(ch)) { + send_to_char(ch, "But you are already part of a group.\r\n"); + return; + } else if (!GROUP(vict)) { + send_to_char(ch, "They are not a part of a group!\r\n"); + return; + } else if (!IS_SET(GROUP_FLAGS(GROUP(vict)), GROUP_OPEN)) { + send_to_char(ch, "That group isn't accepting members.\r\n"); + return; + } + join_group(ch, GROUP(vict)); + } else if (is_abbrev(buf, "kick")) { + skip_spaces(&argument); + if (!(vict = get_char_vis(ch, argument, NULL, FIND_CHAR_ROOM))) { + send_to_char(ch, "Kick out who?\r\n"); + return; + } else if (vict == ch) { + send_to_char(ch, "There are easier ways to leave the group.\r\n"); + return; + } else if (!GROUP(ch) ) { + send_to_char(ch, "But you are not part of a group.\r\n"); + return; + } else if (GROUP_LEADER(GROUP(ch)) != ch ) { + send_to_char(ch, "Only the group's leader can kick members out.\r\n"); + return; + } else if (GROUP(vict) != GROUP(ch)) { + send_to_char(ch, "They are not a member of your group!\r\n"); + return; + } + send_to_char(ch, "You have kicked %s out of the group.\r\n", GET_NAME(vict)); + send_to_char(vict, "You have been kicked out of the group.\r\n"); + leave_group(vict); + } else if (is_abbrev(buf, "leave")) { + if (!GROUP(ch)) { + send_to_char(ch, "But you aren't apart of a group!\r\n"); return; } - - for (f = ch->followers; f; f = next_fol) { - next_fol = f->next; - if (AFF_FLAGGED(f->follower, AFF_GROUP)) { - REMOVE_BIT_AR(AFF_FLAGS(f->follower), AFF_GROUP); - act("$N has disbanded the group.", TRUE, f->follower, NULL, ch, TO_CHAR); - if (!AFF_FLAGGED(f->follower, AFF_CHARM)) - stop_follower(f->follower); - } + + leave_group(ch); + } else if (is_abbrev(buf, "option")) { + skip_spaces(&argument); + if (!GROUP(ch)) { + send_to_char(ch, "But you aren't part of a group!\r\n"); + return; + } else if (GROUP_LEADER(GROUP(ch)) != ch) { + send_to_char(ch, "Only the group leader can adjust the group flags.\r\n"); + return; } - - REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_GROUP); - send_to_char(ch, "You disband the group.\r\n"); - return; - } - if (!(tch = get_char_vis(ch, buf, NULL, FIND_CHAR_ROOM))) { - send_to_char(ch, "There is no such person!\r\n"); - return; - } - if (tch->master != ch) { - send_to_char(ch, "That person is not following you!\r\n"); - return; + if (is_abbrev(argument, "open")) { + TOGGLE_BIT(GROUP_FLAGS(GROUP(ch)), GROUP_OPEN); + send_to_char(ch, "The group is now %s to new members.\r\n", IS_SET(GROUP_FLAGS(GROUP(ch)), GROUP_OPEN) ? "open" : "closed"); + } else if (is_abbrev(argument, "anonymous")) { + TOGGLE_BIT(GROUP_FLAGS(GROUP(ch)), GROUP_ANON); + send_to_char(ch, "The group location is now %s to other players.\r\n", IS_SET(GROUP_FLAGS(GROUP(ch)), GROUP_ANON) ? "invisible" : "visible"); + } else + send_to_char(ch, "The flag options are: Open, Anonymous\r\n"); + } else { + send_to_char(ch, "You must specify a group option, or type HELP GROUP for more info.\r\n"); } - if (!AFF_FLAGGED(tch, AFF_GROUP)) { - send_to_char(ch, "That person isn't in your group.\r\n"); - return; - } - - REMOVE_BIT_AR(AFF_FLAGS(tch), AFF_GROUP); - - act("$N is no longer a member of your group.", FALSE, ch, 0, tch, TO_CHAR); - act("You have been kicked out of $n's group!", FALSE, ch, 0, tch, TO_VICT); - act("$N has been kicked out of $n's group!", FALSE, ch, 0, tch, TO_NOTVICT); - - if (!AFF_FLAGGED(tch, AFF_CHARM)) - stop_follower(tch); } ACMD(do_report) { - char buf[MAX_STRING_LENGTH]; - struct char_data *k; - struct follow_type *f; + struct group_data *group; - if (!AFF_FLAGGED(ch, AFF_GROUP)) { + if ((group = GROUP(ch)) == NULL) { send_to_char(ch, "But you are not a member of any group!\r\n"); return; } - snprintf(buf, sizeof(buf), "$n reports: %d/%dH, %d/%dM, %d/%dV\r\n", + send_to_group(NULL, group, "%s reports: %d/%dH, %d/%dM, %d/%dV\r\n", + GET_NAME(ch), GET_HIT(ch), GET_MAX_HIT(ch), GET_MANA(ch), GET_MAX_MANA(ch), GET_MOVE(ch), GET_MAX_MOVE(ch)); - - k = (ch->master ? ch->master : ch); - - for (f = k->followers; f; f = f->next) - if (AFF_FLAGGED(f->follower, AFF_GROUP) && f->follower != ch) - act(buf, TRUE, ch, NULL, f->follower, TO_VICT); - - if (k != ch) - act(buf, TRUE, ch, NULL, k, TO_VICT); - - send_to_char(ch, "You report to the group.\r\n"); } ACMD(do_split) { char buf[MAX_INPUT_LENGTH]; - int amount, num, share, rest; + int amount, num = 0, share, rest; size_t len; struct char_data *k; - struct follow_type *f; - + if (IS_NPC(ch)) return; @@ -513,20 +499,13 @@ ACMD(do_split) send_to_char(ch, "You don't seem to have that much gold to split.\r\n"); return; } - k = (ch->master ? ch->master : ch); + + if (GROUP(ch)) + while ((k = (struct char_data *) simple_list(GROUP(ch)->members)) != NULL) + if (IN_ROOM(ch) == IN_ROOM(k) && !IS_NPC(k)) + num++; - if (AFF_FLAGGED(k, AFF_GROUP) && (IN_ROOM(k) == IN_ROOM(ch))) - num = 1; - else - num = 0; - - for (f = k->followers; f; f = f->next) - if (AFF_FLAGGED(f->follower, AFF_GROUP) && - (!IS_NPC(f->follower)) && - (IN_ROOM(f->follower) == IN_ROOM(ch))) - num++; - - if (num && AFF_FLAGGED(ch, AFF_GROUP)) { + if (num && GROUP(ch)) { share = amount / num; rest = amount % num; } else { @@ -544,22 +523,13 @@ ACMD(do_split) "%d coin%s %s not splitable, so %s keeps the money.\r\n", rest, (rest == 1) ? "" : "s", (rest == 1) ? "was" : "were", GET_NAME(ch)); } - if (AFF_FLAGGED(k, AFF_GROUP) && IN_ROOM(k) == IN_ROOM(ch) && - !IS_NPC(k) && k != ch) { - increase_gold(k, share); - send_to_char(k, "%s", buf); - } - for (f = k->followers; f; f = f->next) { - if (AFF_FLAGGED(f->follower, AFF_GROUP) && - (!IS_NPC(f->follower)) && - (IN_ROOM(f->follower) == IN_ROOM(ch)) && - f->follower != ch) { + while ((k = (struct char_data *) simple_list(GROUP(ch)->members)) != NULL) + if (k != ch && IN_ROOM(ch) == IN_ROOM(k) && !IS_NPC(k)) { + increase_gold(k, share); + send_to_char(k, "%s", buf); + } - increase_gold(f->follower, share); - send_to_char(f->follower, "%s", buf); - } - } send_to_char(ch, "You split %d coins among %d members -- %d coins each.\r\n", amount, num, share); diff --git a/src/act.wizard.c b/src/act.wizard.c index 93c1048..79fa3c9 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -1245,6 +1245,27 @@ void do_cheat(struct char_data *ch) save_char(ch); } +void return_to_char(struct char_data * ch) +{ + /* If someone switched into your original body, disconnect them. - JE + * Zmey: here we put someone switched in our body to disconnect state but + * we must also NULL his pointer to our character, otherwise close_socket() + * will damage our character's pointer to our descriptor (which is assigned + * below in this function). */ + if (ch->desc->original->desc) { + ch->desc->original->desc->character = NULL; + STATE(ch->desc->original->desc) = CON_DISCONNECT; + } + + /* Now our descriptor points to our original body. */ + ch->desc->character = ch->desc->original; + ch->desc->original = NULL; + + /* And our body's pointer to descriptor now points to our descriptor. */ + ch->desc->character->desc = ch->desc; + ch->desc = NULL; +} + ACMD(do_return) { if (!IS_NPC(ch) && !ch->desc->original) { @@ -1258,24 +1279,7 @@ ACMD(do_return) if (ch->desc && ch->desc->original) { send_to_char(ch, "You return to your original body.\r\n"); - - /* If someone switched into your original body, disconnect them. - JE - * Zmey: here we put someone switched in our body to disconnect state but - * we must also NULL his pointer to our character, otherwise close_socket() - * will damage our character's pointer to our descriptor (which is assigned - * below in this function). */ - if (ch->desc->original->desc) { - ch->desc->original->desc->character = NULL; - STATE(ch->desc->original->desc) = CON_DISCONNECT; - } - - /* Now our descriptor points to our original body. */ - ch->desc->character = ch->desc->original; - ch->desc->original = NULL; - - /* And our body's pointer to descriptor now points to our descriptor. */ - ch->desc->character->desc = ch->desc; - ch->desc = NULL; + return_to_char(ch); } } @@ -2169,7 +2173,6 @@ ACMD(do_wiznet) int level = LVL_IMMORT; skip_spaces(&argument); - delete_doubledollar(argument); if (!*argument) { send_to_char(ch, "Usage: wiznet [ # ] [ | * | @ ]\r\n"); @@ -3637,10 +3640,9 @@ ACMD (do_zcheck) len += snprintf(buf + len, sizeof(buf) - len, "- Has %d experience (limit: %d)\r\n", GET_EXP(mob), MAX_EXP_ALLOWED); - if ((AFF_FLAGGED(mob, AFF_GROUP) || AFF_FLAGGED(mob, AFF_CHARM) || AFF_FLAGGED(mob, AFF_POISON)) && (found = 1)) + if ((AFF_FLAGGED(mob, AFF_CHARM) || AFF_FLAGGED(mob, AFF_POISON)) && (found = 1)) len += snprintf(buf + len, sizeof(buf) - len, - "- Has illegal affection bits set (%s %s %s)\r\n", - AFF_FLAGGED(mob, AFF_GROUP) ? "GROUP" : "", + "- Has illegal affection bits set (%s %s)\r\n", AFF_FLAGGED(mob, AFF_CHARM) ? "CHARM" : "", AFF_FLAGGED(mob, AFF_POISON) ? "POISON" : ""); @@ -4153,6 +4155,11 @@ ACMD(do_copyover) /* For each playing descriptor, save its state */ for (d = descriptor_list; d ; d = d_next) { struct char_data * och = d->character; + + /* If d is currently in someone else's body, return them. */ + if (och && d->original) + return_to_char(och); + /* We delete from the list , so need to save this */ d_next = d->next; diff --git a/src/class.c b/src/class.c index 519c962..dab0fb8 100644 --- a/src/class.c +++ b/src/class.c @@ -1609,6 +1609,7 @@ void init_spell_levels(void) spell_level(SPELL_REMOVE_POISON, CLASS_CLERIC, 10); spell_level(SPELL_IDENTIFY, CLASS_CLERIC, 11); spell_level(SPELL_WORD_OF_RECALL, CLASS_CLERIC, 12); + spell_level(SPELL_DARKNESS, CLASS_CLERIC, 12); spell_level(SPELL_EARTHQUAKE, CLASS_CLERIC, 12); spell_level(SPELL_DISPEL_EVIL, CLASS_CLERIC, 14); spell_level(SPELL_DISPEL_GOOD, CLASS_CLERIC, 14); diff --git a/src/comm.c b/src/comm.c index b564df3..a2847b6 100644 --- a/src/comm.c +++ b/src/comm.c @@ -2418,6 +2418,29 @@ void send_to_room(room_rnum room, const char *messg, ...) } } +/* Sends a message to the entire group, except for ch. + * Send 'ch' as NULL, if you want to message to reach + * everyone. -Vatiken */ +void send_to_group(struct char_data *ch, struct group_data *group, const char * msg, ...) +{ + struct char_data *tch; + va_list args; + + if (msg == NULL) + return; + + while ((tch = simple_list(group->members)) != NULL) { + if (tch != ch && !IS_NPC(tch) && tch->desc && STATE(tch->desc) == CON_PLAYING) { + write_to_output(tch->desc, "%s[%sGroup%s]%s ", + CCGRN(tch, C_NRM), CBGRN(tch, C_NRM), CCGRN(tch, C_NRM), CCNRM(tch, C_NRM)); + va_start(args, msg); + vwrite_to_output(tch->desc, msg, args); + va_end(args); + } + } +} + + /* Thx to Jamie Nelson of 4D for this contribution */ void send_to_range(room_vnum start, room_vnum finish, const char *messg, ...) { diff --git a/src/comm.h b/src/comm.h index af63d4b..cb49fc7 100644 --- a/src/comm.h +++ b/src/comm.h @@ -27,6 +27,8 @@ void send_to_room(room_rnum room, const char *messg, ...) __attribute__ ((format (printf, 2, 3))); void send_to_outdoor(const char *messg, ...) __attribute__ ((format (printf, 1, 2))); +void send_to_group(struct char_data *ch, struct group_data *group, const char * msg, ...) __attribute__ ((format + (printf, 3, 4))); void send_to_range(room_vnum start, room_vnum finish, const char *messg, ...) __attribute__ ((format (printf, 3, 4))); diff --git a/src/db.c b/src/db.c index 2ff4121..cef0cb1 100644 --- a/src/db.c +++ b/src/db.c @@ -511,6 +511,16 @@ void destroy_db(void) free(world[cnt].description); free_extra_descriptions(world[cnt].ex_description); + if (world[cnt].events != NULL) { + if (world[cnt].events->iSize > 0) { + struct event * pEvent; + + while ((pEvent = simple_list(world[cnt].events)) != NULL) + event_cancel(pEvent); + } + free_list(world[cnt].events); + } + /* free any assigned scripts */ if (SCRIPT(&world[cnt])) extract_script(&world[cnt], WLD_TRIGGER); @@ -651,6 +661,7 @@ void boot_db(void) log("Initialize Global Lists"); global_lists = create_list(); + group_list = create_list(); log("Initializing Events"); init_events(); @@ -1724,7 +1735,6 @@ void parse_mobile(FILE *mob_f, int nr) /* Make some basic checks. */ REMOVE_BIT_AR(AFF_FLAGS(mob_proto + i), AFF_CHARM); REMOVE_BIT_AR(AFF_FLAGS(mob_proto + i), AFF_POISON); - REMOVE_BIT_AR(AFF_FLAGS(mob_proto + i), AFF_GROUP); REMOVE_BIT_AR(AFF_FLAGS(mob_proto + i), AFF_SLEEP); if (MOB_FLAGGED(mob_proto + i, MOB_AGGRESSIVE) && MOB_FLAGGED(mob_proto + i, MOB_AGGR_GOOD)) REMOVE_BIT_AR(MOB_FLAGS(mob_proto + i), MOB_AGGR_GOOD); @@ -2346,7 +2356,8 @@ struct char_data *create_char(void) void new_mobile_data(struct char_data *ch) { - ch->events = create_list(); + ch->events = NULL; + ch->group = NULL; } diff --git a/src/dg_mobcmd.c b/src/dg_mobcmd.c index b56e7a5..d8121f6 100644 --- a/src/dg_mobcmd.c +++ b/src/dg_mobcmd.c @@ -872,18 +872,18 @@ ACMD(do_mtransform) int keep_hp = 1; /* new mob keeps the old mob's hp/max hp/exp */ int pos; - if (!MOB_OR_IMPL(ch)) { - send_to_char(ch, "Huh?!?\r\n"); - return; - } + if (!MOB_OR_IMPL(ch)) { + send_to_char(ch, "Huh?!?\r\n"); + return; + } - if (AFF_FLAGGED(ch, AFF_CHARM)) - return; + if (AFF_FLAGGED(ch, AFF_CHARM)) + return; - if (ch->desc) { - send_to_char(ch, "You've got no VNUM to return to, dummy! try 'switch'\r\n"); - return; - } + if (ch->desc) { + send_to_char(ch, "You've got no VNUM to return to, dummy! try 'switch'\r\n"); + return; + } one_argument(argument, arg); @@ -935,11 +935,13 @@ ACMD(do_mtransform) tmpmob.proto_script = ch->proto_script; tmpmob.script = ch->script; tmpmob.memory = ch->memory; + tmpmob.events = ch->events; tmpmob.next_in_room = ch->next_in_room; tmpmob.next = ch->next; tmpmob.next_fighting = ch->next_fighting; tmpmob.followers = ch->followers; tmpmob.master = ch->master; + tmpmob.group = ch->group; GET_WAS_IN(&tmpmob) = GET_WAS_IN(ch); if (keep_hp) { diff --git a/src/fight.c b/src/fight.c index 68ba3df..61128cc 100644 --- a/src/fight.c +++ b/src/fight.c @@ -271,6 +271,10 @@ void raw_kill(struct char_data * ch, struct char_data * killer) if (killer) autoquest_trigger_check(killer, ch, NULL, AQ_MOB_KILL); + /* Alert Group if Applicable */ + if (GROUP(ch)) + send_to_group(ch, GROUP(ch), "%s has died.\r\n", GET_NAME(ch)); + update_pos(ch); make_corpse(ch); @@ -316,20 +320,11 @@ static void perform_group_gain(struct char_data *ch, int base, static void group_gain(struct char_data *ch, struct char_data *victim) { - int tot_members, base, tot_gain; + int tot_members = 0, base, tot_gain; struct char_data *k; - struct follow_type *f; - - if (!(k = ch->master)) - k = ch; - - if (AFF_FLAGGED(k, AFF_GROUP) && (IN_ROOM(k) == IN_ROOM(ch))) - tot_members = 1; - else - tot_members = 0; - - for (f = k->followers; f; f = f->next) - if (AFF_FLAGGED(f->follower, AFF_GROUP) && IN_ROOM(f->follower) == IN_ROOM(ch)) + + while ((k = (struct char_data *) simple_list(GROUP(ch)->members)) != NULL) + if (IN_ROOM(ch) == IN_ROOM(k)) tot_members++; /* round up to the nearest tot_members */ @@ -344,12 +339,9 @@ static void group_gain(struct char_data *ch, struct char_data *victim) else base = 0; - if (AFF_FLAGGED(k, AFF_GROUP) && IN_ROOM(k) == IN_ROOM(ch)) - perform_group_gain(k, base, victim); - - for (f = k->followers; f; f = f->next) - if (AFF_FLAGGED(f->follower, AFF_GROUP) && IN_ROOM(f->follower) == IN_ROOM(ch)) - perform_group_gain(f->follower, base, victim); + while ((k = (struct char_data *) simple_list(GROUP(ch)->members)) != NULL) + if (IN_ROOM(k) == IN_ROOM(ch)) + perform_group_gain(k, base, victim); } static void solo_gain(struct char_data *ch, struct char_data *victim) @@ -738,7 +730,7 @@ int damage(struct char_data *ch, struct char_data *victim, int dam, int attackty /* Uh oh. Victim died. */ if (GET_POS(victim) == POS_DEAD) { if (ch != victim && (IS_NPC(victim) || victim->desc)) { - if (AFF_FLAGGED(ch, AFF_GROUP)) + if (GROUP(ch)) group_gain(ch, victim); else solo_gain(ch, victim); @@ -762,7 +754,7 @@ int damage(struct char_data *ch, struct char_data *victim, int dam, int attackty } die(victim, ch); - if (IS_AFFECTED(ch, AFF_GROUP) && (local_gold > 0) && PRF_FLAGGED(ch, PRF_AUTOSPLIT) ) { + if (GROUP(ch) && (local_gold > 0) && PRF_FLAGGED(ch, PRF_AUTOSPLIT) ) { generic_find("corpse", FIND_OBJ_ROOM, ch, &tmp_char, &corpse_obj); if (corpse_obj) { do_get(ch, "all.coin corpse", 0, 0); @@ -905,8 +897,7 @@ void hit(struct char_data *ch, struct char_data *victim, int type) /* control the fights going on. Called every 2 seconds from comm.c. */ void perform_violence(void) { - struct char_data *ch; - struct follow_type *k; + struct char_data *ch, *tch; for (ch = combat_list; ch; ch = next_combat_list) { next_combat_list = ch->next_fighting; @@ -933,19 +924,25 @@ void perform_violence(void) continue; } - for (k = ch->followers; k; k=k->next) { - /* should followers auto-assist master? */ - if (!IS_NPC(k->follower) && !FIGHTING(k->follower) && PRF_FLAGGED(k->follower, - PRF_AUTOASSIST) && (IN_ROOM(k->follower) == IN_ROOM(ch))) - do_assist(k->follower, GET_NAME(ch), 0, 0); + if (GROUP(ch)) { + while ((tch = (struct char_data *) simple_list(GROUP(ch)->members)) != NULL) { + if (tch == ch) + continue; + if (!IS_NPC(tch) && !PRF_FLAGGED(tch, PRF_AUTOASSIST)) + continue; + if (IN_ROOM(ch) != IN_ROOM(tch)) + continue; + if (FIGHTING(tch)) + continue; + if (GET_POS(tch) != POS_STANDING) + continue; + if (!CAN_SEE(tch, ch)) + continue; + + do_assist(tch, GET_NAME(ch), 0, 0); + } } - /* should master auto-assist followers? */ - if (ch->master && PRF_FLAGGED(ch->master, PRF_AUTOASSIST) && - FIGHTING(ch) && !FIGHTING(ch->master) && !IS_NPC(ch) && - (IN_ROOM(ch->master) == IN_ROOM(ch)) && !IS_NPC(ch->master)) - do_assist(ch->master, GET_NAME(ch), 0, 0); - hit(ch, FIGHTING(ch), TYPE_UNDEFINED); if (MOB_FLAGGED(ch, MOB_SPEC) && GET_MOB_SPEC(ch) && !MOB_FLAGGED(ch, MOB_NOTDEADYET)) { char actbuf[MAX_INPUT_LENGTH] = ""; diff --git a/src/genwld.c b/src/genwld.c index 805a735..b970a78 100644 --- a/src/genwld.c +++ b/src/genwld.c @@ -17,6 +17,7 @@ #include "genzon.h" #include "shop.h" #include "dg_olc.h" +#include "mud_event.h" /* This function will copy the strings so be sure you free your own copies of @@ -167,6 +168,16 @@ int delete_room(room_rnum rnum) extract_script(room, WLD_TRIGGER); free_proto_script(room, WLD_TRIGGER); + if (room->events != NULL) { + if (room->events->iSize > 0) { + struct event * pEvent; + + while ((pEvent = simple_list(room->events)) != NULL) + event_cancel(pEvent); + } + free_list(room->events); + } + /* Change any exit going to this room to go the void. Also fix all the exits * pointing to rooms above this. */ i = top_of_world + 1; @@ -378,10 +389,12 @@ int copy_room(struct room_data *to, struct room_data *from) free_room_strings(to); *to = *from; copy_room_strings(to, from); + to->events = from->events; /* Don't put people and objects in two locations. Should this be done here? */ from->people = NULL; from->contents = NULL; + from->events = NULL; return TRUE; } diff --git a/src/genzon.c b/src/genzon.c index d7d81be..5bbaea9 100644 --- a/src/genzon.c +++ b/src/genzon.c @@ -74,6 +74,12 @@ zone_rnum create_new_zone(zone_vnum vzone_num, room_vnum bottom, room_vnum top, } else if (bottom > top) { *error = "Bottom room cannot be greater than top room.\r\n"; return NOWHERE; + } else if (bottom < 0) { + *error = "Bottom room cannot be less then 0.\r\n"; + return NOWHERE; + } else if (top >= IDXTYPE_MAX) { + *error = "Top greater than IDXTYPE_MAX. (Commonly 65535)\r\n"; + return NOWHERE; } for (i = 0; i < top_of_zone_table; i++) diff --git a/src/handler.c b/src/handler.c index 2dd793e..3d08fd9 100644 --- a/src/handler.c +++ b/src/handler.c @@ -15,6 +15,7 @@ #include "comm.h" #include "db.h" #include "handler.h" +#include "screen.h" #include "interpreter.h" #include "spells.h" #include "dg_scripts.h" @@ -22,6 +23,7 @@ #include "class.h" #include "fight.h" #include "quest.h" +#include "mud_event.h" /* local file scope variables */ static int extractions_pending = 0; @@ -910,6 +912,10 @@ void extract_char_final(struct char_data *ch) if (ch->followers || ch->master) die_follower(ch); + /* Check to see if we are grouped! */ + if (GROUP(ch)) + leave_group(ch); + /* transfer objects to room, if any */ while (ch->carrying) { obj = ch->carrying; @@ -1386,3 +1392,100 @@ int find_all_dots(char *arg) } else return (FIND_INDIV); } + +/* Group Handlers */ +struct group_data * create_group(struct char_data * leader) +{ + struct group_data * new_group; + + /* Allocate Group Memory & Attach to Group List*/ + CREATE(new_group, struct group_data, 1); + add_to_list(new_group, group_list); + + /* Allocate Members List */ + new_group->members = create_list(); + + /* Clear Data */ + new_group->group_flags = 0; + + /* Assign Data */ + SET_BIT(GROUP_FLAGS(new_group), GROUP_OPEN); + + if (IS_NPC(leader)) + SET_BIT(GROUP_FLAGS(new_group), GROUP_NPC); + + join_group(leader, new_group); + + return (new_group); +} + +void free_group(struct group_data * group) +{ + struct char_data *tch; + struct iterator_data Iterator; + + if (group->members->iSize) { + for (tch = (struct char_data *) merge_iterator(&Iterator, group->members); + tch; + tch = next_in_list(&Iterator)) + leave_group(tch); + + remove_iterator(&Iterator); + } + + free_list(group->members); + remove_from_list(group, group_list); + free(group); +} + +void leave_group(struct char_data *ch) +{ + struct group_data *group; + struct char_data *tch; + struct iterator_data Iterator; + bool found_pc = FALSE; + + if ((group = ch->group) == NULL) + return; + + send_to_group(NULL, group, "%s has left the group.\r\n", GET_NAME(ch)); + + remove_from_list(ch, group->members); + ch->group = NULL; + + if (group->members->iSize) { + for (tch = (struct char_data *) merge_iterator(&Iterator, group->members); + tch; tch = next_in_list(&Iterator)) + if (!IS_NPC(tch)) + found_pc = TRUE; + + remove_iterator(&Iterator); + } + + if (!found_pc) + SET_BIT(GROUP_FLAGS(group), GROUP_NPC); + + if (GROUP_LEADER(group) == ch && group->members->iSize) { + group->leader = (struct char_data *) random_from_list(group->members); + send_to_group(NULL, group, "%s has assumed leadership of the group.\r\n", GET_NAME(GROUP_LEADER(group))); + } else if (group->members->iSize == 0) + free_group(group); +} + +void join_group(struct char_data *ch, struct group_data *group) +{ + add_to_list(ch, group->members); + + if (group->leader == NULL) + group->leader = ch; + + ch->group = group; + + if (IS_SET(group->group_flags, GROUP_NPC) && !IS_NPC(ch)) + REMOVE_BIT(GROUP_FLAGS(group), GROUP_NPC); + + if (group->leader == ch) + send_to_group(NULL, group, "%s becomes leader of the group.\r\n", GET_NAME(ch)); + else + send_to_group(NULL, group, "%s joins the group.\r\n", GET_NAME(ch)); +} diff --git a/src/handler.h b/src/handler.h index da14948..288d8cc 100644 --- a/src/handler.h +++ b/src/handler.h @@ -77,6 +77,11 @@ int find_all_dots(char *arg); #define FIND_ALL 1 #define FIND_ALLDOT 2 +/* group */ +struct group_data * create_group(struct char_data * leader); +void free_group(struct group_data * group); +void leave_group(struct char_data *ch); +void join_group(struct char_data *ch, struct group_data *group); /* Generic Find */ int generic_find(char *arg, bitvector_t bitvector, struct char_data *ch, diff --git a/src/interpreter.c b/src/interpreter.c index e31c87d..9f04142 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -323,7 +323,6 @@ cpp_extern const struct command_info cmd_info[] = { { "tstat" , "tstat" , POS_DEAD , do_tstat , LVL_BUILDER, 0 }, { "unlock" , "unlock" , POS_SITTING , do_gen_door , 0, SCMD_UNLOCK }, - { "ungroup" , "ungroup" , POS_DEAD , do_ungroup , 0, 0 }, { "unban" , "unban" , POS_DEAD , do_unban , LVL_GRGOD, 0 }, { "unaffect" , "unaffect", POS_DEAD , do_wizutil , LVL_GOD, SCMD_UNAFFECT }, { "uptime" , "uptime" , POS_DEAD , do_date , LVL_GOD, SCMD_UPTIME }, @@ -1140,7 +1139,6 @@ static int perform_dupe_check(struct descriptor_data *d) d->character->char_specials.timer = 0; REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_MAILING); REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_WRITING); - REMOVE_BIT_AR(AFF_FLAGS(d->character), AFF_GROUP); STATE(d) = CON_PLAYING; MXPSendTag( d, "" ); @@ -1416,7 +1414,6 @@ void nanny(struct descriptor_data *d, char *arg) REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_WRITING); REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_MAILING); REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_CRYO); - REMOVE_BIT_AR(AFF_FLAGS(d->character), AFF_GROUP); d->character->player.time.logon = time(0); write_to_output(d, "Password: "); echo_off(d); diff --git a/src/lists.c b/src/lists.c index d449e9a..8d3231c 100644 --- a/src/lists.c +++ b/src/lists.c @@ -12,8 +12,13 @@ #include "db.h" #include "dg_event.h" +static struct iterator_data Iterator; +static bool loop = FALSE; +static struct list_data *pLastList = NULL; + /* Global lists */ struct list_data * global_lists = NULL; +struct list_data * group_list = NULL; struct list_data * create_list(void) { @@ -53,7 +58,7 @@ void free_list(struct list_data * pList) { void * pContent; - simple_list(NULL); + clear_simple_list(); if (pList->iSize) while ((pContent = simple_list(pList))) @@ -225,6 +230,12 @@ struct item_data * find_in_list(void * pContent, struct list_data * pList) return NULL; } +void clear_simple_list(void) +{ + loop = FALSE; + pLastList = NULL; +} + /** This is the "For Dummies" function, as although it's not as flexible, * it is even easier applied for list searches then using your own iterators * and next_in_list() @@ -239,15 +250,11 @@ struct item_data * find_in_list(void * pContent, struct list_data * pList) void * simple_list(struct list_data * pList) { - static struct iterator_data Iterator; - static bool loop = FALSE; - static struct list_data *pLastList = NULL; void * pContent; /* Reset List */ if (pList == NULL) { - loop = FALSE; - pLastList = NULL; + clear_simple_list(); return NULL; } diff --git a/src/lists.h b/src/lists.h index e85f2f7..1afd0c0 100644 --- a/src/lists.h +++ b/src/lists.h @@ -33,6 +33,7 @@ struct iterator_data { /* Externals */ extern struct list_data * global_lists; +extern struct list_data * group_list; /* Locals */ void add_to_list(void * pContent, struct list_data * pList); @@ -46,4 +47,5 @@ void remove_from_list(void * pContent, struct list_data * pList); struct item_data * find_in_list(void * pContent, struct list_data * pList); void * simple_list(struct list_data * pList); void free_list(struct list_data * pList); +void clear_simple_list(void); #endif diff --git a/src/magic.c b/src/magic.c index 872c0c9..faca3ee 100644 --- a/src/magic.c +++ b/src/magic.c @@ -21,6 +21,7 @@ #include "dg_scripts.h" #include "class.h" #include "fight.h" +#include "mud_event.h" /* local file scope function prototypes */ @@ -574,35 +575,22 @@ static void perform_mag_groups(int level, struct char_data *ch, * Just add a new case to perform_mag_groups. */ void mag_groups(int level, struct char_data *ch, int spellnum, int savetype) { - struct char_data *tch, *k; - struct follow_type *f, *f_next; + struct char_data *tch; if (ch == NULL) return; - if (!AFF_FLAGGED(ch, AFF_GROUP)) + if (!GROUP(ch)) return; - if (ch->master != NULL) - k = ch->master; - else - k = ch; - for (f = k->followers; f; f = f_next) { - f_next = f->next; - tch = f->follower; + + while ((tch = (struct char_data *) simple_list(GROUP(ch)->members)) != NULL) { if (IN_ROOM(tch) != IN_ROOM(ch)) continue; - if (!AFF_FLAGGED(tch, AFF_GROUP)) - continue; - if (ch == tch) - continue; perform_mag_groups(level, ch, tch, spellnum, savetype); } - - if ((k != ch) && AFF_FLAGGED(k, AFF_GROUP)) - perform_mag_groups(level, ch, k, spellnum, savetype); - perform_mag_groups(level, ch, ch, spellnum, savetype); } + /* Mass spells affect every creature in the room except the caster. No spells * of this class currently implemented. */ void mag_masses(int level, struct char_data *ch, int spellnum, int savetype) @@ -663,8 +651,7 @@ void mag_areas(int level, struct char_data *ch, int spellnum, int savetype) continue; if (!IS_NPC(ch) && IS_NPC(tch) && AFF_FLAGGED(tch, AFF_CHARM)) continue; - if (!IS_NPC(tch) && spell_info[spellnum].violent && AFF_FLAGGED(tch, AFF_GROUP) && AFF_FLAGGED(ch, AFF_GROUP) && - ( ((ch->master == NULL) ? ch : ch->master) == ((tch->master == NULL) ? tch : tch->master) ) ) + if (!IS_NPC(tch) && spell_info[spellnum].violent && GROUP(tch) && GROUP(ch) && GROUP(ch) == GROUP(tch)) continue; if ((spellnum == SPELL_EARTHQUAKE) && AFF_FLAGGED(tch, AFF_FLYING)) continue; @@ -784,6 +771,9 @@ void mag_summons(int level, struct char_data *ch, struct obj_data *obj, act(mag_summon_msgs[msg], FALSE, ch, 0, mob, TO_ROOM); load_mtrigger(mob); add_follower(mob, ch); + + if (GROUP(ch) && GROUP_LEADER(GROUP(ch)) == ch) + join_group(mob, GROUP(ch)); } if (handle_corpse) { for (tobj = obj->contains; tobj; tobj = next_obj) { @@ -976,3 +966,42 @@ void mag_creations(int level, struct char_data *ch, int spellnum) load_otrigger(tobj); } +void mag_rooms(int level, struct char_data *ch, int spellnum) +{ + room_rnum rnum; + int duration; + bool failure = FALSE; + event_id IdNum = -1; + const char *msg = NULL; + const char *room = NULL; + + rnum = IN_ROOM(ch); + + if (ROOM_FLAGGED(rnum, ROOM_NOMAGIC)) + failure = TRUE; + + switch (spellnum) { + case SPELL_DARKNESS: + IdNum = eSPL_DARKNESS; + if (ROOM_FLAGGED(rnum, ROOM_DARK)) + failure = TRUE; + + duration = 5; + SET_BIT_AR(ROOM_FLAGS(rnum), ROOM_DARK); + + msg = "You cast a shroud of darkness upon the area."; + room = "$n casts a shroud of darkness upon this area."; + break; + + } + + if (failure || IdNum == -1) { + send_to_char(ch, "You failed!\r\n"); + return; + } + + send_to_char(ch, "%s\r\n", msg); + act(room, FALSE, ch, 0, 0, TO_ROOM); + + NEW_EVENT(eSPL_DARKNESS, &world[rnum], NULL, duration * PASSES_PER_SEC); +} diff --git a/src/medit.c b/src/medit.c index 79f1da2..91123f0 100644 --- a/src/medit.c +++ b/src/medit.c @@ -901,7 +901,6 @@ void medit_parse(struct descriptor_data *d, char *arg) /* Remove unwanted bits right away. */ REMOVE_BIT_AR(AFF_FLAGS(OLC_MOB(d)), AFF_CHARM); REMOVE_BIT_AR(AFF_FLAGS(OLC_MOB(d)), AFF_POISON); - REMOVE_BIT_AR(AFF_FLAGS(OLC_MOB(d)), AFF_GROUP); REMOVE_BIT_AR(AFF_FLAGS(OLC_MOB(d)), AFF_SLEEP); medit_disp_aff_flags(d); return; diff --git a/src/mobact.c b/src/mobact.c index 3214ad1..1696cdd 100644 --- a/src/mobact.c +++ b/src/mobact.c @@ -156,6 +156,8 @@ void mobile_activity(void) { if (ch == vict || !IS_NPC(vict) || !FIGHTING(vict)) continue; + if (GROUP(vict) && GROUP(vict) == GROUP(ch)) + continue; if (IS_NPC(FIGHTING(vict)) || ch == FIGHTING(vict)) continue; diff --git a/src/mud_event.c b/src/mud_event.c index 178291f..c646e01 100644 --- a/src/mud_event.c +++ b/src/mud_event.c @@ -23,7 +23,8 @@ struct list_data * world_events = NULL; struct mud_event_list mud_event_index[] = { { "Null" , NULL , -1 }, /* eNULL */ { "Protocol" , get_protocols , EVENT_DESC }, /* ePROTOCOLS */ - { "Whirlwind" , event_whirlwind, EVENT_CHAR } /* eWHIRLWIND */ + { "Whirlwind" , event_whirlwind, EVENT_CHAR }, /* eWHIRLWIND */ + { "Spell:Darkness",event_countdown, EVENT_ROOM } /* eSPL_DARKNESS */ }; /* init_events() is the ideal function for starting global events. This @@ -54,6 +55,8 @@ EVENTFUNC(event_countdown) { struct mud_event_data * pMudEvent; struct char_data * ch = NULL; + struct room_data * room = NULL; + room_rnum rnum = NOWHERE; pMudEvent = (struct mud_event_data * ) event_obj; @@ -61,11 +64,19 @@ EVENTFUNC(event_countdown) case EVENT_CHAR: ch = (struct char_data * ) pMudEvent->pStruct; break; + case EVENT_ROOM: + room = (struct room_data * ) pMudEvent->pStruct; + rnum = real_room(room->number); + break; default: break; } switch (pMudEvent->iId) { + case eSPL_DARKNESS: + REMOVE_BIT_AR(ROOM_FLAGS(rnum), ROOM_DARK); + send_to_room(rnum, "The dark shroud disappates.\r\n"); + break; default: break; } @@ -82,6 +93,7 @@ void attach_mud_event(struct mud_event_data *pMudEvent, long time) struct event * pEvent; struct descriptor_data * d; struct char_data * ch; + struct room_data * room; pEvent = event_create(mud_event_index[pMudEvent->iId].func, pMudEvent, time); pEvent->isMudEvent = TRUE; @@ -97,8 +109,20 @@ void attach_mud_event(struct mud_event_data *pMudEvent, long time) break; case EVENT_CHAR: ch = (struct char_data *) pMudEvent->pStruct; + + if (ch->events == NULL) + ch->events = create_list(); + add_to_list(pEvent, ch->events); break; + case EVENT_ROOM: + room = (struct room_data *) pMudEvent->pStruct; + + if (room->events == NULL) + room->events = create_list(); + + add_to_list(pEvent, room->events); + break; } } @@ -122,6 +146,7 @@ void free_mud_event(struct mud_event_data *pMudEvent) { struct descriptor_data * d; struct char_data * ch; + struct room_data * room; switch (mud_event_index[pMudEvent->iId].iEvent_Type) { case EVENT_WORLD: @@ -134,6 +159,20 @@ void free_mud_event(struct mud_event_data *pMudEvent) case EVENT_CHAR: ch = (struct char_data *) pMudEvent->pStruct; remove_from_list(pMudEvent->pEvent, ch->events); + + if (ch->events->iSize == 0) { + free_list(ch->events); + ch->events = NULL; + } + break; + case EVENT_ROOM: + room = (struct room_data *) pMudEvent->pStruct; + remove_from_list(pMudEvent->pEvent, room->events); + + if (room->events->iSize == 0) { + free_list(room->events); + room->events = NULL; + } break; } @@ -150,10 +189,13 @@ 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 == NULL) + return NULL; + if (ch->events->iSize == 0) return NULL; - simple_list(NULL); + clear_simple_list(); while ((pEvent = (struct event *) simple_list(ch->events)) != NULL) { if (!pEvent->isMudEvent) @@ -164,9 +206,7 @@ struct mud_event_data * char_has_mud_event(struct char_data * ch, event_id iId) break; } } - - simple_list(NULL); - + if (found) return (pMudEvent); @@ -183,11 +223,46 @@ void clear_char_event_list(struct char_data * ch) if (ch->events->iSize == 0) return; - simple_list(NULL); + clear_simple_list(); while ((pEvent = (struct event *) simple_list(ch->events)) != NULL) { event_cancel(pEvent); - } - - simple_list(NULL); + } } + +/* change_event_duration contributed by Ripley */ +void change_event_duration(struct char_data * ch, event_id iId, long time) { + + struct event * pEvent; + struct mud_event_data * pMudEvent; + bool found = FALSE; + + if (ch->events == NULL); + return; + + if (ch->events->iSize == 0) + return; + + clear_simple_list(); + + while ((pEvent = (struct event *) simple_list(ch->events)) != NULL) { + + if (!pEvent->isMudEvent) + continue; + + pMudEvent = (struct mud_event_data * ) pEvent->event_obj; + + if (pMudEvent->iId == iId) { + found = TRUE; + break; + } + } + + if (found) { + /* So we found the offending event, now build a new one, with the new time */ + attach_mud_event(new_mud_event(iId, pMudEvent->pStruct, pMudEvent->sVariables), time); + event_cancel(pEvent); + } + +} + diff --git a/src/mud_event.h b/src/mud_event.h index 682b810..dc6feb9 100644 --- a/src/mud_event.h +++ b/src/mud_event.h @@ -18,6 +18,7 @@ #define EVENT_WORLD 0 #define EVENT_DESC 1 #define EVENT_CHAR 2 +#define EVENT_ROOM 3 #define NEW_EVENT(event_id, struct, var, time) (attach_mud_event(new_mud_event(event_id, struct, var), time)) @@ -25,6 +26,7 @@ typedef enum { eNULL, ePROTOCOLS, /* The Protocol Detection Event */ eWHIRLWIND, /* The Whirlwind Attack */ + eSPL_DARKNESS, /* Darkness Spell */ } event_id; struct mud_event_list { diff --git a/src/objsave.c b/src/objsave.c index bba2658..10d7b96 100644 --- a/src/objsave.c +++ b/src/objsave.c @@ -1026,11 +1026,15 @@ obj_save_data *objsave_parse_objects(FILE *fl) if (*line == '#') { /* check for false alarm. */ if (sscanf(line, "#%d", &nr) == 1) { - /* Do not save an object if it has been deleted */ - if (real_object(nr) == NOTHING) { - log("SYSERR: Protection: deleting object %d.", nr); + /* If we attempt to load an object with a legal VNUM 0-65534, that + * does not exist, skip it. If the object has a VNUM of NOTHING or + * 65535, then we assume it doesn't exist on purpose. (Custom Item, + * Coins, Corpse, etc...) */ + if (real_object(nr) == NOTHING && nr != NOTHING) { + log("SYSERR: Prevented loading of non-existant item #%d.", nr); continue; } + if (temp) { current->obj = temp; CREATE(current->next, obj_save_data, 1); @@ -1060,12 +1064,11 @@ obj_save_data *objsave_parse_objects(FILE *fl) continue; } - /* Should never get here, but since we did in the past, I'll put - * a safety check in. */ - if (temp == NULL) { - log("SYSERR: Attempting to parse obj_save_data on NULL object."); - abort(); - } + /* If "temp" is NULL, we are most likely progressing through + * a non-existant object, so just keep continuing till we find + * the next object */ + if (temp == NULL) + continue; tag_argument(line, tag); num = atoi(line); diff --git a/src/redit.c b/src/redit.c index 1cdf2b4..ce8e25d 100644 --- a/src/redit.c +++ b/src/redit.c @@ -177,6 +177,9 @@ void redit_setup_existing(struct descriptor_data *d, int real_num) /* and you are your next_in_room -- anderyu (10-05-22) */ room->people = NULL; + /* Nullify the events structure. */ + room->events = NULL; + /* Allocate space for all strings. */ room->name = str_udup(world[real_num].name); room->description = str_udup(world[real_num].description); diff --git a/src/spell_parser.c b/src/spell_parser.c index 374bfb3..695989a 100644 --- a/src/spell_parser.c +++ b/src/spell_parser.c @@ -263,6 +263,9 @@ int call_magic(struct char_data *caster, struct char_data *cvict, if (IS_SET(SINFO.routines, MAG_CREATIONS)) mag_creations(level, caster, spellnum); + if (IS_SET(SINFO.routines, MAG_ROOMS)) + mag_rooms(level, caster, spellnum); + if (IS_SET(SINFO.routines, MAG_MANUAL)) switch (spellnum) { case SPELL_CHARM: MANUAL_SPELL(spell_charm); break; @@ -473,7 +476,7 @@ int cast_spell(struct char_data *ch, struct char_data *tch, send_to_char(ch, "You cannot cast this spell upon yourself!\r\n"); return (0); } - if (IS_SET(SINFO.routines, MAG_GROUPS) && !AFF_FLAGGED(ch, AFF_GROUP)) { + if (IS_SET(SINFO.routines, MAG_GROUPS) && !GROUP(ch)) { send_to_char(ch, "You can't cast this spell if you're not in a group!\r\n"); return (0); } @@ -789,6 +792,10 @@ void mag_assign_spells(void) TAR_CHAR_ROOM | TAR_OBJ_INV, TRUE, MAG_AFFECTS | MAG_ALTER_OBJS, "You feel more optimistic."); + spello(SPELL_DARKNESS, "darkness", 30, 5, 4, POS_STANDING, + TAR_IGNORE, FALSE, MAG_ROOMS, + NULL); + spello(SPELL_DETECT_ALIGN, "detect alignment", 20, 10, 2, POS_STANDING, TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "You feel less aware."); diff --git a/src/spells.h b/src/spells.h index 09142b8..c88c554 100644 --- a/src/spells.h +++ b/src/spells.h @@ -33,6 +33,7 @@ #define MAG_SUMMONS (1 << 8) #define MAG_CREATIONS (1 << 9) #define MAG_MANUAL (1 << 10) +#define MAG_ROOMS (1 << 11) #define TYPE_UNDEFINED (-1) #define SPELL_RESERVED_DBC 0 /* SKILL NUMBER ZERO -- RESERVED */ @@ -91,8 +92,9 @@ #define SPELL_WATERWALK 51 /* Reserved Skill[] DO NOT CHANGE */ #define SPELL_IDENTIFY 52 /* Reserved Skill[] DO NOT CHANGE */ #define SPELL_FLY 53 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_DARKNESS 54 /** Total Number of defined spells */ -#define NUM_SPELLS 53 +#define NUM_SPELLS 54 /* Insert new spells here, up to MAX_SPELLS */ #define MAX_SPELLS 130 @@ -241,6 +243,8 @@ void mag_masses(int level, struct char_data *ch, int spellnum, int savetype); void mag_areas(int level, struct char_data *ch, int spellnum, int savetype); +void mag_rooms(int level, struct char_data *ch, int spellnum); + void mag_summons(int level, struct char_data *ch, struct obj_data *obj, int spellnum, int savetype); diff --git a/src/structs.h b/src/structs.h index 03759e9..7902ca6 100644 --- a/src/structs.h +++ b/src/structs.h @@ -148,6 +148,11 @@ #define HISTORY_SIZE 5 /**< Number of last commands kept in each history */ +/* Group Defines */ +#define GROUP_OPEN (1 << 0) /**< Group is open for members */ +#define GROUP_ANON (1 << 1) /**< Group is Anonymous */ +#define GROUP_NPC (1 << 2) /**< Group created by NPC and thus not listed */ + /* PC classes */ #define CLASS_UNDEFINED (-1) /**< PC Class undefined */ #define CLASS_MAGIC_USER 0 /**< PC Class Magic User */ @@ -280,7 +285,7 @@ #define AFF_SENSE_LIFE 6 /**< Char can sense hidden life */ #define AFF_WATERWALK 7 /**< Char can walk on water */ #define AFF_SANCTUARY 8 /**< Char protected by sanct */ -#define AFF_GROUP 9 /**< (R) Char is grouped */ +#define AFF_UNUSED 9 /**< (R) Char is grouped */ #define AFF_CURSE 10 /**< Char is cursed */ #define AFF_INFRAVISION 11 /**< Char can see in dark */ #define AFF_POISON 12 /**< (R) Char is poisoned */ @@ -804,6 +809,8 @@ struct room_data struct script_data *script; /**< script info for the room */ struct obj_data *contents; /**< List of items in room */ struct char_data *people; /**< List of NPCs / PCs in room */ + + struct list_data * events; }; /* char-related structures */ @@ -835,6 +842,15 @@ struct time_data int played; /**< This is the total accumulated time played in secs */ }; +/* Group Data Struct */ +struct group_data +{ + struct char_data * leader; + struct list_data * members; + int group_flags; +}; + + /** The pclean_criteria_data is set up in config.c and used in db.c to determine * the conditions which will cause a player character to be deleted from disk * if the automagic pwipe system is enabled (see config.c). */ @@ -1035,6 +1051,8 @@ struct char_data struct follow_type *followers; /**< List of characters following */ struct char_data *master; /**< List of character being followed */ + struct group_data *group; /**< Character's Group */ + long pref; /**< unique session id */ struct list_data * events; diff --git a/src/utils.c b/src/utils.c index 8d93523..c0b8594 100644 --- a/src/utils.c +++ b/src/utils.c @@ -573,7 +573,6 @@ void stop_follower(struct char_data *ch) ch->master = NULL; REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_CHARM); - REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_GROUP); } /** Finds the number of follows that are following, and charmed by, the diff --git a/src/utils.h b/src/utils.h index 6dd2af2..8703a42 100644 --- a/src/utils.h +++ b/src/utils.h @@ -867,6 +867,11 @@ do \ /** Defines if ch is outdoors or not. */ #define OUTSIDE(ch) (!ROOM_FLAGGED(IN_ROOM(ch), ROOM_INDOORS)) +/* Group related defines */ +#define GROUP(ch) (ch->group) +#define GROUP_LEADER(group) (group->leader) +#define GROUP_FLAGS(group) (group->group_flags) + /* Happy-hour defines */ #define IS_HAPPYQP (happy_data.qp_rate > 0) #define IS_HAPPYEXP (happy_data.exp_rate > 0)