ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/attack.C
(Generate patch)

Comparing deliantra/server/server/attack.C (file contents):
Revision 1.8 by root, Sun Sep 3 00:18:42 2006 UTC vs.
Revision 1.44 by root, Mon Jan 15 15:41:09 2007 UTC

1/*
2 * static char *rcsid_attack_c =
3 * "$Id: attack.C,v 1.8 2006/09/03 00:18:42 root Exp $";
4 */
5/* 1/*
6 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
7 3
4 Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
8 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 5 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
9 Copyright (C) 1992 Frank Tore Johansen 6 Copyright (C) 1992 Frank Tore Johansen
10 7
11 This program is free software; you can redistribute it and/or modify 8 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by 9 it under the terms of the GNU General Public License as published by
20 17
21 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software 19 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 21
25 The authors can be reached via e-mail to crossfire-devel@real-time.com 22 The authors can be reached via e-mail to <crossfire@schmorp.de>
26*/ 23*/
27#include <assert.h> 24#include <assert.h>
28#include <global.h> 25#include <global.h>
29#include <living.h> 26#include <living.h>
30#include <material.h> 27#include <material.h>
31#include <skills.h> 28#include <skills.h>
32 29
33#ifndef __CEXTRACT__ 30#ifndef __CEXTRACT__
34#include <sproto.h> 31# include <sproto.h>
35#endif 32#endif
36 33
37#include <sounds.h> 34#include <sounds.h>
38 35
39typedef struct att_msg_str { 36typedef struct att_msg_str
37{
40 char *msg1; 38 char *msg1;
41 char *msg2; 39 char *msg2;
42} att_msg; 40} att_msg;
43 41
44/*#define ATTACK_DEBUG*/ 42/*#define ATTACK_DEBUG*/
45 43
46/* cancels object *op. Cancellation basically means an object loses 44/* cancels object *op. Cancellation basically means an object loses
47 * its magical benefits. 45 * its magical benefits.
48 */ 46 */
47void
49void cancellation(object *op) 48cancellation (object *op)
50{ 49{
51 object *tmp;
52
53 if (op->invisible) 50 if (op->invisible)
54 return; 51 return;
55 52
56 if (QUERY_FLAG (op, FLAG_ALIVE) || op->type == CONTAINER || op->type == THROWN_OBJ) { 53 if (QUERY_FLAG (op, FLAG_ALIVE) || op->type == CONTAINER || op->type == THROWN_OBJ)
54 {
57 /* Recur through the inventory */ 55 /* Recurse through the inventory */
58 for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) 56 for (object *tmp = op->inv; tmp; tmp = tmp->below)
59 if (!did_make_save_item(tmp, AT_CANCELLATION,op)) 57 if (!did_make_save_item (tmp, AT_CANCELLATION, op))
60 cancellation(tmp); 58 cancellation (tmp);
61 } 59 }
62 else if(FABS(op->magic)<=(rndm(0, 5))) { 60 else if (FABS (op->magic) <= rndm (0, 5))
61 {
63 /* Nullify this object. This code could probably be more complete */ 62 /* Nullify this object. This code could probably be more complete */
64 /* in what abilities it should cancel */ 63 /* in what abilities it should cancel */
65 op->magic=0; 64 op->magic = 0;
65
66 CLEAR_FLAG(op, FLAG_DAMNED); 66 CLEAR_FLAG (op, FLAG_DAMNED);
67 CLEAR_FLAG(op, FLAG_CURSED); 67 CLEAR_FLAG (op, FLAG_CURSED);
68 CLEAR_FLAG(op, FLAG_KNOWN_MAGICAL); 68 CLEAR_FLAG (op, FLAG_KNOWN_MAGICAL);
69 CLEAR_FLAG(op, FLAG_KNOWN_CURSED); 69 CLEAR_FLAG (op, FLAG_KNOWN_CURSED);
70
70 if (op->env && op->env->type == PLAYER) { 71 if (op->env && op->env->type == PLAYER)
71 esrv_send_item (op->env, op); 72 esrv_send_item (op->env, op);
72 }
73 } 73 }
74} 74}
75
76
77 75
78/* did_make_save_item just checks to make sure the item actually 76/* did_make_save_item just checks to make sure the item actually
79 * made its saving throw based on the tables. It does not take 77 * made its saving throw based on the tables. It does not take
80 * any further action (like destroying the item). 78 * any further action (like destroying the item).
81 */ 79 */
82 80int
83int did_make_save_item(object *op, int type, object *originator) { 81did_make_save_item (object *op, int type, object *originator)
82{
84 int i, roll, saves=0, attacks=0, number; 83 int i, roll, saves = 0, attacks = 0, number;
85 materialtype_t *mt; 84 materialtype_t *mt;
86 85
87 if (op->materialname == NULL) { 86 if (op->materialname == NULL)
87 {
88 for (mt = materialt; mt != NULL && mt->next != NULL; mt=mt->next) { 88 for (mt = materialt; mt != NULL && mt->next != NULL; mt = mt->next)
89 if (op->material & mt->material) 89 if (op->material & mt->material)
90 break; 90 break;
91 } 91 }
92 } else 92 else
93 mt = name_to_material(op->materialname); 93 mt = name_to_material (op->materialname);
94
94 if (mt == NULL) 95 if (mt == NULL)
95 return TRUE;
96 roll = rndm(1, 20);
97
98 /* the attacktypes have no meaning for object saves
99 * If the type is only magic, don't adjust type - basically, if
100 * pure magic is hitting an object, it should save. However, if it
101 * is magic teamed with something else, then strip out the
102 * magic type, and instead let the fire, cold, or whatever component
103 * destroy the item. Otherwise, you get the case of poisoncloud
104 * destroying objects because it has magic attacktype.
105 */
106 if (type != AT_MAGIC)
107 type &= ~(AT_CONFUSION|AT_DRAIN|AT_GHOSTHIT|AT_POISON|AT_SLOW|
108 AT_PARALYZE|AT_TURN_UNDEAD|AT_FEAR|AT_DEPLETE|AT_DEATH|
109 AT_COUNTERSPELL|AT_HOLYWORD|AT_BLIND|AT_LIFE_STEALING|
110 AT_MAGIC);
111
112 if (type == 0)
113 return TRUE;
114 if (roll == 20)
115 return TRUE;
116 if (roll == 1)
117 return FALSE;
118
119 for (number=0; number < NROFATTACKS; number++) {
120 i = 1<<number;
121 if (!(i&type))
122 continue;
123 attacks++;
124 if (op->resist[number] == 100)
125 saves++;
126 else if (roll >= mt->save[number] - op->magic - op->resist[number]/100)
127 saves++;
128 else if ((20-mt->save[number])/3 > originator->stats.dam)
129 saves++;
130 }
131
132 if (saves==attacks || attacks==0)
133 return TRUE;
134 if ((saves==0) || (rndm(1, attacks) > saves))
135 return FALSE;
136 return TRUE; 96 return TRUE;
97
98 roll = rndm (1, 20);
99
100 /* the attacktypes have no meaning for object saves
101 * If the type is only magic, don't adjust type - basically, if
102 * pure magic is hitting an object, it should save. However, if it
103 * is magic teamed with something else, then strip out the
104 * magic type, and instead let the fire, cold, or whatever component
105 * destroy the item. Otherwise, you get the case of poisoncloud
106 * destroying objects because it has magic attacktype.
107 */
108 if (type != AT_MAGIC)
109 type &= ~(AT_CONFUSION | AT_DRAIN | AT_GHOSTHIT | AT_POISON | AT_SLOW |
110 AT_PARALYZE | AT_TURN_UNDEAD | AT_FEAR | AT_DEPLETE | AT_DEATH |
111 AT_COUNTERSPELL | AT_HOLYWORD | AT_BLIND | AT_LIFE_STEALING | AT_MAGIC);
112
113 if (type == 0)
114 return TRUE;
115 if (roll == 20)
116 return TRUE;
117 if (roll == 1)
118 return FALSE;
119
120 for (number = 0; number < NROFATTACKS; number++)
121 {
122 i = 1 << number;
123 if (!(i & type))
124 continue;
125 attacks++;
126 if (op->resist[number] == 100)
127 saves++;
128 else if (roll >= mt->save[number] - op->magic - op->resist[number] / 100)
129 saves++;
130 else if ((20 - mt->save[number]) / 3 > originator->stats.dam)
131 saves++;
132 }
133
134 if (saves == attacks || attacks == 0)
135 return TRUE;
136 if ((saves == 0) || (rndm (1, attacks) > saves))
137 return FALSE;
138 return TRUE;
137} 139}
138 140
139/* This function calls did_make_save_item. It then performs the 141/* This function calls did_make_save_item. It then performs the
140 * appropriate actions to the item (such as burning the item up, 142 * appropriate actions to the item (such as burning the item up,
141 * calling cancellation, etc.) 143 * calling cancellation, etc.)
142 */ 144 */
143 145void
144void save_throw_object (object *op, int type, object *originator) 146save_throw_object (object *op, int type, object *originator)
145{ 147{
146 if ( ! did_make_save_item (op, type,originator)) 148 if (!did_make_save_item (op, type, originator))
147 { 149 {
148 object *env=op->env; 150 object *env = op->env;
149 int x=op->x,y=op->y; 151 int x = op->x, y = op->y;
150 mapstruct *m=op->map; 152 maptile *m = op->map;
151 153
152 op = stop_item (op); 154 op = stop_item (op);
153 if (op == NULL) 155 if (op == NULL)
154 return; 156 return;
155 157
156 /* Hacked the following so that type LIGHTER will work. 158 /* Hacked the following so that type LIGHTER will work.
157 * Also, objects which are potenital "lights" that are hit by 159 * Also, objects which are potenital "lights" that are hit by
158 * flame/elect attacks will be set to glow. "lights" are any 160 * flame/elect attacks will be set to glow. "lights" are any
159 * object with +/- glow_radius and an "other_arch" to change to. 161 * object with +/- glow_radius and an "other_arch" to change to.
160 * (and please note that we cant fail our save and reach this 162 * (and please note that we cant fail our save and reach this
161 * function if the object doesnt contain a material that can burn. 163 * function if the object doesnt contain a material that can burn.
162 * So forget lighting magical swords on fire with this!) -b.t. 164 * So forget lighting magical swords on fire with this!) -b.t.
163 */ 165 */
164 if(type&(AT_FIRE|AT_ELECTRICITY) 166 if (type & (AT_FIRE | AT_ELECTRICITY) && op->other_arch && QUERY_FLAG (op, FLAG_IS_LIGHTABLE))
165 &&op->other_arch&&QUERY_FLAG(op, FLAG_IS_LIGHTABLE)) { 167 {
166 const char *arch=op->other_arch->name; 168 const char *arch = op->other_arch->name;
167 169
168 op = decrease_ob_nr (op, 1); 170 op = decrease_ob_nr (op, 1);
171
169 if (op) 172 if (op)
170 fix_stopped_item (op, m, originator); 173 fix_stopped_item (op, m, originator);
174
171 if((op = get_archetype(arch))!=NULL) { 175 if ((op = get_archetype (arch)) != NULL)
176 {
172 if(env) { 177 if (env)
178 {
173 op->x=env->x,op->y=env->y; 179 op->x = env->x, op->y = env->y;
174 insert_ob_in_ob(op,env); 180 insert_ob_in_ob (op, env);
175 if (env->contr) 181 if (env->contr)
176 esrv_send_item(env, op); 182 esrv_send_item (env, op);
177 } else {
178 op->x=x,op->y=y;
179 insert_ob_in_map(op,m,originator,0);
180 }
181 } 183 }
184 else
182 return; 185 {
183 } 186 op->x = x, op->y = y;
184 if(type&AT_CANCELLATION) { /* Cancellation. */
185 cancellation(op);
186 fix_stopped_item (op, m, originator);
187 return;
188 }
189 if(op->nrof>1) {
190 op = decrease_ob_nr(op,rndm(0, op->nrof-1));
191 if (op)
192 fix_stopped_item (op, m, originator); 187 insert_ob_in_map (op, m, originator, 0);
193 } else {
194 if (op->env) {
195 object *tmp= is_player_inv(op->env);
196
197 if (tmp) {
198 esrv_del_item(tmp->contr, op->count);
199 } 188 }
200 } 189 }
201 if ( ! QUERY_FLAG (op, FLAG_REMOVED)) 190
202 remove_ob(op); 191 return;
203 free_object(op); 192 }
193
194 if (type & AT_CANCELLATION)
195 { /* Cancellation. */
196 cancellation (op);
197 fix_stopped_item (op, m, originator);
198 return;
199 }
200
201 if (op->nrof > 1)
204 } 202 {
203 op = decrease_ob_nr (op, rndm (0, op->nrof - 1));
204
205 if (op)
206 fix_stopped_item (op, m, originator);
207 }
208 else
209 {
210 if (op->env)
211 {
212 object *tmp = op->in_player ();
213
214 if (tmp)
215 esrv_del_item (tmp->contr, op->count);
216 }
217
218 op->destroy ();
219 }
220
205 if(type&(AT_FIRE|AT_ELECTRICITY)) { 221 if (type & (AT_FIRE | AT_ELECTRICITY))
206 if(env) { 222 if (env)
223 {
207 op=get_archetype("burnout"); 224 op = get_archetype ("burnout");
208 op->x=env->x,op->y=env->y; 225 op->x = env->x, op->y = env->y;
209 insert_ob_in_ob(op,env); 226 insert_ob_in_ob (op, env);
210 } else { 227 }
228 else
211 replace_insert_ob_in_map("burnout",originator); 229 replace_insert_ob_in_map ("burnout", originator);
212 } 230
213 } 231 return;
232 }
233
234 /* The value of 50 is arbitrary. */
235 if (type & AT_COLD && (op->resist[ATNR_COLD] < 50) && !QUERY_FLAG (op, FLAG_NO_PICK) && (RANDOM () & 2))
236 {
237 object *tmp;
238 archetype *at = archetype::find ("icecube");
239
240 if (at == NULL)
214 return; 241 return;
215 } 242
216 /* The value of 50 is arbitrary. */
217 if(type&AT_COLD &&(op->resist[ATNR_COLD]<50) &&
218 !QUERY_FLAG(op,FLAG_NO_PICK)&&(RANDOM()&2)) {
219 object *tmp;
220 archetype *at = find_archetype("icecube");
221 if (at == NULL)
222 return;
223 op = stop_item (op); 243 op = stop_item (op);
224 if (op == NULL) 244 if (op == NULL)
225 return;
226 if ((tmp = present_arch(at,op->map,op->x,op->y)) == NULL) {
227 tmp = arch_to_object(at);
228 tmp->x=op->x,tmp->y=op->y;
229 /* This was in the old (pre new movement code) -
230 * icecubes have slow_move set to 1 - don't want
231 * that for ones we create.
232 */
233 tmp->move_slow_penalty=0;
234 tmp->move_slow=0;
235 insert_ob_in_map(tmp,op->map,originator,0);
236 }
237 if ( ! QUERY_FLAG (op, FLAG_REMOVED))
238 remove_ob(op);
239 (void) insert_ob_in_ob(op,tmp);
240 return; 245 return;
246
247 if ((tmp = present_arch (at, op->map, op->x, op->y)) == NULL)
248 {
249 tmp = arch_to_object (at);
250 tmp->x = op->x, tmp->y = op->y;
251 /* This was in the old (pre new movement code) -
252 * icecubes have slow_move set to 1 - don't want
253 * that for ones we create.
254 */
255 tmp->move_slow_penalty = 0;
256 tmp->move_slow = 0;
257 insert_ob_in_map (tmp, op->map, originator, 0);
258 }
259
260 if (!QUERY_FLAG (op, FLAG_REMOVED))
261 op->remove ();
262
263 insert_ob_in_ob (op, tmp);
264 return;
241 } 265 }
242} 266}
243 267
244/* Object op is hitting the map. 268/* Object op is hitting the map.
245 * op is going in direction 'dir' 269 * op is going in direction 'dir'
246 * type is the attacktype of the object. 270 * type is the attacktype of the object.
247 * full_hit is set if monster area does not matter. 271 * full_hit is set if monster area does not matter.
248 * returns 1 if it hits something, 0 otherwise. 272 * returns 1 if it hits something, 0 otherwise.
249 */ 273 */
250 274
275int
251int hit_map(object *op, int dir, int type, int full_hit) { 276hit_map (object *op, int dir, int type, int full_hit)
252 object *tmp, *next; 277{
253 mapstruct *map; 278 maptile *map;
254 sint16 x, y; 279 sint16 x, y;
255 int retflag=0; /* added this flag.. will return 1 if it hits a monster */ 280 int retflag = 0; /* added this flag.. will return 1 if it hits a monster */
256 281
257 tag_t op_tag, next_tag=0;
258
259 if (QUERY_FLAG (op, FLAG_FREED)) { 282 if (QUERY_FLAG (op, FLAG_FREED))
283 {
260 LOG (llevError, "BUG: hit_map(): free object\n"); 284 LOG (llevError, "BUG: hit_map(): free object\n");
261 return 0; 285 return 0;
262 } 286 }
263 287
264 if (QUERY_FLAG (op, FLAG_REMOVED) || op->env != NULL) { 288 if (QUERY_FLAG (op, FLAG_REMOVED) || op->env != NULL)
289 {
265 LOG (llevError, "BUG: hit_map(): hitter (arch %s, name %s) not on a map\n", 290 LOG (llevError, "BUG: hit_map(): hitter (arch %s, name %s) not on a map\n", &op->arch->name, &op->name);
266 &op->arch->name, &op->name);
267 return 0; 291 return 0;
268 } 292 }
269 293
270 if ( ! op->map) { 294 if (!op->map)
295 {
271 LOG (llevError,"BUG: hit_map(): %s has no map\n", &op->name); 296 LOG (llevError, "BUG: hit_map(): %s has no map\n", &op->name);
272 return 0; 297 return 0;
273 } 298 }
274 299
275 if (op->head) op=op->head; 300 if (op->head)
301 op = op->head;
276 302
277 op_tag = op->count;
278
279 map = op->map; 303 map = op->map;
280 x = op->x + freearr_x[dir]; 304 x = op->x + freearr_x[dir];
281 y = op->y + freearr_y[dir]; 305 y = op->y + freearr_y[dir];
282 306
283 int mflags = get_map_flags(map, &map, x, y, &x, &y); 307 if (!xy_normalise (map, x, y))
308 return 0;
309
284 // elmex: a safe map tile can't be hit! 310 // elmex: a safe map tile can't be hit!
285 // this should prevent most harmful effects on items and players there. 311 // this should prevent most harmful effects on items and players there.
286 if ((mflags & P_OUT_OF_MAP) || (mflags & P_SAFE)) 312 mapspace &ms = map->at (x, y);
313
314 if (ms.flags () & P_SAFE)
287 return 0; 315 return 0;
288 316
289 /* peterm: a few special cases for special attacktypes --counterspell 317 /* peterm: a few special cases for special attacktypes --counterspell
290 * must be out here because it strikes things which are not alive 318 * must be out here because it strikes things which are not alive
291 */ 319 */
292 320 if (type & (AT_COUNTERSPELL | AT_CHAOS))
321 {
293 if (type & AT_COUNTERSPELL) { 322 if (type & AT_COUNTERSPELL)
323 {
294 counterspell(op,dir); /* see spell_effect.c */ 324 counterspell (op, dir); /* see spell_effect.c */
295 325
296 /* If the only attacktype is counterspell or magic, don't need 326 /* If the only attacktype is counterspell or magic, don't need
297 * to do any further processing. 327 * to do any further processing.
298 */ 328 */
299 if(!(type & ~(AT_COUNTERSPELL|AT_MAGIC))){ 329 if (!(type & ~(AT_COUNTERSPELL | AT_MAGIC)))
300 return 0; 330 return 0;
301 } 331
302 type &= ~AT_COUNTERSPELL; 332 type &= ~AT_COUNTERSPELL;
303 } 333 }
304 334
305 if(type & AT_CHAOS){ 335 if (type & AT_CHAOS)
336 {
306 shuffle_attack(op,1); /*1 flag tells it to change the face */ 337 shuffle_attack (op, 1); /* flag tells it to change the face */
307 update_object(op,UP_OBJ_FACE); 338 update_object (op, UP_OBJ_FACE);
308 type &= ~AT_CHAOS; 339 type &= ~AT_CHAOS;
340 }
309 } 341 }
310 342
311 next = get_map_ob (map, x, y);
312 if (next)
313 next_tag = next->count;
314
315 while (next) {
316 if (was_destroyed (next, next_tag)) {
317 /* There may still be objects that were above 'next', but there is no 343 /* There may still be objects that were above 'next', but there is no
318 * simple way to find out short of copying all object references and 344 * simple way to find out short of copying all object references and
319 * tags into a temporary array before we start processing the first 345 * tags into a temporary array before we start processing the first
320 * object. That's why we just abort. 346 * object. That's why we just abort on destroy.
321 * 347 *
322 * This happens whenever attack spells (like fire) hit a pile 348 * This happens whenever attack spells (like fire) hit a pile
323 * of objects. This is not a bug - nor an error. The errormessage 349 * of objects. This is not a bug - nor an error.
324 * below was spamming the logs for absolutely no reason. 350 */
351 for (object *next = ms.bot; next && !next->destroyed (); )
352 {
353 object *tmp = next;
354 next = tmp->above;
355
356 /* Something could have happened to 'tmp' while 'tmp->below' was processed.
357 * For example, 'tmp' was put in an icecube.
358 * This is one of the few cases where on_same_map should not be used.
325 */ 359 */
326 /* LOG (llevDebug, "hit_map(): next object destroyed\n"); */ 360 if (tmp->map != map || tmp->x != x || tmp->y != y)
361 continue;
362
363 if (QUERY_FLAG (tmp, FLAG_ALIVE))
364 {
365 hit_player (tmp, op->stats.dam, op, type, full_hit);
366 retflag |= 1;
367
368 if (op->destroyed ())
327 break; 369 break;
328 } 370 }
329 tmp = next; 371 /* Here we are potentially destroying an object. If the object has
330 next = tmp->above; 372 * NO_PASS set, it is also immune - you can't destroy walls. Note
331 if (next) 373 * that weak walls have is_alive set, which prevent objects from
332 next_tag = next->count; 374 * passing over/through them. We don't care what type of movement
375 * the wall blocks - if it blocks any type of movement, can't be
376 * destroyed right now.
377 */
378 else if ((tmp->material || tmp->materialname) && op->stats.dam > 0 && !tmp->move_block)
379 {
380 save_throw_object (tmp, type, op);
333 381
334 if (QUERY_FLAG (tmp, FLAG_FREED)) { 382 if (op->destroyed ())
335 LOG (llevError, "BUG: hit_map(): found freed object\n");
336 break; 383 break;
337 } 384 }
338
339 /* Something could have happened to 'tmp' while 'tmp->below' was processed.
340 * For example, 'tmp' was put in an icecube.
341 * This is one of the few cases where on_same_map should not be used.
342 */
343 if (tmp->map != map || tmp->x != x || tmp->y != y)
344 continue;
345
346 if (QUERY_FLAG (tmp, FLAG_ALIVE)) {
347 hit_player(tmp,op->stats.dam,op,type,full_hit);
348 retflag |=1;
349 if (was_destroyed (op, op_tag))
350 break;
351 }
352 /* Here we are potentially destroying an object. If the object has
353 * NO_PASS set, it is also immune - you can't destroy walls. Note
354 * that weak walls have is_alive set, which prevent objects from
355 * passing over/through them. We don't care what type of movement
356 * the wall blocks - if it blocks any type of movement, can't be
357 * destroyed right now.
358 */
359 else if ((tmp->material || tmp->materialname) && op->stats.dam > 0 &&
360 !tmp->move_block) {
361 save_throw_object(tmp,type,op);
362 if (was_destroyed (op, op_tag))
363 break;
364 }
365 } 385 }
386
366 return 0; 387 return 0;
367} 388}
368 389
390void
369void attack_message(int dam, int type, object *op, object *hitter) { 391attack_message (int dam, int type, object *op, object *hitter)
392{
370 char buf[MAX_BUF], buf1[MAX_BUF], buf2[MAX_BUF]; 393 char buf[MAX_BUF], buf1[MAX_BUF], buf2[MAX_BUF];
371 int i, found=0; 394 int i, found = 0;
372 mapstruct *map; 395 maptile *map;
373 object *next, *tmp; 396 object *next, *tmp;
374 397
375 /* put in a few special messages for some of the common attacktypes 398 /* put in a few special messages for some of the common attacktypes
376 * a player might have. For example, fire, electric, cold, etc 399 * a player might have. For example, fire, electric, cold, etc
377 * [garbled 20010919] 400 * [garbled 20010919]
378 */ 401 */
379 402
380 if (dam == 9998 && op->type == DOOR) { 403 if (dam == 9998 && op->type == DOOR)
404 {
381 sprintf(buf1, "unlock %s", &op->name); 405 sprintf (buf1, "unlock %s", &op->name);
382 sprintf(buf2, " unlocks"); 406 sprintf (buf2, " unlocks");
383 found++; 407 found++;
408 }
409 if (dam < 0)
384 } 410 {
385 if(dam<0) {
386 sprintf(buf1, "hit %s", &op->name); 411 sprintf (buf1, "hit %s", &op->name);
387 sprintf(buf2, " hits"); 412 sprintf (buf2, " hits");
388 found++; 413 found++;
414 }
389 } else if(dam==0) { 415 else if (dam == 0)
416 {
390 sprintf(buf1, "missed %s", &op->name); 417 sprintf (buf1, "missed %s", &op->name);
391 sprintf(buf2, " misses"); 418 sprintf (buf2, " misses");
392 found++; 419 found++;
420 }
393 } else if ((hitter->type == DISEASE || hitter->type == SYMPTOM || 421 else if ((hitter->type == DISEASE || hitter->type == SYMPTOM ||
394 hitter->type == POISONING || 422 hitter->type == POISONING || (type & AT_POISON && op->is_alive ())) && !found)
395 (type & AT_POISON && IS_LIVE(op))) && !found) { 423 {
396 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_SUFFER][i].level != -1; 424 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_SUFFER][i].level != -1; i++)
397 i++) 425 if (dam < attack_mess[ATM_SUFFER][i].level || attack_mess[ATM_SUFFER][i + 1].level == -1)
398 if (dam < attack_mess[ATM_SUFFER][i].level 426 {
399 || attack_mess[ATM_SUFFER][i+1].level == -1) { 427 sprintf (buf1, "%s %s%s", attack_mess[ATM_SUFFER][i].buf1, &op->name, attack_mess[ATM_SUFFER][i].buf2);
400 sprintf(buf1, "%s %s%s", attack_mess[ATM_SUFFER][i].buf1,
401 &op->name, attack_mess[ATM_SUFFER][i].buf2);
402 strcpy (buf2, attack_mess[ATM_SUFFER][i].buf3); 428 strcpy (buf2, attack_mess[ATM_SUFFER][i].buf3);
429 found++;
430 break;
431 }
432 }
433 else if (op->type == DOOR && !found)
434 {
435 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_DOOR][i].level != -1; i++)
436 if (dam < attack_mess[ATM_DOOR][i].level || attack_mess[ATM_DOOR][i + 1].level == -1)
437 {
438 sprintf (buf1, "%s %s%s", attack_mess[ATM_DOOR][i].buf1, &op->name, attack_mess[ATM_DOOR][i].buf2);
439 strcpy (buf2, attack_mess[ATM_DOOR][i].buf3);
440 found++;
441 break;
442 }
443 }
444 else if (hitter->type == PLAYER && op->is_alive ())
445 {
446 if (USING_SKILL (hitter, SK_KARATE))
447 {
448 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_KARATE][i].level != -1; i++)
449 if (dam < attack_mess[ATM_KARATE][i].level || attack_mess[ATM_KARATE][i + 1].level == -1)
450 {
451 sprintf (buf1, "%s %s%s", attack_mess[ATM_KARATE][i].buf1, &op->name, attack_mess[ATM_KARATE][i].buf2);
452 strcpy (buf2, attack_mess[ATM_KARATE][i].buf3);
403 found++; 453 found++;
404 break; 454 break;
405 } 455 }
406 } else if (op->type == DOOR && !found) { 456 }
457 else if (USING_SKILL (hitter, SK_CLAWING))
458 {
407 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_DOOR][i].level != -1; 459 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_CLAW][i].level != -1; i++)
460 if (dam < attack_mess[ATM_CLAW][i].level || attack_mess[ATM_CLAW][i + 1].level == -1)
408 i++) 461 {
409 if (dam < attack_mess[ATM_DOOR][i].level 462 sprintf (buf1, "%s %s%s", attack_mess[ATM_CLAW][i].buf1, &op->name, attack_mess[ATM_CLAW][i].buf2);
410 || attack_mess[ATM_DOOR][i+1].level == -1) {
411 sprintf(buf1, "%s %s%s", attack_mess[ATM_DOOR][i].buf1,
412 &op->name, attack_mess[ATM_DOOR][i].buf2);
413 strcpy (buf2, attack_mess[ATM_DOOR][i].buf3); 463 strcpy (buf2, attack_mess[ATM_CLAW][i].buf3);
414 found++; 464 found++;
415 break; 465 break;
416 }
417 } else if (hitter->type == PLAYER && IS_LIVE(op)) {
418 if (USING_SKILL(hitter, SK_KARATE)) {
419 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_KARATE][i].level != -1;
420 i++)
421 if (dam < attack_mess[ATM_KARATE][i].level
422 || attack_mess[ATM_KARATE][i+1].level == -1) {
423 sprintf(buf1, "%s %s%s", attack_mess[ATM_KARATE][i].buf1,
424 &op->name, attack_mess[ATM_KARATE][i].buf2);
425 strcpy (buf2, attack_mess[ATM_KARATE][i].buf3);
426 found++;
427 break;
428 } 466 }
429 } else if (USING_SKILL(hitter, SK_CLAWING)) {
430 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_CLAW][i].level != -1;
431 i++)
432 if (dam < attack_mess[ATM_CLAW][i].level
433 || attack_mess[ATM_CLAW][i+1].level == -1) {
434 sprintf(buf1, "%s %s%s", attack_mess[ATM_CLAW][i].buf1,
435 &op->name, attack_mess[ATM_CLAW][i].buf2);
436 strcpy (buf2, attack_mess[ATM_CLAW][i].buf3);
437 found++;
438 break;
439 } 467 }
440 } else if (USING_SKILL(hitter, SK_PUNCHING)) { 468 else if (USING_SKILL (hitter, SK_PUNCHING))
469 {
441 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_PUNCH][i].level != -1; 470 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_PUNCH][i].level != -1; i++)
471 if (dam < attack_mess[ATM_PUNCH][i].level || attack_mess[ATM_PUNCH][i + 1].level == -1)
442 i++) 472 {
443 if (dam < attack_mess[ATM_PUNCH][i].level
444 || attack_mess[ATM_PUNCH][i+1].level == -1) {
445 sprintf(buf1, "%s %s%s", attack_mess[ATM_PUNCH][i].buf1, 473 sprintf (buf1, "%s %s%s", attack_mess[ATM_PUNCH][i].buf1, &op->name, attack_mess[ATM_PUNCH][i].buf2);
446 &op->name, attack_mess[ATM_PUNCH][i].buf2);
447 strcpy (buf2, attack_mess[ATM_PUNCH][i].buf3); 474 strcpy (buf2, attack_mess[ATM_PUNCH][i].buf3);
448 found++;
449 break;
450 }
451 }
452 }
453 if (found) {
454 /* done */
455 } else if (IS_ARROW(hitter) && (type == AT_PHYSICAL || type == AT_MAGIC)) {
456 sprintf(buf1, "hit"); /* just in case */
457 for (i=0; i < MAXATTACKMESS; i++)
458 if (dam < attack_mess[ATM_ARROW][i].level
459 || attack_mess[ATM_ARROW][i+1].level == -1) {
460 strcpy (buf2, attack_mess[ATM_ARROW][i].buf3);
461 found++; 475 found++;
462 break; 476 break;
477 }
478 }
479 }
480
481 if (found)
482 {
483 /* done */
484 }
485 else if (hitter->is_arrow () && (type == AT_PHYSICAL || type == AT_MAGIC))
486 {
487 sprintf (buf1, "hit"); /* just in case */
488 for (i = 0; i < MAXATTACKMESS; i++)
489 if (dam < attack_mess[ATM_ARROW][i].level || attack_mess[ATM_ARROW][i + 1].level == -1)
490 {
491 strcpy (buf2, attack_mess[ATM_ARROW][i].buf3);
492 found++;
493 break;
494 }
495 }
496 else if (type & AT_DRAIN && op->is_alive ())
497 {
498 /* drain is first, because some items have multiple attypes */
499 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_DRAIN][i].level != -1; i++)
500 if (dam < attack_mess[ATM_DRAIN][i].level || attack_mess[ATM_DRAIN][i + 1].level == -1)
501 {
502 sprintf (buf1, "%s %s%s", attack_mess[ATM_DRAIN][i].buf1, &op->name, attack_mess[ATM_DRAIN][i].buf2);
503 strcpy (buf2, attack_mess[ATM_DRAIN][i].buf3);
504 found++;
505 break;
506 }
507 }
508 else if (type & AT_ELECTRICITY && op->is_alive ())
509 {
510 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_ELEC][i].level != -1; i++)
511 if (dam < attack_mess[ATM_ELEC][i].level || attack_mess[ATM_ELEC][i + 1].level == -1)
512 {
513 sprintf (buf1, "%s %s%s", attack_mess[ATM_ELEC][i].buf1, &op->name, attack_mess[ATM_ELEC][i].buf2);
514 strcpy (buf2, attack_mess[ATM_ELEC][i].buf3);
515 found++;
516 break;
517 }
518 }
519 else if (type & AT_COLD && op->is_alive ())
520 {
521 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_COLD][i].level != -1; i++)
522 if (dam < attack_mess[ATM_COLD][i].level || attack_mess[ATM_COLD][i + 1].level == -1)
523 {
524 sprintf (buf1, "%s %s%s", attack_mess[ATM_COLD][i].buf1, &op->name, attack_mess[ATM_COLD][i].buf2);
525 strcpy (buf2, attack_mess[ATM_COLD][i].buf3);
526 found++;
527 break;
528 }
529 }
530 else if (type & AT_FIRE)
531 {
532 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_FIRE][i].level != -1; i++)
533 if (dam < attack_mess[ATM_FIRE][i].level || attack_mess[ATM_FIRE][i + 1].level == -1)
534 {
535 sprintf (buf1, "%s %s%s", attack_mess[ATM_FIRE][i].buf1, &op->name, attack_mess[ATM_FIRE][i].buf2);
536 strcpy (buf2, attack_mess[ATM_FIRE][i].buf3);
537 found++;
538 break;
539 }
540 }
541 else if (hitter->current_weapon != NULL)
542 {
543 int mtype;
544
545 switch (hitter->current_weapon->weapontype)
546 {
547 case WEAP_HIT:
548 mtype = ATM_BASIC;
549 break;
550 case WEAP_SLASH:
551 mtype = ATM_SLASH;
552 break;
553 case WEAP_PIERCE:
554 mtype = ATM_PIERCE;
555 break;
556 case WEAP_CLEAVE:
557 mtype = ATM_CLEAVE;
558 break;
559 case WEAP_SLICE:
560 mtype = ATM_SLICE;
561 break;
562 case WEAP_STAB:
563 mtype = ATM_STAB;
564 break;
565 case WEAP_WHIP:
566 mtype = ATM_WHIP;
567 break;
568 case WEAP_CRUSH:
569 mtype = ATM_CRUSH;
570 break;
571 case WEAP_BLUD:
572 mtype = ATM_BLUD;
573 break;
574 default:
575 mtype = ATM_BASIC;
576 break;
577 }
578 for (i = 0; i < MAXATTACKMESS && attack_mess[mtype][i].level != -1; i++)
579 if (dam < attack_mess[mtype][i].level || attack_mess[mtype][i + 1].level == -1)
580 {
581 sprintf (buf1, "%s %s%s", attack_mess[mtype][i].buf1, &op->name, attack_mess[mtype][i].buf2);
582 strcpy (buf2, attack_mess[mtype][i].buf3);
583 found++;
584 break;
585 }
586 }
587 else
588 {
589 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_BASIC][i].level != -1; i++)
590 if (dam < attack_mess[ATM_BASIC][i].level || attack_mess[ATM_BASIC][i + 1].level == -1)
591 {
592 sprintf (buf1, "%s %s%s", attack_mess[ATM_BASIC][i].buf1, &op->name, attack_mess[ATM_BASIC][i].buf2);
593 strcpy (buf2, attack_mess[ATM_BASIC][i].buf3);
594 found++;
595 break;
596 }
597 }
598
599 if (!found)
600 {
601 strcpy (buf1, "hit");
602 strcpy (buf2, " hits");
603 }
604
605 /* bail out if a monster is casting spells */
606 if (!(hitter->type == PLAYER || (hitter->owner != NULL && hitter->owner->type == PLAYER)))
607 return;
608
609 /* scale down magic considerably. */
610 if (type & AT_MAGIC && rndm (0, 5))
611 return;
612
613 /* Did a player hurt another player? Inform both! */
614 if (op->type == PLAYER && (hitter->owner == NULL ? hitter->type : hitter->owner->type) == PLAYER)
615 {
616 if (hitter->owner != NULL)
617 sprintf (buf, "%s's %s%s you.", &hitter->owner->name, &hitter->name, buf2);
618 else
619 {
620 sprintf (buf, "%s%s you.", &hitter->name, buf2);
621 if (dam != 0)
622 {
623 if (dam < 10)
624 play_sound_player_only (op->contr, SOUND_PLAYER_IS_HIT1, 0, 0);
625 else if (dam < 20)
626 play_sound_player_only (op->contr, SOUND_PLAYER_IS_HIT2, 0, 0);
627 else
628 play_sound_player_only (op->contr, SOUND_PLAYER_IS_HIT3, 0, 0);
463 } 629 }
464 } else if (type & AT_DRAIN && IS_LIVE(op)) {
465 /* drain is first, because some items have multiple attypes */
466 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_DRAIN][i].level != -1;
467 i++)
468 if (dam < attack_mess[ATM_DRAIN][i].level
469 || attack_mess[ATM_DRAIN][i+1].level == -1) {
470 sprintf(buf1, "%s %s%s", attack_mess[ATM_DRAIN][i].buf1,
471 &op->name, attack_mess[ATM_DRAIN][i].buf2);
472 strcpy (buf2, attack_mess[ATM_DRAIN][i].buf3);
473 found++;
474 break;
475 } 630 }
476 } else if (type & AT_ELECTRICITY && IS_LIVE(op)) {
477 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_ELEC][i].level != -1;
478 i++)
479 if (dam < attack_mess[ATM_ELEC][i].level
480 || attack_mess[ATM_ELEC][i+1].level == -1) {
481 sprintf(buf1, "%s %s%s", attack_mess[ATM_ELEC][i].buf1,
482 &op->name, attack_mess[ATM_ELEC][i].buf2);
483 strcpy (buf2, attack_mess[ATM_ELEC][i].buf3);
484 found++;
485 break;
486 }
487 } else if (type & AT_COLD && IS_LIVE(op)) {
488 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_COLD][i].level != -1;
489 i++)
490 if (dam < attack_mess[ATM_COLD][i].level
491 || attack_mess[ATM_COLD][i+1].level == -1) {
492 sprintf(buf1, "%s %s%s", attack_mess[ATM_COLD][i].buf1,
493 &op->name, attack_mess[ATM_COLD][i].buf2);
494 strcpy (buf2, attack_mess[ATM_COLD][i].buf3);
495 found++;
496 break;
497 }
498 } else if (type & AT_FIRE) {
499 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_FIRE][i].level != -1;
500 i++)
501 if (dam < attack_mess[ATM_FIRE][i].level
502 || attack_mess[ATM_FIRE][i+1].level == -1) {
503 sprintf(buf1, "%s %s%s", attack_mess[ATM_FIRE][i].buf1,
504 &op->name, attack_mess[ATM_FIRE][i].buf2);
505 strcpy (buf2, attack_mess[ATM_FIRE][i].buf3);
506 found++;
507 break;
508 }
509 } else if (hitter->current_weapon != NULL) {
510 int mtype;
511 switch (hitter->current_weapon->weapontype) {
512 case WEAP_HIT: mtype = ATM_BASIC; break;
513 case WEAP_SLASH: mtype = ATM_SLASH; break;
514 case WEAP_PIERCE: mtype = ATM_PIERCE; break;
515 case WEAP_CLEAVE: mtype = ATM_CLEAVE; break;
516 case WEAP_SLICE: mtype = ATM_SLICE; break;
517 case WEAP_STAB: mtype = ATM_STAB; break;
518 case WEAP_WHIP: mtype = ATM_WHIP; break;
519 case WEAP_CRUSH: mtype = ATM_CRUSH; break;
520 case WEAP_BLUD: mtype = ATM_BLUD; break;
521 default: mtype = ATM_BASIC; break;
522 }
523 for (i=0; i < MAXATTACKMESS && attack_mess[mtype][i].level != -1;
524 i++)
525 if (dam < attack_mess[mtype][i].level
526 || attack_mess[mtype][i+1].level == -1) {
527 sprintf(buf1, "%s %s%s", attack_mess[mtype][i].buf1,
528 &op->name, attack_mess[mtype][i].buf2);
529 strcpy (buf2, attack_mess[mtype][i].buf3);
530 found++;
531 break;
532 }
533 } else {
534 for (i=0; i < MAXATTACKMESS && attack_mess[ATM_BASIC][i].level != -1;
535 i++)
536 if (dam < attack_mess[ATM_BASIC][i].level
537 || attack_mess[ATM_BASIC][i+1].level == -1) {
538 sprintf(buf1, "%s %s%s", attack_mess[ATM_BASIC][i].buf1,
539 &op->name, attack_mess[ATM_BASIC][i].buf2);
540 strcpy (buf2, attack_mess[ATM_BASIC][i].buf3);
541 found++;
542 break;
543 }
544 }
545
546 if (!found) {
547 strcpy (buf1, "hit");
548 strcpy (buf2, " hits");
549 }
550
551 /* bail out if a monster is casting spells */
552 if (!(hitter->type == PLAYER ||
553 (get_owner(hitter) != NULL && hitter->owner->type == PLAYER)))
554 return;
555
556 /* scale down magic considerably. */
557 if (type & AT_MAGIC && rndm(0, 5))
558 return;
559
560 /* Did a player hurt another player? Inform both! */
561 if(op->type==PLAYER &&
562 (get_owner(hitter)==NULL?hitter->type:hitter->owner->type)==PLAYER) {
563 if(get_owner(hitter)!=NULL)
564 sprintf(buf,"%s's %s%s you.",
565 &hitter->owner->name, &hitter->name, buf2);
566 else {
567 sprintf(buf,"%s%s you.", &hitter->name, buf2);
568 if (dam != 0) {
569 if (dam < 10)
570 play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT1,0,0);
571 else if (dam < 20)
572 play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT2,0,0);
573 else
574 play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT3,0,0);
575 }
576 }
577 new_draw_info(NDI_BLACK, 0,op,buf); 631 new_draw_info (NDI_BLACK, 0, op, buf);
578 } /* end of player hitting player */ 632 } /* end of player hitting player */
579 633
580 if(hitter->type==PLAYER) { 634 if (hitter->type == PLAYER)
635 {
581 sprintf(buf,"You %s.",buf1); 636 sprintf (buf, "You %s.", buf1);
582 if (dam != 0) { 637 if (dam != 0)
638 {
583 if (dam < 10) 639 if (dam < 10)
584 play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS1,0,0); 640 play_sound_player_only (hitter->contr, SOUND_PLAYER_HITS1, 0, 0);
585 else if (dam < 20) 641 else if (dam < 20)
586 play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS2,0,0); 642 play_sound_player_only (hitter->contr, SOUND_PLAYER_HITS2, 0, 0);
587 else 643 else
588 play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS3,0,0); 644 play_sound_player_only (hitter->contr, SOUND_PLAYER_HITS3, 0, 0);
589 } 645 }
590 new_draw_info(NDI_BLACK, 0, hitter, buf); 646 new_draw_info (NDI_BLACK, 0, hitter, buf);
647 }
591 } else if(get_owner(hitter)!=NULL&&hitter->owner->type==PLAYER) { 648 else if (hitter->owner != NULL && hitter->owner->type == PLAYER)
649 {
592 /* look for stacked spells and start reducing the message chances */ 650 /* look for stacked spells and start reducing the message chances */
593 if (hitter->type == SPELL_EFFECT && 651 if (hitter->type == SPELL_EFFECT && (hitter->subtype == SP_EXPLOSION || hitter->subtype == SP_BULLET || hitter->subtype == SP_CONE))
594 (hitter->subtype == SP_EXPLOSION || 652 {
595 hitter->subtype == SP_BULLET ||
596 hitter->subtype == SP_CONE)) {
597 i=4; 653 i = 4;
598 map = hitter->map; 654 map = hitter->map;
599 if (out_of_map(map, hitter->x, hitter->y)) 655 if (out_of_map (map, hitter->x, hitter->y))
600 return;
601 next = get_map_ob(map, hitter->x, hitter->y);
602 if (next)
603 while(next) {
604 if (next->type == SPELL_EFFECT &&
605 (next->subtype == SP_EXPLOSION || next->subtype==SP_BULLET ||
606 next->subtype == SP_CONE))
607 i*=3;
608 tmp = next;
609 next = tmp->above;
610 }
611 if (i < 0)
612 return;
613 if (rndm(0, i) != 0)
614 return;
615 } else if (rndm(0, 5) != 0)
616 return; 656 return;
657 next = GET_MAP_OB (map, hitter->x, hitter->y);
658 if (next)
659 while (next)
660 {
661 if (next->type == SPELL_EFFECT && (next->subtype == SP_EXPLOSION || next->subtype == SP_BULLET || next->subtype == SP_CONE))
662 i *= 3;
663 tmp = next;
664 next = tmp->above;
665 }
666 if (i < 0)
667 return;
668 if (rndm (0, i) != 0)
669 return;
670 }
671 else if (rndm (0, 5) != 0)
672 return;
617 sprintf(buf,"Your %s%s %s.", &hitter->name, buf2, &op->name); 673 sprintf (buf, "Your %s%s %s.", &hitter->name, buf2, &op->name);
618 play_sound_map(op->map, op->x, op->y, SOUND_PLAYER_HITS4); 674 play_sound_map (op->map, op->x, op->y, SOUND_PLAYER_HITS4);
619 new_draw_info(NDI_BLACK, 0, hitter->owner, buf); 675 new_draw_info (NDI_BLACK, 0, hitter->owner, buf);
620 } 676 }
621} 677}
622 678
623 679
680static int
624static int get_attack_mode (object **target, object **hitter, 681get_attack_mode (object **target, object **hitter, int *simple_attack)
625 int *simple_attack)
626{ 682{
627 if (QUERY_FLAG (*target, FLAG_FREED) || QUERY_FLAG (*hitter, FLAG_FREED)) { 683 if (QUERY_FLAG (*target, FLAG_FREED) || QUERY_FLAG (*hitter, FLAG_FREED))
684 {
628 LOG (llevError, "BUG: get_attack_mode(): freed object\n"); 685 LOG (llevError, "BUG: get_attack_mode(): freed object\n");
629 return 1; 686 return 1;
630 } 687 }
631 if ((*target)->head) 688 if ((*target)->head)
632 *target = (*target)->head; 689 *target = (*target)->head;
633 if ((*hitter)->head) 690 if ((*hitter)->head)
634 *hitter = (*hitter)->head; 691 *hitter = (*hitter)->head;
635 if ((*hitter)->env != NULL || (*target)->env != NULL) { 692 if ((*hitter)->env != NULL || (*target)->env != NULL)
693 {
636 *simple_attack = 1; 694 *simple_attack = 1;
637 return 0; 695 return 0;
638 } 696 }
639 if (QUERY_FLAG (*target, FLAG_REMOVED) 697 if (QUERY_FLAG (*target, FLAG_REMOVED)
640 || QUERY_FLAG (*hitter, FLAG_REMOVED)
641 || (*hitter)->map == NULL || !on_same_map((*hitter), (*target))) 698 || QUERY_FLAG (*hitter, FLAG_REMOVED) || (*hitter)->map == NULL || !on_same_map ((*hitter), (*target)))
642 { 699 {
643 LOG (llevError, "BUG: hitter (arch %s, name %s) with no relation to " 700 LOG (llevError, "BUG: hitter (arch %s, name %s) with no relation to " "target\n", &(*hitter)->arch->name, &(*hitter)->name);
644 "target\n", &(*hitter)->arch->name, &(*hitter)->name);
645 return 1; 701 return 1;
646 } 702 }
647 *simple_attack = 0; 703 *simple_attack = 0;
648 return 0; 704 return 0;
649} 705}
650 706
707static int
651static int abort_attack (object *target, object *hitter, int simple_attack) 708abort_attack (object *target, object *hitter, int simple_attack)
652{ 709{
710
653/* Check if target and hitter are still in a relation similar to the one 711/* Check if target and hitter are still in a relation similar to the one
654 * determined by get_attack_mode(). Returns true if the relation has changed. 712 * determined by get_attack_mode(). Returns true if the relation has changed.
655 */ 713 */
656 int new_mode; 714 int new_mode;
657 715
658 if (hitter->env == target || target->env == hitter) 716 if (hitter->env == target || target->env == hitter)
659 new_mode = 1; 717 new_mode = 1;
660 else if (QUERY_FLAG (hitter, FLAG_REMOVED) 718 else if (QUERY_FLAG (hitter, FLAG_REMOVED) || QUERY_FLAG (target, FLAG_REMOVED) || hitter->map == NULL || !on_same_map (hitter, target))
661 || QUERY_FLAG (target, FLAG_REMOVED)
662 || hitter->map == NULL || !on_same_map(hitter, target))
663 return 1; 719 return 1;
664 else 720 else
665 new_mode = 0; 721 new_mode = 0;
666 return new_mode != simple_attack; 722 return new_mode != simple_attack;
667} 723}
668 724
669static void thrown_item_effect (object *, object *); 725static void thrown_item_effect (object *, object *);
670 726
727static int
671static int attack_ob_simple (object *op, object *hitter, int base_dam, 728attack_ob_simple (object *op, object *hitter, int base_dam, int base_wc)
672 int base_wc)
673{ 729{
674 int simple_attack, roll, dam=0; 730 int simple_attack, roll, dam = 0;
675 uint32 type; 731 uint32 type;
676 shstr op_name; 732 shstr op_name;
677 tag_t op_tag, hitter_tag;
678 733
679 if (get_attack_mode (&op, &hitter, &simple_attack)) 734 if (get_attack_mode (&op, &hitter, &simple_attack))
735 goto error;
736
737 if (hitter->current_weapon)
738 if (INVOKE_OBJECT (WEAPON_ATTACK, hitter->current_weapon, ARG_OBJECT (hitter), ARG_OBJECT (op)))
739 return RESULT_INT (0);
740
741 if (INVOKE_OBJECT (ATTACK, op, ARG_OBJECT (hitter)))
742 return RESULT_INT (0);
743
744 /*
745 * A little check to make it more difficult to dance forward and back
746 * to avoid ever being hit by monsters.
747 */
748 if (!simple_attack && QUERY_FLAG (op, FLAG_MONSTER) && op->speed_left > -(FABS (op->speed)) * 0.3)
749 {
750 /* Decrease speed BEFORE calling process_object. Otherwise, an
751 * infinite loop occurs, with process_object calling move_monster,
752 * which then gets here again. By decreasing the speed before
753 * we call process_object, the 'if' statement above will fail.
754 */
755 op->speed_left--;
756 process_object (op);
757
758 if (op->destroyed () || hitter->destroyed () || abort_attack (op, hitter, simple_attack))
680 goto error; 759 goto error;
681
682 if (hitter->current_weapon)
683 if (INVOKE_OBJECT (WEAPON_ATTACK, hitter->current_weapon, ARG_OBJECT (hitter), ARG_OBJECT (op)))
684 return RESULT_INT (0);
685
686 if (INVOKE_OBJECT (ATTACK, op, ARG_OBJECT (hitter)))
687 return RESULT_INT (0);
688
689 op_tag = op->count;
690 hitter_tag = hitter->count;
691
692 /*
693 * A little check to make it more difficult to dance forward and back
694 * to avoid ever being hit by monsters.
695 */
696 if ( ! simple_attack && QUERY_FLAG (op, FLAG_MONSTER)
697 && op->speed_left > -(FABS(op->speed))*0.3)
698 { 760 }
699 /* Decrease speed BEFORE calling process_object. Otherwise, an
700 * infinite loop occurs, with process_object calling move_monster,
701 * which then gets here again. By decreasing the speed before
702 * we call process_object, the 'if' statement above will fail.
703 */
704 op->speed_left--;
705 process_object(op);
706 if (was_destroyed (op, op_tag) || was_destroyed (hitter, hitter_tag)
707 || abort_attack (op, hitter, simple_attack))
708 goto error;
709 }
710 761
711 op_name = op->name; 762 op_name = op->name;
712 763
713 roll=random_roll(1, 20, hitter, PREFER_HIGH); 764 roll = random_roll (1, 20, hitter, PREFER_HIGH);
714 765
715 /* Adjust roll for various situations. */ 766 /* Adjust roll for various situations. */
716 if ( ! simple_attack) 767 if (!simple_attack)
717 roll += adj_attackroll(hitter,op); 768 roll += adj_attackroll (hitter, op);
718 769
719 /* See if we hit the creature */ 770 /* See if we hit the creature */
720 if(roll==20 || op->stats.ac>=base_wc-roll) { 771 if (roll == 20 || op->stats.ac >= base_wc - roll)
772 {
721 int hitdam = base_dam; 773 int hitdam = base_dam;
774
722 if (settings.casting_time == TRUE) { 775 if (settings.casting_time == TRUE)
776 {
723 if ((hitter->type == PLAYER)&&(hitter->casting_time > -1)){ 777 if ((hitter->type == PLAYER) && (hitter->casting_time > -1))
778 {
724 hitter->casting_time = -1; 779 hitter->casting_time = -1;
725 new_draw_info(NDI_UNIQUE, 0,hitter,"You attacked and lost " 780 new_draw_info (NDI_UNIQUE, 0, hitter, "You attacked and lost your spell!");
726 "your spell!");
727 } 781 }
728 if ((op->casting_time > -1)&&(hitdam > 0)){ 782 if ((op->casting_time > -1) && (hitdam > 0))
783 {
729 op->casting_time = -1; 784 op->casting_time = -1;
730 if (op->type == PLAYER) { 785 if (op->type == PLAYER)
786 {
731 new_draw_info(NDI_UNIQUE, 0,op,"You were hit and lost " 787 new_draw_info (NDI_UNIQUE, 0, op, "You were hit and lost your spell!");
732 "your spell!"); 788 new_draw_info_format (NDI_ALL | NDI_UNIQUE, 5, NULL, "%s was hit by %s and lost a spell.", &op_name, &hitter->name);
733 new_draw_info_format(NDI_ALL|NDI_UNIQUE,5,NULL,
734 "%s was hit by %s and lost a spell.",
735 &op_name,&hitter->name);
736 } 789 }
737 } 790 }
738 } 791 }
739 if ( ! simple_attack) 792 if (!simple_attack)
740 { 793 {
741 /* If you hit something, the victim should *always* wake up. 794 /* If you hit something, the victim should *always* wake up.
742 * Before, invisible hitters could avoid doing this. 795 * Before, invisible hitters could avoid doing this.
743 * -b.t. */ 796 * -b.t. */
744 if (QUERY_FLAG (op, FLAG_SLEEP)) 797 if (QUERY_FLAG (op, FLAG_SLEEP))
745 CLEAR_FLAG(op,FLAG_SLEEP); 798 CLEAR_FLAG (op, FLAG_SLEEP);
746 799
747 /* If the victim can't see the attacker, it may alert others 800 /* If the victim can't see the attacker, it may alert others
748 * for help. */ 801 * for help. */
749 if (op->type != PLAYER && ! can_see_enemy (op, hitter) 802 if (op->type != PLAYER && !can_see_enemy (op, hitter) && !op->owner && rndm (0, op->stats.Int))
750 && ! get_owner (op) && rndm(0, op->stats.Int))
751 npc_call_help (op); 803 npc_call_help (op);
752 804
753 /* if you were hidden and hit by a creature, you are discovered*/ 805 /* if you were hidden and hit by a creature, you are discovered */
754 if (op->hide && QUERY_FLAG (hitter, FLAG_ALIVE)) { 806 if (op->hide && QUERY_FLAG (hitter, FLAG_ALIVE))
807 {
755 make_visible (op); 808 make_visible (op);
756 if (op->type == PLAYER) 809 if (op->type == PLAYER)
757 new_draw_info (NDI_UNIQUE, 0, op, 810 new_draw_info (NDI_UNIQUE, 0, op, "You were hit by a wild attack. " "You are no longer hidden!");
758 "You were hit by a wild attack. "
759 "You are no longer hidden!");
760 } 811 }
761 812
762 /* thrown items (hitter) will have various effects 813 /* thrown items (hitter) will have various effects
763 * when they hit the victim. For things like thrown daggers, 814 * when they hit the victim. For things like thrown daggers,
764 * this sets 'hitter' to the actual dagger, and not the 815 * this sets 'hitter' to the actual dagger, and not the
765 * wrapper object. 816 * wrapper object.
766 */ 817 */
767 thrown_item_effect (hitter, op); 818 thrown_item_effect (hitter, op);
768 if (was_destroyed (hitter, hitter_tag)
769 || was_destroyed (op, op_tag)
770 || abort_attack (op, hitter, simple_attack))
771 goto leave;
772 }
773 819
774 /* Need to do at least 1 damage, otherwise there is no point 820 if (hitter->destroyed () || op->destroyed () || abort_attack (op, hitter, simple_attack))
775 * to go further and it will cause FPE's below.
776 */
777 if (hitdam<=0) hitdam=1;
778
779 type=hitter->attacktype;
780 if(!type) type=AT_PHYSICAL;
781 /* Handle monsters that hit back */
782 if ( ! simple_attack && QUERY_FLAG (op, FLAG_HITBACK)
783 && QUERY_FLAG (hitter, FLAG_ALIVE))
784 {
785 if (op->attacktype & AT_ACID && hitter->type==PLAYER)
786 new_draw_info(NDI_UNIQUE, 0,hitter,"You are splashed by acid!\n");
787 hit_player(hitter, random_roll(0, (op->stats.dam), hitter,
788 PREFER_LOW),op, op->attacktype, 1);
789 if (was_destroyed (op, op_tag)
790 || was_destroyed (hitter, hitter_tag)
791 || abort_attack (op, hitter, simple_attack))
792 goto leave;
793 }
794
795 /* In the new attack code, it should handle multiple attack
796 * types in its area, so remove it from here.
797 */
798 dam=hit_player(op, random_roll(1, hitdam, hitter, PREFER_HIGH),
799 hitter, type, 1);
800 if (was_destroyed (op, op_tag) || was_destroyed (hitter, hitter_tag)
801 || abort_attack (op, hitter, simple_attack))
802 goto leave; 821 goto leave;
803 } /* end of if hitter hit op */ 822 }
823
824 /* Need to do at least 1 damage, otherwise there is no point
825 * to go further and it will cause FPE's below.
826 */
827 if (hitdam <= 0)
828 hitdam = 1;
829
830 type = hitter->attacktype;
831
832 if (!type)
833 type = AT_PHYSICAL;
834
835 /* Handle monsters that hit back */
836 if (!simple_attack && QUERY_FLAG (op, FLAG_HITBACK) && QUERY_FLAG (hitter, FLAG_ALIVE))
837 {
838 if (op->attacktype & AT_ACID && hitter->type == PLAYER)
839 new_draw_info (NDI_UNIQUE, 0, hitter, "You are splashed by acid!\n");
840
841 hit_player (hitter, random_roll (0, (op->stats.dam), hitter, PREFER_LOW), op, op->attacktype, 1);
842
843 if (op->destroyed () || hitter->destroyed () || abort_attack (op, hitter, simple_attack))
844 goto leave;
845 }
846
847 /* In the new attack code, it should handle multiple attack
848 * types in its area, so remove it from here.
849 */
850 dam = hit_player (op, random_roll (1, hitdam, hitter, PREFER_HIGH), hitter, type, 1);
851
852 if (op->destroyed () || hitter->destroyed () || abort_attack (op, hitter, simple_attack))
853 goto leave;
854 } /* end of if hitter hit op */
804 /* if we missed, dam=0 */ 855 /* if we missed, dam=0 */
805 856
806 /*attack_message(dam, type, op, hitter);*/ 857 /*attack_message(dam, type, op, hitter); */
807 858
808 goto leave; 859 goto leave;
809 860
810 error: 861error:
811 dam = 1; 862 dam = 1;
812 863
813 leave: 864leave:
814 865
815 return dam; 866 return dam;
816} 867}
817 868
869int
818int attack_ob (object *op, object *hitter) 870attack_ob (object *op, object *hitter)
819{ 871{
820 872
821 if (hitter->head) 873 if (hitter->head)
822 hitter = hitter->head; 874 hitter = hitter->head;
823 return attack_ob_simple (op, hitter, hitter->stats.dam, hitter->stats.wc); 875 return attack_ob_simple (op, hitter, hitter->stats.dam, hitter->stats.wc);
824} 876}
825 877
826/* op is the arrow, tmp is what is stopping the arrow. 878/* op is the arrow, tmp is what is stopping the arrow.
827 * 879 *
828 * Returns 1 if op was inserted into tmp's inventory, 0 otherwise. 880 * Returns 1 if op was inserted into tmp's inventory, 0 otherwise.
829 */ 881 */
882static int
830static int stick_arrow (object *op, object *tmp) 883stick_arrow (object *op, object *tmp)
831{ 884{
832 /* If the missile hit a player, we insert it in their inventory. 885 /* If the missile hit a player, we insert it in their inventory.
833 * However, if the missile is heavy, we don't do so (assume it falls 886 * However, if the missile is heavy, we don't do so (assume it falls
834 * to the ground after a hit). What a good value for this is up to 887 * to the ground after a hit). What a good value for this is up to
835 * debate - 5000 is 5 kg, so arrows, knives, and other light weapons 888 * debate - 5000 is 5 kg, so arrows, knives, and other light weapons
836 * stick around. 889 * stick around.
837 */ 890 */
838 if (op->weight <= 5000 && tmp->stats.hp >= 0) { 891 if (op->weight <= 5000 && tmp->stats.hp >= 0)
892 {
839 if(tmp->head != NULL) 893 if (tmp->head != NULL)
840 tmp = tmp->head; 894 tmp = tmp->head;
841 remove_ob (op); 895
896 op->remove ();
842 op = insert_ob_in_ob(op,tmp); 897 op = insert_ob_in_ob (op, tmp);
898
843 if (tmp->type== PLAYER) 899 if (tmp->type == PLAYER)
844 esrv_send_item (tmp, op); 900 esrv_send_item (tmp, op);
901
845 return 1; 902 return 1;
903 }
846 } else 904 else
847 return 0; 905 return 0;
848} 906}
849 907
850/* hit_with_arrow() disassembles the missile, attacks the victim and 908/* hit_with_arrow() disassembles the missile, attacks the victim and
851 * reassembles the missile. 909 * reassembles the missile.
852 * 910 *
853 * It returns a pointer to the reassembled missile, or NULL if the missile 911 * It returns a pointer to the reassembled missile, or NULL if the missile
854 * isn't available anymore. 912 * isn't available anymore.
855 */ 913 */
914object *
856object *hit_with_arrow (object *op, object *victim) 915hit_with_arrow (object *op, object *victim)
857{ 916{
858 object *container, *hitter; 917 object *container, *hitter;
859 int hit_something = 0; 918 int hit_something = 0;
860 tag_t victim_tag, hitter_tag;
861 sint16 victim_x, victim_y;
862 919
863 /* Disassemble missile */ 920 /* Disassemble missile */
864 if (op->inv) { 921 if (op->inv)
922 {
865 container = op; 923 container = op;
866 hitter = op->inv; 924 hitter = op->inv;
867 remove_ob (hitter); 925 hitter->remove ();
868 insert_ob_in_map(hitter, container->map,hitter,INS_NO_MERGE | INS_NO_WALK_ON); 926 insert_ob_in_map (hitter, container->map, hitter, INS_NO_MERGE | INS_NO_WALK_ON);
869 /* Note that we now have an empty THROWN_OBJ on the map. Code that 927 /* Note that we now have an empty THROWN_OBJ on the map. Code that
870 * might be called until this THROWN_OBJ is either reassembled or 928 * might be called until this THROWN_OBJ is either reassembled or
871 * removed at the end of this function must be able to deal with empty 929 * removed at the end of this function must be able to deal with empty
872 * THROWN_OBJs. */ 930 * THROWN_OBJs. */
873 } else { 931 }
932 else
933 {
874 container = NULL; 934 container = 0;
875 hitter = op; 935 hitter = op;
876 } 936 }
877 937
878 /* Try to hit victim */ 938 /* Try to hit victim */
879 victim_x = victim->x;
880 victim_y = victim->y;
881 victim_tag = victim->count;
882 hitter_tag = hitter->count;
883
884 hit_something = attack_ob_simple (victim, hitter, op->stats.dam, op->stats.wc); 939 hit_something = attack_ob_simple (victim, hitter, op->stats.dam, op->stats.wc);
885 940
886 /* Arrow attacks door, rune of summoning is triggered, demon is put on 941 /* Arrow attacks door, rune of summoning is triggered, demon is put on
887 * arrow, move_apply() calls this function, arrow sticks in demon, 942 * arrow, move_apply() calls this function, arrow sticks in demon,
888 * attack_ob_simple() returns, and we've got an arrow that still exists 943 * attack_ob_simple() returns, and we've got an arrow that still exists
889 * but is no longer on the map. Ugh. (Beware: Such things can happen at 944 * but is no longer on the map. Ugh. (Beware: Such things can happen at
890 * other places as well!) 945 * other places as well!)
891 */ 946 */
892 if (was_destroyed (hitter, hitter_tag) || hitter->env != NULL) { 947 if (hitter->destroyed () || hitter->env != NULL)
948 {
893 if (container) { 949 if (container)
894 remove_ob (container);
895 free_object (container);
896 } 950 {
951 container->remove ();
952 container->destroy ();
953 }
954
897 return NULL; 955 return 0;
898 } 956 }
899 957
900 /* Missile hit victim */ 958 /* Missile hit victim */
901 /* if the speed is > 10, then this is a fast moving arrow, we go straight 959 /* if the speed is > 10, then this is a fast moving arrow, we go straight
902 * through the target 960 * through the target
903 */ 961 */
904 if (hit_something && op->speed <= 10.0) 962 if (hit_something && op->speed <= 10.0)
905 { 963 {
906 /* Stop arrow */ 964 /* Stop arrow */
907 if (container == NULL) { 965 if (!container)
966 {
908 hitter = fix_stopped_arrow (hitter); 967 hitter = fix_stopped_arrow (hitter);
909 if (hitter == NULL) 968 if (!hitter)
910 return NULL; 969 return 0;
970 }
911 } else { 971 else
912 remove_ob (container); 972 container->destroy ();
913 free_object (container);
914 }
915 973
916 /* Try to stick arrow into victim */ 974 /* Try to stick arrow into victim */
917 if ( ! was_destroyed (victim, victim_tag) 975 if (!victim->destroyed () && stick_arrow (hitter, victim))
918 && stick_arrow (hitter, victim))
919 return NULL; 976 return 0;
920 977
921 /* Else try to put arrow on victim's map square 978 /* Else try to put arrow on victim's map square
922 * remove check for P_WALL here. If the arrow got to this 979 * remove check for P_WALL here. If the arrow got to this
923 * space, that is good enough - with the new movement code, 980 * space, that is good enough - with the new movement code,
924 * there is now the potential for lots of spaces where something 981 * there is now the potential for lots of spaces where something
925 * can fly over but not otherwise move over. What is the correct 982 * can fly over but not otherwise move over. What is the correct
926 * way to handle those otherwise? 983 * way to handle those otherwise?
927 */ 984 */
928 if (victim_x != hitter->x || victim_y != hitter->y) { 985 if (victim->x != hitter->x || victim->y != hitter->y)
929 remove_ob (hitter); 986 {
987 hitter->remove ();
930 hitter->x = victim_x; 988 hitter->x = victim->x;
931 hitter->y = victim_y; 989 hitter->y = victim->y;
932 insert_ob_in_map (hitter, victim->map, hitter,0); 990 insert_ob_in_map (hitter, victim->map, hitter, 0);
991 }
933 } else { 992 else
934 /* Else leave arrow where it is */ 993 /* Else leave arrow where it is */
935 merge_ob (hitter, NULL); 994 merge_ob (hitter, NULL);
936 } 995
937 return NULL; 996 return 0;
938 } 997 }
939 998
940 if (hit_something && op->speed >= 10.0) 999 if (hit_something && op->speed >= 10.0)
941 op->speed -= 1.0; 1000 op->speed -= 1.0;
942 1001
943 /* Missile missed victim - reassemble missile */ 1002 /* Missile missed victim - reassemble missile */
944 if (container) { 1003 if (container)
945 remove_ob (hitter); 1004 {
1005 hitter->remove ();
946 insert_ob_in_ob (hitter, container); 1006 insert_ob_in_ob (hitter, container);
947 } 1007 }
1008
948 return op; 1009 return op;
949} 1010}
950 1011
951 1012
1013void
952void tear_down_wall(object *op) 1014tear_down_wall (object *op)
953{ 1015{
954 int perc=0; 1016 int perc = 0;
955 1017
956 if (!op->stats.maxhp) { 1018 if (!op->stats.maxhp)
1019 {
957 LOG(llevError, "TEAR_DOWN wall %s had no maxhp.\n", &op->name); 1020 LOG (llevError, "TEAR_DOWN wall %s had no maxhp.\n", &op->name);
958 perc = 1; 1021 perc = 1;
1022 }
959 } else if(!GET_ANIM_ID(op)) { 1023 else if (!GET_ANIM_ID (op))
1024 {
960 /* Object has been called - no animations, so remove it */ 1025 /* Object has been called - no animations, so remove it */
961 if(op->stats.hp<0) { 1026 if (op->stats.hp < 0)
962 remove_ob(op); /* Should update LOS */ 1027 op->destroy ();
963 free_object(op);
964 /* Don't know why this is here - remove_ob should do it for us */
965 /*update_position(m, x, y);*/
966 } 1028
967 return; /* no animations, so nothing more to do */ 1029 return; /* no animations, so nothing more to do */
968 } 1030 }
969 perc = NUM_ANIMATIONS(op) 1031
970 - ((int)NUM_ANIMATIONS(op)*op->stats.hp)/op->stats.maxhp; 1032 perc = NUM_ANIMATIONS (op) - ((int) NUM_ANIMATIONS (op) * op->stats.hp) / op->stats.maxhp;
1033
971 if (perc >= (int) NUM_ANIMATIONS(op)) 1034 if (perc >= (int) NUM_ANIMATIONS (op))
972 perc = NUM_ANIMATIONS(op)-1; 1035 perc = NUM_ANIMATIONS (op) - 1;
973 else if (perc < 1) 1036 else if (perc < 1)
974 perc = 1; 1037 perc = 1;
1038
975 SET_ANIMATION(op, perc); 1039 SET_ANIMATION (op, perc);
976 update_object(op,UP_OBJ_FACE); 1040 update_object (op, UP_OBJ_FACE);
977 if(perc==NUM_ANIMATIONS(op)-1) { /* Reached the last animation */ 1041
1042 if (perc == NUM_ANIMATIONS (op) - 1)
1043 { /* Reached the last animation */
978 if(op->face==blank_face) { 1044 if (op->face == blank_face)
979 /* If the last face is blank, remove the ob */ 1045 /* If the last face is blank, remove the ob */
980 remove_ob(op); /* Should update LOS */ 1046 op->destroy ();
981 free_object(op); 1047 else
982
983 /* remove_ob should call update_position for us */
984 /*update_position(m, x, y);*/
985
986 } else { /* The last face was not blank, leave an image */ 1048 { /* The last face was not blank, leave an image */
987 CLEAR_FLAG(op, FLAG_BLOCKSVIEW); 1049 CLEAR_FLAG (op, FLAG_BLOCKSVIEW);
988 update_all_los(op->map, op->x, op->y); 1050 update_all_los (op->map, op->x, op->y);
989 op->move_block = 0; 1051 op->move_block = 0;
990 CLEAR_FLAG(op, FLAG_ALIVE); 1052 CLEAR_FLAG (op, FLAG_ALIVE);
991 } 1053 }
992 } 1054 }
993} 1055}
994 1056
1057void
995void scare_creature(object *target, object *hitter) 1058scare_creature (object *target, object *hitter)
996{ 1059{
997 object *owner = get_owner(hitter); 1060 object *owner = hitter->owner;
998 1061
999 if (!owner) owner=hitter; 1062 if (!owner)
1063 owner = hitter;
1000 1064
1001 SET_FLAG(target, FLAG_SCARED); 1065 SET_FLAG (target, FLAG_SCARED);
1002 if (!target->enemy) target->enemy=owner; 1066 if (!target->enemy)
1067 target->enemy = owner;
1003} 1068}
1004 1069
1005 1070
1006/* This returns the amount of damage hitter does to op with the 1071/* This returns the amount of damage hitter does to op with the
1007 * appropriate attacktype. Only 1 attacktype should be set at a time. 1072 * appropriate attacktype. Only 1 attacktype should be set at a time.
1008 * This doesn't damage the player, but returns how much it should 1073 * This doesn't damage the player, but returns how much it should
1009 * take. However, it will do other effects (paralyzation, slow, etc.) 1074 * take. However, it will do other effects (paralyzation, slow, etc.)
1010 * Note - changed for PR code - we now pass the attack number and not 1075 * Note - changed for PR code - we now pass the attack number and not
1011 * the attacktype. Makes it easier for the PR code. */ 1076 * the attacktype. Makes it easier for the PR code. */
1012 1077int
1013int hit_player_attacktype(object *op, object *hitter, int dam, 1078hit_player_attacktype (object *op, object *hitter, int dam, uint32 attacknum, int magic)
1014 uint32 attacknum, int magic) { 1079{
1015
1016 int doesnt_slay = 1; 1080 int doesnt_slay = 1;
1017 1081
1018 /* Catch anyone that may be trying to send us a bitmask instead of the number */ 1082 /* Catch anyone that may be trying to send us a bitmask instead of the number */
1019 if (attacknum >= NROFATTACKS) { 1083 if (attacknum >= NROFATTACKS)
1084 {
1020 LOG(llevError, "hit_player_attacktype: Invalid attacknumber passed: %u\n", attacknum); 1085 LOG (llevError, "hit_player_attacktype: Invalid attacknumber passed: %u\n", attacknum);
1021 return 0; 1086 return 0;
1022 }
1023 1087 }
1088
1024 if (dam < 0) { 1089 if (dam < 0)
1090 {
1025 LOG(llevError,"hit_player_attacktype called with negative damage: %d\n", dam); 1091 LOG (llevError, "hit_player_attacktype called with negative damage: %d\n", dam);
1026 return 0; 1092 return 0;
1027 }
1028 1093 }
1094
1029 /* AT_INTERNAL is supposed to do exactly dam. Put a case here so 1095 /* AT_INTERNAL is supposed to do exactly dam. Put a case here so
1030 * people can't mess with that or it otherwise get confused. */ 1096 * people can't mess with that or it otherwise get confused. */
1031 if (attacknum == ATNR_INTERNAL) return dam; 1097 if (attacknum == ATNR_INTERNAL)
1032 1098 return dam;
1099
1033 if (hitter->slaying) { 1100 if (hitter->slaying)
1101 {
1034 if(((op->race != NULL) && strstr(hitter->slaying, op->race)) || 1102 if (((op->race != NULL) && strstr (hitter->slaying, op->race)) ||
1035 (op->arch && (op->arch->name != NULL) && 1103 (op->arch && (op->arch->name != NULL) && strstr (op->arch->name, hitter->slaying)))
1036 strstr(op->arch->name, hitter->slaying))
1037 ){ 1104 {
1038 doesnt_slay = 0; 1105 doesnt_slay = 0;
1039 dam *= 3; 1106 dam *= 3;
1040 } 1107 }
1041 } 1108 }
1042 1109
1043 /* Adjust the damage for resistance. Note that neg. values increase damage. */ 1110 /* Adjust the damage for resistance. Note that neg. values increase damage. */
1044 if (op->resist[attacknum]) { 1111 if (op->resist[attacknum])
1112 {
1045 /* basically: dam = dam*(100-op->resist[attacknum])/100; 1113 /* basically: dam = dam*(100-op->resist[attacknum])/100;
1046 * in case 0>dam>1, we try to "simulate" a float value-effect */ 1114 * in case 0>dam>1, we try to "simulate" a float value-effect */
1047 dam *= (100-op->resist[attacknum]); 1115 dam *= (100 - op->resist[attacknum]);
1048 if (dam >= 100) dam /= 100; 1116 if (dam >= 100)
1117 dam /= 100;
1049 else 1118 else
1050 dam = (dam > (random_roll(0, 99, op, PREFER_LOW))) ? 1 : 0; 1119 dam = (dam > (random_roll (0, 99, op, PREFER_LOW))) ? 1 : 0;
1051 } 1120 }
1052 1121
1053 /* Special hack. By default, if immune to something, you 1122 /* Special hack. By default, if immune to something, you
1054 * shouldn't need to worry. However, acid is an exception, since 1123 * shouldn't need to worry. However, acid is an exception, since
1055 * it can still damage your items. Only include attacktypes if 1124 * it can still damage your items. Only include attacktypes if
1056 * special processing is needed */ 1125 * special processing is needed */
1057 1126
1058 if ((op->resist[attacknum] >= 100) && 1127 if ((op->resist[attacknum] >= 100) && doesnt_slay && (attacknum != ATNR_ACID))
1059 doesnt_slay && (attacknum != ATNR_ACID))
1060 return 0; 1128 return 0;
1061 1129
1062 /* Keep this in order - makes things easier to find */ 1130 /* Keep this in order - makes things easier to find */
1131
1132 switch (attacknum)
1063 1133 {
1064 switch(attacknum) {
1065 case ATNR_PHYSICAL: 1134 case ATNR_PHYSICAL:
1066 /* here also check for diseases */ 1135 /* here also check for diseases */
1067 check_physically_infect(op, hitter); 1136 check_physically_infect (op, hitter);
1068 break; 1137 break;
1069 1138
1070 /* Don't need to do anything for: 1139 /* Don't need to do anything for:
1071 magic, 1140 magic,
1072 fire, 1141 fire,
1073 electricity, 1142 electricity,
1074 cold */ 1143 cold */
1075 1144
1076 case ATNR_CONFUSION: 1145 case ATNR_CONFUSION:
1077 case ATNR_POISON: 1146 case ATNR_POISON:
1078 case ATNR_SLOW: 1147 case ATNR_SLOW:
1079 case ATNR_PARALYZE: 1148 case ATNR_PARALYZE:
1080 case ATNR_FEAR: 1149 case ATNR_FEAR:
1081 case ATNR_CANCELLATION: 1150 case ATNR_CANCELLATION:
1082 case ATNR_DEPLETE: 1151 case ATNR_DEPLETE:
1083 case ATNR_BLIND: 1152 case ATNR_BLIND:
1084 { 1153 {
1085 /* chance for inflicting a special attack depends on the 1154 /* chance for inflicting a special attack depends on the
1086 * difference between attacker's and defender's level 1155 * difference between attacker's and defender's level
1087 */ 1156 */
1088 int level_diff = MIN(110, MAX(0, op->level - hitter->level)); 1157 int level_diff = MIN (110, MAX (0, op->level - hitter->level));
1089 1158
1090 /* First, only creatures/players with speed can be affected. 1159 /* First, only creatures/players with speed can be affected.
1091 * Second, just getting hit doesn't mean it always affects 1160 * Second, just getting hit doesn't mean it always affects
1092 * you. Third, you still get a saving through against the 1161 * you. Third, you still get a saving through against the
1093 * effect. 1162 * effect.
1094 */ 1163 */
1095 if (op->speed && 1164 if (op->speed &&
1096 (QUERY_FLAG(op, FLAG_MONSTER) || op->type==PLAYER) && 1165 (QUERY_FLAG (op, FLAG_MONSTER) || op->type == PLAYER) &&
1097 !(rndm(0, (attacknum == ATNR_SLOW?6:3)-1)) && 1166 !(rndm (0, (attacknum == ATNR_SLOW ? 6 : 3) - 1)) && !did_make_save (op, level_diff, op->resist[attacknum] / 10))
1098 !did_make_save(op, level_diff, op->resist[attacknum]/10)) { 1167 {
1099 1168
1100 /* Player has been hit by something */ 1169 /* Player has been hit by something */
1101 if (attacknum == ATNR_CONFUSION) confuse_player(op,hitter,dam); 1170 if (attacknum == ATNR_CONFUSION)
1171 confuse_player (op, hitter, dam);
1102 else if (attacknum == ATNR_POISON) poison_player(op,hitter,dam); 1172 else if (attacknum == ATNR_POISON)
1173 poison_player (op, hitter, dam);
1103 else if (attacknum == ATNR_SLOW) slow_player(op,hitter,dam); 1174 else if (attacknum == ATNR_SLOW)
1104 else if (attacknum == ATNR_PARALYZE) paralyze_player(op,hitter,dam); 1175 slow_player (op, hitter, dam);
1176 else if (attacknum == ATNR_PARALYZE)
1177 paralyze_player (op, hitter, dam);
1105 else if (attacknum == ATNR_FEAR) scare_creature(op, hitter); 1178 else if (attacknum == ATNR_FEAR)
1179 scare_creature (op, hitter);
1106 else if (attacknum == ATNR_CANCELLATION) cancellation(op); 1180 else if (attacknum == ATNR_CANCELLATION)
1181 cancellation (op);
1107 else if (attacknum == ATNR_DEPLETE) drain_stat(op); 1182 else if (attacknum == ATNR_DEPLETE)
1183 op->drain_stat ();
1108 else if (attacknum == ATNR_BLIND && !QUERY_FLAG(op,FLAG_UNDEAD) && 1184 else if (attacknum == ATNR_BLIND && !QUERY_FLAG (op, FLAG_UNDEAD) && !QUERY_FLAG (op, FLAG_GENERATOR))
1109 !QUERY_FLAG(op,FLAG_GENERATOR)) blind_player(op,hitter,dam); 1185 blind_player (op, hitter, dam);
1110 } 1186 }
1111 dam = 0; /* These are all effects and don't do real damage */ 1187 dam = 0; /* These are all effects and don't do real damage */
1112 } 1188 }
1113 break; 1189 break;
1190
1114 case ATNR_ACID: 1191 case ATNR_ACID:
1115 { 1192 {
1116 int flag=0; 1193 int flag = 0;
1117 1194
1118 /* Items only get corroded if you're not on a battleground and 1195 /* Items only get corroded if you're not on a battleground and
1119 * if your acid resistance is below 50%. */ 1196 * if your acid resistance is below 50%. */
1120 if (!op_on_battleground(op, NULL, NULL) && 1197 if (!op_on_battleground (op, NULL, NULL) && (op->resist[ATNR_ACID] < 50))
1121 (op->resist[ATNR_ACID] < 50))
1122 { 1198 {
1123 object *tmp;
1124 for(tmp=op->inv; tmp!=NULL; tmp=tmp->below) { 1199 for (object *tmp = op->inv; tmp; tmp = tmp->below)
1200 {
1125 if(tmp->invisible) 1201 if (tmp->invisible)
1126 continue; 1202 continue;
1127 if(!QUERY_FLAG(tmp, FLAG_APPLIED) || 1203 if (!QUERY_FLAG (tmp, FLAG_APPLIED) || (tmp->resist[ATNR_ACID] >= 10))
1128 (tmp->resist[ATNR_ACID] >= 10))
1129 /* >= 10% acid res. on itmes will protect these */ 1204 /* >= 10% acid res. on items will protect these */
1130 continue; 1205 continue;
1131 if(!(tmp->material & M_IRON)) 1206 if (!(tmp->material & M_IRON))
1132 continue; 1207 continue;
1133 if(tmp->magic < -4) /* Let's stop at -5 */ 1208 if (tmp->magic < -4) /* Let's stop at -5 */
1134 continue; 1209 continue;
1135 if(tmp->type==RING || 1210 if (tmp->type == RING
1136 /* removed boots and gloves from exclusion list in 1211 /* removed boots and gloves from exclusion list in PR */
1137 PR */
1138 tmp->type==GIRDLE || 1212 || tmp->type == GIRDLE
1139 tmp->type==AMULET || 1213 || tmp->type == AMULET
1140 tmp->type==WAND || 1214 || tmp->type == WAND
1141 tmp->type==ROD || 1215 || tmp->type == ROD
1142 tmp->type==HORN) 1216 || tmp->type == HORN)
1143 continue; /* To avoid some strange effects */ 1217 continue; /* To avoid some strange effects */
1144 1218
1145 /* High damage acid has better chance of corroding 1219 /* High damage acid has better chance of corroding
1146 objects */ 1220 objects */
1147 if(rndm(0, dam+4) >
1148 random_roll(0, 39, op, PREFER_HIGH)+2*tmp->magic) { 1221 if (rndm (0, dam + 4) > random_roll (0, 39, op, PREFER_HIGH) + 2 * tmp->magic)
1222 {
1149 if(op->type == PLAYER) 1223 if (op->type == PLAYER)
1150 /* Make this more visible */ 1224 /* Make this more visible */
1151 new_draw_info_format(NDI_UNIQUE|NDI_RED,0, op, 1225 new_draw_info_format (NDI_UNIQUE | NDI_RED, 0, op,
1152 "The %s's acid corrodes your %s!", 1226 "The %s's acid corrodes your %s!", query_name (hitter), query_name (tmp));
1153 query_name(hitter), query_name(tmp));
1154 flag = 1; 1227 flag = 1;
1155 tmp->magic--; 1228 tmp->magic--;
1156 if(op->type == PLAYER) 1229 if (op->type == PLAYER)
1157 esrv_send_item(op, tmp); 1230 esrv_send_item (op, tmp);
1231 }
1158 } 1232 }
1233
1234 if (flag)
1235 op->update_stats (); /* Something was corroded */
1159 } 1236 }
1160 if(flag)
1161 fix_player(op); /* Something was corroded */
1162 }
1163 } 1237 }
1164 break; 1238 break;
1239
1165 case ATNR_DRAIN: 1240 case ATNR_DRAIN:
1166 { 1241 {
1167 /* rate is the proportion of exp drained. High rate means 1242 /* rate is the proportion of exp drained. High rate means
1168 * not much is drained, low rate means a lot is drained. 1243 * not much is drained, low rate means a lot is drained.
1169 */ 1244 */
1170 int rate; 1245 int rate;
1171 1246
1172 if(op->resist[ATNR_DRAIN] >= 0) 1247 if (op->resist[ATNR_DRAIN] >= 0)
1173 rate = 400 + op->resist[ATNR_DRAIN] * 3; 1248 rate = 400 + op->resist[ATNR_DRAIN] * 3;
1174 else 1249 else
1175 rate = 400 * 100 / (100 - op->resist[ATNR_DRAIN]); 1250 rate = 400 * 100 / (100 - op->resist[ATNR_DRAIN]);
1176 1251
1177 if(op->stats.exp <= rate) { 1252 if (op->stats.exp <= rate)
1253 {
1178 if(op->type == GOLEM) 1254 if (op->type == GOLEM)
1179 dam = 999; /* Its force is "sucked" away. 8) */ 1255 dam = 999; /* Its force is "sucked" away. 8) */
1180 else 1256 else
1181 /* If we can't drain, lets try to do physical damage */ 1257 /* If we can't drain, lets try to do physical damage */
1182 dam = hit_player_attacktype(op, hitter, dam, ATNR_PHYSICAL, magic); 1258 dam = hit_player_attacktype (op, hitter, dam, ATNR_PHYSICAL, magic);
1259 }
1183 } else { 1260 else
1261 {
1184 /* Randomly give the hitter some hp */ 1262 /* Randomly give the hitter some hp */
1185 if(hitter->stats.hp<hitter->stats.maxhp && 1263 if (hitter->stats.hp < hitter->stats.maxhp &&
1186 (op->level > hitter->level) && 1264 (op->level > hitter->level) && random_roll (0, (op->level - hitter->level + 2), hitter, PREFER_HIGH) > 3)
1187 random_roll(0, (op->level-hitter->level+2), hitter, PREFER_HIGH)>3)
1188 hitter->stats.hp++; 1265 hitter->stats.hp++;
1189 1266
1190 /* Can't do drains on battleground spaces. 1267 /* Can't do drains on battleground spaces.
1191 * Move the wiz check up here - before, the hitter wouldn't gain exp 1268 * Move the wiz check up here - before, the hitter wouldn't gain exp
1192 * exp, but the wiz would still lose exp! If drainee is a wiz, 1269 * exp, but the wiz would still lose exp! If drainee is a wiz,
1193 * nothing happens. 1270 * nothing happens.
1194 * Try to credit the owner. We try to display player -> player drain 1271 * Try to credit the owner. We try to display player -> player drain
1195 * attacks, hence all the != PLAYER checks. 1272 * attacks, hence all the != PLAYER checks.
1196 */ 1273 */
1197 if (!op_on_battleground(hitter, NULL, NULL) && !QUERY_FLAG(op,FLAG_WAS_WIZ)) { 1274 if (!op_on_battleground (hitter, NULL, NULL) && !QUERY_FLAG (op, FLAG_WAS_WIZ))
1275 {
1198 object *owner = get_owner(hitter); 1276 object *owner = hitter->owner;
1199 1277
1200 if (owner && owner != hitter) { 1278 if (owner && owner != hitter)
1279 {
1201 if (op->type != PLAYER || owner->type != PLAYER) 1280 if (op->type != PLAYER || owner->type != PLAYER)
1202 change_exp(owner, op->stats.exp/(rate*2), 1281 change_exp (owner, op->stats.exp / (rate * 2),
1203 hitter->chosen_skill ? hitter->chosen_skill->skill : (const char *)0, SK_EXP_TOTAL); 1282 hitter->chosen_skill ? hitter->chosen_skill->skill : (const char *) 0, SK_EXP_TOTAL);
1283 }
1204 } else if (op->type != PLAYER || hitter->type != PLAYER) { 1284 else if (op->type != PLAYER || hitter->type != PLAYER)
1285 {
1205 change_exp(hitter, op->stats.exp/(rate*2), 1286 change_exp (hitter, op->stats.exp / (rate * 2),
1206 hitter->chosen_skill ? hitter->chosen_skill->skill : (const char*)0, 0); 1287 hitter->chosen_skill ? hitter->chosen_skill->skill : (const char *) 0, 0);
1288 }
1289 change_exp (op, -op->stats.exp / rate, NULL, 0);
1207 } 1290 }
1208 change_exp(op,-op->stats.exp/rate, NULL, 0); 1291
1209 }
1210 dam = 1; /* Drain is an effect. Still return 1 - otherwise, if you have pure 1292 dam = 1; /* Drain is an effect. Still return 1 - otherwise, if you have pure
1211 * drain attack, you won't know that you are actually sucking out EXP, 1293 * drain attack, you won't know that you are actually sucking out EXP,
1212 * as the messages will say you missed 1294 * as the messages will say you missed
1213 */ 1295 */
1214 } 1296 }
1215 } 1297 }
1216 break; 1298 break;
1299
1217 case ATNR_TURN_UNDEAD: 1300 case ATNR_TURN_UNDEAD:
1218 { 1301 {
1219 if (QUERY_FLAG(op,FLAG_UNDEAD)) { 1302 if (QUERY_FLAG (op, FLAG_UNDEAD))
1220 object *owner = get_owner(hitter) == NULL ? hitter : get_owner(hitter); 1303 {
1304 object *owner = hitter->owner ? (object *)hitter->owner : hitter;
1221 object *god = find_god (determine_god (owner)); 1305 object *god = find_god (determine_god (owner));
1222 int div = 1; 1306 int div = 1;
1223 1307
1224 /* if undead are not an enemy of your god, you turn them 1308 /* if undead are not an enemy of your god, you turn them
1225 * at half strength */ 1309 * at half strength */
1226 if (! god || ! god->slaying ||
1227 strstr (god->slaying, undead_name) == NULL) 1310 if (!god || !god->slaying || strstr (god->slaying, undead_name) == NULL)
1228 div = 2; 1311 div = 2;
1229 /* Give a bonus if you resist turn undead */ 1312 /* Give a bonus if you resist turn undead */
1230 if (op->level * div < 1313 if (op->level * div < (turn_bonus[owner->stats.Wis] + owner->level + (op->resist[ATNR_TURN_UNDEAD] / 100)))
1231 (turn_bonus[owner->stats.Wis]+owner->level +
1232 (op->resist[ATNR_TURN_UNDEAD]/100)))
1233 scare_creature(op, owner); 1314 scare_creature (op, owner);
1234 } 1315 }
1235 else 1316 else
1236 dam = 0; /* don't damage non undead - should we damage 1317 dam = 0; /* don't damage non undead - should we damage
1237 undead? */ 1318 undead? */
1238 } break; 1319 }
1239 case ATNR_DEATH:
1240 deathstrike_player(op, hitter, &dam);
1241 break; 1320 break;
1321
1322 case ATNR_DEATH:
1323 deathstrike_player (op, hitter, &dam);
1324 break;
1325
1242 case ATNR_CHAOS: 1326 case ATNR_CHAOS:
1243 LOG(llevError, 1327 LOG (llevError, "%s was hit by %s with non-specific chaos.\n", op->debug_desc (), hitter->debug_desc2 ());
1244 "%s was hit by %s with non-specific chaos.\n",
1245 query_name(op),
1246 query_name(hitter));
1247 dam = 0; 1328 dam = 0;
1248 break; 1329 break;
1330
1249 case ATNR_COUNTERSPELL: 1331 case ATNR_COUNTERSPELL:
1250 LOG(llevError, 1332 LOG (llevError, "%s was hit by %s with counterspell attack.\n", op->debug_desc (), hitter->debug_desc2 ());
1251 "%s was hit by %s with counterspell attack.\n",
1252 query_name(op),
1253 query_name(hitter));
1254 dam = 0; 1333 dam = 0;
1255 /* This should never happen. Counterspell is handled 1334 /* This should never happen. Counterspell is handled
1256 * seperately and filtered out. If this does happen, 1335 * seperately and filtered out. If this does happen,
1257 * Counterspell has no effect on anything but spells, so it 1336 * Counterspell has no effect on anything but spells, so it
1258 * does no damage. */ 1337 * does no damage. */
1259 break; 1338 break;
1339
1260 case ATNR_HOLYWORD: 1340 case ATNR_HOLYWORD:
1261 { 1341 {
1262 /* This has already been handled by hit_player, 1342 /* This has already been handled by hit_player,
1263 * no need to check twice -- DAMN */ 1343 * no need to check twice -- DAMN */
1264 1344 object *owner = hitter->owner ? (object *)hitter->owner : hitter;
1265 object *owner = get_owner(hitter)==NULL?hitter:get_owner(hitter); 1345
1266
1267 /* As with turn undead above, give a bonus on the saving throw */ 1346 /* As with turn undead above, give a bonus on the saving throw */
1268 if((op->level+(op->resist[ATNR_HOLYWORD]/100)) < 1347 if ((op->level + (op->resist[ATNR_HOLYWORD] / 100)) < owner->level + turn_bonus[owner->stats.Wis])
1269 owner->level+turn_bonus[owner->stats.Wis])
1270 scare_creature(op, owner); 1348 scare_creature (op, owner);
1349 }
1271 } break; 1350 break;
1351
1272 case ATNR_LIFE_STEALING: 1352 case ATNR_LIFE_STEALING:
1273 { 1353 {
1274 int new_hp; 1354 int new_hp;
1355
1275 /* this is replacement to drain for players, instead of taking 1356 /* this is replacement to drain for players, instead of taking
1276 * exp it takes hp. It is geared for players, probably not 1357 * exp it takes hp. It is geared for players, probably not
1277 * much use giving it to monsters 1358 * much use giving it to monsters
1278 * 1359 *
1279 * life stealing doesn't do a lot of damage, but it gives the 1360 * life stealing doesn't do a lot of damage, but it gives the
1280 * damage it does do to the player. Given that, 1361 * damage it does do to the player. Given that,
1281 * it only does 1/10'th normal damage (hence the divide by 1362 * it only does 1/10'th normal damage (hence the divide by
1282 * 1000). 1363 * 1000).
1283 */ 1364 */
1284 /* You can't steal life from something undead */ 1365 /* You can't steal life from something undead */
1285 if ((op->type == GOLEM) || (QUERY_FLAG(op, FLAG_UNDEAD))) return 0; 1366 if ((op->type == GOLEM) || (QUERY_FLAG (op, FLAG_UNDEAD)))
1367 return 0;
1368
1286 /* If drain protection is higher than life stealing, use that */ 1369 /* If drain protection is higher than life stealing, use that */
1287 if (op->resist[ATNR_DRAIN] >= op->resist[ATNR_LIFE_STEALING]) 1370 if (op->resist[ATNR_DRAIN] >= op->resist[ATNR_LIFE_STEALING])
1288 dam = (dam*(100 - op->resist[ATNR_DRAIN])) / 3000; 1371 dam = (dam * (100 - op->resist[ATNR_DRAIN])) / 3000;
1372 else
1289 else dam = (dam*(100 - op->resist[ATNR_LIFE_STEALING])) / 3000; 1373 dam = (dam * (100 - op->resist[ATNR_LIFE_STEALING])) / 3000;
1374
1290 /* You die at -1 hp, not zero. */ 1375 /* You die at -1 hp, not zero. */
1291 if (dam > (op->stats.hp+1)) dam = op->stats.hp+1; 1376 if (dam > (op->stats.hp + 1))
1377 dam = op->stats.hp + 1;
1378
1292 new_hp = hitter->stats.hp + dam; 1379 new_hp = hitter->stats.hp + dam;
1293 if (new_hp > hitter->stats.maxhp) new_hp = hitter->stats.maxhp; 1380 if (new_hp > hitter->stats.maxhp)
1294 if (new_hp > hitter->stats.hp) hitter->stats.hp = new_hp; 1381 new_hp = hitter->stats.maxhp;
1382
1383 if (new_hp > hitter->stats.hp)
1384 hitter->stats.hp = new_hp;
1295 } 1385 }
1296 } 1386 }
1387
1297 return dam; 1388 return dam;
1298} 1389}
1299
1300 1390
1301/* GROS: This code comes from hit_player. It has been made external to 1391/* GROS: This code comes from hit_player. It has been made external to
1302 * allow script procedures to "kill" objects in a combat-like fashion. 1392 * allow script procedures to "kill" objects in a combat-like fashion.
1303 * It was initially used by (kill-object) developed for the Collector's 1393 * It was initially used by (kill-object) developed for the Collector's
1304 * Sword. Note that nothing has been changed from the original version 1394 * Sword. Note that nothing has been changed from the original version
1311 * This function was a bit of a mess with hitter getting changed, 1401 * This function was a bit of a mess with hitter getting changed,
1312 * values being stored away but not used, etc. I've cleaned it up 1402 * values being stored away but not used, etc. I've cleaned it up
1313 * a bit - I think it should be functionally equivalant. 1403 * a bit - I think it should be functionally equivalant.
1314 * MSW 2002-07-17 1404 * MSW 2002-07-17
1315 */ 1405 */
1406int
1316int kill_object(object *op,int dam, object *hitter, int type) 1407kill_object (object *op, int dam, object *hitter, int type)
1317{ 1408{
1318 char buf[MAX_BUF]; 1409 char buf[MAX_BUF];
1319 const char *skill; 1410 const char *skill;
1320 int maxdam=0; 1411 int maxdam = 0;
1321 int battleg=0; /* true if op standing on battleground */ 1412 int battleg = 0; /* true if op standing on battleground */
1322 int pk=0; /* true if op and what controls hitter are both players*/ 1413 int pk = 0; /* true if op and what controls hitter are both players */
1323 object *owner=NULL; 1414 object *owner = NULL;
1324 object *skop=NULL; 1415 object *skop = NULL;
1325 1416
1326 if (op->stats.hp>=0) 1417 if (op->stats.hp >= 0)
1327 return -1; 1418 return -1;
1328 1419
1329 if (INVOKE_OBJECT (KILL, op, ARG_OBJECT (hitter))) 1420 if (INVOKE_OBJECT (KILL, op, ARG_OBJECT (hitter)))
1330 return 0; 1421 return 0;
1331 1422
1332 /* maxdam needs to be the amount of damage it took to kill 1423 /* maxdam needs to be the amount of damage it took to kill
1333 * this creature. The function(s) that call us have already 1424 * this creature. The function(s) that call us have already
1334 * adjusted the creatures HP total, so that is negative. 1425 * adjusted the creatures HP total, so that is negative.
1335 */ 1426 */
1336 maxdam = dam + op->stats.hp + 1; 1427 maxdam = dam + op->stats.hp + 1;
1337 1428
1338 if(QUERY_FLAG(op,FLAG_BLOCKSVIEW)) 1429 if (QUERY_FLAG (op, FLAG_BLOCKSVIEW))
1339 update_all_los(op->map,op->x, op->y); /* makes sure los will be recalculated */ 1430 update_all_los (op->map, op->x, op->y); /* makes sure los will be recalculated */
1340 1431
1341 if(op->type==DOOR) { 1432 if (op->type == DOOR)
1433 {
1342 op->speed = 0.1; 1434 op->set_speed (0.1);
1343 update_ob_speed(op);
1344 op->speed_left= -0.05; 1435 op->speed_left = -0.05;
1345 return maxdam; 1436 return maxdam;
1346 } 1437 }
1438
1347 if(QUERY_FLAG (op, FLAG_FRIENDLY) && op->type != PLAYER) { 1439 if (QUERY_FLAG (op, FLAG_FRIENDLY) && op->type != PLAYER)
1440 {
1348 remove_friendly_object(op); 1441 remove_friendly_object (op);
1349 if (get_owner (op) != NULL && op->owner->type == PLAYER && 1442
1350 op->owner->contr->ranges[range_golem] == op) { 1443 if (op->owner && op->owner->type == PLAYER && op->owner->contr->ranges[range_golem] == op)
1351 op->owner->contr->ranges[range_golem]=NULL; 1444 op->owner->contr->ranges[range_golem] = 0;
1352 op->owner->contr->golem_count=0;
1353 }
1354 1445
1355 remove_ob(op); 1446 op->destroy ();
1356 free_object(op);
1357 return maxdam; 1447 return maxdam;
1358 } 1448 }
1359 1449
1360 /* Now lets start dealing with experience we get for killing something */ 1450 /* Now lets start dealing with experience we get for killing something */
1361 1451
1362 owner=get_owner(hitter); 1452 owner = hitter->owner;
1363 if(owner==NULL) 1453 if (!owner)
1364 owner=hitter; 1454 owner = hitter;
1365 1455
1366 /* is the victim (op) standing on battleground? */ 1456 /* is the victim (op) standing on battleground? */
1367 if (op_on_battleground(op, NULL, NULL)) battleg=1; 1457 if (op_on_battleground (op, NULL, NULL))
1368 1458 battleg = 1;
1459
1369 /* is this player killing?*/ 1460 /* is this player killing? */
1370 if (op->type == PLAYER && owner->type == PLAYER) pk=1; 1461 if (op->type == PLAYER && owner->type == PLAYER)
1462 pk = 1;
1371 1463
1372 /* Player killed something */ 1464 /* Player killed something */
1373 if(owner->type==PLAYER) { 1465 if (owner->type == PLAYER)
1466 {
1374 Log_Kill(owner->name, 1467 Log_Kill (owner->name,
1375 query_name(op),op->type, 1468 query_name (op), op->type, (owner != hitter) ? query_name (hitter) : NULL, (owner != hitter) ? hitter->type : 0);
1376 (owner!=hitter) ? query_name(hitter) : NULL,
1377 (owner!=hitter) ? hitter->type : 0);
1378 1469
1379 /* Log players killing other players - makes it easier to detect 1470 /* Log players killing other players - makes it easier to detect
1380 * and filter out malicious player killers - that is why the 1471 * and filter out malicious player killers - that is why the
1381 * ip address is included. 1472 * ip address is included.
1382 */ 1473 */
1383 if (op->type == PLAYER && !battleg) { 1474 if (op->type == PLAYER && !battleg)
1475 {
1384 time_t t=time(NULL); 1476 time_t t = time (NULL);
1385 struct tm *tmv; 1477 struct tm *tmv;
1386 char buf[256]; 1478 char buf[256];
1387 1479
1388 tmv = localtime(&t); 1480 tmv = localtime (&t);
1389 strftime(buf, 256,"%a %b %d %H:%M:%S %Y", tmv); 1481 strftime (buf, 256, "%a %b %d %H:%M:%S %Y", tmv);
1390 1482
1391 LOG(llevInfo,"%s PLAYER_KILL_PLAYER: %s (%s) killed %s\n", 1483 LOG (llevInfo, "%s PLAYER_KILL_PLAYER: %s (%s) killed %s\n", buf, &owner->name, owner->contr->ns->host, query_name (op));
1392 buf, &owner->name, owner->contr->socket.host, query_name(op));
1393 } 1484 }
1394 1485
1395 /* try to filter some things out - basically, if you are 1486 /* try to filter some things out - basically, if you are
1396 * killing a level 1 creature and your level 20, you 1487 * killing a level 1 creature and your level 20, you
1397 * probably don't want to see that. 1488 * probably don't want to see that.
1398 */ 1489 */
1399 if ( owner->level < op->level * 2|| op->stats.exp>1000) { 1490 if (owner->level < op->level * 2 || op->stats.exp > 1000)
1491 {
1400 if(owner!=hitter) { 1492 if (owner != hitter)
1401 new_draw_info_format(NDI_BLACK, 0, owner, 1493 new_draw_info_format (NDI_BLACK, 0, owner, "You killed %s with %s.", query_name (op), query_name (hitter));
1402 "You killed %s with %s.",query_name(op), 1494 else
1403 query_name(hitter)); 1495 new_draw_info_format (NDI_BLACK, 0, owner, "You killed %s.", query_name (op));
1496
1497 /* Only play sounds for melee kills */
1498 if (hitter->type == PLAYER)
1499 play_sound_map (owner->map, owner->x, owner->y, SOUND_PLAYER_KILLS);
1500 }
1501
1502 /* If a player kills another player, not on
1503 * battleground, the "killer" looses 1 luck. Since this is
1504 * not reversible, it's actually quite a pain IMHO. -AV
1505 * Fix bug in that we were changing the luck of the hitter, not
1506 * player that the object belonged to - so if you killed another player
1507 * with spells, pets, whatever, there was no penalty.
1508 * Changed to make luck penalty configurable in settings.
1509 */
1510 if (op->type == PLAYER && owner != op && !battleg)
1511 owner->change_luck (-settings.pk_luck_penalty);
1512
1513 /* This code below deals with finding the appropriate skill
1514 * to credit exp to. This is a bit problematic - we should
1515 * probably never really have to look at current_weapon->skill
1516 */
1517 skill = 0;
1518
1519 if (hitter->skill && hitter->type != PLAYER)
1520 skill = hitter->skill;
1521 else if (owner->chosen_skill)
1522 {
1523 skill = owner->chosen_skill->skill;
1524 skop = owner->chosen_skill;
1525 }
1526 else if (QUERY_FLAG (owner, FLAG_READY_WEAPON))
1527 skill = owner->current_weapon->skill;
1528 else
1529 LOG (llevError, "kill_object - unable to find skill that killed monster\n");
1530
1531 /* We have the skill we want to credit to - now find the object this goes
1532 * to. Make sure skop is an actual skill, and not a skill tool!
1533 */
1534 if ((!skop || skop->type != SKILL) && skill)
1535 {
1536 int i;
1537
1538 for (i = 0; i < NUM_SKILLS; i++)
1539 if (owner->contr->last_skill_ob[i] && !strcmp (owner->contr->last_skill_ob[i]->skill, skill))
1540 {
1541 skop = owner->contr->last_skill_ob[i];
1542 break;
1543 }
1544 }
1545 } /* Was it a player that hit somethign */
1546 else
1547 skill = 0;
1548
1549 /* Pet (or spell) killed something. */
1550 if (owner != hitter)
1551 sprintf (buf, "%s killed %s with %s%s%s.", &owner->name,
1552 query_name (op), query_name (hitter), battleg ? " (duel)" : "", pk ? " (pk)" : "");
1553 else
1554 sprintf (buf, "%s killed %s%s%s%s.", &hitter->name, &op->name,
1555 (QUERY_FLAG (hitter, FLAG_MONSTER)) || hitter->type == PLAYER ?
1556 " in hand to hand combat" : "", battleg ? " (duel)" : "", pk ? " (pk)" : "");
1557
1558 /* These may have been set in the player code section above */
1559 if (!skop)
1560 skop = hitter->chosen_skill;
1561
1562 if (!skill && skop)
1563 skill = skop->skill;
1564
1565 new_draw_info (NDI_ALL, op->type == PLAYER ? 1 : 10, NULL, buf);
1566
1567 /* If you didn't kill yourself, and your not the wizard */
1568 if (owner != op && !QUERY_FLAG (op, FLAG_WAS_WIZ))
1569 {
1570 int exp;
1571
1572 /* Really don't give much experience for killing other players */
1573 // schmorp: temporarily? reduce the amount of exp gained for pking enourmously
1574 if (op->type == PLAYER)
1575 {
1576 if (battleg)
1577 {
1578 new_draw_info (NDI_UNIQUE, 0, owner, "Your foe has fallen!");
1579 new_draw_info (NDI_UNIQUE, 0, owner, "VICTORY!!!");
1404 } 1580 }
1405 else { 1581 else
1406 new_draw_info_format(NDI_BLACK, 0, owner, 1582 exp = op->stats.exp / 1000;
1407 "You killed %s.",query_name(op)); 1583 }
1584 else
1585 exp = calc_skill_exp (owner, op, skop);
1586
1587 /* if op is standing on "battleground" (arena), no way to gain
1588 * exp by killing him
1589 */
1590 if (battleg)
1591 exp = 0;
1592
1593 /* Don't know why this is set this way - doesn't make
1594 * sense to just divide everything by two for no reason.
1595 */
1596
1597 if (!settings.simple_exp)
1598 exp = exp / 2;
1599
1600 if (owner->type != PLAYER || owner->contr->party == NULL)
1601 change_exp (owner, exp, skill, 0);
1602 else
1603 {
1604 int shares = 0, count = 0;
1605 player *pl;
1606 partylist *party = owner->contr->party;
1607
1608 add_kill_to_party (party, query_name (owner), query_name (op), exp);
1609
1610 for_all_players (pl)
1611 if (party && pl->ob->contr->party == party && on_same_map (pl->ob, owner))
1612 {
1613 count++;
1614 shares += (pl->ob->level + 4);
1615 }
1616
1617 if (count == 1 || shares > exp || !shares)
1618 change_exp (owner, exp, skill, SK_EXP_TOTAL);
1619 else
1620 {
1621 int share = exp / shares, given = 0, nexp;
1622
1623 for_all_players (pl)
1624 if (party && pl->ob->contr->party == party && on_same_map (pl->ob, owner))
1625 {
1626 nexp = (pl->ob->level + 4) * share;
1627 change_exp (pl->ob, nexp, skill, SK_EXP_TOTAL);
1628 given += nexp;
1629 }
1630
1631 exp -= given;
1632 /* give any remainder to the player */
1633 change_exp (owner, exp, skill, SK_EXP_ADD_SKILL);
1408 } 1634 }
1409 /* Only play sounds for melee kills */ 1635 } /* else part of a party */
1410 if (hitter->type == PLAYER) 1636 } /* end if person didn't kill himself */
1411 play_sound_map(owner->map, owner->x, owner->y, SOUND_PLAYER_KILLS); 1637
1638 if (op->type != PLAYER)
1639 {
1640 if (QUERY_FLAG (op, FLAG_FRIENDLY))
1412 } 1641 {
1642 object *owner1 = op->owner;
1413 1643
1414 /* If a player kills another player, not on 1644 if (owner1 && owner1->type == PLAYER)
1415 * battleground, the "killer" looses 1 luck. Since this is
1416 * not reversible, it's actually quite a pain IMHO. -AV
1417 * Fix bug in that we were changing the luck of the hitter, not
1418 * player that the object belonged to - so if you killed another player
1419 * with spells, pets, whatever, there was no penalty.
1420 * Changed to make luck penalty configurable in settings.
1421 */
1422 if(op->type == PLAYER && owner != op && !battleg)
1423 change_luck(owner, -settings.pk_luck_penalty);
1424
1425 /* This code below deals with finding the appropriate skill
1426 * to credit exp to. This is a bit problematic - we should
1427 * probably never really have to look at current_weapon->skill
1428 */
1429 skill = NULL;
1430 if (hitter->skill && hitter->type!=PLAYER) skill = hitter->skill;
1431 else if (owner->chosen_skill) {
1432 skill = owner->chosen_skill->skill;
1433 skop = owner->chosen_skill;
1434 }
1435 else if (QUERY_FLAG(owner, FLAG_READY_WEAPON)) skill=owner->current_weapon->skill;
1436 else
1437 LOG(llevError,"kill_object - unable to find skill that killed monster\n");
1438
1439 /* We have the skill we want to credit to - now find the object this goes
1440 * to. Make sure skop is an actual skill, and not a skill tool!
1441 */
1442 if ((!skop || skop->type != SKILL) && skill) {
1443 int i;
1444
1445 for (i=0; i<NUM_SKILLS; i++)
1446 if (owner->contr->last_skill_ob[i] &&
1447 !strcmp(owner->contr->last_skill_ob[i]->skill, skill)) {
1448 skop = owner->contr->last_skill_ob[i];
1449 break;
1450 } 1645 {
1451 } 1646 play_sound_player_only (owner1->contr, SOUND_PET_IS_KILLED, 0, 0);
1452 } /* Was it a player that hit somethign */ 1647 /* Maybe we should include the owner that killed this, maybe not */
1453 else { 1648 new_draw_info_format (NDI_UNIQUE, 0, owner1, "Your pet, the %s, is killed by %s.", &op->name, &hitter->name);
1454 skill = NULL;
1455 }
1456
1457 /* Pet (or spell) killed something. */
1458 if(owner != hitter ) {
1459 (void) sprintf(buf,"%s killed %s with %s%s%s.",&owner->name,
1460 query_name(op),query_name(hitter), battleg? " (duel)":"", pk? " (pk)":"");
1461 }
1462 else {
1463 (void) sprintf(buf,"%s killed %s%s%s%s.",&hitter->name,&op->name,
1464 (QUERY_FLAG(hitter, FLAG_MONSTER)) || hitter->type == PLAYER ?
1465 " in hand to hand combat":"", battleg? " (duel)":"", pk? " (pk)":"");
1466 }
1467 /* These may have been set in the player code section above */
1468 if (!skop) skop = hitter->chosen_skill;
1469 if (!skill && skop) skill=skop->skill;
1470
1471 new_draw_info(NDI_ALL, op->type==PLAYER?1:10, NULL, buf);
1472
1473
1474 /* If you didn't kill yourself, and your not the wizard */
1475 if(owner!=op && !QUERY_FLAG(op, FLAG_WAS_WIZ)) {
1476 int exp;
1477
1478 /* Really don't give much experience for killing other players */
1479 // schmorp: temporary? reduce the amount of exp gained for pking enourmously
1480 if (op->type==PLAYER) {
1481 if (battleg) {
1482 new_draw_info(NDI_UNIQUE, 0,owner, "Your foe has fallen!");
1483 new_draw_info(NDI_UNIQUE, 0,owner, "VICTORY!!!");
1484 } 1649 }
1485 else
1486 exp = op->stats.exp / 1000;
1487 }
1488 else
1489 exp = calc_skill_exp(owner, op, skop);
1490 1650
1491 /* if op is standing on "battleground" (arena), no way to gain
1492 * exp by killing him
1493 */
1494 if (battleg) exp = 0;
1495
1496 /* Don't know why this is set this way - doesn't make
1497 * sense to just divide everything by two for no reason.
1498 */
1499
1500 if (!settings.simple_exp)
1501 exp=exp/2;
1502
1503 if(owner->type!=PLAYER || owner->contr->party==NULL) {
1504 change_exp(owner,exp, skill, 0);
1505 }
1506 else {
1507 int shares=0,count=0;
1508
1509 player *pl;
1510
1511 partylist *party=owner->contr->party;
1512#ifdef PARTY_KILL_LOG
1513 add_kill_to_party(party, query_name(owner), query_name(op), exp);
1514#endif
1515 for(pl=first_player;pl!=NULL;pl=pl->next) {
1516 if(party && pl->ob->contr->party==party && on_same_map(pl->ob, owner)) {
1517 count++;
1518 shares+=(pl->ob->level+4);
1519 }
1520 }
1521 if(count==1 || shares>exp)
1522 change_exp(owner,exp, skill, SK_EXP_TOTAL);
1523 else {
1524 int share=exp/shares,given=0,nexp;
1525 for(pl=first_player;pl!=NULL;pl=pl->next) {
1526 if(party && pl->ob->contr->party==party && on_same_map(pl->ob, owner)) {
1527 nexp=(pl->ob->level+4)*share;
1528 change_exp(pl->ob,nexp, skill, SK_EXP_TOTAL);
1529 given+=nexp;
1530 }
1531 }
1532 exp-=given;
1533 /* give any remainder to the player */
1534 change_exp(owner,exp, skill, SK_EXP_ADD_SKILL);
1535 }
1536 } /* else part of a party */
1537
1538 } /* end if person didn't kill himself */
1539
1540 if(op->type!=PLAYER) {
1541 if(QUERY_FLAG(op,FLAG_FRIENDLY)) {
1542 object *owner1 = get_owner(op);
1543
1544 if(owner1!= NULL && owner1->type == PLAYER) {
1545 play_sound_player_only(owner1->contr, SOUND_PET_IS_KILLED,0,0);
1546 /* Maybe we should include the owner that killed this, maybe not */
1547 new_draw_info_format(NDI_UNIQUE, 0,owner1,"Your pet, the %s, is killed by %s.",
1548 &op->name,&hitter->name);
1549 }
1550 remove_friendly_object(op); 1651 remove_friendly_object (op);
1551 } 1652 }
1552 remove_ob(op); 1653
1553 free_object(op); 1654 op->destroy ();
1655 }
1656 else
1554 } 1657 {
1555 /* Player has been killed! */ 1658 /* Player has been killed! */
1556 else {
1557 if(owner->type==PLAYER) { 1659 if (owner->type == PLAYER)
1558 snprintf(op->contr->killer, BIG_NAME, "%s the %s", &owner->name, owner->contr->title); 1660 snprintf (op->contr->killer, sizeof (op->contr->killer), "%s the %s", &owner->name, owner->contr->title);
1559 }
1560 else { 1661 else
1561 strncpy(op->contr->killer,hitter->name,BIG_NAME); 1662 assign (op->contr->killer, hitter->name);
1562 op->contr->killer[BIG_NAME-1]='\0';
1563 }
1564 } 1663 }
1664
1565 /* This was return -1 - that doesn't seem correct - if we return -1, process 1665 /* This was return -1 - that doesn't seem correct - if we return -1, process
1566 * continues in the calling function. 1666 * continues in the calling function.
1567 */ 1667 */
1568 return maxdam; 1668 return maxdam;
1569} 1669}
1570 1670
1571/* Find out if this is friendly fire (PVP and attacker is peaceful) or not 1671/* Find out if this is friendly fire (PVP and attacker is peaceful) or not
1572 * Returns 0 this is not friendly fire 1672 * Returns 0 this is not friendly fire
1573 */ 1673 */
1574 1674
1675int
1575int friendly_fire(object *op, object *hitter){ 1676friendly_fire (object *op, object *hitter)
1677{
1576 object *owner; 1678 object *owner;
1577 int friendlyfire; 1679 int friendlyfire;
1578
1579 if (hitter->head) hitter=hitter->head;
1580 1680
1681 if (hitter->head)
1682 hitter = hitter->head;
1683
1581 friendlyfire = 0; 1684 friendlyfire = 0;
1582 1685
1583 if(op->type == PLAYER) { 1686 if (op->type == PLAYER)
1687 {
1584 if (op_on_battleground (hitter, 0, 0)) 1688 if (op_on_battleground (hitter, 0, 0))
1585 return 0; 1689 return 0;
1586 1690
1587 if(hitter->type == PLAYER && hitter->contr->peaceful == 1) 1691 if (hitter->type == PLAYER && hitter->contr->peaceful == 1)
1588 return 1; 1692 return 1;
1589 1693
1590 if((owner = get_owner(hitter))!=NULL) { 1694 if ((owner = hitter->owner) != NULL)
1695 {
1591 if(owner->type == PLAYER && owner->contr->peaceful == 1) 1696 if (owner->type == PLAYER && owner->contr->peaceful == 1)
1592 friendlyfire = 2; 1697 friendlyfire = 2;
1593 } 1698 }
1594 1699
1595 if (hitter->type == SPELL || hitter->type == POISONING || 1700 if (hitter->type == SPELL || hitter->type == POISONING || hitter->type == DISEASE || hitter->type == RUNE)
1596 hitter->type == DISEASE || hitter->type == RUNE)
1597 friendlyfire = 0; 1701 friendlyfire = 0;
1598 } 1702 }
1599 return friendlyfire; 1703 return friendlyfire;
1600} 1704}
1601 1705
1602 1706
1603/* This isn't used just for players, but in fact most objects. 1707/* This isn't used just for players, but in fact most objects.
1604 * op is the object to be hit, dam is the amount of damage, hitter 1708 * op is the object to be hit, dam is the amount of damage, hitter
1605 * is what is hitting the object, type is the attacktype, and 1709 * is what is hitting the object, type is the attacktype, and
1606 * full_hit is set if monster area does not matter. 1710 * full_hit is set if monster area does not matter.
1607 * dam is base damage - protections/vulnerabilities/slaying matches can 1711 * dam is base damage - protections/vulnerabilities/slaying matches can
1608 * modify it. 1712 * modify it.
1609 */ 1713 */
1610
1611 /* Oct 95 - altered the following slightly for MULTIPLE_GODS hack 1714/* Oct 95 - altered the following slightly for MULTIPLE_GODS hack
1612 * which needs new attacktype AT_HOLYWORD to work . b.t. */ 1715 * which needs new attacktype AT_HOLYWORD to work . b.t. */
1613 1716int
1614int hit_player(object *op,int dam, object *hitter, int type, int full_hit) { 1717hit_player (object *op, int dam, object *hitter, int type, int full_hit)
1718{
1615 int maxdam=0, ndam=0, attacktype=1, magic=(type & AT_MAGIC); 1719 int maxdam = 0, ndam = 0, attacktype = 1, magic = (type & AT_MAGIC);
1616 int maxattacktype, attacknum; 1720 int maxattacktype, attacknum;
1617 int body_attack = op && op->head; /* Did we hit op's head? */ 1721 int body_attack = op && op->head; /* Did we hit op's head? */
1618 int simple_attack; 1722 int simple_attack;
1619 tag_t op_tag, hitter_tag;
1620 int rtn_kill = 0; 1723 int rtn_kill = 0;
1621 int friendlyfire; 1724 int friendlyfire;
1622 1725
1623 if (get_attack_mode (&op, &hitter, &simple_attack)) 1726 if (get_attack_mode (&op, &hitter, &simple_attack))
1727 return 0;
1728
1729 /* very simple: if our target has no_damage 1 set or is wiz, we can't hurt him */
1730 if (QUERY_FLAG (op, FLAG_WIZ) || QUERY_FLAG (op, FLAG_NO_DAMAGE))
1731 return 0;
1732
1733#ifdef PROHIBIT_PLAYERKILL
1734 if (op->type == PLAYER)
1735 {
1736 object *owner = hitter->owner;
1737
1738 if (!owner)
1739 owner = hitter;
1740
1741 if (owner->type == PLAYER && (!op_on_battleground (op, 0, 0) && (op->contr->peaceful || owner->contr->peaceful)) && op != owner)
1624 return 0; 1742 return 0;
1743 }
1744#endif
1625 1745
1626 /* very simple: if our target has no_damage 1 set or is wiz, we can't hurt him */ 1746 if (body_attack)
1627 if (QUERY_FLAG (op, FLAG_WIZ) || QUERY_FLAG (op, FLAG_NO_DAMAGE)) 1747 {
1748 /* slow and paralyze must hit the head. But we don't want to just
1749 * return - we still need to process other attacks the spell still
1750 * might have. So just remove the paralyze and slow attacktypes,
1751 * and keep on processing if we have other attacktypes.
1752 * return if only magic or nothing is left - under normal code
1753 * we don't attack with pure magic if there is another attacktype.
1754 * Only do processing if the initial attacktype includes one of those
1755 * attack so we don't cancel out things like magic bullet.
1756 */
1757 if (type & (AT_PARALYZE | AT_SLOW))
1758 {
1759 type &= ~(AT_PARALYZE | AT_SLOW);
1760
1761 if (!type || type == AT_MAGIC)
1628 return 0; 1762 return 0;
1763 }
1764 }
1629 1765
1630#ifdef PROHIBIT_PLAYERKILL 1766 if (!simple_attack && op->type == DOOR)
1631 if (op->type == PLAYER) { 1767 {
1632 object *owner = get_owner (hitter); 1768 for (object *tmp = op->inv; tmp; tmp = tmp->below)
1633 if (!owner) owner = hitter; 1769 if (tmp->type == RUNE || tmp->type == TRAP)
1634 if (owner->type == PLAYER 1770 {
1635 && (!op_on_battleground (op, 0, 0) && (op->contr->peaceful || owner->contr->peaceful)) 1771 spring_trap (tmp, hitter);
1636 && op != owner) { 1772
1773 if (hitter->destroyed () || op->destroyed () || abort_attack (op, hitter, simple_attack))
1637 return 0; 1774 return 0;
1775
1776 break;
1638 } 1777 }
1778 }
1779
1780 if (!QUERY_FLAG (op, FLAG_ALIVE) || op->stats.hp < 0)
1639 } 1781 {
1782 /* FIXME: If a player is killed by a rune in a door, the
1783 * destroyed() check above doesn't return, and might get here.
1784 */
1785 LOG (llevDebug, "victim %s already dead in hit_player()\n", op->debug_desc ());
1786 return 0;
1787 }
1788
1789#ifdef ATTACK_DEBUG
1790 LOG (llevDebug, "hit player: attacktype %d, dam %d\n", type, dam);
1640#endif 1791#endif
1641 1792
1642 op_tag = op->count;
1643 hitter_tag = hitter->count;
1644
1645 if (body_attack) {
1646 /* slow and paralyze must hit the head. But we don't want to just
1647 * return - we still need to process other attacks the spell still
1648 * might have. So just remove the paralyze and slow attacktypes,
1649 * and keep on processing if we have other attacktypes.
1650 * return if only magic or nothing is left - under normal code
1651 * we don't attack with pure magic if there is another attacktype.
1652 * Only do processing if the initial attacktype includes one of those
1653 * attack so we don't cancel out things like magic bullet.
1654 */
1655 if (type & (AT_PARALYZE | AT_SLOW)) {
1656 type &= ~(AT_PARALYZE | AT_SLOW);
1657 if (!type || type==AT_MAGIC) return 0;
1658 }
1659 }
1660
1661 if ( ! simple_attack && op->type == DOOR) {
1662 object *tmp;
1663 for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
1664 if (tmp->type == RUNE || tmp->type == TRAP) {
1665 spring_trap (tmp, hitter);
1666 if (was_destroyed (hitter, hitter_tag)
1667 || was_destroyed (op, op_tag)
1668 || abort_attack (op, hitter, simple_attack))
1669 return 0;
1670 break;
1671 }
1672 }
1673
1674 if ( ! QUERY_FLAG (op, FLAG_ALIVE) || op->stats.hp < 0) {
1675 /* FIXME: If a player is killed by a rune in a door, the
1676 * was_destroyed() check above doesn't return, and might get here.
1677 */
1678 LOG (llevDebug, "victim (arch %s, name %s) already dead in "
1679 "hit_player()\n", &op->arch->name, &op->name);
1680 return 0;
1681 }
1682
1683#ifdef ATTACK_DEBUG
1684 LOG(llevDebug,"hit player: attacktype %d, dam %d\n", type, dam);
1685#endif
1686
1687 if (magic) { 1793 if (magic)
1794 {
1688 /* basically: dam = dam*(100-op->resist[attacknum])/100; 1795 /* basically: dam = dam*(100-op->resist[attacknum])/100;
1689 * in case 0>dam>1, we try to "simulate" a float value-effect */ 1796 * in case 0>dam>1, we try to "simulate" a float value-effect */
1690 dam = dam*(100-op->resist[ATNR_MAGIC]); 1797 dam = dam * (100 - op->resist[ATNR_MAGIC]);
1691 if (dam >= 100) 1798 if (dam >= 100)
1692 dam /= 100; 1799 dam /= 100;
1693 else 1800 else
1694 dam = (dam > (rndm(0, 99))) ? 1 : 0; 1801 dam = (dam > (rndm (0, 99))) ? 1 : 0;
1695 } 1802 }
1696 1803
1697 /* AT_CHAOS here is a weapon or monster. Spells are handled by hit_map 1804 /* AT_CHAOS here is a weapon or monster. Spells are handled by hit_map
1698 * If the attacktype still has chaos, shuffle it, then clear the Chaos bit 1805 * If the attacktype still has chaos, shuffle it, then clear the Chaos bit
1699 */ 1806 */
1700 if(type & AT_CHAOS){ 1807 if (type & AT_CHAOS)
1808 {
1701 shuffle_attack(op,0); /*0 flag tells it to not change the face */ 1809 shuffle_attack (op, 0); /*0 flag tells it to not change the face */
1702 update_object(op,UP_OBJ_FACE); 1810 update_object (op, UP_OBJ_FACE);
1703 type &= ~AT_CHAOS; 1811 type &= ~AT_CHAOS;
1704 } 1812 }
1705 1813
1706 /* Holyword is really an attacktype modifier (like magic is). If 1814 /* Holyword is really an attacktype modifier (like magic is). If
1707 * holyword is part of an attacktype, then make sure the creature is 1815 * holyword is part of an attacktype, then make sure the creature is
1708 * a proper match, otherwise no damage. 1816 * a proper match, otherwise no damage.
1709 */ 1817 */
1710 if (type & AT_HOLYWORD) { 1818 if (type & AT_HOLYWORD)
1819 {
1711 object *god; 1820 object *god;
1821
1712 if ((!hitter->slaying || 1822 if ((!hitter->slaying ||
1713 (!(op->race && strstr(hitter->slaying,op->race)) && 1823 (!(op->race && strstr (hitter->slaying, op->race)) &&
1714 !(op->name && strstr(hitter->slaying,op->name)))) && 1824 !(op->name && strstr (hitter->slaying, op->name)))) &&
1715 (!QUERY_FLAG(op,FLAG_UNDEAD) || 1825 (!QUERY_FLAG (op, FLAG_UNDEAD) ||
1716 (hitter->title != NULL 1826 (hitter->title != NULL
1717 && (god = find_god(determine_god(hitter))) != NULL 1827 && (god = find_god (determine_god (hitter))) != NULL && god->race != NULL && strstr (god->race, undead_name) != NULL)))
1718 && god->race != NULL
1719 && strstr(god->race,undead_name) != NULL)))
1720 return 0; 1828 return 0;
1721 } 1829 }
1722 1830
1723 maxattacktype = type; /* initialize this to something */ 1831 maxattacktype = type; /* initialise this to something */
1724 for (attacknum=0; attacknum<NROFATTACKS; attacknum++, attacktype=1<<attacknum) { 1832 for (attacknum = 0; attacknum < NROFATTACKS; attacknum++, attacktype = 1 << attacknum)
1833 {
1725 /* Magic isn't really a true attack type - it gets combined with other 1834 /* Magic isn't really a true attack type - it gets combined with other
1726 * attack types. As such, skip it over. However, if magic is 1835 * attack types. As such, skip it over. However, if magic is
1727 * the only attacktype in the group, then still attack with it 1836 * the only attacktype in the group, then still attack with it
1728 */ 1837 */
1729 if ((attacktype==AT_MAGIC) && (type & ~AT_MAGIC)) continue; 1838 if ((attacktype == AT_MAGIC) && (type & ~AT_MAGIC))
1839 continue;
1730 1840
1731 /* Go through and hit the player with each attacktype, one by one. 1841 /* Go through and hit the player with each attacktype, one by one.
1732 * hit_player_attacktype only figures out the damage, doesn't inflict 1842 * hit_player_attacktype only figures out the damage, doesn't inflict
1733 * it. It will do the appropriate action for attacktypes with 1843 * it. It will do the appropriate action for attacktypes with
1734 * effects (slow, paralization, etc. 1844 * effects (slow, paralization, etc.
1735 */ 1845 */
1736 if (type & attacktype) { 1846 if (type & attacktype)
1847 {
1737 ndam=hit_player_attacktype(op,hitter,dam,attacknum,magic); 1848 ndam = hit_player_attacktype (op, hitter, dam, attacknum, magic);
1738 /* the >= causes us to prefer messages from special attacks, if 1849 /* the >= causes us to prefer messages from special attacks, if
1739 * the damage is equal. 1850 * the damage is equal.
1740 */ 1851 */
1741 if (ndam >= maxdam) { 1852 if (ndam >= maxdam)
1853 {
1742 maxdam = ndam; 1854 maxdam = ndam;
1743 maxattacktype = 1<<attacknum; 1855 maxattacktype = 1 << attacknum;
1744 } 1856 }
1745 } 1857 }
1746 } 1858 }
1747 1859
1748 /* if this is friendly fire then do a set % of damage only 1860 /* if this is friendly fire then do a set % of damage only
1749 * Note - put a check in to make sure this attack is actually 1861 * Note - put a check in to make sure this attack is actually
1750 * doing damage - otherwise, the +1 in the code below will make 1862 * doing damage - otherwise, the +1 in the code below will make
1751 * an attack do damage before when it otherwise didn't 1863 * an attack do damage before when it otherwise didn't
1752 */ 1864 */
1753 friendlyfire = friendly_fire(op, hitter); 1865 friendlyfire = friendly_fire (op, hitter);
1754 if (friendlyfire && maxdam){ 1866 if (friendlyfire && maxdam)
1867 {
1755 maxdam = ((dam * settings.set_friendly_fire) / 100); 1868 maxdam = ((dam * settings.set_friendly_fire) / 100);
1756#ifndef COZY_SERVER 1869#ifndef COZY_SERVER
1870 maxdam++;
1871#endif
1872
1873#ifdef ATTACK_DEBUG
1874 LOG (llevDebug, "Friendly fire (type:%d setting: %d%) did %d damage dropped to %d\n",
1875 friendlyfire, settings.set_friendly_fire, dam, maxdam);
1876#endif
1877 }
1878
1879 if (!full_hit)
1880 {
1881 archetype *at;
1882 int area;
1883 int remainder;
1884
1885 area = 0;
1886 for (at = op->arch; at != NULL; at = at->more)
1887 area++;
1888 assert (area > 0);
1889
1890 /* basically: maxdam /= area; we try to "simulate" a float
1891 value-effect */
1892 remainder = 100 * (maxdam % area) / area;
1893 maxdam /= area;
1894 if (RANDOM () % 100 < remainder)
1757 maxdam++; 1895 maxdam++;
1896 }
1897
1898#ifdef ATTACK_DEBUG
1899 LOG (llevDebug, "Attacktype %d did %d damage\n", type, maxdam);
1758#endif 1900#endif
1759
1760#ifdef ATTACK_DEBUG
1761 LOG(llevDebug,"Friendly fire (type:%d setting: %d%) did %d damage dropped to %d\n",
1762 friendlyfire, settings.set_friendly_fire, dam, maxdam);
1763#endif
1764 }
1765 1901
1766 if (!full_hit) { 1902 if (hitter->owner)
1767 archetype *at;
1768 int area;
1769 int remainder;
1770
1771 area = 0;
1772 for(at = op->arch; at != NULL; at = at->more)
1773 area++;
1774 assert(area > 0);
1775
1776 /* basically: maxdam /= area; we try to "simulate" a float
1777 value-effect */
1778 remainder = 100*(maxdam%area)/area;
1779 maxdam /= area;
1780 if (RANDOM()%100 < remainder)
1781 maxdam++;
1782 }
1783
1784#ifdef ATTACK_DEBUG
1785 LOG(llevDebug,"Attacktype %d did %d damage\n", type, maxdam);
1786#endif
1787
1788 if(get_owner(hitter))
1789 op->enemy=hitter->owner; 1903 op->enemy = hitter->owner;
1790 else if (QUERY_FLAG(hitter,FLAG_ALIVE)) 1904 else if (QUERY_FLAG (hitter, FLAG_ALIVE))
1791 op->enemy=hitter; 1905 op->enemy = hitter;
1792 1906
1793 if(QUERY_FLAG(op,FLAG_UNAGGRESSIVE) && op->type != PLAYER) { 1907 if (QUERY_FLAG (op, FLAG_UNAGGRESSIVE) && op->type != PLAYER)
1908 {
1794 /* The unaggressives look after themselves 8) */ 1909 /* The unaggressives look after themselves 8) */
1795 CLEAR_FLAG(op, FLAG_UNAGGRESSIVE); 1910 CLEAR_FLAG (op, FLAG_UNAGGRESSIVE);
1796 npc_call_help(op); 1911 npc_call_help (op);
1797 } 1912 }
1798 1913
1799 if (magic && did_make_save(op, op->level, 0)) 1914 if (magic && did_make_save (op, op->level, 0))
1800 maxdam=maxdam/2; 1915 maxdam = maxdam / 2;
1801 1916
1802 attack_message(maxdam, maxattacktype, op, hitter); 1917 attack_message (maxdam, maxattacktype, op, hitter);
1803 1918
1804 op->stats.hp-=maxdam; 1919 op->stats.hp -= maxdam;
1805 1920
1806 /* Eneq(@csd.uu.se): Check to see if monster runs away. */ 1921 /* Eneq(@csd.uu.se): Check to see if monster runs away. */
1807 if ((op->stats.hp>=0) && 1922 if ((op->stats.hp >= 0) &&
1808 (QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER) && 1923 (QUERY_FLAG (op, FLAG_MONSTER) || op->type == PLAYER) &&
1809 op->stats.hp<(signed short)(((float)op->run_away/(float)100)* 1924 op->stats.hp < (signed short) (((float) op->run_away / (float) 100) * (float) op->stats.maxhp))
1810 (float)op->stats.maxhp)) { 1925 {
1811 1926
1812 if (QUERY_FLAG(op, FLAG_MONSTER)) 1927 if (QUERY_FLAG (op, FLAG_MONSTER))
1813 SET_FLAG(op, FLAG_RUN_AWAY); 1928 SET_FLAG (op, FLAG_RUN_AWAY);
1814 else 1929 else
1815 scare_creature(op, hitter); 1930 scare_creature (op, hitter);
1816 } 1931 }
1817 1932
1818 if(QUERY_FLAG(op,FLAG_TEAR_DOWN)) { 1933 if (QUERY_FLAG (op, FLAG_TEAR_DOWN))
1934 {
1819 if (maxdam) 1935 if (maxdam)
1820 tear_down_wall(op); 1936 tear_down_wall (op);
1937
1821 return maxdam; /* nothing more to do for wall */ 1938 return maxdam; /* nothing more to do for wall */
1822 } 1939 }
1823 1940
1824 /* See if the creature has been killed */ 1941 /* See if the creature has been killed */
1825 rtn_kill = kill_object(op, maxdam, hitter, type); 1942 rtn_kill = kill_object (op, maxdam, hitter, type);
1826 if (rtn_kill != -1) 1943 if (rtn_kill != -1)
1827 return rtn_kill; 1944 return rtn_kill;
1828 1945
1829 1946
1830 /* Used to be ghosthit removal - we now use the ONE_HIT flag. Note 1947 /* Used to be ghosthit removal - we now use the ONE_HIT flag. Note
1831 * that before if the player was immune to ghosthit, the monster 1948 * that before if the player was immune to ghosthit, the monster
1832 * remained - that is no longer the case. 1949 * remained - that is no longer the case.
1833 */ 1950 */
1834 if(QUERY_FLAG(hitter, FLAG_ONE_HIT)) { 1951 if (QUERY_FLAG (hitter, FLAG_ONE_HIT))
1952 {
1835 if(QUERY_FLAG(hitter,FLAG_FRIENDLY)) 1953 if (QUERY_FLAG (hitter, FLAG_FRIENDLY))
1836 remove_friendly_object(hitter); 1954 remove_friendly_object (hitter);
1837 remove_ob(hitter); 1955
1838 free_object(hitter); 1956 hitter->destroy ();
1839 } 1957 }
1840 /* Lets handle creatures that are splitting now */ 1958 /* Lets handle creatures that are splitting now */
1841 else if(type&AT_PHYSICAL&&!QUERY_FLAG(op, FLAG_FREED)&&QUERY_FLAG(op,FLAG_SPLITTING)) { 1959 else if (type & AT_PHYSICAL && !QUERY_FLAG (op, FLAG_FREED) && QUERY_FLAG (op, FLAG_SPLITTING))
1960 {
1842 int i; 1961 int i;
1843 int friendly = QUERY_FLAG(op,FLAG_FRIENDLY); 1962 int friendly = QUERY_FLAG (op, FLAG_FRIENDLY);
1844 int unaggressive = QUERY_FLAG(op, FLAG_UNAGGRESSIVE); 1963 int unaggressive = QUERY_FLAG (op, FLAG_UNAGGRESSIVE);
1845 object *owner = get_owner(op); 1964 object *owner = op->owner;
1846 1965
1847 if(!op->other_arch) { 1966 if (!op->other_arch)
1967 {
1848 LOG(llevError,"SPLITTING without other_arch error.\n"); 1968 LOG (llevError, "SPLITTING without other_arch error.\n");
1849 return maxdam; 1969 return maxdam;
1850 } 1970 }
1851 remove_ob(op); 1971
1852 for(i=0;i<NROFNEWOBJS(op);i++) { /* This doesn't handle op->more yet */ 1972 op->remove ();
1973
1974 for (i = 0; i < NROFNEWOBJS (op); i++)
1975 { /* This doesn't handle op->more yet */
1853 object *tmp=arch_to_object(op->other_arch); 1976 object *tmp = arch_to_object (op->other_arch);
1854 int j; 1977 int j;
1855 1978
1856 tmp->stats.hp=op->stats.hp; 1979 tmp->stats.hp = op->stats.hp;
1980
1857 if (friendly) { 1981 if (friendly)
1858 SET_FLAG(tmp, FLAG_FRIENDLY); 1982 {
1859 add_friendly_object(tmp); 1983 add_friendly_object (tmp);
1860 tmp->attack_movement = PETMOVE; 1984 tmp->attack_movement = PETMOVE;
1985
1861 if (owner!=NULL) 1986 if (owner)
1862 set_owner(tmp,owner); 1987 tmp->set_owner (owner);
1863 } 1988 }
1989
1864 if (unaggressive) 1990 if (unaggressive)
1865 SET_FLAG(tmp, FLAG_UNAGGRESSIVE); 1991 SET_FLAG (tmp, FLAG_UNAGGRESSIVE);
1992
1866 j=find_first_free_spot(tmp,op->map,op->x,op->y); 1993 j = find_first_free_spot (tmp, op->map, op->x, op->y);
1994
1867 if (j==-1) /* No spot to put this monster */ 1995 if (j == -1) /* No spot to put this monster */
1868 free_object(tmp); 1996 tmp->destroy ();
1869 else { 1997 else
1998 {
1870 tmp->x=op->x+freearr_x[j],tmp->y=op->y+freearr_y[j]; 1999 tmp->x = op->x + freearr_x[j], tmp->y = op->y + freearr_y[j];
1871 insert_ob_in_map(tmp,op->map,NULL,0); 2000 insert_ob_in_map (tmp, op->map, NULL, 0);
1872 } 2001 }
1873 } 2002 }
1874 if(friendly) 2003
1875 remove_friendly_object(op); 2004 op->destroy ();
1876 free_object(op);
1877 } 2005 }
1878 else if(type & AT_DRAIN && hitter->type==GRIMREAPER&&hitter->value++>10) { 2006 else if (type & AT_DRAIN && hitter->type == GRIMREAPER && hitter->value++ > 10)
1879 remove_ob(hitter); 2007 hitter->destroy ();
1880 free_object(hitter); 2008
1881 }
1882 return maxdam; 2009 return maxdam;
1883} 2010}
1884 2011
1885 2012
2013void
1886void poison_player(object *op, object *hitter, int dam) 2014poison_player (object *op, object *hitter, int dam)
1887{ 2015{
1888 archetype *at = find_archetype("poisoning"); 2016 archetype *at = archetype::find ("poisoning");
1889 object *tmp=present_arch_in_ob(at,op); 2017 object *tmp = present_arch_in_ob (at, op);
1890 2018
1891 if(tmp==NULL) { 2019 if (tmp == NULL)
2020 {
1892 if((tmp=arch_to_object(at))==NULL) 2021 if ((tmp = arch_to_object (at)) == NULL)
1893 LOG(llevError,"Failed to clone arch poisoning.\n"); 2022 LOG (llevError, "Failed to clone arch poisoning.\n");
1894 else { 2023 else
2024 {
1895 tmp = insert_ob_in_ob(tmp,op); 2025 tmp = insert_ob_in_ob (tmp, op);
1896 /* peterm: give poisoning some teeth. It should 2026 /* peterm: give poisoning some teeth. It should
1897 * be able to kill things better than it does: 2027 * be able to kill things better than it does:
1898 * damage should be dependent something--I choose to 2028 * damage should be dependent something--I choose to
1899 * do this: if it's a monster, the damage from the 2029 * do this: if it's a monster, the damage from the
1900 * poisoning goes as the level of the monster/2. 2030 * poisoning goes as the level of the monster/2.
1901 * If anything else, goes as damage. 2031 * If anything else, goes as damage.
1902 */ 2032 */
1903 2033
1904 if(QUERY_FLAG(hitter,FLAG_ALIVE)) 2034 if (QUERY_FLAG (hitter, FLAG_ALIVE))
1905 tmp->stats.dam += hitter->level/2; 2035 tmp->stats.dam += hitter->level / 2;
1906 else 2036 else
1907 tmp->stats.dam = dam; 2037 tmp->stats.dam = dam;
1908 2038
1909 copy_owner(tmp,hitter); /* so we get credit for poisoning kills */ 2039 tmp->set_owner (hitter); /* so we get credit for poisoning kills */
1910 if(hitter->skill && hitter->skill != tmp->skill) { 2040 if (hitter->skill && hitter->skill != tmp->skill)
2041 {
1911 tmp->skill = hitter->skill; 2042 tmp->skill = hitter->skill;
1912 } 2043 }
1913 2044
1914 tmp->stats.food+=dam; /* more damage, longer poisoning */ 2045 tmp->stats.food += dam; /* more damage, longer poisoning */
1915 2046
1916 if(op->type==PLAYER) { 2047 if (op->type == PLAYER)
2048 {
1917 /* player looses stats, maximum is -10 of each */ 2049 /* player looses stats, maximum is -10 of each */
1918 tmp->stats.Con= MAX(-(dam/4+1), -10); 2050 tmp->stats.Con = MAX (-(dam / 4 + 1), -10);
1919 tmp->stats.Str= MAX(-(dam/3+2), -10); 2051 tmp->stats.Str = MAX (-(dam / 3 + 2), -10);
1920 tmp->stats.Dex= MAX(-(dam/6+1), -10); 2052 tmp->stats.Dex = MAX (-(dam / 6 + 1), -10);
1921 tmp->stats.Int= MAX(-dam/7, -10); 2053 tmp->stats.Int = MAX (-dam / 7, -10);
1922 SET_FLAG(tmp,FLAG_APPLIED); 2054 SET_FLAG (tmp, FLAG_APPLIED);
1923 fix_player(op); 2055 op->update_stats ();
1924 new_draw_info(NDI_UNIQUE, 0,op,"You suddenly feel very ill."); 2056 new_draw_info (NDI_UNIQUE, 0, op, "You suddenly feel very ill.");
1925 } 2057 }
1926 if (hitter->type == PLAYER) 2058 if (hitter->type == PLAYER)
1927 new_draw_info_format(NDI_UNIQUE, 0, hitter, "You poison %s.", &op->name); 2059 new_draw_info_format (NDI_UNIQUE, 0, hitter, "You poison %s.", &op->name);
1928 else if (get_owner(hitter) != NULL && hitter->owner->type == PLAYER) 2060 else if (hitter->owner != NULL && hitter->owner->type == PLAYER)
1929 new_draw_info_format(NDI_UNIQUE, 0, hitter->owner, 2061 new_draw_info_format (NDI_UNIQUE, 0, hitter->owner, "Your %s poisons %s.", &hitter->name, &op->name);
1930 "Your %s poisons %s.", &hitter->name, &op->name);
1931 } 2062 }
1932 tmp->speed_left=0; 2063 tmp->speed_left = 0;
1933 } 2064 }
1934 else 2065 else
1935 tmp->stats.food++; 2066 tmp->stats.food++;
1936} 2067}
1937 2068
2069void
1938void slow_player(object *op,object *hitter,int dam) 2070slow_player (object *op, object *hitter, int dam)
2071{
1939{ archetype *at = find_archetype("slowness"); 2072 archetype *at = archetype::find ("slowness");
1940 object *tmp; 2073 object *tmp;
2074
1941 if(at == NULL) { 2075 if (at == NULL)
2076 {
1942 LOG(llevError,"Can't find slowness archetype.\n"); 2077 LOG (llevError, "Can't find slowness archetype.\n");
1943 } 2078 }
1944 if((tmp=present_arch_in_ob(at,op)) == NULL) { 2079 if ((tmp = present_arch_in_ob (at, op)) == NULL)
2080 {
1945 tmp = arch_to_object(at); 2081 tmp = arch_to_object (at);
1946 tmp = insert_ob_in_ob(tmp,op); 2082 tmp = insert_ob_in_ob (tmp, op);
1947 new_draw_info(NDI_UNIQUE, 0,op,"The world suddenly moves very fast!"); 2083 new_draw_info (NDI_UNIQUE, 0, op, "The world suddenly moves very fast!");
2084 }
1948 } else 2085 else
1949 tmp->stats.food++; 2086 tmp->stats.food++;
1950 SET_FLAG(tmp, FLAG_APPLIED); 2087 SET_FLAG (tmp, FLAG_APPLIED);
1951 tmp->speed_left=0; 2088 tmp->speed_left = 0;
1952 fix_player(op); 2089 op->update_stats ();
1953} 2090}
1954 2091
2092void
1955void confuse_player(object *op, object *hitter, int dam) 2093confuse_player (object *op, object *hitter, int dam)
1956{ 2094{
1957 object *tmp; 2095 object *tmp;
1958 int maxduration; 2096 int maxduration;
1959 2097
1960 tmp = present_in_ob_by_name(FORCE,"confusion", op); 2098 tmp = present_in_ob_by_name (FORCE, "confusion", op);
1961 if(!tmp) { 2099 if (!tmp)
2100 {
1962 tmp = get_archetype(FORCE_NAME); 2101 tmp = get_archetype (FORCE_NAME);
1963 tmp = insert_ob_in_ob(tmp,op); 2102 tmp = insert_ob_in_ob (tmp, op);
1964 }
1965 2103 }
2104
1966 /* Duration added per hit and max. duration of confusion both depend 2105 /* Duration added per hit and max. duration of confusion both depend
1967 * on the player's resistance 2106 * on the player's resistance
1968 */ 2107 */
1969 tmp->speed = 0.05; 2108 tmp->speed = 0.05;
1970 tmp->subtype = FORCE_CONFUSION; 2109 tmp->subtype = FORCE_CONFUSION;
1971 tmp->duration = 8 + MAX(1, 5*(100-op->resist[ATNR_CONFUSION])/100); 2110 tmp->duration = 8 + MAX (1, 5 * (100 - op->resist[ATNR_CONFUSION]) / 100);
1972 tmp->name = "confusion"; 2111 tmp->name = "confusion";
1973 maxduration = MAX(2, 30*(100-op->resist[ATNR_CONFUSION])/100); 2112 maxduration = MAX (2, 30 * (100 - op->resist[ATNR_CONFUSION]) / 100);
1974 if( tmp->duration > maxduration) 2113 if (tmp->duration > maxduration)
1975 tmp->duration = maxduration; 2114 tmp->duration = maxduration;
1976 2115
1977 if(op->type == PLAYER && !QUERY_FLAG(op,FLAG_CONFUSED)) 2116 if (op->type == PLAYER && !QUERY_FLAG (op, FLAG_CONFUSED))
1978 new_draw_info(NDI_UNIQUE, 0,op,"You suddenly feel very confused!"); 2117 new_draw_info (NDI_UNIQUE, 0, op, "You suddenly feel very confused!");
1979 SET_FLAG(op, FLAG_CONFUSED); 2118 SET_FLAG (op, FLAG_CONFUSED);
1980} 2119}
1981 2120
2121void
1982void blind_player(object *op, object *hitter, int dam) 2122blind_player (object *op, object *hitter, int dam)
1983{ 2123{
1984 object *tmp,*owner; 2124 object *tmp, *owner;
1985 2125
1986 /* Save some work if we know it isn't going to affect the player */ 2126 /* Save some work if we know it isn't going to affect the player */
1987 if (op->resist[ATNR_BLIND]==100) return; 2127 if (op->resist[ATNR_BLIND] == 100)
2128 return;
1988 2129
1989 tmp = present_in_ob(BLINDNESS,op); 2130 tmp = present_in_ob (BLINDNESS, op);
1990 if(!tmp) { 2131 if (!tmp)
2132 {
1991 tmp = get_archetype("blindness"); 2133 tmp = get_archetype ("blindness");
1992 SET_FLAG(tmp, FLAG_BLIND); 2134 SET_FLAG (tmp, FLAG_BLIND);
1993 SET_FLAG(tmp, FLAG_APPLIED); 2135 SET_FLAG (tmp, FLAG_APPLIED);
1994 /* use floats so we don't lose too much precision due to rounding errors. 2136 /* use floats so we don't lose too much precision due to rounding errors.
1995 * speed is a float anyways. 2137 * speed is a float anyways.
1996 */ 2138 */
1997 tmp->speed = tmp->speed * (100.0 - (float)op->resist[ATNR_BLIND]) / 100; 2139 tmp->speed = tmp->speed * (100.0 - (float) op->resist[ATNR_BLIND]) / 100;
1998 2140
1999 tmp = insert_ob_in_ob(tmp,op); 2141 tmp = insert_ob_in_ob (tmp, op);
2000 change_abil(op,tmp); /* Mostly to display any messages */ 2142 change_abil (op, tmp); /* Mostly to display any messages */
2001 fix_player(op); /* This takes care of some other stuff */ 2143 op->update_stats (); /* This takes care of some other stuff */
2002 2144
2003 if(hitter->owner) owner = get_owner(hitter); 2145 if (hitter->owner)
2146 owner = hitter->owner;
2147 else
2004 else owner = hitter; 2148 owner = hitter;
2005 2149
2006 new_draw_info_format(NDI_UNIQUE,0,owner, 2150 new_draw_info_format (NDI_UNIQUE, 0, owner, "Your attack blinds %s!", query_name (op));
2007 "Your attack blinds %s!",query_name(op));
2008 } 2151 }
2009 tmp->stats.food += dam; 2152 tmp->stats.food += dam;
2010 if(tmp->stats.food > 10) tmp->stats.food = 10; 2153 if (tmp->stats.food > 10)
2154 tmp->stats.food = 10;
2011} 2155}
2012 2156
2157void
2013void paralyze_player(object *op, object *hitter, int dam) 2158paralyze_player (object *op, object *hitter, int dam)
2014{ 2159{
2015 float effect,max; 2160 float effect, max;
2161
2016 /* object *tmp; */ 2162 /* object *tmp; */
2017 2163
2018 /* This is strange stuff... someone knows for what this is 2164 /* This is strange stuff... someone knows for what this is
2019 * written? Well, i think this can and should be removed 2165 * written? Well, i think this can and should be removed
2020 */ 2166 */
2021 2167
2022 /* 2168 /*
2023 if((tmp=present(PARAIMAGE,op->map,op->x,op->y))==NULL) { 2169 if((tmp=present(PARAIMAGE,op->map,op->x,op->y))==NULL) {
2024 tmp=clone_arch(PARAIMAGE); 2170 tmp=clone_arch(PARAIMAGE);
2025 tmp->x=op->x,tmp->y=op->y; 2171 tmp->x=op->x,tmp->y=op->y;
2026 insert_ob_in_map(tmp,op->map,tmp,INS_NO_MERGE | INS_NO_WALK_ON); 2172 insert_ob_in_map(tmp,op->map,tmp,INS_NO_MERGE | INS_NO_WALK_ON);
2027 } 2173 }
2028 */ 2174 */
2029 2175
2030 /* Do this as a float - otherwise, rounding might very well reduce this to 0 */ 2176 /* Do this as a float - otherwise, rounding might very well reduce this to 0 */
2031 effect = (float)dam * 3.0 * (100.0 - op->resist[ATNR_PARALYZE]) / 100; 2177 effect = (float) dam *3.0 * (100.0 - op->resist[ATNR_PARALYZE]) / 100;
2032 2178
2033 if (effect==0) return; 2179 if (effect == 0)
2180 return;
2034 2181
2035 op->speed_left-=FABS(op->speed)*effect; 2182 op->speed_left -= FABS (op->speed) * effect;
2036 /* tmp->stats.food+=(signed short) effect/op->speed; */ 2183 /* tmp->stats.food+=(signed short) effect/op->speed; */
2037 2184
2038 /* max number of ticks to be affected for. */ 2185 /* max number of ticks to be affected for. */
2039 max = (100 - op->resist[ATNR_PARALYZE])/ 2; 2186 max = (100 - op->resist[ATNR_PARALYZE]) / 2;
2040 if (op->speed_left< -(FABS(op->speed)*max)) 2187 if (op->speed_left < -(FABS (op->speed) * max))
2041 op->speed_left = (float) -(FABS(op->speed)*max); 2188 op->speed_left = (float) -(FABS (op->speed) * max);
2042 2189
2043/* tmp->stats.food = (signed short) (max/FABS(op->speed)); */ 2190/* tmp->stats.food = (signed short) (max/FABS(op->speed)); */
2044} 2191}
2045 2192
2046 2193
2047/* Attempts to kill 'op'. hitter is the attack object, dam is 2194/* Attempts to kill 'op'. hitter is the attack object, dam is
2048 * the computed damaged. 2195 * the computed damaged.
2049 */ 2196 */
2197void
2050void deathstrike_player(object *op, object *hitter, int *dam) 2198deathstrike_player (object *op, object *hitter, int *dam)
2051{ 2199{
2052 /* The intention of a death attack is to kill outright things 2200 /* The intention of a death attack is to kill outright things
2053 ** that are a lot weaker than the attacker, have a chance of killing 2201 ** that are a lot weaker than the attacker, have a chance of killing
2054 ** things somewhat weaker than the caster, and no chance of 2202 ** things somewhat weaker than the caster, and no chance of
2055 ** killing something equal or stronger than the attacker. 2203 ** killing something equal or stronger than the attacker.
2056 ** Also, if a deathstrike attack has a slaying, any monster 2204 ** Also, if a deathstrike attack has a slaying, any monster
2057 ** whose name or race matches a comma-delimited list in the slaying 2205 ** whose name or race matches a comma-delimited list in the slaying
2058 ** field of the deathstriking object */ 2206 ** field of the deathstriking object */
2059 2207
2060 int atk_lev, def_lev, kill_lev; 2208 int atk_lev, def_lev, kill_lev;
2061 2209
2062 if(hitter->slaying) 2210 if (hitter->slaying)
2063 if(!( (QUERY_FLAG(op,FLAG_UNDEAD)&&strstr(hitter->slaying,undead_name)) || 2211 if (!((QUERY_FLAG (op, FLAG_UNDEAD) && strstr (hitter->slaying, undead_name)) || (op->race && strstr (hitter->slaying, op->race))))
2064 (op->race&&strstr(hitter->slaying,op->race)))) return; 2212 return;
2065 2213
2066 def_lev = op->level; 2214 def_lev = op->level;
2067 if (def_lev < 1) { 2215 if (def_lev < 1)
2216 {
2068 LOG (llevError, "BUG: arch %s, name %s with level < 1\n", 2217 LOG (llevError, "BUG: arch %s, name %s with level < 1\n", &op->arch->name, &op->name);
2069 &op->arch->name, &op->name);
2070 def_lev = 1; 2218 def_lev = 1;
2071 } 2219 }
2072 atk_lev = (hitter->chosen_skill?hitter->chosen_skill->level:hitter->level) / 2; 2220 atk_lev = (hitter->chosen_skill ? hitter->chosen_skill->level : hitter->level) / 2;
2073 /* LOG(llevDebug,"Deathstrike - attack level %d, defender level %d\n", 2221 /* LOG(llevDebug,"Deathstrike - attack level %d, defender level %d\n",
2074 atk_lev, def_lev); */ 2222 atk_lev, def_lev); */
2075 2223
2076 if(atk_lev >= def_lev ){ 2224 if (atk_lev >= def_lev)
2225 {
2077 kill_lev = random_roll(0, atk_lev-1, hitter, PREFER_HIGH); 2226 kill_lev = random_roll (0, atk_lev - 1, hitter, PREFER_HIGH);
2078 2227
2079 /* Note that the below effectively means the ratio of the atk vs 2228 /* Note that the below effectively means the ratio of the atk vs
2080 * defener level is important - if level 52 character has very little 2229 * defener level is important - if level 52 character has very little
2081 * chance of killing a level 50 monster. This should probably be 2230 * chance of killing a level 50 monster. This should probably be
2082 * redone. 2231 * redone.
2083 */ 2232 */
2084 if(kill_lev >= def_lev) { 2233 if (kill_lev >= def_lev)
2234 {
2085 *dam = op->stats.hp+10; /* take all hp. they can still save for 1/2 */ 2235 *dam = op->stats.hp + 10; /* take all hp. they can still save for 1/2 */
2086 /* I think this doesn't really do much. Because of 2236 /* I think this doesn't really do much. Because of
2087 * integer rounding, this only makes any difference if the 2237 * integer rounding, this only makes any difference if the
2088 * attack level is double the defender level. 2238 * attack level is double the defender level.
2089 */ 2239 */
2090 *dam *= kill_lev / def_lev; 2240 *dam *= kill_lev / def_lev;
2091 } 2241 }
2092 } else { 2242 }
2243 else
2244 {
2093 *dam = 0; /* no harm done */ 2245 *dam = 0; /* no harm done */
2094 } 2246 }
2095} 2247}
2096 2248
2097/* thrown_item_effect() - handles any special effects of thrown 2249/* thrown_item_effect() - handles any special effects of thrown
2098 * items (like attacking living creatures--a potion thrown at a 2250 * items (like attacking living creatures--a potion thrown at a
2099 * monster). 2251 * monster).
2100 */ 2252 */
2253static void
2101static void thrown_item_effect (object *hitter, object *victim) 2254thrown_item_effect (object *hitter, object *victim)
2102{ 2255{
2103 if(!QUERY_FLAG(hitter,FLAG_ALIVE)) { 2256 if (!QUERY_FLAG (hitter, FLAG_ALIVE))
2257 {
2104 /* May not need a switch for just 2 types, but this makes it 2258 /* May not need a switch for just 2 types, but this makes it
2105 * easier for expansion. 2259 * easier for expansion.
2106 */ 2260 */
2107 switch (hitter->type) { 2261 switch (hitter->type)
2262 {
2108 case POTION: 2263 case POTION:
2109 /* should player get a save throw instead of checking magic protection? */ 2264 /* should player get a save throw instead of checking magic protection? */
2110 if(QUERY_FLAG(victim,FLAG_ALIVE)&&!QUERY_FLAG(victim,FLAG_UNDEAD) 2265 if (QUERY_FLAG (victim, FLAG_ALIVE) && !QUERY_FLAG (victim, FLAG_UNDEAD) && (victim->resist[ATNR_MAGIC] < 60))
2111 &&(victim->resist[ATNR_MAGIC]<60)) (void) apply_potion(victim,hitter); 2266 (void) apply_potion (victim, hitter);
2112 break; 2267 break;
2113 2268
2114 case POISON: /* poison drinks */ 2269 case POISON: /* poison drinks */
2115 /* As with potions, should monster get a save? */ 2270 /* As with potions, should monster get a save? */
2116 if(QUERY_FLAG(victim,FLAG_ALIVE)&&!QUERY_FLAG(victim,FLAG_UNDEAD) 2271 if (QUERY_FLAG (victim, FLAG_ALIVE) && !QUERY_FLAG (victim, FLAG_UNDEAD) && (victim->resist[ATNR_POISON] < 60))
2117 &&(victim->resist[ATNR_POISON]<60)) apply_poison(victim,hitter); 2272 apply_poison (victim, hitter);
2118 break; 2273 break;
2119 2274
2120 /* Removed case statements that did nothing. 2275 /* Removed case statements that did nothing.
2121 * food may be poisonous, but monster must be willing to eat it, 2276 * food may be poisonous, but monster must be willing to eat it,
2122 * so we don't handle it here. 2277 * so we don't handle it here.
2123 * Containers should perhaps break open, but that code was disabled. 2278 * Containers should perhaps break open, but that code was disabled.
2124 */ 2279 */
2125 } 2280 }
2126 } 2281 }
2127} 2282}
2128 2283
2129/* adj_attackroll() - adjustments to attacks by various conditions */ 2284/* adj_attackroll() - adjustments to attacks by various conditions */
2130 2285
2286int
2131int adj_attackroll (object *hitter, object *target) { 2287adj_attackroll (object *hitter, object *target)
2288{
2132 object *attacker = hitter; 2289 object *attacker = hitter;
2133 int adjust=0; 2290 int adjust = 0;
2134 2291
2135 /* safety */ 2292 /* safety */
2136 if(!target||!hitter||!hitter->map||!target->map||!on_same_map(hitter,target)) { 2293 if (!target || !hitter || !hitter->map || !target->map || !on_same_map (hitter, target))
2294 {
2137 LOG (llevError, "BUG: adj_attackroll(): hitter and target not on same " 2295 LOG (llevError, "BUG: adj_attackroll(): hitter and target not on same " "map\n");
2138 "map\n"); 2296 return 0;
2297 }
2298
2299 /* aimed missiles use the owning object's sight */
2300 if (is_aimed_missile (hitter))
2301 {
2302 if ((attacker = hitter->owner) == NULL)
2303 attacker = hitter;
2304 /* A player who saves but hasn't quit still could have objects
2305 * owned by him - need to handle that case to avoid crashes.
2306 */
2307 if (QUERY_FLAG (attacker, FLAG_REMOVED))
2308 attacker = hitter;
2309 }
2310 else if (!QUERY_FLAG (hitter, FLAG_ALIVE))
2139 return 0; 2311 return 0;
2140 }
2141 2312
2142 /* aimed missiles use the owning object's sight */
2143 if(is_aimed_missile(hitter)) {
2144 if ((attacker = get_owner(hitter))==NULL) attacker = hitter;
2145 /* A player who saves but hasn't quit still could have objects
2146 * owned by him - need to handle that case to avoid crashes.
2147 */
2148 if (QUERY_FLAG(attacker, FLAG_REMOVED)) attacker = hitter;
2149 }
2150 else if(!QUERY_FLAG(hitter,FLAG_ALIVE))
2151 return 0;
2152
2153 /* determine the condtions under which we make an attack. 2313 /* determine the condtions under which we make an attack.
2154 * Add more cases, as the need occurs. */ 2314 * Add more cases, as the need occurs. */
2155 2315
2156 if(!can_see_enemy(attacker,target)) { 2316 if (!can_see_enemy (attacker, target))
2317 {
2157 /* target is unseen */ 2318 /* target is unseen */
2158 if(target->invisible || QUERY_FLAG(attacker,FLAG_BLIND)) 2319 if (target->invisible || QUERY_FLAG (attacker, FLAG_BLIND))
2159 adjust -= 10; 2320 adjust -= 10;
2160 /* dark map penalty for the hitter (lacks infravision if we got here). */ 2321 /* dark map penalty for the hitter (lacks infravision if we got here). */
2161 else if(target->map&&target->map->darkness>0&&!stand_in_light(target)) 2322 else if (target->map && target->map->darkness > 0 && !stand_in_light (target))
2162 adjust -= target->map->darkness; 2323 adjust -= target->map->darkness;
2163 } 2324 }
2164 2325
2165 if(QUERY_FLAG(attacker,FLAG_SCARED)) 2326 if (QUERY_FLAG (attacker, FLAG_SCARED))
2166 adjust -= 3; 2327 adjust -= 3;
2167 2328
2168 if(QUERY_FLAG(target,FLAG_UNAGGRESSIVE)) 2329 if (QUERY_FLAG (target, FLAG_UNAGGRESSIVE))
2169 adjust += 1; 2330 adjust += 1;
2170 2331
2171 if(QUERY_FLAG(target,FLAG_SCARED)) 2332 if (QUERY_FLAG (target, FLAG_SCARED))
2172 adjust += 1; 2333 adjust += 1;
2173 2334
2174 if(QUERY_FLAG(attacker,FLAG_CONFUSED)) 2335 if (QUERY_FLAG (attacker, FLAG_CONFUSED))
2175 adjust -= 3; 2336 adjust -= 3;
2176 2337
2177 /* if we attack at a different 'altitude' its harder */ 2338 /* if we attack at a different 'altitude' its harder */
2178 if((attacker->move_type & target->move_type)==0) 2339 if ((attacker->move_type & target->move_type) == 0)
2179 adjust -= 2; 2340 adjust -= 2;
2180 2341
2181#if 0 2342#if 0
2182 /* slower attacks are less likely to succeed. We should use a 2343 /* slower attacks are less likely to succeed. We should use a
2183 * comparison between attacker/target speeds BUT, players have 2344 * comparison between attacker/target speeds BUT, players have
2184 * a generally faster speed, so this will wind up being a HUGE 2345 * a generally faster speed, so this will wind up being a HUGE
2185 * disadantage for the monsters! Too bad, because missiles which 2346 * disadantage for the monsters! Too bad, because missiles which
2186 * fly fast should have a better chance of hitting a slower target. 2347 * fly fast should have a better chance of hitting a slower target.
2187 */ 2348 */
2188 if(hitter->speed<target->speed) 2349 if (hitter->speed < target->speed)
2189 adjust += ((float) hitter->speed-target->speed); 2350 adjust += ((float) hitter->speed - target->speed);
2190#endif 2351#endif
2191 2352
2192#if 0 2353#if 0
2193 LOG(llevDebug,"adj_attackroll() returns %d (%d)\n",adjust,attacker->count); 2354 LOG (llevDebug, "adj_attackroll() returns %d (%d)\n", adjust, attacker->count);
2194#endif 2355#endif
2195 2356
2196 return adjust; 2357 return adjust;
2197} 2358}
2198 2359
2199 2360
2200/* determine if the object is an 'aimed' missile */ 2361/* determine if the object is an 'aimed' missile */
2362int
2201int is_aimed_missile ( object *op) { 2363is_aimed_missile (object *op)
2364{
2202 2365
2203 /* I broke what used to be one big if into a few nested 2366 /* I broke what used to be one big if into a few nested
2204 * ones so that figuring out the logic is at least possible. 2367 * ones so that figuring out the logic is at least possible.
2205 */ 2368 */
2206 if (op && (op->move_type & MOVE_FLYING)) { 2369 if (op && (op->move_type & MOVE_FLYING))
2370 {
2207 if (op->type==ARROW || op->type==THROWN_OBJ) 2371 if (op->type == ARROW || op->type == THROWN_OBJ)
2208 return 1; 2372 return 1;
2209 else if (op->type==SPELL_EFFECT && (op->subtype == SP_BULLET || 2373 else if (op->type == SPELL_EFFECT && (op->subtype == SP_BULLET || op->subtype == SP_EXPLOSION))
2210 op->subtype == SP_EXPLOSION))
2211 return 1; 2374 return 1;
2212 } 2375 }
2213 return 0; 2376 return 0;
2214} 2377}
2215

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines