Atrinik Server  4.0
plugin_arena.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 
86 #define GLOBAL_NO_PROTOTYPES
87 #include <global.h>
88 #include <plugin.h>
89 #include <plugin_hooklist.h>
90 #include <stdarg.h>
91 #include <player.h>
92 #include <object.h>
93 
95 #define PLUGIN_NAME "Arena"
96 
98 #define PLUGIN_VERSION "Arena plugin 1.0"
99 
100 #define logger_print hooks->logger_print
101 
103 typedef struct arena_map_players {
105  object *op;
106 
110 
112 typedef struct arena_maps_struct {
114  char path[HUGE_BUF];
115 
117  int players;
118 
120  int parties;
121 
124 
127 
130 
132  uint32_t flags;
133 
135  char message_arena_full[MAX_BUF];
136 
138  char message_arena_party[MAX_BUF];
139 
143 
149 #define ARENA_FLAG_NONE 0
150 
151 #define ARENA_FLAG_PARTY 1
152 
153 #define ARENA_FLAG_PARTY_PLAYERS 2
154 
158 
160 struct plugin_hooklist *hooks;
161 
162 MODULEAPI void initPlugin(struct plugin_hooklist *hooklist)
163 {
164  hooks = hooklist;
165 }
166 
167 MODULEAPI void closePlugin(void)
168 {
169 }
170 
171 MODULEAPI void getPluginProperty(int *type, ...)
172 {
173  va_list args;
174  const char *propname;
175  int size;
176  char *buf;
177 
178  va_start(args, type);
179  propname = va_arg(args, const char *);
180 
181  if (!strcmp(propname, "Identification")) {
182  buf = va_arg(args, char *);
183  size = va_arg(args, int);
184  va_end(args);
185  snprintf(buf, size, PLUGIN_NAME);
186  } else if (!strcmp(propname, "FullName")) {
187  buf = va_arg(args, char *);
188  size = va_arg(args, int);
189  va_end(args);
190  snprintf(buf, size, PLUGIN_VERSION);
191  }
192 
193  va_end(args);
194 }
195 
196 MODULEAPI void postinitPlugin(void)
197 {
198  hooks->register_global_event(PLUGIN_NAME, GEVENT_LOGOUT);
199 }
200 
210 static int check_arena_player(object *op, arena_map_players *player_list)
211 {
212  arena_map_players *player_list_tmp;
213 
214  /* Go through the list of players. */
215  for (player_list_tmp = player_list; player_list_tmp; player_list_tmp = player_list_tmp->next) {
216  if (player_list_tmp->op == op) {
217  return 1;
218  }
219  }
220 
221  return 0;
222 }
223 
231 static void remove_arena_player(object *op, arena_map_players **player_list)
232 {
233  arena_map_players *currP, *prevP = NULL;
234 
235  for (currP = *player_list; currP; prevP = currP, currP = currP->next) {
236  if (currP->op == op) {
237  if (!prevP) {
238  *player_list = currP->next;
239  } else {
240  prevP->next = currP->next;
241  }
242 
243  free(currP);
244  break;
245  }
246  }
247 }
248 
256 static void arena_map_parse_line(arena_maps_struct *arena_map, const char *line)
257 {
258  /* Maximum number of players */
259  if (strncmp(line, "max_players ", 12) == 0) {
260  arena_map->max_players = atoi(line + 12);
261  } else if (strncmp(line, "max_parties ", 12) == 0) {
262  /* Maximum number of parties */
263  arena_map->max_parties = atoi(line + 12);
264  } else if (strncmp(line, "party ", 6) == 0) {
265  /* Whether to allow arena party mode */
266  line += 6;
267 
268  if (!strcmp(line, "true") || *line == '1') {
269  arena_map->flags |= ARENA_FLAG_PARTY;
270  }
271  } else if (strncmp(line, "party_players ", 14) == 0) {
272  /* Or even party players? */
273  line += 14;
274 
275  if (!strcmp(line, "true") || *line == '1') {
276  arena_map->flags |= ARENA_FLAG_PARTY_PLAYERS;
277  }
278  } else if (strncmp(line, "message_full ", 13) == 0) {
279  /* Message for when the arena is full */
280  strncpy(arena_map->message_arena_full, line + 13, sizeof(arena_map->message_arena_full) - 1);
281  } else if (strncmp(line, "message_party ", 14) == 0) {
282  /* Message when you need to join a party to enter */
283  strncpy(arena_map->message_arena_party, line + 13, sizeof(arena_map->message_arena_party) - 1);
284  }
285 }
286 
296 static void arena_map_parse_script(const char *arena_script, object *exit_ob, arena_maps_struct *arena_map)
297 {
298  FILE *fh;
299  char buf[MAX_BUF], *path, *arena_script_path;
300 
301  path = hooks->map_get_path(exit_ob->map, arena_script, 0, NULL);
302  arena_script_path = hooks->create_pathname(path);
303  free(path);
304 
305  /* Initialize defaults */
306  arena_map->max_players = 0;
307  arena_map->max_parties = 0;
308  arena_map->players = 0;
309  arena_map->parties = 0;
310  arena_map->flags = ARENA_FLAG_NONE;
311  strncpy(arena_map->message_arena_full, "Sorry, this arena seems to be full.", sizeof(arena_map->message_arena_full) - 1);
312  strncpy(arena_map->message_arena_party, "You must be in a party in order to enter this arena.", sizeof(arena_map->message_arena_party) - 1);
313 
314  fh = fopen(arena_script_path, "r");
315 
316  if (!fh) {
317  LOG(BUG, "Arena: Could not open arena script: %s", arena_script_path);
318  return;
319  }
320 
321  while (fgets(buf, sizeof(buf), fh)) {
322  /* Ignore comments and empty lines */
323  if (*buf == '#' || *buf == '\n') {
324  continue;
325  }
326 
327  /* Remove newline and parse the line */
328  buf[strlen(buf) - 1] = '\0';
329  arena_map_parse_line(arena_map, buf);
330  }
331 
332  fclose(fh);
333 }
334 
344 static int arena_full(arena_maps_struct *arena_map)
345 {
346  /* Simple case: The map has nothing to do with parties. */
347  if (!(arena_map->flags & ARENA_FLAG_PARTY) && !(arena_map->flags & ARENA_FLAG_PARTY_PLAYERS) && arena_map->players == arena_map->max_players) {
348  return 1;
349  } else if (arena_map->flags & ARENA_FLAG_PARTY) {
350  /* Otherwise a party map. */
351 
352  /* If this is party players arena, count in players. */
353  if (arena_map->flags & ARENA_FLAG_PARTY_PLAYERS && arena_map->players == arena_map->max_players) {
354  return 1;
355  }
356 
357  /* Always check for maximum parties, even if this is party players
358  * arena. */
359  if (arena_map->parties == arena_map->max_parties) {
360  return 1;
361  }
362  }
363 
364  return 0;
365 }
366 
378 static int arena_enter(object *who, object *exit_ob, const char *arena_script)
379 {
380  char *path;
381  arena_maps_struct *arena_maps_tmp;
382 
383  /* The exit must have a path. */
384  if (!EXIT_PATH(exit_ob)) {
385  return 0;
386  }
387 
388  path = hooks->map_get_path(exit_ob->map, EXIT_PATH(exit_ob), MAP_UNIQUE(exit_ob->map), who->name);
389 
390  /* Go through the list of arenas */
391  for (arena_maps_tmp = arena_maps; arena_maps_tmp; arena_maps_tmp = arena_maps_tmp->next) {
392  /* If the exit's path matches this arena */
393  if (strcmp(arena_maps_tmp->path, path) == 0) {
394  free(path);
395 
396  /* If the arena is full, show a message to the player */
397  if (arena_full(arena_maps_tmp)) {
398  hooks->draw_info(COLOR_WHITE, who, arena_maps_tmp->message_arena_full);
399  return 1;
400  } else if (arena_maps_tmp->flags & ARENA_FLAG_PARTY && !CONTR(who)->party) {
401  /* Not full but it's party arena and the player is not in a party? */
402  hooks->draw_info(COLOR_WHITE, who, arena_maps_tmp->message_arena_party);
403  return 1;
404  } else {
405  arena_map_players *player_list_tmp = malloc(sizeof(arena_map_players));
406 
407  /* Add the player to the list of players and increase the number of
408  * players/parties */
409 
410  /* For party arenas, also increase the parties count */
411  if (arena_maps_tmp->flags & ARENA_FLAG_PARTY) {
412  arena_map_players *player_list_party;
413  int new_party = 1;
414 
415  /* Loop through the player list */
416  for (player_list_party = arena_maps_tmp->player_list; player_list_party; player_list_party = player_list_party->next) {
417  /* If we found a match for this party number, do not
418  * increase the count */
419  if (CONTR(who)->party && CONTR(who)->party == CONTR(player_list_party->op)->party) {
420  new_party = 0;
421  break;
422  }
423  }
424 
425  /* Increase the count, if this is a new party in the arena
426  * */
427  if (new_party) {
428  arena_maps_tmp->parties++;
429  }
430  }
431 
432  /* Increase the number of players */
433  arena_maps_tmp->players++;
434 
435  player_list_tmp->next = arena_maps_tmp->player_list;
436  arena_maps_tmp->player_list = player_list_tmp;
437 
438  /* Store the player object */
439  player_list_tmp->op = who;
440  return 0;
441  }
442  }
443  }
444 
445  /* If we are here, the arena doesn't have an entry in the linked list --
446  * create it */
447  arena_maps_tmp = malloc(sizeof(arena_maps_struct));
448  strncpy(arena_maps_tmp->path, path, sizeof(arena_maps_tmp->path) - 1);
449  free(path);
450 
451  /* Parse script options */
452  arena_map_parse_script(arena_script, exit_ob, arena_maps_tmp);
453 
454  /* If this arena is full, show a message and return */
455  if (arena_full(arena_maps_tmp)) {
456  hooks->draw_info(COLOR_WHITE, who, arena_maps_tmp->message_arena_full);
457  free(arena_maps_tmp);
458  return 1;
459  } else if (arena_maps_tmp->flags & ARENA_FLAG_PARTY && !CONTR(who)->party) {
460  /* Otherwise if not full and the player is not in party */
461  hooks->draw_info(COLOR_WHITE, who, arena_maps_tmp->message_arena_party);
462  free(arena_maps_tmp);
463  return 1;
464  }
465 
466  /* Add this player to the player count */
467  arena_maps_tmp->players++;
468 
469  /* Add to the party count, if this is party arena */
470  if (arena_maps_tmp->flags & ARENA_FLAG_PARTY) {
471  arena_maps_tmp->parties++;
472  }
473 
474  /* Make a list of players in this arena */
475  arena_maps_tmp->player_list = malloc(sizeof(arena_map_players));
476 
477  /* Store the player */
478  arena_maps_tmp->player_list->op = who;
479 
480  arena_maps_tmp->player_list->next = NULL;
481 
482  arena_maps_tmp->next = arena_maps;
483  arena_maps = arena_maps_tmp;
484 
485  return 0;
486 }
487 
497 static int arena_sign(object *who, const char *path)
498 {
499  arena_maps_struct *arena_maps_tmp;
500 
501  /* Sanity check */
502  if (!path || path[0] == '\0') {
503  return 1;
504  }
505 
506  for (arena_maps_tmp = arena_maps; arena_maps_tmp; arena_maps_tmp = arena_maps_tmp->next) {
507  /* If the path matches */
508  if (!strcmp(arena_maps_tmp->path, path) && arena_maps_tmp->player_list) {
509  arena_map_players *player_list_tmp;
510 
511  hooks->draw_info(COLOR_YELLOW, who, "This arena has the following players in:\n");
512 
513  /* Now go through the list of players in this arena */
514  for (player_list_tmp = arena_maps_tmp->player_list; player_list_tmp; player_list_tmp = player_list_tmp->next) {
515  hooks->draw_info_format(COLOR_YELLOW, who, "%s (level %d)", player_list_tmp->op->name, player_list_tmp->op->level);
516  }
517 
518  if (!(arena_maps_tmp->flags & ARENA_FLAG_PARTY) || (arena_maps_tmp->flags & ARENA_FLAG_PARTY && arena_maps_tmp->flags & ARENA_FLAG_PARTY_PLAYERS)) {
519  hooks->draw_info_format(COLOR_YELLOW, who, "\nTotal players: %d\nMaximum players: %d", arena_maps_tmp->players, arena_maps_tmp->max_players);
520  }
521 
522  if (arena_maps_tmp->flags & ARENA_FLAG_PARTY) {
523  hooks->draw_info_format(COLOR_YELLOW, who, "\nTotal parties: %d\nMaximum parties: %d", arena_maps_tmp->parties, arena_maps_tmp->max_parties);
524  }
525 
526  return 1;
527  }
528  }
529 
530  hooks->draw_info(COLOR_YELLOW, who, "This arena is currently empty.");
531  return 1;
532 }
533 
539 static int arena_event(object *who, object *exit_ob, const char *event_options, const char *arena_script)
540 {
541  /* If the first 5 characters are "sign|", this is an arena sign */
542  if (event_options && !strncmp(event_options, "sign|", 5)) {
543  event_options += 5;
544  return arena_sign(who, event_options);
545  } else {
546  /* Otherwise arena entrance */
547  return arena_enter(who, exit_ob, arena_script);
548  }
549 }
550 
558 static int arena_leave(object *who)
559 {
560  arena_maps_struct *arena_maps_tmp;
561 
562  /* Sanity checks */
563  if (!who || !who->map || !who->map->path || !who->name) {
564  return 0;
565  }
566 
567  /* Go through the list of arenas */
568  for (arena_maps_tmp = arena_maps; arena_maps_tmp; arena_maps_tmp = arena_maps_tmp->next) {
569  /* If it matches, and the player really is in the arena */
570  if (!strcmp(arena_maps_tmp->path, who->map->path) && check_arena_player(who, arena_maps_tmp->player_list)) {
571  /* If this is party arena, we will want to see if we have to
572  * decrease the parties count */
573  if (arena_maps_tmp->flags & ARENA_FLAG_PARTY) {
574  arena_map_players *player_list_party;
575  int do_remove = 1;
576 
577  /* Loop through the player list for this map */
578  for (player_list_party = arena_maps_tmp->player_list; player_list_party; player_list_party = player_list_party->next) {
579  /* If the party number matches, we're not going to remove
580  * this party */
581  if (player_list_party->op != who && CONTR(who)->party && CONTR(who)->party == CONTR(player_list_party->op)->party) {
582  do_remove = 0;
583  break;
584  }
585  }
586 
587  /* Removing the party? Then decrease the count. */
588  if (do_remove) {
589  arena_maps_tmp->parties--;
590  }
591  }
592 
593  /* Decrease the count of players */
594  arena_maps_tmp->players--;
595 
596  /* Remove the player from this the arena's player list */
597  remove_arena_player(who, &arena_maps_tmp->player_list);
598  return 0;
599  }
600  }
601 
602  return 0;
603 }
604 
605 MODULEAPI void *triggerEvent(int *type, ...)
606 {
607  object *activator, *who, *other, *event;
608  va_list args;
609  int eventcode, event_type;
610  static int result = 0;
611 
612  va_start(args, type);
613  event_type = va_arg(args, int);
614  if (event_type == PLUGIN_EVENT_UNIT) {
615  va_end(args);
616  return &result;
617  }
618 
619  eventcode = va_arg(args, int);
620  activator = va_arg(args, object *);
621 
622  if (event_type == PLUGIN_EVENT_NORMAL) {
623  switch (eventcode) {
624  case EVENT_APPLY:
625  case EVENT_TRIGGER:
626  {
627  char *text, *script, *options;
628  int parm1, parm2, parm3, parm4;
629 
630  who = va_arg(args, object *);
631  other = va_arg(args, object *);
632  event = va_arg(args, object *);
633  text = va_arg(args, char *);
634  parm1 = va_arg(args, int);
635  parm2 = va_arg(args, int);
636  parm3 = va_arg(args, int);
637  parm4 = va_arg(args, int);
638  script = va_arg(args, char *);
639  options = va_arg(args, char *);
640 
641  (void) other;
642  (void) event;
643  (void) text;
644  (void) parm1;
645  (void) parm2;
646  (void) parm3;
647  (void) parm4;
648 
649  result = arena_event(activator, who, options, script);
650  break;
651  }
652  }
653  } else if (event_type == PLUGIN_EVENT_MAP) {
654  switch (eventcode) {
655  case MEVENT_LEAVE:
656  result = arena_leave(activator);
657  break;
658  }
659  } else if (event_type == PLUGIN_EVENT_GLOBAL) {
660  switch (eventcode) {
661  case GEVENT_PLAYER_DEATH:
662  case GEVENT_LOGOUT:
663  result = arena_leave(activator);
664  break;
665  }
666  }
667 
668  va_end(args);
669  return &result;
670 }
671 
static void arena_map_parse_script(const char *arena_script, object *exit_ob, arena_maps_struct *arena_map)
Definition: plugin_arena.c:296
#define ARENA_FLAG_PARTY_PLAYERS
Definition: plugin_arena.c:153
struct plugin_hooklist * hooks
Definition: plugin_arena.c:160
char message_arena_party[MAX_BUF]
Definition: plugin_arena.c:138
uint8_t type
One of operation types.
Definition: sound_ambient.c:45
static int arena_sign(object *who, const char *path)
Definition: plugin_arena.c:497
shstr * path
Definition: map.h:568
static void remove_arena_player(object *op, arena_map_players **player_list)
Definition: plugin_arena.c:231
struct arena_map_players * next
Definition: plugin_arena.c:108
#define ARENA_FLAG_NONE
Definition: plugin_arena.c:149
static int arena_leave(object *who)
Definition: plugin_arena.c:558
struct arena_maps_struct arena_maps_struct
struct arena_map_players arena_map_players
static void arena_map_parse_line(arena_maps_struct *arena_map, const char *line)
Definition: plugin_arena.c:256
static int arena_enter(object *who, object *exit_ob, const char *arena_script)
Definition: plugin_arena.c:378
#define PLUGIN_NAME
Definition: plugin_arena.c:95
#define PLUGIN_VERSION
Definition: plugin_arena.c:98
#define EVENT_APPLY
Definition: plugin.h:75
struct arena_maps_struct * next
Definition: plugin_arena.c:141
#define MEVENT_LEAVE
Definition: plugin.h:121
#define ARENA_FLAG_PARTY
Definition: plugin_arena.c:151
MODULEAPI void * triggerEvent(int *type,...)
Definition: plugin_arena.c:605
#define EVENT_TRIGGER
Definition: plugin.h:93
static int arena_full(arena_maps_struct *arena_map)
Definition: plugin_arena.c:344
char path[HUGE_BUF]
Definition: plugin_arena.c:114
static int arena_event(object *who, object *exit_ob, const char *event_options, const char *arena_script)
Definition: plugin_arena.c:539
arena_maps_struct * arena_maps
Definition: plugin_arena.c:157
struct mapdef * map
Definition: object.h:139
#define PLUGIN_EVENT_NORMAL
Definition: plugin.h:59
const char * name
Definition: object.h:168
#define GEVENT_PLAYER_DEATH
Definition: plugin.h:157
char message_arena_full[MAX_BUF]
Definition: plugin_arena.c:135
#define PLUGIN_EVENT_UNIT
Definition: plugin.h:65
#define GEVENT_LOGOUT
Definition: plugin.h:155
MODULEAPI void initPlugin(struct plugin_hooklist *hooklist)
Definition: plugin_arena.c:162
#define MAP_UNIQUE(m)
Definition: map.h:96
static int check_arena_player(object *op, arena_map_players *player_list)
Definition: plugin_arena.c:210
MODULEAPI void getPluginProperty(int *type,...)
Definition: plugin_arena.c:171
#define PLUGIN_EVENT_MAP
Definition: plugin.h:61
MODULEAPI void postinitPlugin(void)
Definition: plugin_arena.c:196
int8_t level
Definition: object.h:347
#define PLUGIN_EVENT_GLOBAL
Definition: plugin.h:63
arena_map_players * player_list
Definition: plugin_arena.c:123
MODULEAPI void closePlugin(void)
Definition: plugin_arena.c:167