/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik Strfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * **************************************************************************/ /*************************************************************************** * ROM 2.4 is copyright 1993-1998 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@hypercube.org) * * Gabrielle Taylor (gtaylor@hypercube.org) * * Brian Moore (zump@rom.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * **************************************************************************/ /* JH 3/22/2004 11:25PM * * Party.c: Group and party code. Includes following, gold splitting, * * grouping, etc. Mainly from act_comm.c * */ #if defined(macintosh) #include <types.h> #else #include <sys/types.h> #include <sys/time.h> #endif #include <cstdio> #include <cstring> #include <cstdlib> #include <ctime> #include "merc.h" #include "interp.h" #include "recycle.h" #include "tables.h" void do_follow (CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; one_argument (argument, arg); if (arg[0] == '\0') { send_to_char ("Follow whom?\n\r", ch); return; } if ((victim = get_char_room (ch, NULL, arg)) == NULL) { send_to_char ("They aren't here.\n\r", ch); return; } if (IS_AFFECTED (ch, AFF_CHARM) && ch->master != NULL) { act ("But you'd rather follow $N!", ch, NULL, ch->master, TO_CHAR); return; } if (victim == ch) { if (ch->master == NULL) { send_to_char ("You already follow yourself.\n\r", ch); return; } stop_follower (ch); return; } if (!IS_NPC (victim) && IS_SET (victim->act, PLR_NOFOLLOW) && !IS_IMMORTAL (ch)) { act ("$N doesn't seem to want any followers.\n\r", ch, NULL, victim, TO_CHAR); return; } REMOVE_BIT (ch->act, PLR_NOFOLLOW); if (ch->master != NULL) stop_follower (ch); add_follower (ch, victim); return; } void add_follower (CHAR_DATA * ch, CHAR_DATA * master) { if (ch->master != NULL) { bug ("Add_follower: non-null master.", 0); return; } ch->master = master; ch->leader = NULL; if (can_see (master, ch)) act ("$n now follows you.", ch, NULL, master, TO_VICT); act ("You now follow $N.", ch, NULL, master, TO_CHAR); return; } void stop_follower (CHAR_DATA * ch) { if (ch->master == NULL) { bug ("Stop_follower: null master.", 0); return; } if (IS_AFFECTED (ch, AFF_CHARM)) { STR_REMOVE_BIT (ch->affected_by, AFF_CHARM); affect_strip (ch, gsn_dummy); } if (can_see (ch->master, ch) && ch->in_room != NULL) { act ("$n stops following you.", ch, NULL, ch->master, TO_VICT); act ("You stop following $N.", ch, NULL, ch->master, TO_CHAR); } if (ch->master->pet == ch) ch->master->pet = NULL; ch->master = NULL; ch->leader = NULL; return; } /* nukes charmed monsters and pets */ void nuke_pets (CHAR_DATA * ch) { CHAR_DATA *pet; if ((pet = ch->pet) != NULL) { stop_follower (pet); if (pet->in_room != NULL) act ("$N slowly fades away.", ch, NULL, pet, TO_NOTVICT); extract_char (pet, TRUE); } ch->pet = NULL; return; } void die_follower (CHAR_DATA * ch) { CHAR_DATA *fch; if (ch->master != NULL) { if (ch->master->pet == ch) ch->master->pet = NULL; stop_follower (ch); } ch->leader = NULL; for (fch = char_list; fch != NULL; fch = fch->next) { if (fch->master == ch) stop_follower (fch); if (fch->leader == ch) fch->leader = fch; } return; } void do_order (CHAR_DATA * ch, char *argument) { char buf[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; CHAR_DATA *victim; CHAR_DATA *och; CHAR_DATA *och_next; bool found; bool fAll; argument = one_argument (argument, arg); one_argument (argument, arg2); if (!str_cmp (arg2, "delete") || !str_cmp (arg2, "mob")) { send_to_char ("That will NOT be done.\n\r", ch); return; } if (arg[0] == '\0' || argument[0] == '\0') { send_to_char ("Order whom to do what?\n\r", ch); return; } if (IS_AFFECTED (ch, AFF_CHARM)) { send_to_char ("You feel like taking, not giving, orders.\n\r", ch); return; } if (!str_cmp (arg, "all")) { fAll = TRUE; victim = NULL; } else { fAll = FALSE; if ((victim = get_char_room (ch, NULL, arg)) == NULL) { send_to_char ("They aren't here.\n\r", ch); return; } if (victim == ch) { send_to_char ("Aye aye, right away!\n\r", ch); return; } if (!IS_AFFECTED (victim, AFF_CHARM) || victim->master != ch || (IS_IMMORTAL (victim) && victim->trust >= ch->trust)) { send_to_char ("Do it yourself!\n\r", ch); return; } } found = FALSE; for (och = ch->in_room->people; och != NULL; och = och_next) { och_next = och->next_in_room; if (IS_AFFECTED (och, AFF_CHARM) && och->master == ch && (fAll || och == victim)) { found = TRUE; sprintf (buf, "$n orders you to '%s'.", argument); act (buf, ch, NULL, och, TO_VICT); interpret (och, argument); } } if (found) { WAIT_STATE (ch, PULSE_VIOLENCE); send_to_char ("Ok.\n\r", ch); } else send_to_char ("You have no followers here.\n\r", ch); return; } void do_group (CHAR_DATA * ch, char *argument) { char buf[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; one_argument (argument, arg); if (arg[0] == '\0') { CHAR_DATA *gch; CHAR_DATA *leader; leader = (ch->leader != NULL) ? ch->leader : ch; sprintf (buf, "%s's group:\n\r", PERS (leader, ch)); send_to_char (buf, ch); for (gch = char_list; gch != NULL; gch = gch->next) { if (is_same_group (gch, ch)) { sprintf (buf, "[Lvl %2d] %-16s %4d/%4d hp %4d/%4d mv %5d xp\n\r", gch->level, capitalize (PERS (gch, ch)), gch->hit, gch->max_hit, gch->move, gch->max_move, gch->exp); send_to_char (buf, ch); } } return; } if ((victim = get_char_room (ch, NULL, arg)) == NULL) { send_to_char ("They aren't here.\n\r", ch); return; } if (ch->master != NULL || (ch->leader != NULL && ch->leader != ch)) { send_to_char ("But you are following someone else!\n\r", ch); return; } if (victim->master != ch && ch != victim) { act_new ("$N isn't following you.", ch, NULL, victim, TO_CHAR, POS_SLEEPING); return; } if (IS_AFFECTED (victim, AFF_CHARM)) { send_to_char ("You can't remove charmed mobs from your group.\n\r", ch); return; } if (IS_AFFECTED (ch, AFF_CHARM)) { act_new ("You like your master too much to leave $m!", ch, NULL, victim, TO_VICT, POS_SLEEPING); return; } if (is_same_group (victim, ch) && ch != victim) { victim->leader = NULL; act_new ("$n removes $N from $s group.", ch, NULL, victim, TO_NOTVICT, POS_RESTING); act_new ("$n removes you from $s group.", ch, NULL, victim, TO_VICT, POS_SLEEPING); act_new ("You remove $N from your group.", ch, NULL, victim, TO_CHAR, POS_SLEEPING); return; } victim->leader = ch; act_new ("$N joins $n's group.", ch, NULL, victim, TO_NOTVICT, POS_RESTING); act_new ("You join $n's group.", ch, NULL, victim, TO_VICT, POS_SLEEPING); act_new ("$N joins your group.", ch, NULL, victim, TO_CHAR, POS_SLEEPING); return; } /* * 'Split' originally by Gnort, God of Chaos. */ void do_split (CHAR_DATA * ch, char *argument) { char buf[MAX_STRING_LENGTH]; char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; CHAR_DATA *gch; int members; int amount_gold = 0, amount_silver = 0; int share_gold, share_silver; int extra_gold, extra_silver; argument = one_argument (argument, arg1); one_argument (argument, arg2); if (arg1[0] == '\0') { send_to_char ("Split how much?\n\r", ch); return; } amount_silver = atoi (arg1); if (arg2[0] != '\0') amount_gold = atoi (arg2); if (amount_gold < 0 || amount_silver < 0) { send_to_char ("Your group wouldn't like that.\n\r", ch); return; } if (amount_gold == 0 && amount_silver == 0) { send_to_char ("You hand out zero coins, but no one notices.\n\r", ch); return; } if (ch->gold < amount_gold || ch->silver < amount_silver) { send_to_char ("You don't have that much to split.\n\r", ch); return; } members = 0; for (gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room) { if (is_same_group (gch, ch) && !IS_AFFECTED (gch, AFF_CHARM)) members++; } if (members < 2) { send_to_char ("Just keep it all.\n\r", ch); return; } share_silver = amount_silver / members; extra_silver = amount_silver % members; share_gold = amount_gold / members; extra_gold = amount_gold % members; if (share_gold == 0 && share_silver == 0) { send_to_char ("Don't even bother, cheapskate.\n\r", ch); return; } ch->silver -= amount_silver; ch->silver += share_silver + extra_silver; ch->gold -= amount_gold; ch->gold += share_gold + extra_gold; if (share_silver > 0) { sprintf (buf, "You split %d silver coins. Your share is %d silver.\n\r", amount_silver, share_silver + extra_silver); send_to_char (buf, ch); } if (share_gold > 0) { sprintf (buf, "You split %d gold coins. Your share is %d gold.\n\r", amount_gold, share_gold + extra_gold); send_to_char (buf, ch); } if (share_gold == 0) { sprintf (buf, "$n splits %d silver coins. Your share is %d silver.", amount_silver, share_silver); } else if (share_silver == 0) { sprintf (buf, "$n splits %d gold coins. Your share is %d gold.", amount_gold, share_gold); } else { sprintf (buf, "$n splits %d silver and %d gold coins, giving you %d silver and %d gold.\n\r", amount_silver, amount_gold, share_silver, share_gold); } for (gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room) { if (gch != ch && is_same_group (gch, ch) && !IS_AFFECTED (gch, AFF_CHARM)) { act (buf, ch, NULL, gch, TO_VICT); gch->gold += share_gold; gch->silver += share_silver; } } return; } void do_gtell (CHAR_DATA * ch, char *argument) { CHAR_DATA *gch; if (argument[0] == '\0') { send_to_char ("Tell your group what?\n\r", ch); return; } if (IS_SET (ch->comm, COMM_NOTELL)) { send_to_char ("Your message didn't get through!\n\r", ch); return; } for (gch = char_list; gch != NULL; gch = gch->next) { if (is_same_group (gch, ch)) act_new ("{N$n tells the group '{n$t{N'{x", ch, argument, gch, TO_VICT, POS_SLEEPING); } act ("{NYou tell the group '{n$t{N'{x", ch, argument, gch, TO_CHAR); return; } /* * It is very important that this be an equivalence relation: * (1) A ~ A * (2) if A ~ B then B ~ A * (3) if A ~ B and B ~ C, then A ~ C */ bool is_same_group (CHAR_DATA * ach, CHAR_DATA * bch) { if (ach == NULL || bch == NULL) return FALSE; if (ach->leader != NULL) ach = ach->leader; if (bch->leader != NULL) bch = bch->leader; return ach == bch; }