Atrinik Server 2.5
server/party.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00034 const char *const party_loot_modes[PARTY_LOOT_MAX] =
00035 {
00036     "normal", "leader", "random"
00037 };
00038 
00041 const char *const party_loot_modes_help[PARTY_LOOT_MAX] =
00042 {
00043     "everyone is able to loot the corpse",
00044     "only the leader can loot the corpse",
00045     "loot is randomly split between party members when the corpse is opened"
00046 };
00047 
00049 party_struct *first_party = NULL;
00050 
00055 void add_party_member(party_struct *party, object *op)
00056 {
00057     objectlink *ol = get_objectlink();
00058     unsigned char buf[MAX_BUF];
00059     SockList sl;
00060 
00061     /* Add the player to the party's linked list of members. */
00062     ol->objlink.ob = op;
00063     objectlink_link(&party->members, NULL, NULL, party->members, ol);
00064     /* And set up player's pointer to the party. */
00065     CONTR(op)->party = party;
00066 
00067     /* Tell the client what party we have joined. */
00068     sl.buf = buf;
00069     SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_PARTY);
00070     SockList_AddChar(&sl, CMD_PARTY_JOIN);
00071     SockList_AddString(&sl, party->name);
00072     Send_With_Handling(&CONTR(op)->socket, &sl);
00073 
00074     CONTR(op)->last_party_hp = 0;
00075     CONTR(op)->last_party_sp = 0;
00076     CONTR(op)->last_party_grace = 0;
00077 }
00078 
00083 void remove_party_member(party_struct *party, object *op)
00084 {
00085     objectlink *ol;
00086     unsigned char buf[MAX_BUF];
00087     SockList sl;
00088 
00089     /* Go through the party members, and remove the player that is
00090      * leaving. */
00091     for (ol = party->members; ol; ol = ol->next)
00092     {
00093         if (ol->objlink.ob == op)
00094         {
00095             objectlink_unlink(&party->members, NULL, ol);
00096             break;
00097         }
00098     }
00099 
00100     sl.buf = buf;
00101 
00102     if (party->members)
00103     {
00104         SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_PARTY);
00105         SockList_AddChar(&sl, CMD_PARTY_REMOVE_MEMBER);
00106         SockList_AddString(&sl, op->name);
00107 
00108         for (ol = party->members; ol; ol = ol->next)
00109         {
00110             if (CONTR(ol->objlink.ob)->socket.socket_version >= 1054)
00111             {
00112             Send_With_Handling(&CONTR(ol->objlink.ob)->socket, &sl);
00113             }
00114         }
00115     }
00116 
00117     /* If no members left, remove the party. */
00118     if (!party->members)
00119     {
00120         remove_party(CONTR(op)->party);
00121     }
00122     /* Otherwise choose a new leader, if the old one left. */
00123     else if (op->name == party->leader)
00124     {
00125         FREE_AND_ADD_REF_HASH(party->leader, party->members->objlink.ob->name);
00126         new_draw_info_format(0, COLOR_WHITE, party->members->objlink.ob, "You are the new leader of party %s!", party->name);
00127     }
00128 
00129     SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_PARTY);
00130     SockList_AddChar(&sl, CMD_PARTY_LEAVE);
00131     Send_With_Handling(&CONTR(op)->socket, &sl);
00132 
00133     CONTR(op)->party = NULL;
00134 }
00135 
00140 static party_struct *make_party(const char *name)
00141 {
00142     party_struct *party = (party_struct *) get_poolchunk(pool_parties);
00143 
00144     memset(party, 0, sizeof(party_struct));
00145     FREE_AND_COPY_HASH(party->name, name);
00146 
00147     party->next = first_party;
00148     first_party = party;
00149 
00150     return party;
00151 }
00152 
00157 void form_party(object *op, const char *name)
00158 {
00159     party_struct *party = make_party(name);
00160 
00161     add_party_member(party, op);
00162     new_draw_info_format(0, COLOR_WHITE, op, "You have formed party: %s", name);
00163     FREE_AND_ADD_REF_HASH(party->leader, op->name);
00164     CONTR(op)->stat_formed_party++;
00165 }
00166 
00171 party_struct *find_party(const char *name)
00172 {
00173     party_struct *tmp;
00174 
00175     for (tmp = first_party; tmp; tmp = tmp->next)
00176     {
00177         if (!strcmp(tmp->name, name))
00178         {
00179             return tmp;
00180         }
00181     }
00182 
00183     return NULL;
00184 }
00185 
00202 sint16 party_member_get_skill(object *op, object *skill)
00203 {
00204     sint16 skill_id = skill->stats.sp;
00205 
00206     switch (skill_id)
00207     {
00208         /* Handle weapon types. */
00209         case SK_MELEE_WEAPON:
00210         case SK_SLASH_WEAP:
00211         case SK_CLEAVE_WEAP:
00212         case SK_PIERCE_WEAP:
00213             if (CONTR(op)->set_skill_weapon != NO_SKILL_READY)
00214             {
00215                 return CONTR(op)->set_skill_weapon;
00216             }
00217 
00218             break;
00219 
00220         /* Handle archery weapon types. */
00221         case SK_MISSILE_WEAPON:
00222         case SK_XBOW_WEAP:
00223         case SK_SLING_WEAP:
00224             if (CONTR(op)->set_skill_archery != NO_SKILL_READY)
00225             {
00226                 return CONTR(op)->set_skill_archery;
00227             }
00228 
00229             break;
00230 
00231         /* Everything else. */
00232         default:
00233             if (CONTR(op)->skill_ptr[skill_id])
00234             {
00235                 return skill_id;
00236             }
00237     }
00238 
00239     return NO_SKILL_READY;
00240 }
00241 
00246 static void party_loot_random(object *pl, object *corpse)
00247 {
00248     int count = 0, pl_id;
00249     party_struct *party = CONTR(pl)->party;
00250     objectlink *ol;
00251     object *tmp, *tmp_next;
00252 
00253     for (ol = party->members; ol; ol = ol->next)
00254     {
00255         if (on_same_map(ol->objlink.ob, pl))
00256         {
00257             count++;
00258         }
00259     }
00260 
00261     if (count == 1)
00262     {
00263         return;
00264     }
00265 
00266     for (tmp = corpse->inv; tmp; tmp = tmp_next)
00267     {
00268         int num = 1;
00269 
00270         tmp_next = tmp->below;
00271 
00272         /* Skip unpickable objects. */
00273         if (!can_pick(pl, tmp))
00274         {
00275             continue;
00276         }
00277 
00278         pl_id = rndm(1, count);
00279 
00280         for (ol = party->members; ol; ol = ol->next)
00281         {
00282             if (on_same_map(ol->objlink.ob, pl))
00283             {
00284                 if (num == pl_id)
00285                 {
00286                     if (player_can_carry(ol->objlink.ob, WEIGHT_NROF(tmp, tmp->nrof)))
00287                     {
00288                         new_draw_info_format(0, COLOR_BLUE, ol->objlink.ob, "You receive the %s.", query_name(tmp, NULL));
00289                         esrv_del_item(CONTR(pl), tmp->count, tmp->env);
00290                         remove_ob(tmp);
00291                         tmp = insert_ob_in_ob(tmp, ol->objlink.ob);
00292                         esrv_send_item(ol->objlink.ob, tmp);
00293                     }
00294 
00295                     break;
00296                 }
00297 
00298                 num++;
00299             }
00300         }
00301     }
00302 }
00303 
00309 int party_can_open_corpse(object *pl, object *corpse)
00310 {
00311     /* Check if the player is in the same party. */
00312     if (!CONTR(pl)->party || corpse->slaying != CONTR(pl)->party->name)
00313     {
00314         new_draw_info(0, COLOR_WHITE, pl, "It's not your party's bounty.");
00315         return 0;
00316     }
00317 
00318     switch (CONTR(pl)->party->loot)
00319     {
00320         /* Normal: anyone can access it. */
00321         case PARTY_LOOT_NORMAL:
00322         default:
00323             return 1;
00324 
00325         /* Only leader can access it. */
00326         case PARTY_LOOT_LEADER:
00327             if (pl->name != CONTR(pl)->party->leader)
00328             {
00329                 new_draw_info(0, COLOR_WHITE, pl, "You're not the party's leader.");
00330                 return 0;
00331             }
00332 
00333             return 1;
00334     }
00335 }
00336 
00341 void party_handle_corpse(object *pl, object *corpse)
00342 {
00343     /* Sanity check. */
00344     if (!CONTR(pl)->party)
00345     {
00346         return;
00347     }
00348 
00349     switch (CONTR(pl)->party->loot)
00350     {
00351         case PARTY_LOOT_RANDOM:
00352             party_loot_random(pl, corpse);
00353             break;
00354     }
00355 }
00356 
00364 void send_party_message(party_struct *party, const char *msg, int flag, object *op)
00365 {
00366     objectlink *ol;
00367 
00368     for (ol = party->members; ol; ol = ol->next)
00369     {
00370         if (ol->objlink.ob == op)
00371         {
00372             continue;
00373         }
00374 
00375         if (flag == PARTY_MESSAGE_STATUS)
00376         {
00377             new_draw_info(0, COLOR_YELLOW, ol->objlink.ob, msg);
00378         }
00379         else if (flag == PARTY_MESSAGE_CHAT)
00380         {
00381             new_draw_info(NDI_PLAYER, COLOR_YELLOW, ol->objlink.ob, msg);
00382         }
00383     }
00384 }
00385 
00389 void remove_party(party_struct *party)
00390 {
00391     objectlink *ol;
00392     party_struct *tmp, *prev = NULL;
00393 
00394     for (ol = party->members; ol; ol = ol->next)
00395     {
00396         CONTR(ol->objlink.ob)->party = NULL;
00397         objectlink_unlink(&party->members, NULL, ol);
00398         return_poolchunk(ol, pool_objectlink);
00399     }
00400 
00401     for (tmp = first_party; tmp; prev = tmp, tmp = tmp->next)
00402     {
00403         if (tmp == party)
00404         {
00405             if (!prev)
00406             {
00407                 first_party = tmp->next;
00408             }
00409             else
00410             {
00411                 prev->next = tmp->next;
00412             }
00413 
00414             break;
00415         }
00416     }
00417 
00418     FREE_AND_CLEAR_HASH(party->name);
00419     FREE_AND_CLEAR_HASH(party->leader);
00420     return_poolchunk(party, pool_parties);
00421 }
00422 
00426 void party_update_who(player *pl)
00427 {
00428     unsigned char sockbuf[HUGE_BUF];
00429     uint8 hp, sp, grace;
00430     SockList sl;
00431 
00432     if (!pl->party)
00433     {
00434         return;
00435     }
00436 
00437     sl.buf = sockbuf;
00438     SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_PARTY);
00439     SockList_AddChar(&sl, CMD_PARTY_UPDATE);
00440 
00441     hp = MAX(1, MIN((double) pl->ob->stats.hp / pl->ob->stats.maxhp * 100.0f, 100));
00442     sp = MAX(1, MIN((double) pl->ob->stats.sp / pl->ob->stats.maxsp * 100.0f, 100));
00443     grace = MAX(1, MIN((double) pl->ob->stats.grace / pl->ob->stats.maxgrace * 100.0f, 100));
00444 
00445     if (hp != pl->last_party_hp || sp != pl->last_party_sp || grace != pl->last_party_grace)
00446     {
00447         objectlink *ol;
00448 
00449         SockList_AddString(&sl, pl->ob->name);
00450         SockList_AddChar(&sl, hp);
00451         SockList_AddChar(&sl, sp);
00452         SockList_AddChar(&sl, grace);
00453 
00454         for (ol = pl->party->members; ol; ol = ol->next)
00455         {
00456             if (CONTR(ol->objlink.ob)->socket.socket_version >= 1054)
00457             {
00458             Send_With_Handling(&CONTR(ol->objlink.ob)->socket, &sl);
00459             }
00460         }
00461     }
00462 }