Atrinik Server  4.0
move.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 <arch.h>
32 #include <player.h>
33 #include <object.h>
34 #include <door.h>
35 
41 int get_random_dir(void)
42 {
43  return rndm(1, 8);
44 }
45 
53 int get_randomized_dir(int dir)
54 {
55  return absdir(dir + rndm(0, 2) + rndm(0, 2) - 2);
56 }
57 
77 int object_move_to(object *op, int dir, object *originator, mapstruct *m,
78  int x, int y)
79 {
80  HARD_ASSERT(op != NULL);
81  HARD_ASSERT(originator != NULL);
82  HARD_ASSERT(m != NULL);
83 
84  SOFT_ASSERT_RC(dir > 0 && dir <= NUM_DIRECTION, 0, "Invalid direction: %d",
85  dir);
86  SOFT_ASSERT_RC(x >= 0 && x < m->width, 0, "Invalid X coordinate: %d", x);
87  SOFT_ASSERT_RC(y >= 0 && y < m->height, 0, "Invalid Y coordinate: %d", y);
88 
89  object *floor =
90  GET_MAP_OB_LAYER(op->map, op->x, op->y, LAYER_FLOOR, op->sub_layer);
91  int z = floor != NULL ? floor->z : 0;
92  int z_highest = 0, sub_layer = 0;
93  object *floor_tmp;
94 
95  FOR_MAP_LAYER_BEGIN(m, x, y, LAYER_FLOOR, -1, floor_tmp) {
96  if (floor_tmp->z - z > MOVE_MAX_HEIGHT_DIFF) {
97  continue;
98  }
99 
100  if (floor_tmp->z > z_highest) {
101  z_highest = floor_tmp->z;
102  sub_layer = floor_tmp->sub_layer;
103  }
105 
106  object_remove(op, 0);
107 
108  op->sub_layer = sub_layer;
109  op->x = x;
110  op->y = y;
111  op = object_insert_map(op, m, originator, INS_FALL_THROUGH);
112 
113  if (op == NULL) {
114  return 1;
115  }
116 
117  if (op->map == m && op->x == x && op->y == y) {
118  floor = GET_MAP_OB_LAYER(m, x, y, LAYER_FLOOR, sub_layer);
119  int fall_floors = (int) ((z - (floor != NULL ? floor->z : 0)) / 50.0 +
120  0.5);
121 
122  if (fall_floors > 0 && IS_LIVE(op)) {
123  OBJ_DESTROYED_BEGIN(op) {
124  attack_perform_fall(op, fall_floors);
125 
126  if (OBJ_DESTROYED(op)) {
127  return 1;
128  }
129  } OBJ_DESTROYED_END();
130  }
131  }
132 
133  if (op->type == PLAYER) {
134  CONTR(op)->stat_steps_taken++;
135  }
136 
137  return 1;
138 }
139 
155 int move_ob(object *op, int dir, object *originator)
156 {
157  HARD_ASSERT(op != NULL);
158 
159  SOFT_ASSERT_RC(!QUERY_FLAG(op, FLAG_REMOVED), 0, "Trying to move a removed "
160  "object: %s", object_get_str(op));
161 
162  op = HEAD(op);
163 
164  if (QUERY_FLAG(op, FLAG_CONFUSED)) {
165  dir = get_randomized_dir(dir);
166  }
167 
168  op->anim_flags |= ANIM_FLAG_MOVING;
169  op->anim_flags &= ~ANIM_FLAG_STOP_MOVING;
170  op->direction = dir;
171 
172  int xt = op->x + freearr_x[dir];
173  int yt = op->y + freearr_y[dir];
174  mapstruct *m = get_map_from_coord(op->map, &xt, &yt);
175 
176  if (m == NULL) {
177  return 0;
178  }
179 
180  if (op->type != PLAYER || !CONTR(op)->tcl) {
181  int flags = object_blocked(op, m, xt, yt);
182 
183  if (flags != 0) {
184  if (flags & P_DOOR_CLOSED) {
185  door_show_message(op, m, xt, yt);
186  }
187 
188  return 0;
189  }
190  }
191 
192  bool opened_door = false;
193  for (object *tmp = op; tmp != NULL; tmp = tmp->more) {
194  int tmp_x = xt + tmp->arch->clone.x;
195  int tmp_y = yt + tmp->arch->clone.y;
196  mapstruct *tmp_map = get_map_from_coord(m, &tmp_x, &tmp_y);
197  if (tmp_map == NULL) {
198  return 0;
199  }
200 
201  if (door_try_open(op, tmp_map, tmp_x, tmp_y, false)) {
202  opened_door = true;
203  }
204  }
205 
206  if (opened_door) {
207  return -1;
208  }
209 
210  if (!object_move_to(op, dir, originator, m, xt, yt)) {
211  return 0;
212  }
213 
214  return dir;
215 }
216 
237 int transfer_ob(object *op, int x, int y, int randomly, object *originator, object *trap)
238 {
239  int i, ret;
240 
241  if (trap != NULL && EXIT_PATH(trap)) {
242  if (op->type == PLAYER && trap->msg && strncmp(EXIT_PATH(trap), "/!", 2) && strncmp(EXIT_PATH(trap), "/random/", 8)) {
243  draw_info(COLOR_NAVY, op, trap->msg);
244  }
245 
246  object_enter_map(op, trap, NULL, 0, 0, false);
247  return 1;
248  } else if (randomly) {
249  i = map_free_spot(op->map, x, y, 0, SIZEOFFREE3, op->arch, NULL);
250  } else {
251  i = map_free_spot_first(op->map, x, y, op->arch, op);
252  }
253 
254  /* No free spot */
255  if (i == -1) {
256  return 0;
257  }
258 
259  if (op->head != NULL) {
260  op = op->head;
261  }
262 
263  object_remove(op, 0);
264 
265  op->x = x + freearr_x[i];
266  op->y = y + freearr_y[i];
267 
268  ret = (object_insert_map(op, op->map, originator, 0) == NULL);
269 
270  return ret;
271 }
272 
284 int push_ob(object *op, int dir, object *pusher)
285 {
286  object *tmp, *floor_ob;
287  mapstruct *m;
288  int x, y;
289 
290  /* Don't allow pushing multi-arch objects. */
291  if (op->head) {
292  return 0;
293  }
294 
295  /* Check whether we are strong enough to push this object. */
296  if (op->weight && (op->weight / 50000 - 1 > 0 ? rndm(0, op->weight / 50000 - 1) : 0) > pusher->stats.Str) {
297  return 0;
298  }
299 
300  x = op->x + freearr_x[dir];
301  y = op->y + freearr_y[dir];
302 
303  if (!(m = get_map_from_coord(op->map, &x, &y))) {
304  return 0;
305  }
306 
307  floor_ob = GET_MAP_OB_LAYER(m, x, y, LAYER_FLOOR, 0);
308 
309  /* Floor has no-push flag set? */
310  if (floor_ob && QUERY_FLAG(floor_ob, FLAG_XRAYS)) {
311  return 0;
312  }
313 
314  if (blocked(op, m, x, y, op->terrain_flag)) {
315  return 0;
316  }
317 
318  /* Try to find something that would block the push. */
319  for (tmp = GET_MAP_OB(m, x, y); tmp; tmp = tmp->above) {
320  if (tmp->head || IS_LIVE(tmp) || tmp->type == EXIT) {
321  return 0;
322  }
323  }
324 
325  object_remove(op, 0);
326 
327  op->x = op->x + freearr_x[dir];
328  op->y = op->y + freearr_y[dir];
329  object_insert_map(op, op->map, pusher, 0);
330  return 1;
331 }
#define EXIT
Definition: define.h:312
void door_show_message(object *op, mapstruct *m, int x, int y)
Definition: door.c:312
#define MOVE_MAX_HEIGHT_DIFF
Definition: define.h:1604
int get_randomized_dir(int dir)
Definition: move.c:53
mapstruct * get_map_from_coord(mapstruct *m, int *x, int *y)
Definition: map.c:1869
#define OBJ_DESTROYED(_op)
Definition: object.h:701
int blocked(object *op, mapstruct *m, int x, int y, int terrain)
Definition: map.c:598
#define LAYER_FLOOR
Definition: map.h:49
struct obj * above
Definition: object.h:120
int object_blocked(object *op, mapstruct *m, int x, int y)
Definition: object.c:3224
static int absdir(int d)
Definition: define.h:1838
#define IS_LIVE(op)
Definition: define.h:841
#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
#define OBJ_DESTROYED_BEGIN(_op)
Definition: object.h:695
int push_ob(object *op, int dir, object *pusher)
Definition: move.c:284
int16_t y
Definition: object.h:276
#define P_DOOR_CLOSED
Definition: map.h:272
#define NUM_DIRECTION
Definition: map.h:853
const char * object_get_str(const object *op)
Definition: object.c:3151
uint8_t sub_layer
Definition: object.h:408
int8_t direction
Definition: object.h:350
#define INS_FALL_THROUGH
Definition: object.h:575
int transfer_ob(object *op, int x, int y, int randomly, object *originator, object *trap)
Definition: move.c:237
uint32_t weight
Definition: object.h:246
int16_t z
Definition: object.h:286
struct mapdef * map
Definition: object.h:139
#define SIZEOFFREE3
Definition: define.h:658
#define FOR_MAP_LAYER_END
Definition: define.h:1657
#define HEAD(op)
Definition: object.h:657
int16_t x
Definition: object.h:273
#define FOR_MAP_LAYER_BEGIN(_m, _x, _y, _layer, _sub_layer, _obj)
Definition: define.h:1630
#define FLAG_REMOVED
Definition: define.h:930
int object_move_to(object *op, int dir, object *originator, mapstruct *m, int x, int y)
Definition: move.c:77
object * object_insert_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1741
#define FLAG_XRAYS
Definition: define.h:1110
bool door_try_open(object *op, mapstruct *m, int x, int y, bool test)
Definition: door.c:231
living stats
Definition: object.h:481
int get_random_dir(void)
Definition: move.c:41
int freearr_x[SIZEOFFREE]
Definition: object.c:84
uint8_t type
Definition: object.h:360
uint16_t terrain_flag
Definition: object.h:301
const char * msg
Definition: object.h:183
int8_t Str
Definition: living.h:103
uint8_t anim_flags
Definition: object.h:390
struct obj * head
Definition: object.h:136
int map_free_spot_first(mapstruct *m, int x, int y, archetype_t *at, object *op)
Definition: map.c:3009
#define FLAG_CONFUSED
Definition: define.h:872
int move_ob(object *op, int dir, object *originator)
Definition: move.c:155
void attack_perform_fall(object *op, int fall_floors)
Definition: attack.c:1435
Definition: map.h:536
int freearr_y[SIZEOFFREE]
Definition: object.c:99
struct obj * more
Definition: object.h:133
#define OBJ_DESTROYED_END()
Definition: object.h:705