Atrinik Server  4.0
exit.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 
38 #include <global.h>
39 #include <plugin.h>
40 #include <object.h>
41 #include <object_methods.h>
42 #include <exit.h>
43 
54 static object *
55 exit_find (object *op, bool do_load)
56 {
57  HARD_ASSERT(op != NULL);
58 
59  object *altern[20];
60  int nrofalt = 0;
61 
62  /* Find all other teleporters within range. This range should really
63  * be settable by some object attribute instead of using hard coded
64  * values. */
65  for (int i = -5; i < 6; i++) {
66  for (int j = -5; j < 6; j++) {
67  if (i == 0 && j == 0) {
68  /* Skip our own tile */
69  continue;
70  }
71 
72  int x = op->x + i;
73  int y = op->y + j;
74  mapstruct *m;
75  if (do_load) {
76  m = get_map_from_coord(op->map, &x, &y);
77  } else {
78  m = get_map_from_coord2(op->map, &x, &y);
79  }
80 
81  if (m == NULL) {
82  continue;
83  }
84 
85  FOR_MAP_PREPARE(m, x, y, tmp) {
86  if (tmp->type == op->type && tmp->sub_type == op->sub_type) {
87  /* Assumes altern can hold at least one element */
88  altern[nrofalt++] = tmp;
89 
90  /* Reached the maximum, no point in going on. */
91  if (nrofalt == arraysize(altern)) {
92  goto loop_exit;
93  }
94  }
95  } FOR_MAP_FINISH();
96  }
97  }
98 
99 loop_exit:
100 
101  if (nrofalt == 0) {
102  return NULL;
103  }
104 
105  return altern[rndm(0, nrofalt - 1)];
106 }
107 
119 static bool
120 exit_activate (object *op, object *applier)
121 {
122  HARD_ASSERT(op != NULL);
123  HARD_ASSERT(applier != NULL);
124 
125  if (EXIT_PATH(op) != NULL) {
126  return object_enter_map(applier, op, NULL, 0, 0, false);
127  }
128 
129  int x, y;
130  mapstruct *m = exit_get_destination(op, &x, &y, true);
131  if (m == NULL) {
132  return false;
133  }
134 
135  int i = map_free_spot(m, x, y, 1, SIZEOFFREE1, applier->arch, applier);
136  if (i == -1) {
137  return false;
138  }
139 
140  applier->direction = i;
141  SET_ANIMATION_STATE(applier);
142 
143  object_remove(applier, 0);
144  applier->x = x + freearr_x[i];
145  applier->y = y + freearr_y[i];
146  object_insert_map(applier, m, NULL, 0);
147 
148  return true;
149 }
150 
152 static int
153 apply_func (object *op, object *applier, int aflags)
154 {
155  HARD_ASSERT(op != NULL);
156  HARD_ASSERT(applier != NULL);
157 
158  if (op->map == NULL) {
159  return OBJECT_METHOD_OK;
160  }
161 
162  /* Do not allow multi-part objects to use exits. */
163  if (op->more != NULL) {
164  return OBJECT_METHOD_OK;
165  }
166 
167  if (QUERY_FLAG(applier, FLAG_NO_TELEPORT)) {
168  return OBJECT_METHOD_OK;
169  }
170 
171  bool is_shop = false;
172  for (int sub_layer = 0; sub_layer < NUM_SUB_LAYERS; sub_layer++) {
173  object *tmp = GET_MAP_OB_LAYER(op->map,
174  op->x,
175  op->y,
176  LAYER_FLOOR,
177  sub_layer);
178  if (tmp != NULL && tmp->type == SHOP_FLOOR) {
179  is_shop = true;
180  break;
181  }
182  }
183 
184  /* It's a shop exit, don't let the player out until they've paid for
185  * all the items they want to buy (if any). */
186  if (is_shop && applier->type == PLAYER && !shop_pay_items(applier)) {
187  int i = map_free_spot(applier->map,
188  applier->x,
189  applier->y,
190  1,
191  SIZEOFFREE1, applier->arch,
192  NULL);
193  if (i != -1) {
194  object_remove(applier, 0);
195  applier->x += freearr_x[i];
196  applier->y += freearr_y[i];
197  object_insert_map(applier, applier->map, op, 0);
198  }
199 
200  return OBJECT_METHOD_OK;
201  }
202 
203  /* Don't display messages for random maps. */
204  if (op->msg != NULL && (EXIT_PATH(op) == NULL ||
205  (strncmp(EXIT_PATH(op), "/!", 2) != 0 &&
206  strncmp(EXIT_PATH(op), "/random/", 8) != 0))) {
207  draw_info(COLOR_NAVY, applier, op->msg);
208  } else if (is_shop) {
209  draw_info(COLOR_WHITE, applier, "Thank you for visiting our shop.");
210  }
211 
212  if (op->race != NULL) {
213  play_sound_map(op->map, CMD_SOUND_EFFECT, op->race, op->x, op->y, 0, 0);
214  }
215 
216  if (!exit_activate(op, applier)) {
217  if (!QUERY_FLAG(op, FLAG_SYS_OBJECT)) {
218  char *name = object_get_name_s(op, applier);
219  draw_info_format(COLOR_WHITE, applier, "The %s is closed.", name);
220  efree(name);
221  }
222 
223  log_error("Exit %s leads nowhere, applier: %s",
224  object_get_str(op),
225  object_get_str(applier));
226  return OBJECT_METHOD_OK;
227  }
228 
229  return OBJECT_METHOD_OK;
230 }
231 
233 static int
234 move_on_func (object *op, object *victim, object *originator, int state)
235 {
236  HARD_ASSERT(op != NULL);
237  HARD_ASSERT(victim != NULL);
238 
239  return apply_func(op, victim, 0);
240 }
241 
243 static void
244 process_func (object *op)
245 {
246  HARD_ASSERT(op != NULL);
247 
248  if (op->map == NULL) {
249  return;
250  }
251 
252  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
253  if (tmp == op || QUERY_FLAG(tmp, FLAG_NO_TELEPORT)) {
254  continue;
255  }
256 
257  if (HAS_EVENT(op, EVENT_TRIGGER)) {
258  int ret = trigger_event(EVENT_TRIGGER,
259  tmp,
260  op,
261  NULL,
262  NULL,
263  0,
264  0,
265  0,
266  0);
267  if (ret == 1) {
268  return;
269  } else if (ret == 2) {
270  continue;
271  }
272  }
273 
274  object_apply(op, tmp, 0);
275  } FOR_MAP_FINISH();
276 }
277 
279 static int
280 trigger_func (object *op, object *cause, int state)
281 {
282  HARD_ASSERT(op != NULL);
283  HARD_ASSERT(cause != NULL);
284 
285  process_func(op);
286  return OBJECT_METHOD_OK;
287 }
288 
290 static void
291 insert_map_func (object *op)
292 {
293  HARD_ASSERT(op != NULL);
294 
295  if (EXIT_PATH(op) != NULL) {
296  /* Exit has a path, ensure it's absolute and take unique maps
297  * into account. */
298  bool is_unique = MAP_UNIQUE(op->map) && !map_path_isabs(EXIT_PATH(op));
299  char *path = map_get_path(op->map,
300  EXIT_PATH(op),
301  is_unique,
302  NULL);
303  FREE_AND_COPY_HASH(EXIT_PATH(op), path);
304  efree(path);
305  } else if (op->last_heal > 0 && op->last_heal <= TILED_NUM &&
306  op->map->tile_path[op->last_heal - 1] != NULL) {
307  FREE_AND_ADD_REF_HASH(EXIT_PATH(op),
308  op->map->tile_path[op->last_heal - 1]);
309 
310  EXIT_X(op) = op->x;
311  EXIT_Y(op) = op->y;
312 
313  if (QUERY_FLAG(op, FLAG_XRAYS)) {
314  int dir;
315  if (op->last_heal - 1 == TILED_UP) {
316  dir = absdir(op->direction + 4);
317  } else {
318  dir = op->direction;
319  }
320 
321  EXIT_X(op) += freearr_x[dir];
322  EXIT_Y(op) += freearr_y[dir];
323  }
324  } else if (EXIT_X(op) != -1 && EXIT_Y(op) != -1) {
325  /* Exit with no path but has X/Y coordinates, use the map's path. */
326  FREE_AND_ADD_REF_HASH(EXIT_PATH(op), op->map->path);
327  }
328 
329  /* If the exit has a usable path, add it to the map's list of exits. */
330  if (EXIT_PATH(op) != NULL) {
331  map_exit_t *exit = ecalloc(1, sizeof(*exit));
332  exit->obj = op;
333  DL_APPEND(op->map->exits, exit);
334  }
335 }
336 
338 static void
339 remove_map_func (object *op)
340 {
341  HARD_ASSERT(op != NULL);
342 
343  map_exit_t *exit, *tmp;
344  DL_FOREACH_SAFE(op->map->exits, exit, tmp) {
345  if (exit->obj == op) {
346  DL_DELETE(op->map->exits, exit);
347  efree(exit);
348  break;
349  }
350  }
351 }
352 
357 {
358  OBJECT_METHODS(EXIT)->apply_func = apply_func;
359  OBJECT_METHODS(EXIT)->move_on_func = move_on_func;
360  OBJECT_METHODS(EXIT)->process_func = process_func;
361  OBJECT_METHODS(EXIT)->trigger_func = trigger_func;
362  OBJECT_METHODS(EXIT)->insert_map_func = insert_map_func;
363  OBJECT_METHODS(EXIT)->remove_map_func = remove_map_func;
364 }
365 
382 mapstruct *
383 exit_get_destination (object *op, int *x, int *y, bool do_load)
384 {
385  HARD_ASSERT(op != NULL);
386 
387  if (EXIT_PATH(op) != NULL) {
388  mapstruct *m;
389  if (do_load) {
390  m = ready_map_name(EXIT_PATH(op), NULL, 0);
391  } else {
392  m = has_been_loaded_sh(EXIT_PATH(op));
393  }
394 
395  if (m == NULL) {
396  return NULL;
397  }
398 
399  int xt = EXIT_X(op);
400  int yt = EXIT_Y(op);
401  m = get_map_from_coord(m, &xt, &yt);
402 
403  if (x != NULL) {
404  *x = xt;
405  }
406 
407  if (y != NULL) {
408  *y = yt;
409  }
410 
411  return m;
412  } else if (op->sub_type != 0) {
413  object *other_exit = exit_find(op, do_load);
414  if (other_exit == NULL) {
415  return NULL;
416  }
417 
418  if (x != NULL) {
419  *x = other_exit->x;
420  }
421 
422  if (y != NULL) {
423  *y = other_exit->y;
424  }
425 
426  return other_exit->map;
427  }
428 
429  return NULL;
430 }
#define FREE_AND_ADD_REF_HASH(_sv_, _nv_)
Definition: global.h:116
#define FREE_AND_COPY_HASH(_sv_, _nv_)
Definition: global.h:100
#define EXIT
Definition: define.h:312
#define FLAG_SYS_OBJECT
Definition: define.h:1243
static int trigger_func(object *op, object *cause, int state)
Definition: exit.c:280
static int apply_func(object *op, object *applier, int aflags)
Definition: exit.c:153
const char * race
Definition: object.h:174
OBJECT_TYPE_INIT_DEFINE(exit)
Definition: exit.c:356
int trigger_event(int event_type, object *const activator, object *const me, object *const other, const char *msg, int parm1, int parm2, int parm3, int flags)
Definition: plugins.c:510
mapstruct * get_map_from_coord2(mapstruct *m, int *x, int *y)
Definition: map.c:2000
#define TILED_UP
Definition: global.h:203
shstr * path
Definition: map.h:568
#define SIZEOFFREE1
Definition: define.h:654
mapstruct * get_map_from_coord(mapstruct *m, int *x, int *y)
Definition: map.c:1869
int16_t last_heal
Definition: object.h:310
bool shop_pay_items(object *op)
Definition: shop.c:542
#define SHOP_FLOOR
Definition: define.h:316
#define LAYER_FLOOR
Definition: map.h:49
#define HAS_EVENT(ob, event)
Definition: plugin.h:179
static int absdir(int d)
Definition: define.h:1838
#define PLAYER
Definition: define.h:122
bool object_enter_map(object *op, object *exit, mapstruct *m, int x, int y, bool fixed_pos)
Definition: object.c:2956
int map_free_spot(mapstruct *m, int x, int y, int start, int stop, archetype_t *at, object *op)
Definition: map.c:2942
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
struct archetype * arch
Definition: object.h:225
void object_remove(object *op, int flags)
Definition: object.c:1623
int object_apply(object *op, object *applier, int aflags)
char * object_get_name_s(const object *op, const object *caller)
Definition: item.c:398
static object * exit_find(object *op, bool do_load)
Definition: exit.c:55
int16_t y
Definition: object.h:276
#define EVENT_TRIGGER
Definition: plugin.h:93
const char * object_get_str(const object *op)
Definition: object.c:3151
int8_t direction
Definition: object.h:350
struct mapdef * map
Definition: object.h:139
static bool exit_activate(object *op, object *applier)
Definition: exit.c:120
shstr * tile_path[TILED_NUM]
Definition: map.h:571
static int move_on_func(object *op, object *victim, object *originator, int state)
Definition: exit.c:234
#define FOR_MAP_FINISH()
Definition: define.h:1759
#define TILED_NUM
Definition: global.h:208
static void insert_map_func(object *op)
Definition: exit.c:291
int16_t x
Definition: object.h:273
#define NUM_SUB_LAYERS
Definition: map.h:71
object * object_insert_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1741
void play_sound_map(mapstruct *map, int type, const char *filename, int x, int y, int loop, int volume)
Definition: sounds.c:159
#define FLAG_XRAYS
Definition: define.h:1110
static void process_func(object *op)
Definition: exit.c:244
int freearr_x[SIZEOFFREE]
Definition: object.c:84
uint8_t type
Definition: object.h:360
static void remove_map_func(object *op)
Definition: exit.c:339
#define OBJECT_METHODS(type)
#define MAP_UNIQUE(m)
Definition: map.h:96
#define FLAG_NO_TELEPORT
Definition: define.h:1284
const char * msg
Definition: object.h:183
mapstruct * has_been_loaded_sh(shstr *name)
Definition: map.c:389
#define OBJECT_METHOD_OK
#define SET_ANIMATION_STATE(ob)
Definition: global.h:287
mapstruct * ready_map_name(const char *name, mapstruct *originator, int flags)
Definition: map.c:1584
Definition: map.h:536
Definition: map.h:517
mapstruct * exit_get_destination(object *op, int *x, int *y, bool do_load)
Definition: exit.c:383
int freearr_y[SIZEOFFREE]
Definition: object.c:99
struct obj * more
Definition: object.h:133
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:1752
uint8_t sub_type
Definition: object.h:363