Atrinik Server  4.0
party.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
30 #include <global.h>
31 #include <toolkit/packet.h>
32 #include <player.h>
33 #include <object.h>
34 
38 const char *const party_loot_modes[PARTY_LOOT_MAX] = {
39  "normal", "leader", "owner", "random", "split"
40 };
41 
45 const char *const party_loot_modes_help[PARTY_LOOT_MAX] = {
46  "everyone in the party is able to loot the corpse",
47  "only the party leader can loot the corpse",
48  "only the corpse owner can loot the corpse; standard behavior when outside of a party",
49  "loot is randomly split between party members when the corpse is opened",
50  "loot is evenly split between party members when the corpse is opened"
51 };
52 
55 
59 static mempool_struct *pool_party;
60 
64 void party_init(void)
65 {
66  pool_party = mempool_create("parties", 25, sizeof(party_struct),
67  MEMPOOL_ALLOW_FREEING, NULL, NULL, NULL, NULL);
68 }
69 
73 void party_deinit(void)
74 {
75 }
76 
84 void add_party_member(party_struct *party, object *op)
85 {
86  objectlink *ol;
87  packet_struct *packet;
88 
89  ol = get_objectlink();
90  /* Add the player to the party's linked list of members. */
91  ol->objlink.ob = op;
92  objectlink_link(&party->members, NULL, NULL, party->members, ol);
93  /* And set up player's pointer to the party. */
94  CONTR(op)->party = party;
95 
96  packet = packet_new(CLIENT_CMD_PARTY, 64, 64);
97  packet_debug_data(packet, 0, "Party command type");
98  packet_append_uint8(packet, CMD_PARTY_JOIN);
99  packet_debug_data(packet, 0, "Party name");
100  packet_append_string_terminated(packet, party->name);
101  socket_send_packet(CONTR(op)->cs, packet);
102 
103  CONTR(op)->last_party_hp = 0;
104  CONTR(op)->last_party_sp = 0;
105 }
106 
114 void remove_party_member(party_struct *party, object *op)
115 {
116  objectlink *ol;
117  packet_struct *packet;
118 
119  /* Go through the party members, and remove the player that is
120  * leaving. */
121  for (ol = party->members; ol; ol = ol->next) {
122  if (ol->objlink.ob == op) {
123  objectlink_unlink(&party->members, NULL, ol);
124  free_objectlink_simple(ol);
125  break;
126  }
127  }
128 
129  SOFT_ASSERT(ol != NULL, "Could not find player %s in party members!",
130  object_get_str(op));
131 
132  if (party->members) {
133  packet = packet_new(CLIENT_CMD_PARTY, 64, 64);
134  packet_debug_data(packet, 0, "Party command type");
135  packet_append_uint8(packet, CMD_PARTY_REMOVE_MEMBER);
136  packet_debug_data(packet, 0, "Member name");
137  packet_append_string_terminated(packet, op->name);
138 
139  for (ol = party->members; ol; ol = ol->next) {
140  socket_send_packet(CONTR(ol->objlink.ob)->cs,
141  packet_dup(packet));
142  }
143 
144  packet_free(packet);
145  }
146 
147  /* If no members left, remove the party. */
148  if (!party->members) {
149  remove_party(CONTR(op)->party);
150  } else if (op->name == party->leader) {
151  /* Otherwise choose a new leader, if the old one left. */
153  draw_info_format(COLOR_WHITE, party->members->objlink.ob,
154  "You are the new leader of party %s!", party->name);
155  }
156 
157  packet = packet_new(CLIENT_CMD_PARTY, 4, 0);
158  packet_debug_data(packet, 0, "Party command type");
159  packet_append_uint8(packet, CMD_PARTY_LEAVE);
160  socket_send_packet(CONTR(op)->cs, packet);
161 
162  CONTR(op)->party = NULL;
163 }
164 
172 static party_struct *make_party(const char *name)
173 {
174  party_struct *party = mempool_get(pool_party);
175 
176  FREE_AND_COPY_HASH(party->name, name);
177 
178  party->next = first_party;
179  first_party = party;
180 
181  return party;
182 }
183 
191 void form_party(object *op, const char *name)
192 {
193  party_struct *party = make_party(name);
194 
195  add_party_member(party, op);
196  draw_info_format(COLOR_WHITE, op, "You have formed party: %s", name);
197  FREE_AND_ADD_REF_HASH(party->leader, op->name);
198  CONTR(op)->stat_formed_party++;
199 }
200 
208 party_struct *find_party(const char *name)
209 {
210  party_struct *tmp;
211 
212  for (tmp = first_party; tmp; tmp = tmp->next) {
213  if (!strcmp(tmp->name, name)) {
214  return tmp;
215  }
216  }
217 
218  return NULL;
219 }
220 
230 int party_can_open_corpse(object *pl, object *corpse)
231 {
232  /* Check if the player is in the same party. */
233  if (!CONTR(pl)->party || corpse->slaying != CONTR(pl)->party->name) {
234  draw_info(COLOR_WHITE, pl, "It's not your party's bounty.");
235  return 0;
236  }
237 
238  switch (CONTR(pl)->party->loot) {
239  /* Normal: anyone can access it. */
240  case PARTY_LOOT_NORMAL:
241  default:
242  return 1;
243 
244  /* Only leader can access it. */
245  case PARTY_LOOT_LEADER:
246 
247  if (pl->name != CONTR(pl)->party->leader) {
248  draw_info(COLOR_WHITE, pl, "You're not the party's leader.");
249  return 0;
250  }
251 
252  return 1;
253  }
254 }
255 
263 static void party_loot_random(object *pl, object *corpse)
264 {
265  int count = 0, pl_id;
266  party_struct *party;
267  objectlink *ol;
268  object *tmp, *tmp_next;
269 
270  party = CONTR(pl)->party;
271 
272  for (ol = party->members; ol; ol = ol->next) {
273  if (on_same_map(ol->objlink.ob, pl)) {
274  count++;
275  }
276  }
277 
278  for (tmp = corpse->inv; tmp; tmp = tmp_next) {
279  int num = 1;
280 
281  tmp_next = tmp->below;
282 
283  /* Skip unpickable objects. */
284  if (!object_can_pick(pl, tmp)) {
285  continue;
286  }
287 
288  pl_id = rndm(1, count);
289 
290  for (ol = party->members; ol; ol = ol->next) {
291  if (on_same_map(ol->objlink.ob, pl)) {
292  if (num == pl_id) {
293  if (player_can_carry(ol->objlink.ob, WEIGHT_NROF(tmp, tmp->nrof))) {
294  char *name = object_get_name_s(tmp, NULL);
295  draw_info_format(COLOR_BLUE, ol->objlink.ob,
296  "You receive the %s.", name);
297  efree(name);
298  object_remove(tmp, 0);
299  object_insert_into(tmp, ol->objlink.ob, 0);
300  }
301 
302  break;
303  }
304 
305  num++;
306  }
307  }
308  }
309 }
310 
318 static void party_loot_split(object *pl, object *corpse)
319 {
320  party_struct *party;
321  objectlink *ol, *ol_loot, *ol_next;
322  uint32_t count;
323  int64_t value;
324  object *tmp, *next;
325 
326  party = CONTR(pl)->party;
327  ol_loot = NULL;
328  count = 0;
329  value = 0;
330 
331  for (ol = party->members; ol != NULL; ol = ol->next) {
332  if (on_same_map(ol->objlink.ob, pl)) {
333  if (party->loot_idx == count) {
334  ol_loot = ol;
335  }
336 
337  count++;
338  }
339  }
340 
341  if (party->loot_idx >= count) {
342  party->loot_idx = 0;
343  ol_loot = party->members;
344  }
345 
346  /* Sanity check. */
347  if (ol_loot == NULL) {
348  return;
349  }
350 
351  for (tmp = corpse->inv; tmp; tmp = next) {
352  next = tmp->below;
353 
354  /* Skip unpickable objects. */
355  if (!object_can_pick(pl, tmp)) {
356  continue;
357  }
358 
359  if (tmp->type == MONEY) {
360  value += tmp->value * tmp->nrof;
361  object_remove(tmp, 0);
362  continue;
363  }
364 
365  for (ol = ol_loot; ol != NULL; ol = ol_next) {
366  ol_next = ol->next;
367 
368  if (ol_next == NULL) {
369  ol_next = party->members;
370  }
371 
372  if (on_same_map(ol->objlink.ob, pl) && player_can_carry(ol->objlink.ob, WEIGHT_NROF(tmp, tmp->nrof))) {
373  char *name = object_get_name_s(tmp, NULL);
374  draw_info_format(COLOR_BLUE, ol->objlink.ob, "You receive the "
375  "%s.", name);
376  efree(name);
377  object_remove(tmp, 0);
378  object_insert_into(tmp, ol->objlink.ob, 0);
379  break;
380  }
381 
382  if (ol == ol_loot) {
383  break;
384  }
385  }
386 
387  party->loot_idx++;
388  ol_loot = ol_loot->next;
389 
390  if (party->loot_idx >= count) {
391  party->loot_idx = 0;
392  ol_loot = party->members;
393  }
394  }
395 
396  if (value > 0) {
397  int64_t value_split;
398  uint32_t num;
399 
400  for (num = 0, ol = party->members; ol; ol = ol->next) {
401  if (on_same_map(ol->objlink.ob, pl)) {
402  value_split = value / count;
403 
404  if (num == 0) {
405  value_split += value % count;
406  }
407 
408  draw_info_format(COLOR_BLUE, ol->objlink.ob, "You receive %s.", shop_get_cost_string(value_split));
409  shop_insert_coins(ol->objlink.ob, value_split);
410 
411  num++;
412  }
413  }
414  }
415 }
416 
424 void party_handle_corpse(object *pl, object *corpse)
425 {
426  object *tmp, *next;
427 
428  /* Sanity check. */
429  if (!CONTR(pl)->party) {
430  return;
431  }
432 
433  /* Reclaim arrows. */
434  for (tmp = corpse->inv; tmp; tmp = next) {
435  next = tmp->below;
436 
437  if (tmp->type == ARROW && OBJECT_VALID(tmp->attacked_by, tmp->attacked_by_count) &&
438  tmp->attacked_by->type == PLAYER && CONTR(tmp->attacked_by)->party == CONTR(pl)->party &&
439  on_same_map(tmp->attacked_by, pl)) {
440  if (object_can_pick(tmp->attacked_by, tmp) && player_can_carry(tmp->attacked_by, WEIGHT_NROF(tmp, tmp->nrof))) {
441  pick_up(tmp->attacked_by, tmp, 0);
442  }
443  }
444  }
445 
446  switch (CONTR(pl)->party->loot) {
447  case PARTY_LOOT_RANDOM:
448  party_loot_random(pl, corpse);
449  break;
450 
451  case PARTY_LOOT_SPLIT:
452  party_loot_split(pl, corpse);
453  break;
454  }
455 }
456 
470 void send_party_message(party_struct *party, const char *msg, int flag, object *op, object *except)
471 {
472  HARD_ASSERT(party != NULL);
473  HARD_ASSERT(msg != NULL);
474 
475  SOFT_ASSERT(op != NULL || flag == PARTY_MESSAGE_STATUS,
476  "'op' argument not supplied");
477 
478  objectlink *ol;
479 
480  for (ol = party->members; ol; ol = ol->next) {
481  if (ol->objlink.ob == except) {
482  continue;
483  }
484 
485  if (flag == PARTY_MESSAGE_STATUS) {
486  draw_info(COLOR_YELLOW, ol->objlink.ob, msg);
487  } else if (flag == PARTY_MESSAGE_CHAT) {
488  draw_info_type(CHAT_TYPE_PARTY, op->name, COLOR_YELLOW, ol->objlink.ob, msg);
489  }
490  }
491 }
492 
499 {
500  party_struct *tmp, *prev = NULL;
501 
502  while (party->members != NULL) {
503  CONTR(party->members->objlink.ob)->party = NULL;
504  objectlink_unlink(&party->members, NULL, party->members);
505  free_objectlink_simple(party->members);
506  }
507 
508  for (tmp = first_party; tmp; prev = tmp, tmp = tmp->next) {
509  if (tmp == party) {
510  if (!prev) {
511  first_party = tmp->next;
512  } else {
513  prev->next = tmp->next;
514  }
515 
516  break;
517  }
518  }
519 
520  FREE_AND_CLEAR_HASH(party->name);
521  FREE_AND_CLEAR_HASH(party->leader);
522  mempool_return(pool_party, party);
523 }
524 
531 {
532  uint8_t hp, sp;
533 
534  if (!pl->party) {
535  return;
536  }
537 
538  hp = MAX(1, MIN((double) pl->ob->stats.hp / pl->ob->stats.maxhp * 100.0f,
539  100));
540  sp = MAX(1, MIN((double) pl->ob->stats.sp / pl->ob->stats.maxsp * 100.0f,
541  100));
542 
543  if (hp != pl->last_party_hp || sp != pl->last_party_sp) {
544  packet_struct *packet;
545  objectlink *ol;
546 
547  packet = packet_new(CLIENT_CMD_PARTY, 64, 64);
548  packet_debug_data(packet, 0, "Party command type");
549  packet_append_uint8(packet, CMD_PARTY_UPDATE);
550  packet_debug_data(packet, 0, "Member name");
551  packet_append_string_terminated(packet, pl->ob->name);
552  packet_debug_data(packet, 0, "Health");
553  packet_append_uint8(packet, hp);
554  packet_debug_data(packet, 0, "Mana");
555  packet_append_uint8(packet, sp);
556 
557  for (ol = pl->party->members; ol; ol = ol->next) {
558  socket_send_packet(CONTR(ol->objlink.ob)->cs,
559  packet_dup(packet));
560  }
561 
562  packet_free(packet);
563  }
564 }
#define FREE_AND_ADD_REF_HASH(_sv_, _nv_)
Definition: global.h:116
#define FREE_AND_COPY_HASH(_sv_, _nv_)
Definition: global.h:100
const char * shop_get_cost_string(int64_t cost)
Definition: shop.c:178
party_struct * first_party
Definition: party.c:54
void remove_party_member(party_struct *party, object *op)
Definition: party.c:114
Definition: object.h:488
tag_t attacked_by_count
Definition: object.h:222
uint32_t loot_idx
Definition: party.h:107
int player_can_carry(object *pl, uint32_t weight)
Definition: player.c:1036
static void party_loot_split(object *pl, object *corpse)
Definition: party.c:318
const char * slaying
Definition: object.h:180
object * ob
Definition: player.h:185
static void party_loot_random(object *pl, object *corpse)
Definition: party.c:263
#define MONEY
Definition: define.h:226
void send_party_message(party_struct *party, const char *msg, int flag, object *op, object *except)
Definition: party.c:470
#define PLAYER
Definition: define.h:122
int16_t sp
Definition: living.h:78
void remove_party(party_struct *party)
Definition: party.c:498
static mempool_struct * pool_party
Definition: party.c:59
#define CMD_PARTY_REMOVE_MEMBER
Definition: party.h:151
void object_remove(object *op, int flags)
Definition: object.c:1623
int16_t maxsp
Definition: living.h:81
int32_t hp
Definition: living.h:72
char * object_get_name_s(const object *op, const object *caller)
Definition: item.c:398
object * ob
Definition: object.h:496
int32_t maxhp
Definition: living.h:75
void party_init(void)
Definition: party.c:64
void pick_up(object *op, object *alt, int no_mevent)
Definition: player.c:2019
const char * object_get_str(const object *op)
Definition: object.c:3151
struct party_struct * next
Definition: party.h:117
struct sound_ambient_match * next
Next match rule in a linked list.
Definition: sound_ambient.c:39
const char *const party_loot_modes_help[PARTY_LOOT_MAX]
Definition: party.c:45
object * object_insert_into(object *op, object *where, int flag)
Definition: object.c:2158
const char * name
Definition: object.h:168
int party_can_open_corpse(object *pl, object *corpse)
Definition: party.c:230
uint8_t last_party_sp
Definition: player.h:522
void party_update_who(player *pl)
Definition: party.c:530
struct obj * below
Definition: object.h:114
uint32_t nrof
Definition: object.h:264
union oblnk::@3 objlink
#define ARROW
Definition: define.h:170
uint64_t num
Number of successful updates.
Definition: metaserver.c:43
void party_deinit(void)
Definition: party.c:73
#define CMD_PARTY_UPDATE
Definition: party.h:147
void shop_insert_coins(object *op, int64_t value)
Definition: shop.c:587
uint8_t last_party_hp
Definition: player.h:519
int on_same_map(object *op1, object *op2)
Definition: map.c:2414
static party_struct * make_party(const char *name)
Definition: party.c:172
living stats
Definition: object.h:481
void form_party(object *op, const char *name)
Definition: party.c:191
struct oblnk * next
Definition: object.h:500
uint8_t type
Definition: object.h:360
#define PARTY_MESSAGE_STATUS
Definition: party.h:41
#define PARTY_MESSAGE_CHAT
Definition: party.h:45
#define FREE_AND_CLEAR_HASH(_nv_)
Definition: global.h:130
party_struct * party
Definition: player.h:555
#define OBJECT_VALID(_ob_, _count_)
Definition: object.h:548
shstr * leader
Definition: party.h:87
struct obj * inv
Definition: object.h:123
party_struct * find_party(const char *name)
Definition: party.c:208
const char *const party_loot_modes[PARTY_LOOT_MAX]
Definition: party.c:38
bool object_can_pick(const object *op, const object *item)
Definition: object.c:2335
objectlink * members
Definition: party.h:112
void party_handle_corpse(object *pl, object *corpse)
Definition: party.c:424
shstr * name
Definition: party.h:92
#define CMD_PARTY_JOIN
Definition: party.h:135
#define CMD_PARTY_LEAVE
Definition: party.h:143
int64_t value
Definition: object.h:240
struct obj * attacked_by
Definition: object.h:199
void add_party_member(party_struct *party, object *op)
Definition: party.c:84