Atrinik Server  4.0
projectile.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 
31 #include <global.h>
32 #include <arch.h>
33 #include <object_methods.h>
34 
44 static object *projectile_stick(object *op, object *victim)
45 {
46  object *owner;
47 
48  /* Only insert arrows, and as long as they are no more than 1kg, and can be
49  * picked up. */
50  if (op->type != ARROW || op->weight > 1000 || QUERY_FLAG(op, FLAG_NO_PICK)) {
51  return op;
52  }
53 
54  owner = object_owner(op);
55 
56  if (owner) {
57  op->attacked_by = owner;
58  op->attacked_by_count = owner->count;
59  }
60 
61  object_remove(op, 0);
62  op = object_insert_into(op, victim, 0);
63 
64  return op;
65 }
66 
69 {
70  mapstruct *m;
71  int x, y;
72 
73  if (!op->map) {
74  return;
75  }
76 
77  if (op->last_sp-- <= 0 || !op->direction) {
79  return;
80  }
81 
82  x = op->x + DIRX(op);
83  y = op->y + DIRY(op);
84  m = get_map_from_coord(op->map, &x, &y);
85 
86  if (!m) {
87  object_remove(op, 0);
88  object_destroy(op);
89  return;
90  }
91 
92  if (wall(m, x, y)) {
93  if (QUERY_FLAG(op, FLAG_REFLECTING)) {
94  if (op->direction & 1) {
95  op->direction = absdir(op->direction + 4);
96  } else {
97  int left, right;
98 
99  left = wall(op->map, op->x + freearr_x[absdir(op->direction - 1)], op->y + freearr_y[absdir(op->direction - 1)]);
100  right = wall(op->map, op->x + freearr_x[absdir(op->direction + 1)], op->y + freearr_y[absdir(op->direction + 1)]);
101 
102  if (left == right) {
103  op->direction = absdir(op->direction + 4);
104  } else if (left) {
105  op->direction = absdir(op->direction + 2);
106  } else if (right) {
107  op->direction = absdir(op->direction - 2);
108  }
109  }
110 
112  } else {
114  return;
115  }
116  }
117 
118  op = object_projectile_move(op);
119 
120  if (!op) {
121  return;
122  }
123 
124  if (GET_MAP_FLAGS(op->map, op->x, op->y) & (P_IS_MONSTER | P_IS_PLAYER)) {
125  object *tmp;
126  int ret;
127 
128  FOR_MAP_LAYER_BEGIN(op->map, op->x, op->y, LAYER_LIVING, -1, tmp)
129  {
130  tmp = HEAD(tmp);
131 
132  if (((QUERY_FLAG(op, FLAG_IS_MISSILE) && QUERY_FLAG(tmp, FLAG_REFL_MISSILE)) || (QUERY_FLAG(op, FLAG_IS_SPELL) && QUERY_FLAG(tmp, FLAG_REFL_SPELL))) && rndm(0, 99) < 90 - (op->level / 10)) {
133  op->direction = absdir(op->direction + 4);
136  } else {
137  ret = object_projectile_hit(op, tmp);
138 
139  if (ret == OBJECT_METHOD_OK) {
141  return;
142  } else if (ret == OBJECT_METHOD_ERROR) {
143  return;
144  }
145  }
146  }
148  }
149 }
150 
152 object *common_object_projectile_move(object *op)
153 {
154  mapstruct *m;
155  int x, y;
156 
157  x = op->x + freearr_x[op->direction];
158  y = op->y + freearr_y[op->direction];
159 
160  m = get_map_from_coord(op->map, &x, &y);
161 
162  if (m == NULL) {
164  return NULL;
165  }
166 
167  OBJ_DESTROYED_BEGIN(op) {
168  if (!object_move_to(op, op->direction, op, m, x, y)) {
170  return NULL;
171  }
172 
173  if (OBJ_DESTROYED(op)) {
174  return NULL;
175  }
176  } OBJ_DESTROYED_END();
177 
178  return op;
179 }
180 
182 object *common_object_projectile_stop_missile(object *op, int reason)
183 {
184  /* Reset 'owner' when picking it up. */
185  if (reason == OBJECT_PROJECTILE_PICKUP) {
186  op->attacked_by = NULL;
187  op->attacked_by_count = 0;
188  }
189 
190  /* Already stopped, nothing to do. */
191  if (DBL_EQUAL(op->speed, 0.0)) {
192  return op;
193  }
194 
195  /* Small chance of breaking */
196  if (op->last_eat && rndm_chance(op->last_eat)) {
197  object_remove(op, 0);
198  object_destroy(op);
199  return NULL;
200  }
201 
202  /* Restore arrow's properties. */
203  if (op->type == ARROW) {
204  object *owner;
205 
206  owner = object_owner(op);
207  object_owner_clear(op);
208 
209  op->direction = 0;
211 
212  CLEAR_FLAG(op, FLAG_FLYING);
215  CLEAR_FLAG(op, FLAG_FLY_ON);
216 
217  /* Restore WC, damage and range. */
218  op->stats.wc = op->last_heal;
219  op->stats.dam = op->stats.hp;
220  op->last_sp = op->stats.sp;
221 
222  op->last_heal = op->stats.hp = op->stats.sp = 0;
223 
224  /* Reset level, speed and wc_range. */
225  op->level = op->arch->clone.level;
226  op->speed = op->arch->clone.speed;
227  op->stats.wc_range = op->arch->clone.stats.wc_range;
228 
229  if (QUERY_FLAG(&op->arch->clone, FLAG_CAN_STACK)) {
231  }
232 
233  if (!owner || owner->type != PLAYER) {
235  SET_FLAG(op, FLAG_NO_PICK);
236 
237  op->type = MISC_OBJECT;
238  op->speed = 0.1f;
239  op->speed_left = 0.0f;
240  op->stats.food = 20;
241  }
242 
244 
245  bool insert_map = op->map != NULL;
246  if (insert_map) {
247  object_remove(op, 0);
248  }
249 
250  op->layer = op->arch->clone.layer;
251 
252  if (insert_map) {
253  op = object_insert_map(op, op->map, op, INS_FALL_THROUGH);
254  } else {
255  op = object_merge(op);
256  }
257  } else if (op->inv) {
258  object *payload;
259 
260  /* Not an arrow, the object has payload instead. */
261 
262  payload = op->inv;
263 
264  object_remove(payload, 0);
265  object_remove(op, 0);
266  object_destroy(op);
267  payload->x = op->x;
268  payload->y = op->y;
269  payload = object_insert_map(payload, op->map, op, INS_FALL_THROUGH);
270 
271  return payload;
272  } else {
273  /* Should not happen... */
274 
275  object_remove(op, 0);
276  object_destroy(op);
277  return NULL;
278  }
279 
280  return op;
281 }
282 
284 object *common_object_projectile_stop_spell(object *op, int reason)
285 {
286  if (reason == OBJECT_PROJECTILE_STOP_HIT && op->stats.dam > 0) {
287  return op;
288  }
289 
290  if (op->other_arch) {
291  explode_object(op);
292  } else {
293  object_remove(op, 0);
294  object_destroy(op);
295  }
296 
297  return NULL;
298 }
299 
301 object *common_object_projectile_fire_missile(object *op, object *shooter, int dir)
302 {
303  object_owner_set(op, shooter);
304  op->direction = dir;
306 
307  if (DBL_EQUAL(op->speed, 0.0)) {
308  op->speed = 1.0;
309  }
310 
311  /* Save the shooter's level. */
312  if (!op->level) {
313  op->level = SK_level(shooter);
314  }
315 
316  op->speed_left = 0;
318 
319  SET_FLAG(op, FLAG_FLYING);
321  SET_FLAG(op, FLAG_WALK_ON);
322  SET_FLAG(op, FLAG_FLY_ON);
323 
324  /* Do not allow stacking, otherwise it is possible for rapidly-fired
325  * missiles to merge, which does not make sense. */
327 
328  op->x = shooter->x;
329  op->y = shooter->y;
330  op->layer = LAYER_EFFECT;
331  op->sub_layer = shooter->sub_layer;
332  op = object_insert_map(op, shooter->map, op, 0);
333 
334  if (!op) {
335  return NULL;
336  }
337 
338  object_process(op);
339 
340  return op;
341 }
342 
344 int common_object_projectile_hit(object *op, object *victim)
345 {
346  object *owner;
347 
348  owner = object_owner(op);
349 
350  /* Victim is not an alive object or we're friends with the victim,
351  * pass... */
352  if (!IS_LIVE(victim) || is_friend_of(owner, victim)) {
354  }
355 
356  if (op->stats.dam > 0) {
357  int dam;
358 
359  op = projectile_stick(op, victim);
360 
361  OBJ_DESTROYED_BEGIN(op) {
362  dam = attack_hit(victim, op, op->stats.dam);
363 
364  if (OBJ_DESTROYED(op)) {
365  return OBJECT_METHOD_ERROR;
366  }
367 
368  op->stats.dam -= dam;
369  } OBJ_DESTROYED_END();
370  }
371 
372  return OBJECT_METHOD_OK;
373 }
374 
376 int common_object_projectile_move_on(object *op, object *victim, object *originator, int state)
377 {
378  int ret;
379 
380  (void) originator;
381 
382  if (!state) {
384  }
385 
386  ret = object_projectile_hit(op, victim);
387 
388  if (ret == OBJECT_METHOD_OK) {
390  return OBJECT_METHOD_OK;
391  }
392 
393  return OBJECT_METHOD_OK;
394 }
void object_destroy(object *ob)
Definition: object.c:1441
tag_t attacked_by_count
Definition: object.h:222
object * object_projectile_move(object *op)
object * common_object_projectile_move(object *op)
Definition: projectile.c:152
double speed_left
Definition: object.h:472
mapstruct * get_map_from_coord(mapstruct *m, int *x, int *y)
Definition: map.c:1869
int SK_level(object *op)
Definition: skill_util.c:470
int object_projectile_hit(object *op, object *victim)
int16_t last_heal
Definition: object.h:310
#define OBJ_DESTROYED(_op)
Definition: object.h:701
#define OBJECT_METHOD_ERROR
#define FLAG_FLY_ON
Definition: define.h:968
object * object_projectile_stop(object *op, int reason)
int16_t last_sp
Definition: object.h:313
int wall(mapstruct *m, int x, int y)
Definition: map.c:486
#define FLAG_IS_SPELL
Definition: define.h:1318
int common_object_projectile_move_on(object *op, object *victim, object *originator, int state)
Definition: projectile.c:376
uint8_t layer
Definition: object.h:405
#define OBJECT_PROJECTILE_STOP_EOL
#define MISC_OBJECT
Definition: define.h:349
void object_process(object *op)
static int absdir(int d)
Definition: define.h:1838
#define IS_LIVE(op)
Definition: define.h:841
#define PLAYER
Definition: define.h:122
int16_t sp
Definition: living.h:78
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
struct archetype * arch
Definition: object.h:225
struct archetype * other_arch
Definition: object.h:228
void object_remove(object *op, int flags)
Definition: object.c:1623
int32_t hp
Definition: living.h:72
#define OBJ_DESTROYED_BEGIN(_op)
Definition: object.h:695
int16_t y
Definition: object.h:276
#define P_IS_PLAYER
Definition: map.h:256
uint8_t sub_layer
Definition: object.h:408
int8_t direction
Definition: object.h:350
object * common_object_projectile_stop_spell(object *op, int reason)
Definition: projectile.c:284
#define INS_FALL_THROUGH
Definition: object.h:575
int is_friend_of(object *op, object *obj)
Definition: monster.c:1685
uint32_t weight
Definition: object.h:246
#define FLAG_NO_PICK
Definition: define.h:900
object * object_insert_into(object *op, object *where, int flag)
Definition: object.c:2158
struct mapdef * map
Definition: object.h:139
int16_t dam
Definition: living.h:87
#define SET_FLAG(xyz, p)
Definition: define.h:741
#define OBJECT_PROJECTILE_STOP_HIT
#define LAYER_LIVING
Definition: map.h:59
void explode_object(object *op)
Definition: spell_util.c:799
uint8_t wc_range
Definition: living.h:100
object * common_object_projectile_stop_missile(object *op, int reason)
Definition: projectile.c:182
#define ARROW
Definition: define.h:170
#define FLAG_IS_USED_UP
Definition: define.h:976
#define FLAG_FLYING
Definition: define.h:918
#define FOR_MAP_LAYER_END
Definition: define.h:1657
double speed
Definition: object.h:469
int common_object_projectile_hit(object *op, object *victim)
Definition: projectile.c:344
#define HEAD(op)
Definition: object.h:657
#define OBJECT_METHOD_UNHANDLED
object * object_merge(object *op)
Definition: object.c:479
int16_t x
Definition: object.h:273
#define FOR_MAP_LAYER_BEGIN(_m, _x, _y, _layer, _sub_layer, _obj)
Definition: define.h:1630
int16_t last_eat
Definition: object.h:319
int16_t wc
Definition: living.h:90
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 OBJECT_PROJECTILE_PICKUP
#define FOR_MAP_LAYER_BREAK
Definition: define.h:1650
void object_owner_set(object *op, object *owner)
Definition: object.c:788
#define FLAG_CAN_STACK
Definition: define.h:1016
#define LAYER_EFFECT
Definition: map.h:61
object * common_object_projectile_fire_missile(object *op, object *shooter, int dir)
Definition: projectile.c:301
#define FLAG_REFL_MISSILE
Definition: define.h:1024
tag_t count
Definition: object.h:142
living stats
Definition: object.h:481
#define FLAG_REFL_SPELL
Definition: define.h:1028
int attack_hit(object *op, object *hitter, int dam)
Definition: attack.c:669
int freearr_x[SIZEOFFREE]
Definition: object.c:84
uint8_t type
Definition: object.h:360
#define CLEAR_FLAG(xyz, p)
Definition: define.h:751
object * object_owner(object *op)
Definition: object.c:857
#define OBJECT_METHOD_OK
#define SET_ANIMATION_STATE(ob)
Definition: global.h:287
struct obj * inv
Definition: object.h:123
void object_owner_clear(object *op)
Definition: object.c:741
#define P_IS_MONSTER
Definition: map.h:258
static object * projectile_stick(object *op, object *victim)
Definition: projectile.c:44
#define FLAG_WALK_ON
Definition: define.h:904
#define FLAG_IS_MISSILE
Definition: define.h:1322
#define OBJECT_PROJECTILE_STOP_WALL
void object_update_speed(object *op)
Definition: object.c:1043
Definition: map.h:536
#define FLAG_REFLECTING
Definition: define.h:984
int8_t level
Definition: object.h:347
int freearr_y[SIZEOFFREE]
Definition: object.c:99
#define OBJ_DESTROYED_END()
Definition: object.h:705
object clone
An object from which to do object_copy().
Definition: arch.h:47
void common_object_projectile_process(object *op)
Definition: projectile.c:68
struct obj * attacked_by
Definition: object.h:199
int16_t food
Definition: living.h:84