Crossfire Server, Branches 1.12  R18729
projectile.c
Go to the documentation of this file.
1 /*
2  CrossFire, A Multiplayer game for X-windows
3 
4  Copyright (C) 2007 Mark Wedel & Crossfire Development Team
5  Copyright (C) 1992 Frank Tore Johansen
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21  The authors can be reached via e-mail at crossfire-devel@real-time.com
22 */
27 #include <global.h>
28 #include <sproto.h>
29 #include <ob_methods.h>
30 #include <ob_types.h>
31 
36 void stop_projectile(object *op) {
37  /* Lauwenmark: Handle for plugin stop event */
38  execute_event(op, EVENT_STOP, NULL, NULL, NULL, SCRIPT_FIX_NOTHING);
39  if (op->inv) {
40  object *payload = op->inv;
41 
42  remove_ob(payload);
43  clear_owner(payload);
44  insert_ob_in_map(payload, op->map, payload, 0);
45  remove_ob(op);
46  free_object(op);
47  } else {
48  op = fix_stopped_arrow(op);
49  if (op)
50  merge_ob(op, NULL);
51  }
52 }
53 
63  object *tmp;
64  sint16 new_x, new_y;
65  int was_reflected, mflags;
66  mapstruct *m;
67 
68  if (op->map == NULL) {
69  LOG(llevError, "BUG: Projectile had no map.\n");
70  remove_ob(op);
71  free_object(op);
72  return METHOD_ERROR;
73  }
74 
75  /* Calculate target map square */
76  new_x = op->x+DIRX(op);
77  new_y = op->y+DIRY(op);
78  was_reflected = 0;
79 
80  m = op->map;
81  mflags = get_map_flags(m, &m, new_x, new_y, &new_x, &new_y);
82 
83  if (mflags&P_OUT_OF_MAP) {
84  stop_projectile(op);
85  return METHOD_OK;
86  }
87 
88  /* only need to look for living creatures if this flag is set */
89  if (mflags&P_IS_ALIVE) {
90  for (tmp = GET_MAP_OB(m, new_x, new_y); tmp != NULL; tmp = tmp->above)
91  if (QUERY_FLAG(tmp, FLAG_ALIVE))
92  break;
93 
94 
95  /* Not really fair, but don't let monsters hit themselves with
96  * their own arrow - this can be because they fire it then
97  * move into it.
98  */
99 
100  if (tmp != NULL && tmp != op->owner) {
101  /* Found living object, but it is reflecting the missile. Update
102  * as below. (Note that for living creatures there is a small
103  * chance that reflect_missile fails.)
104  */
105 
106  if (QUERY_FLAG(tmp, FLAG_REFL_MISSILE)
107  && (rndm(0, 99)) < (90-op->level/10)) {
108  int number = op->face->number;
109 
110  op->direction = absdir(op->direction+4);
111  op->state = 0;
112  if (GET_ANIM_ID(op)) {
113  number += 4;
114  if (number > GET_ANIMATION(op, 8))
115  number -= 8;
116  op->face = &new_faces[number];
117  }
118  was_reflected = 1; /* skip normal movement calculations */
119  } else {
120  /* Attack the object. */
121  op = hit_with_arrow(op, tmp);
122  if (op == NULL)
123  return METHOD_OK;
124  }
125  } /* if this is not hitting its owner */
126  } /* if there is something alive on this space */
127 
128  if (OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, new_x, new_y))) {
129  int retry = 0;
130 
131  /* if the object doesn't reflect, stop the arrow from moving
132  * note that this code will now catch cases where a monster is
133  * on a wall but has reflecting - the arrow won't reflect.
134  * Mapmakers shouldn't put monsters on top of wall in the first
135  * place, so I don't consider that a problem.
136  */
137  if (!QUERY_FLAG(op, FLAG_REFLECTING) || !(rndm(0, 19))) {
138  stop_projectile(op);
139  return METHOD_OK;
140  } else {
141  /* If one of the major directions (n,s,e,w), just reverse it */
142  if (op->direction&1) {
143  op->direction = absdir(op->direction+4);
144  retry = 1;
145  }
146  /* There were two blocks with identical code -
147  * use this retry here to make this one block
148  * that did the same thing.
149  */
150  while (retry < 2) {
151  int left, right, mflags;
152  mapstruct *m1;
153  sint16 x1, y1;
154 
155  retry++;
156 
157  /* Need to check for P_OUT_OF_MAP: if the arrow is tavelling
158  * over a corner in a tiled map, it is possible that
159  * op->direction is within an adjacent map but either
160  * op->direction-1 or op->direction+1 does not exist.
161  */
162  mflags = get_map_flags(op->map, &m1, op->x+freearr_x[absdir(op->direction-1)], op->y+freearr_y[absdir(op->direction-1)], &x1, &y1);
163  left = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, (GET_MAP_MOVE_BLOCK(m1, x1, y1)));
164 
165  mflags = get_map_flags(op->map, &m1, op->x+freearr_x[absdir(op->direction+1)], op->y+freearr_y[absdir(op->direction+1)], &x1, &y1);
166  right = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, (GET_MAP_MOVE_BLOCK(m1, x1, y1)));
167 
168  if (left == right)
169  op->direction = absdir(op->direction+4);
170  else if (left)
171  op->direction = absdir(op->direction+2);
172  else if (right)
173  op->direction = absdir(op->direction-2);
174 
175  mflags = get_map_flags(op->map, &m1, op->x+DIRX(op), op->y+DIRY(op), &x1, &y1);
176 
177  /* If this space is not out of the map and not blocked, valid space -
178  * don't need to retry again.
179  */
180  if (!(mflags&P_OUT_OF_MAP)
181  && !OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m1, x1, y1)))
182  break;
183  }
184  /* Couldn't find a direction to move the arrow to - just
185  * top it from moving.
186  */
187  if (retry == 2) {
188  stop_projectile(op);
189  return METHOD_OK;
190  }
191  /* update object image for new facing */
192  /* many thrown objects *don't *have more than one face */
193  if (GET_ANIM_ID(op))
194  SET_ANIMATION(op, op->direction);
195  } /* object is reflected */
196  } /* object ran into a wall */
197 
198  /* Move the arrow. */
199  remove_ob(op);
200  op->x = new_x;
201  op->y = new_y;
202 
203  /* decrease the speed as it flies. 0.05 means a standard bow will shoot
204  * about 17 squares. Tune as needed.
205  */
206  op->speed -= 0.05;
207  insert_ob_in_map(op, m, op, 0);
208  return METHOD_OK;
209 }
210 
219 method_ret common_projectile_move_on(ob_methods *context, object *trap, object *victim, object *originator) {
220  if (common_pre_ob_move_on(trap, victim, originator) == METHOD_ERROR)
221  return METHOD_OK;
222  if (trap->inv == NULL) {
223  common_post_ob_move_on(trap, victim, originator);
224  return METHOD_OK;
225  }
226 
227  /* bad bug: monster throw a object, make a step forwards, step on object ,
228  * trigger this here and get hit by own missile - and will be own enemy.
229  * Victim then is his own enemy and will start to kill herself (this is
230  * removed) but we have not synced victim and his missile. To avoid senseless
231  * action, we avoid hits here
232  */
233  if ((QUERY_FLAG(victim, FLAG_ALIVE) && trap->speed)
234  && trap->owner != victim)
235  hit_with_arrow(trap, victim);
236  common_post_ob_move_on(trap, victim, originator);
237  return METHOD_OK;
238 }
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny)
Definition: map.c:330
signed short sint16
Definition: global.h:72
method_ret common_pre_ob_move_on(object *trap, object *victim, object *originator)
Definition: common_apply.c:51
New_Face * new_faces
Definition: image.c:38
#define METHOD_ERROR
Definition: ob_methods.h:44
#define SET_ANIMATION(ob, newanim)
Definition: global.h:247
short freearr_x[SIZEOFFREE]
Definition: object.c:75
object * merge_ob(object *op, object *top)
Definition: object.c:1724
#define DIRX(xyz)
Definition: define.h:785
#define GET_ANIMATION(ob, anim)
Definition: global.h:248
struct obj * above
Definition: object.h:146
sint16 x
Definition: object.h:179
#define FLAG_REFLECTING
Definition: define.h:558
int absdir(int d)
Definition: object.c:3417
#define DIRY(xyz)
Definition: define.h:786
short freearr_y[SIZEOFFREE]
Definition: object.c:81
char method_ret
Definition: ob_methods.h:41
int rndm(int min, int max)
Definition: utils.c:174
uint16 number
Definition: face.h:43
void remove_ob(object *op)
Definition: object.c:1515
#define FLAG_ALIVE
Definition: define.h:526
void clear_owner(object *op)
Definition: object.c:544
#define EVENT_STOP
Definition: plugin.h:68
#define METHOD_OK
Definition: ob_methods.h:42
struct mapdef * map
Definition: object.h:155
object * hit_with_arrow(object *op, object *victim)
Definition: attack.c:975
method_ret common_process_projectile(ob_methods *context, object *op)
Definition: projectile.c:62
void stop_projectile(object *op)
Definition: projectile.c:36
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:740
#define P_OUT_OF_MAP
Definition: map.h:272
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:213
sint16 y
Definition: object.h:179
float speed
Definition: object.h:181
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
uint8 state
Definition: object.h:200
object * insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1992
void common_post_ob_move_on(object *trap, object *victim, object *originator)
Definition: common_apply.c:88
sint8 direction
Definition: object.h:185
struct obj * owner
Definition: object.h:228
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: standalone.c:225
#define GET_ANIM_ID(ob)
Definition: global.h:249
method_ret common_projectile_move_on(ob_methods *context, object *trap, object *victim, object *originator)
Definition: projectile.c:219
#define GET_MAP_OB(M, X, Y)
Definition: map.h:193
struct obj * inv
Definition: object.h:148
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
void free_object(object *ob)
Definition: object.c:1238
Definition: map.h:346
#define P_IS_ALIVE
Definition: map.h:258
New_Face * face
Definition: object.h:183
#define FLAG_REFL_MISSILE
Definition: define.h:569
sint16 level
Definition: object.h:202
#define SCRIPT_FIX_NOTHING
Definition: global.h:451
object * fix_stopped_arrow(object *op)
Definition: time.c:483