/* * This file is part of Deliantra, the Roguelike Realtime MMORPG. * * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * Copyright (©) 2002 Mark Wedel & Crossfire Development Team * Copyright (©) 1992 Frank Tore Johansen * * Deliantra is free software: you can redistribute it and/or modify it under * the terms of the Affero GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the Affero GNU General Public License * and the GNU General Public License along with this program. If not, see * . * * The authors can be reached via e-mail to */ #include #include #include static partylist *firstparty; partylist * get_firstparty () { return firstparty; } static void remove_party (partylist *target_party) { if (firstparty == NULL) { LOG (llevError, "remove_party(): I was asked to remove party %s, but no parties are defined", target_party->partyname); return; } for_all_players (pl) if (pl->party == target_party) pl->party = NULL; partylist **prevlink = &firstparty; for (partylist *p = firstparty; p; p = p->next) if (p->next == target_party) { prevlink = &p->next; break; } *prevlink = target_party->next; free (target_party->partyleader); free (target_party->partyname); sfree (target_party); } /* Remove unused parties, this could be made to scale a lot better. */ void obsolete_parties () { int player_count; partylist *party; partylist *next = NULL; if (!firstparty) return; /* we can't obsolete parties if there aren't any */ for (party = firstparty; party != NULL; party = next) { next = party->next; player_count = 0; for_all_players (pl) if (pl->party == party) player_count++; if (player_count == 0) remove_party (party); } } void add_kill_to_party (partylist *party, const char *killer, const char *dead, long exp) { int i, pos; if (party == NULL) return; if (party->kills >= PARTY_KILL_LOG) { pos = PARTY_KILL_LOG - 1; for (i = 0; i < PARTY_KILL_LOG - 1; i++) party->party_kills[i] = party->party_kills[i + 1]; } else pos = party->kills; party->kills++; party->total_exp += exp; party->party_kills[pos].exp = exp; assign (party->party_kills[pos].killer, killer); assign (party->party_kills[pos].dead, dead); party->party_kills[pos].killer[MAX_NAME] = 0; party->party_kills[pos].dead[MAX_NAME] = 0; } static int confirm_party_password (object *op) { partylist *tmppartylist; for (tmppartylist = firstparty; tmppartylist != NULL; tmppartylist = tmppartylist->next) { if (!strcmp (op->contr->party_to_join->partyname, tmppartylist->partyname)) { if (strcmp (op->contr->write_buf + 1, tmppartylist->passwd) == 0) return 0; else return 1; } } return 1; } static void send_party_message (object *op, const char *msg) { for_all_players (pl) if (pl->ob->contr->party == op->contr->party && pl->ob != op) pl->send_msg (NDI_UNIQUE, MSG_CHANNEL ("party"), msg); } void receive_party_password (object *op, char k) { if (confirm_party_password (op) == 0) { partylist *joined_party = op->contr->party_to_join; char buf[MAX_BUF]; op->contr->party = op->contr->party_to_join; op->contr->party_to_join = NULL; new_draw_info_format (NDI_UNIQUE, 0, op, "You have joined party: %s\n", joined_party->partyname); snprintf (buf, MAX_BUF, "%s joins party %s", &op->name, joined_party->partyname); send_party_message (op, buf); op->contr->ns->state = ST_PLAYING; return; } else { new_draw_info (NDI_UNIQUE, 0, op, "You entered the wrong password"); op->contr->party_to_join = NULL; op->contr->ns->state = ST_PLAYING; return; } } int command_gsay (object *op, char *params) { if (!params) return 0; command_party (op, format ("say %s", params)); return 0; } int command_party (object *op, char *params) { dynbuf_text &buf = msg_dynbuf; buf.clear (); partylist *party = op->contr->party; if (!params) params = (char *)""; if (!strcmp (params, "help")) buf << "\n" " - To form a party type: C \n" " - To join a party type: C \n" " - If the party has a passwd, it will you prompt you for it.\n" " - For a list of current parties type: C\n" " - To leave a party type: C\n" " - To change a passwd for a party type: C \n" " - There is an 8 character max\n" " - To talk to party members type: C \n" " - To see who is in your party: C\n" " - To see what you've killed, type: C\n"; else if (strncmp (params, "form ", 5) == 0) { params += 5; if (party) buf << "You are already a member of party " << party->partyname << ". You must leave it first."; else { for (partylist *tmpparty = firstparty; tmpparty; tmpparty = tmpparty->next) { if (!strcmp (tmpparty->partyname, params)) { buf << "The party " << tmpparty->partyname << " already exists, pick another name"; goto reply; } } /* Forms the party struct for a party called 'params'. it is the responsibility * of the caller to ensure that the name is unique, and that it is placed in the * main party list correctly */ party = salloc0 (); party->partyname = strdup (params); party->total_exp = 0; party->kills = 0; party->passwd[0] = '\0'; party->next = NULL; party->partyleader = strdup (op->name); buf << "You have formed party: " << party->partyname << "."; party->next = firstparty; op->contr->party = firstparty = party; } } else if (strcmp (params, "list") == 0) { if (!firstparty) buf << "There are no parties active right now"; else { buf << "Party name Leader\n\n" "---------- ------\n\n"; for (partylist *p = firstparty; p; p = p->next) buf.printf ("%-32s %s\n\n", p->partyname, p->partyleader); } } else if (strncmp (params, "join ", 5) == 0) { params += 5; /* Can't join a party cause non exist */ if (!firstparty) buf << "Party: " << params << " does not exist. You must form it first."; else if (party) buf << "You are already a member of party " << party->partyname << ". You must leave it first."; else for (partylist *p = firstparty; p; p = p->next) if (!strcmp (p->partyname, params)) { if (!*p->passwd) { op->contr->party = p; buf << op->name << " joins party " << p->partyname << "."; send_party_message (op, buf); buf.clear (); buf << "You have joined party: " << p->partyname << "."; } else get_party_password (op, p); goto reply; } else buf << "Party " << params << " does not exist. You must form it first."; } else if (!party) buf << "You are not a member of any party.\n\n" "For help try: C"; else if (!*params) buf << "You are a member of party " << party->partyname << "."; else if (!strncmp (params, "kills", 5)) { if (!party->kills) buf << "You haven't killed anything yet."; else { int max = min (party->kills - 1, PARTY_KILL_LOG - 1); buf << " Killed | Killer| Exp\n" << " ----------------+----------------+--------\n"; for (int i = 0; i <= max; i++) { sint64 exp = party->party_kills[i].exp; char suffix = ' '; if (exp > 1000000) { exp /= 1000000; suffix = 'M'; } else if (exp > 1000) { exp /= 1000; suffix = 'k'; } buf.printf (" %16s|%16s|%6.1f%c\n", party->party_kills[i].dead, party->party_kills[i].killer, (double)exp, suffix); } buf << " ----------------+----------------+--------\n"; { sint64 exp = party->total_exp; char suffix = ' '; if (exp > 1000000) { exp /= 1000000; suffix = 'M'; } else if (exp > 1000) { exp /= 1000; suffix = 'k'; } buf.printf (" Totals: %d kills, %.1f%c exp", party->kills, (double)exp, suffix); } } } else if (strncmp (params, "say ", 4) == 0) { params += 4; buf << "[" << party->partyname << "] " << op->name << " says: " << params; send_party_message (op, buf); buf.clear (); buf << "[" << party->partyname << "] You say: " << params; } else if (strcmp (params, "leave") == 0) { buf << op->name << " leaves party " << party->partyname << "."; send_party_message (op, buf); buf.clear (); buf << "You leave party " << party->partyname << "."; op->contr->party = 0; obsolete_parties (); } else if (strcmp (params, "who") == 0) { buf << "Members of party " << party->partyname << ".\n"; for_all_players (pl) if (pl->ob->contr->party == party) buf.printf (" - %s/%d %s\n\n", &pl->ob->name, pl->ob->level, *pl->ob->contr->own_title ? pl->ob->contr->own_title : pl->ob->contr->title); } else if (strncmp (params, "passwd ", 7) == 0) { params += 7; if (strlen (params) > 8) buf << "The password must not exceed 8 characters"; else { strcpy (party->passwd, params); buf << "The password for party " << party->partyname << " is set to B<" << params << "> by " << &op->name; } } else buf << "I did not understand your command. For help try: C"; reply: op->contr->send_msg (NDI_UNIQUE | NDI_REPLY, MSG_CHANNEL ("party"), buf); return 1; }