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

Comparing deliantra/server/server/time.C (file contents):
Revision 1.99 by root, Sat Nov 7 18:30:06 2009 UTC vs.
Revision 1.128 by root, Wed Dec 5 19:03:27 2018 UTC

1/* 1/*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG. 2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 * 3 *
4 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team 6 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen 7 * Copyright (©) 1992 Frank Tore Johansen
7 * 8 *
8 * Deliantra is free software: you can redistribute it and/or modify it under 9 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the 10 * the terms of the Affero GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your 11 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version. 12 * option) any later version.
12 * 13 *
13 * This program is distributed in the hope that it will be useful, 14 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 17 * GNU General Public License for more details.
17 * 18 *
18 * You should have received a copy of the Affero GNU General Public License 19 * You should have received a copy of the Affero GNU General Public License
19 * and the GNU General Public License along with this program. If not, see 20 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>. 21 * <http://www.gnu.org/licenses/>.
21 * 22 *
22 * The authors can be reached via e-mail to <support@deliantra.net> 23 * The authors can be reached via e-mail to <support@deliantra.net>
23 */ 24 */
24 25
25/* 26/*
26 * Routines that is executed from objects based on their speed have been 27 * Routines that is executed from objects based on their speed have been
28 */ 29 */
29#include <global.h> 30#include <global.h>
30#include <spells.h> 31#include <spells.h>
31#include <sproto.h> 32#include <sproto.h>
32 33
33/* The following removes doors. The functions check to see if similar 34/* The following removes doors. The functions check to see if similar
34 * doors are next to the one that is being removed, and if so, set it 35 * doors are next to the one that is being removed, and if so, set it
35 * so those will be removed shortly (in a cascade like fashion.) 36 * so those will be removed shortly (in a cascade like fashion.)
36 */ 37 */
37void 38void
38remove_door (object *op) 39remove_door (object *op)
50 } 51 }
51 } 52 }
52 53
53 if (op->other_arch) 54 if (op->other_arch)
54 { 55 {
55 object *tmp = arch_to_object (op->other_arch); 56 object *tmp = op->other_arch->instance ();
56 tmp->x = op->x; 57 tmp->x = op->x;
57 tmp->y = op->y; 58 tmp->y = op->y;
58 tmp->map = op->map; 59 tmp->map = op->map;
59 tmp->level = op->level; 60 tmp->level = op->level;
60 insert_ob_in_map (tmp, op->map, op, 0); 61 insert_ob_in_map (tmp, op->map, op, 0);
69 int i; 70 int i;
70 object *tmp; 71 object *tmp;
71 72
72 for (i = 1; i < 9; i += 2) 73 for (i = 1; i < 9; i += 2)
73 { 74 {
74 tmp = present (LOCKED_DOOR, op->map, op->x + freearr_x[i], op->y + freearr_y[i]); 75 tmp = present (LOCKED_DOOR, op->map, op->x + DIRX (i), op->y + DIRY (i));
75 if (tmp && tmp->slaying == op->slaying) 76 if (tmp && tmp->slaying == op->slaying)
76 { /* same key both doors */ 77 { /* same key both doors */
77 tmp->set_speed (0.1f); 78 tmp->set_speed (0.1f);
78 tmp->speed_left = -0.2f; 79 tmp->speed_left = -0.2f;
79 } 80 }
80 } 81 }
81 82
82 if (op->other_arch) 83 if (op->other_arch)
83 { 84 {
84 tmp = arch_to_object (op->other_arch); 85 tmp = op->other_arch->instance ();
85 tmp->x = op->x; 86 tmp->x = op->x;
86 tmp->y = op->y; 87 tmp->y = op->y;
87 tmp->map = op->map; 88 tmp->map = op->map;
88 tmp->level = op->level; 89 tmp->level = op->level;
89 insert_ob_in_map (tmp, op->map, op, 0); 90 insert_ob_in_map (tmp, op->map, op, 0);
107 return; 108 return;
108 109
109 object *op; 110 object *op;
110 int dir; 111 int dir;
111 112
112 if (QUERY_FLAG (gen, FLAG_CONTENT_ON_GEN)) 113 if (gen->flag [FLAG_CONTENT_ON_GEN])
113 { 114 {
114 // either copy one item from the inventory... 115 // either copy one item from the inventory...
115 if (!gen->inv) 116 if (!gen->inv)
116 return; 117 return;
117 118
125 if (dir < 0) 126 if (dir < 0)
126 return; 127 return;
127 128
128 op = op->deep_clone (); 129 op = op->deep_clone ();
129 130
130 CLEAR_FLAG (op, FLAG_IS_A_TEMPLATE); 131 op->clr_flag (FLAG_IS_A_TEMPLATE);
131 unflag_inv (op, FLAG_IS_A_TEMPLATE); 132 unflag_inv (op, FLAG_IS_A_TEMPLATE);
132 } 133 }
133 else if (gen->other_arch) 134 else if (gen->other_arch)
134 { 135 {
135 // ...or use other_arch 136 // ...or use other_arch
136 dir = find_free_spot (gen->other_arch, gen->map, gen->x, gen->y, 1, SIZEOFFREE1 + 1); 137 dir = find_free_spot (gen->other_arch, gen->map, gen->x, gen->y, 1, SIZEOFFREE1 + 1);
137 if (dir < 0) 138 if (dir < 0)
138 return; 139 return;
139 140
140 op = arch_to_object (gen->other_arch); 141 op = gen->other_arch->instance ();
141 } 142 }
142 else 143 else
143 return; 144 return;
144 145
145 op->expand_tail (); 146 op->expand_tail ();
168 169
169 if (op->env) 170 if (op->env)
170 switch (op->subtype) 171 switch (op->subtype)
171 { 172 {
172 case FORCE_CONFUSION: 173 case FORCE_CONFUSION:
173 CLEAR_FLAG (op->env, FLAG_CONFUSED); 174 op->env->clr_flag (FLAG_CONFUSED);
174 new_draw_info (NDI_UNIQUE, 0, op->env, "You regain your senses.\n"); 175 new_draw_info (NDI_UNIQUE, 0, op->env, "You regain your senses.\n");
175 176
176 default: 177 default:
177 CLEAR_FLAG (op, FLAG_APPLIED); 178 op->clr_flag (FLAG_APPLIED);
178 change_abil (op->env, op); 179 change_abil (op->env, op);
179 op->env->update_stats (); 180 op->env->update_stats ();
180 } 181 }
181 182
182 op->destroy (); 183 op->destroy ();
186remove_blindness (object *op) 187remove_blindness (object *op)
187{ 188{
188 if (--op->stats.food > 0) 189 if (--op->stats.food > 0)
189 return; 190 return;
190 191
191 CLEAR_FLAG (op, FLAG_APPLIED); 192 op->clr_flag (FLAG_APPLIED);
192 193
193 if (op->env) 194 if (op->env)
194 { 195 {
195 change_abil (op->env, op); 196 change_abil (op->env, op);
196 op->env->update_stats (); 197 op->env->update_stats ();
200} 201}
201 202
202static void 203static void
203poison_more (object *op) 204poison_more (object *op)
204{ 205{
205 if (op->env == NULL || !QUERY_FLAG (op->env, FLAG_ALIVE) || op->env->stats.hp < 0) 206 if (op->env == NULL || !op->env->flag [FLAG_ALIVE] || op->env->stats.hp < 0)
206 { 207 {
207 op->destroy (); 208 op->destroy ();
208 return; 209 return;
209 } 210 }
210 211
213 /* need to unapply the object before update_stats is called, else fix_player 214 /* need to unapply the object before update_stats is called, else fix_player
214 * will not do anything. 215 * will not do anything.
215 */ 216 */
216 if (op->env->type == PLAYER) 217 if (op->env->type == PLAYER)
217 { 218 {
218 CLEAR_FLAG (op, FLAG_APPLIED); 219 op->clr_flag (FLAG_APPLIED);
219 op->env->update_stats (); 220 op->env->update_stats ();
220 new_draw_info (NDI_UNIQUE, 0, op->env, "You feel much better now."); 221 new_draw_info (NDI_UNIQUE, 0, op->env, "You feel much better now.");
221 } 222 }
222 223
223 op->destroy (); 224 op->destroy ();
237static void 238static void
238move_gate (object *op) 239move_gate (object *op)
239{ /* 1 = going down, 0 = going up */ 240{ /* 1 = going down, 0 = going up */
240 object *tmp; 241 object *tmp;
241 242
242 if (op->stats.wc < 0 || (int) op->stats.wc >= NUM_ANIMATIONS (op)) 243 if (uint32_t (op->stats.wc) >= op->anim_frames ())
243 { 244 {
244 LOG (llevError, "Gate error: animation was %d, max=%d\n", op->stats.wc, NUM_ANIMATIONS (op)); 245 LOG (llevError, "%s: gate error: animation was %d, max=%d\n", op->debug_desc (), op->stats.wc, op->anim_frames ());
245 op->stats.wc = 0; 246 op->stats.wc = 0;
246 } 247 }
247 248
248 /* We're going down */
249 if (op->value) 249 if (op->value)
250 { 250 {
251 /* We're going down */
251 if (--op->stats.wc <= 0) 252 if (--op->stats.wc <= 0)
252 { /* Reached bottom, let's stop */ 253 { /* Reached bottom, let's stop */
253 op->stats.wc = 0; 254 op->stats.wc = 0;
254 if (op->arch->has_active_speed ()) 255 if (op->arch->has_active_speed ())
255 op->value = 0; 256 op->value = 0;
256 else 257 else
257 op->set_speed (0); 258 op->set_speed (0);
258 } 259 }
259 260
260 if ((int) op->stats.wc < (NUM_ANIMATIONS (op) / 2 + 1)) 261 if (op->stats.wc < op->anim_frames () / 2 + 1)
261 { 262 {
262 op->move_block = 0; 263 op->move_block = 0;
263 CLEAR_FLAG (op, FLAG_BLOCKSVIEW); 264 op->clr_flag (FLAG_BLOCKSVIEW);
264 update_all_los (op->map, op->x, op->y); 265 update_all_los (op->map, op->x, op->y);
265 } 266 }
266
267 SET_ANIMATION (op, op->stats.wc);
268 update_object (op, UP_OBJ_CHANGE);
269 return;
270 }
271
272 /* We're going up */
273
274 /* First, lets see if we are already at the top */
275 if ((unsigned char) op->stats.wc == (NUM_ANIMATIONS (op) - 1))
276 {
277
278 /* Check to make sure that only non pickable and non rollable
279 * objects are above the gate. If so, we finish closing the gate,
280 * otherwise, we fall through to the code below which should lower
281 * the gate slightly.
282 */
283
284 for (tmp = op->above; tmp; tmp = tmp->above)
285 if (!QUERY_FLAG (tmp, FLAG_NO_PICK) || QUERY_FLAG (tmp, FLAG_CAN_ROLL) || QUERY_FLAG (tmp, FLAG_ALIVE))
286 break;
287
288 if (!tmp)
289 {
290 if (op->arch->has_active_speed ())
291 op->value = 1;
292 else
293 op->set_speed (0);
294
295 return;
296 }
297 }
298
299 if (op->stats.food)
300 { /* The gate is going temporarily down */
301 if (--op->stats.wc <= 0)
302 { /* Gone all the way down? */
303 op->stats.food = 0; /* Then let's try again */
304 op->stats.wc = 0;
305 }
306 } 267 }
307 else 268 else
269 {
270 /* We're going up */
271
272 /* First, lets see if we are already at the top */
273 if (op->stats.wc == op->anim_frames () - 1)
274 {
275 /* Check to make sure that only non pickable and non rollable
276 * objects are above the gate. If so, we finish closing the gate,
277 * otherwise, we fall through to the code below which should lower
278 * the gate slightly.
279 */
280
281 for (tmp = op->above; tmp; tmp = tmp->above)
282 if (!tmp->flag [FLAG_NO_PICK] || tmp->flag [FLAG_CAN_ROLL] || tmp->flag [FLAG_ALIVE])
283 break;
284
285 if (!tmp)
286 {
287 if (op->arch->has_active_speed ())
288 op->value = 1;
289 else
290 op->set_speed (0);
291
292 return;
293 }
294 }
295
296 if (op->stats.food)
297 { /* The gate is going temporarily down */
298 if (--op->stats.wc <= 0)
299 { /* Gone all the way down? */
300 op->stats.food = 0; /* Then let's try again */
301 op->stats.wc = 0;
302 }
303 }
304 else
308 { /* The gate is still going up */ 305 { /* The gate is still going up */
309 op->stats.wc++; 306 op->stats.wc++;
307 min_it (op->stats.wc, op->anim_frames () - 1);
310 308
311 if (op->stats.wc >= NUM_ANIMATIONS (op))
312 op->stats.wc = NUM_ANIMATIONS (op) - 1;
313
314 /* If there is something on top of the gate, we try to roll it off. 309 /* If there is something on top of the gate, we try to roll it off.
315 * If a player/monster, we don't roll, we just hit them with damage 310 * If a player/monster, we don't roll, we just hit them with damage
316 */ 311 */
317 if (op->stats.wc >= NUM_ANIMATIONS (op) / 2) 312 if (op->stats.wc >= op->anim_frames () / 2)
318 { 313 {
319 /* Halfway or further, check blocks */ 314 /* Halfway or further, check blocks */
320 /* First, get the top object on the square. */ 315 /* First, get the top object on the square. */
321 for (tmp = op->above; tmp && tmp->above; tmp = tmp->above) 316 for (tmp = op->above; tmp && tmp->above; tmp = tmp->above)
322 ; 317 ;
323 318
324 if (tmp) 319 if (tmp)
325 {
326 if (QUERY_FLAG (tmp, FLAG_ALIVE))
327 { 320 {
328 hit_player (tmp, random_roll (0, op->stats.dam, tmp, PREFER_LOW), op, AT_PHYSICAL, 1); 321 if (tmp->flag [FLAG_ALIVE])
329 op->play_sound (sound_find ("blocked_gate"));
330
331 if (tmp->type == PLAYER)
332 new_draw_info_format (NDI_UNIQUE, 0, tmp, "You are crushed by the %s!", &op->name);
333 }
334 /* If the object is not alive, and the object either can
335 * be picked up or the object rolls, move the object
336 * off the gate.
337 */
338 else if (!QUERY_FLAG (tmp, FLAG_ALIVE) && (!QUERY_FLAG (tmp, FLAG_NO_PICK) || QUERY_FLAG (tmp, FLAG_CAN_ROLL)))
339 {
340 /* If it has speed, it should move itself, otherwise: */
341 int i = find_free_spot (tmp, op->map, op->x, op->y, 1, SIZEOFFREE1 + 1);
342
343 /* If there is a free spot, move the object someplace */
344 if (i > 0)
345 { 322 {
323 hit_player (tmp, random_roll (0, op->stats.dam, tmp, PREFER_LOW), op, AT_PHYSICAL, 1);
324 op->play_sound (sound_find ("blocked_gate"));
325
326 if (tmp->type == PLAYER)
327 new_draw_info_format (NDI_UNIQUE, 0, tmp, "You are crushed by the %s!", &op->name);
328 }
329 /* If the object is not alive, and the object either can
330 * be picked up or the object rolls, move the object
331 * off the gate.
332 */
333 else if (!tmp->flag [FLAG_ALIVE] && (!tmp->flag [FLAG_NO_PICK] || tmp->flag [FLAG_CAN_ROLL]))
334 {
335 /* If it has speed, it should move itself, otherwise: */
336 int i = find_free_spot (tmp, op->map, op->x, op->y, 1, SIZEOFFREE1 + 1);
337
338 /* If there is a free spot, move the object someplace */
339 if (i > 0)
340 {
346 mapxy pos (tmp); 341 mapxy pos (tmp);
347 pos.move (i); 342 pos.move (i);
348 if (pos.normalise ()) 343 if (pos.normalise ())
349 tmp->move_to (pos); 344 tmp->move_to (pos);
345 }
350 } 346 }
351 } 347 }
352 }
353 348
354 /* See if there is still anything blocking the gate */ 349 /* See if there is still anything blocking the gate */
355 for (tmp = op->above; tmp; tmp = tmp->above) 350 for (tmp = op->above; tmp; tmp = tmp->above)
356 if (!QUERY_FLAG (tmp, FLAG_NO_PICK) || QUERY_FLAG (tmp, FLAG_CAN_ROLL) || QUERY_FLAG (tmp, FLAG_ALIVE)) 351 if (!tmp->flag [FLAG_NO_PICK] || tmp->flag [FLAG_CAN_ROLL] || tmp->flag [FLAG_ALIVE])
357 break; 352 break;
358 353
359 /* IF there is, start putting the gate down */ 354 /* IF there is, start putting the gate down */
360 if (tmp) 355 if (tmp)
361 op->stats.food = 1; 356 op->stats.food = 1;
362 else 357 else
363 { 358 {
364 op->move_block = MOVE_ALL; 359 op->move_block = MOVE_ALL;
365 360
366 if (!op->arch->stats.ac) 361 if (!op->arch->stats.ac)
367 SET_FLAG (op, FLAG_BLOCKSVIEW); 362 op->set_flag (FLAG_BLOCKSVIEW);
363
368 update_all_los (op->map, op->x, op->y); 364 update_all_los (op->map, op->x, op->y);
369 } 365 }
370 } /* gate is halfway up */ 366 } /* gate is halfway up */
371
372 SET_ANIMATION (op, op->stats.wc);
373 update_object (op, UP_OBJ_CHANGE);
374 } /* gate is going up */ 367 } /* gate is going up */
368 }
369
370 op->update_anim_frame (op->stats.wc);
375} 371}
376 372
377/* hp : how long door is open/closed 373/* hp : how long door is open/closed
378 * maxhp : initial value for hp 374 * maxhp : initial value for hp
379 * sp : 1 = open, 0 = close 375 * sp : 1 = open, 0 = close
470} 466}
471 467
472void 468void
473animate_trigger (object *op) 469animate_trigger (object *op)
474{ 470{
475 if ((unsigned char) ++op->stats.wc >= NUM_ANIMATIONS (op)) 471 if (uint32_t (++op->stats.wc) >= op->anim_frames ())
476 { 472 {
477 op->stats.wc = 0; 473 op->stats.wc = 0;
478 check_trigger (op, NULL); 474 check_trigger (op, NULL);
479 } 475 }
480 else 476 else
481 { 477 op->update_anim_frame (op->stats.wc);
482 SET_ANIMATION (op, op->stats.wc);
483 update_object (op, UP_OBJ_FACE);
484 }
485} 478}
486 479
487static void 480static void
488move_hole (object *op) 481move_hole (object *op)
489{ /* 1 = opening, 0 = closing */ 482{ /* 1 = opening, 0 = closing */
490 if (op->value) 483 if (op->value)
491 { /* We're opening */ 484 {
485 /* We're opening */
486 op->stats.wc--;
492 if (--op->stats.wc <= 0) 487 if (op->stats.wc <= 0)
493 { /* Opened, let's stop */ 488 { /* Opened, let's stop */
494 op->stats.wc = 0; 489 op->stats.wc = 0;
495 op->set_speed (0); 490 op->set_speed (0);
496 491
497 /* Hard coding this makes sense for holes I suppose */ 492 /* Hard coding this makes sense for holes I suppose */
500 { 495 {
501 next = tmp->above; 496 next = tmp->above;
502 move_apply (op, tmp, tmp); 497 move_apply (op, tmp, tmp);
503 } 498 }
504 } 499 }
505 500 }
506 SET_ANIMATION (op, op->stats.wc); 501 else
507 update_object (op, UP_OBJ_FACE);
508 return;
509 } 502 {
510
511 /* We're closing */ 503 /* We're closing */
512 op->move_on = 0; 504 op->move_on = 0;
513 505
514 op->stats.wc++; 506 op->stats.wc++;
515 if ((int) op->stats.wc >= NUM_ANIMATIONS (op)) 507 if (op->stats.wc >= op->anim_frames ())
516 op->stats.wc = NUM_ANIMATIONS (op) - 1; 508 {
517 509 op->stats.wc = op->anim_frames () - 1;
518 SET_ANIMATION (op, op->stats.wc);
519 update_object (op, UP_OBJ_FACE);
520 if ((unsigned char) op->stats.wc == (NUM_ANIMATIONS (op) - 1))
521 op->set_speed (0); /* closed, let's stop */ 510 op->set_speed (0); /* closed, let's stop */
511 }
512 }
513
514 op->update_anim_frame (op->stats.wc);
522} 515}
523 516
524 517
525/* stop_item() returns a pointer to the stopped object. The stopped object 518/* stop_item() returns a pointer to the stopped object. The stopped object
526 * may or may not have been removed from maps or inventories. It will not 519 * may or may not have been removed from maps or inventories. It will not
573fix_stopped_item (object *op, maptile *map, object *originator) 566fix_stopped_item (object *op, maptile *map, object *originator)
574{ 567{
575 if (map == NULL) 568 if (map == NULL)
576 return; 569 return;
577 570
578 if (QUERY_FLAG (op, FLAG_REMOVED)) 571 if (op->flag [FLAG_REMOVED])
579 insert_ob_in_map (op, map, originator, 0); 572 insert_ob_in_map (op, map, originator, 0);
580 else if (op->type == ARROW) 573 else if (op->type == ARROW)
581 merge_ob (op, NULL); /* only some arrows actually need this */ 574 merge_ob (op, NULL); /* only some arrows actually need this */
582} 575}
583 576
609 op->stats.hp = 0; 602 op->stats.hp = 0;
610 op->stats.grace = 0; 603 op->stats.grace = 0;
611 op->level = 0; 604 op->level = 0;
612 op->face = op->arch->face; 605 op->face = op->arch->face;
613 op->owner = 0; 606 op->owner = 0;
607
608 op->clr_flag (FLAG_NO_PICK); /* fire_bow makes arrows NO_PICK so monsters (or anything else) don't pick them mid-flight */
614 609
615 update_object (op, UP_OBJ_CHANGE); 610 update_object (op, UP_OBJ_CHANGE);
616 611
617 return op; 612 return op;
618} 613}
646 if (op) 641 if (op)
647 merge_ob (op, 0); 642 merge_ob (op, 0);
648 } 643 }
649} 644}
650 645
651/* Move an arrow along its course. op is the arrow or thrown object. 646/* Move an arrow or throwen_obj along its course. op is the arrow or thrown object.
652 */ 647 */
653void 648void
654move_arrow (object *op) 649move_arrow (object *op)
655{ 650{
656 int was_reflected; 651 int was_reflected;
657 652
658 if (!op->map) 653 if (!op->map)
659 { 654 {
660 LOG (llevError, "BUG: Arrow had no map.\n"); 655 LOG (llevError | logBacktrace, "BUG: Arrow %s had no map.\n", op->debug_desc ());
661 op->destroy (); 656 op->destroy ();
662 return; 657 return;
663 } 658 }
664 659
665 /* we need to stop thrown objects at some point. Like here. */ 660 /* we need to stop thrown objects at some point. Like here. */
684 stop_arrow (op); 679 stop_arrow (op);
685 return; 680 return;
686 } 681 }
687 } 682 }
688 683
684 /* decrease the speed as it flies. 0.05 means a standard bow will shoot
685 * about 17 squares. Tune as needed.
686 */
687 op->set_speed (op->speed - 0.05);
688
689 /* if the arrow is moving too slow.. stop it. 0.5 was chosen as lower 689 /* if the arrow is moving too slow.. stop it. 0.5 was chosen as lower
690 values look rediculous. */ 690 values look ridiculous. */
691 if (op->speed < 0.5 && op->type == ARROW) 691 if (op->speed < (op->type == ARROW ? 0.5 : MIN_ACTIVE_SPEED))
692 { 692 {
693 stop_arrow (op); 693 stop_arrow (op);
694 return; 694 return;
695 } 695 }
696 696
709 if (pos->flags () & P_IS_ALIVE) 709 if (pos->flags () & P_IS_ALIVE)
710 { 710 {
711 object *tmp; 711 object *tmp;
712 712
713 for (tmp = pos->bot; tmp; tmp = tmp->above) 713 for (tmp = pos->bot; tmp; tmp = tmp->above)
714 if (QUERY_FLAG (tmp, FLAG_ALIVE)) 714 if (tmp->flag [FLAG_ALIVE] && tmp != op->owner)
715 break; 715 {
716
717 /* Not really fair, but don't let monsters hit themselves with 716 /* Not really fair, but don't let monsters hit themselves with
718 * their own arrow - this can be because they fire it then 717 * their own arrow - this can be because they fire it then
719 * move into it. 718 * move into it.
720 */ 719 */
721 if (tmp && tmp != op->owner) 720
722 {
723 /* Found living object, but it is reflecting the missile. Update 721 /* Found living object, but it is reflecting the missile. Update
724 * as below. (Note that for living creatures there is a small 722 * as below. (Note that for living creatures there is a small
725 * chance that reflect_missile fails.) 723 * chance that reflect_missile fails.)
726 */ 724 */
727 if (QUERY_FLAG (tmp, FLAG_REFL_MISSILE) && (rndm (0, 99)) < (90 - op->level / 10)) 725 if (tmp->flag [FLAG_REFL_MISSILE] && (rndm (0, 99)) < (90 - op->level / 10))
728 { 726 {
729 int number = op->face;
730
731 op->direction = absdir (op->direction + 4); 727 op->direction = absdir (op->direction + 4);
732 update_turn_face (op); 728 update_turn_face (op);
733 was_reflected = 1; /* skip normal movement calculations */ 729 was_reflected = 1; /* skip normal movement calculations */
734 } 730 }
735 else 731 else
736 { 732 {
737 /* Attack the object. */ 733 /* Attack the object. */
738 op = hit_with_arrow (op, tmp); 734 op = hit_with_arrow (op, tmp);
739 735
740 if (!op) 736 if (!op)
741 return; 737 return;
742 } 738 }
743 } /* if this is not hitting its owner */ 739
744 } /* if there is something alive on this space */ 740 break;
741 }
742 }
745 743
746 if (OB_TYPE_MOVE_BLOCK (op, pos->move_block)) 744 if (OB_TYPE_MOVE_BLOCK (op, pos->move_block))
747 { 745 {
748 int retry = 0; 746 int retry = 0;
749 747
751 * note that this code will now catch cases where a monster is 749 * note that this code will now catch cases where a monster is
752 * on a wall but has reflecting - the arrow won't reflect. 750 * on a wall but has reflecting - the arrow won't reflect.
753 * Mapmakers shouldn't put monsters on top of wall in the first 751 * Mapmakers shouldn't put monsters on top of wall in the first
754 * place, so I don't consider that a problem. 752 * place, so I don't consider that a problem.
755 */ 753 */
756 if (!QUERY_FLAG (op, FLAG_REFLECTING) || !(rndm (0, 19))) 754 if (!op->flag [FLAG_REFLECTING] || !rndm (0, 19))
757 { 755 {
758 stop_arrow (op); 756 stop_arrow (op);
759 return; 757 return;
760 } 758 }
761 else 759 else
815 if (op->has_anim ()) 813 if (op->has_anim ())
816 op->set_anim_frame (op->direction); 814 op->set_anim_frame (op->direction);
817 } /* object is reflected */ 815 } /* object is reflected */
818 } /* object ran into a wall */ 816 } /* object ran into a wall */
819 817
820 /* decrease the speed as it flies. 0.05 means a standard bow will shoot
821 * about 17 squares. Tune as needed.
822 */
823 op->speed -= 0.05;
824
825 /* Move the arrow. */ 818 /* Move the arrow. */
826 op->move_to (pos); 819 op->move_to (pos);
827} 820}
828 821
829static void 822static void
830change_object (object *op) 823change_object (object *op)
831{ /* Doesn`t handle linked objs yet */ 824{ /* Doesn`t handle linked objs yet */
832 int i, j;
833
834 if (!op->other_arch) 825 if (!op->other_arch)
835 { 826 {
836 LOG (llevError, "Change object (%s) without other_arch error.\n", op->debug_desc ()); 827 LOG (llevError, "Change object (%s) without other_arch error.\n", op->debug_desc ());
837 return; 828 return;
838 } 829 }
839 830
840 /* In non-living items only change when food value is 0 */ 831 /* In non-living items only change when food value is 0 */
841 if (!QUERY_FLAG (op, FLAG_ALIVE)) 832 if (!op->flag [FLAG_ALIVE])
842 { 833 {
843 if (op->stats.food-- > 0) 834 if (op->stats.food-- > 0)
844 return; 835 return;
845 836
846 op->stats.food = 1; /* so 1 other_arch is made */ 837 op->stats.food = 1; /* so 1 other_arch is made */
847 } 838 }
848 839
849 object *env = op->env; 840 object *env = op->env;
850 841
851 op->remove (); 842 op->remove ();
852 for (i = 0; i < op->stats.food; i++) 843 for (int i = 0; i < op->stats.food; i++)
853 { 844 {
854 object *tmp = arch_to_object (op->other_arch); 845 object *tmp = op->other_arch->instance ();
855 846
856 tmp->stats.hp = op->stats.hp; /* The only variable it keeps. */ 847 tmp->stats.hp = op->stats.hp; /* The only variable it keeps. */
857 848
858 if (env) 849 if (env)
859 env->insert (tmp); 850 env->insert (tmp);
860 else 851 else
861 { 852 {
862 j = find_first_free_spot (tmp, op->map, op->x, op->y); 853 int j = find_first_free_spot (tmp, op->map, op->x, op->y);
854
863 if (j < 0) /* No free spot */ 855 if (j < 0) /* No free spot */
864 tmp->destroy (); 856 tmp->destroy ();
865 else 857 else
866 { 858 {
867 mapxy pos (op); pos.move (j); 859 mapxy pos (op); pos.move (j);
892 884
893 if (op->head) 885 if (op->head)
894 head = op->head; 886 head = op->head;
895 887
896 for (tmp = op->above; tmp; tmp = tmp->above) 888 for (tmp = op->above; tmp; tmp = tmp->above)
897 if (!QUERY_FLAG (tmp, FLAG_IS_FLOOR)) 889 if (!tmp->flag [FLAG_IS_FLOOR])
898 break; 890 break;
899 891
900 /* If nothing above us to move, nothing to do */ 892 /* If nothing above us to move, nothing to do */
901 if (!tmp || QUERY_FLAG (tmp, FLAG_WIZPASS)) 893 if (!tmp || tmp->flag [FLAG_WIZPASS])
902 return; 894 return;
903 895
904 if (EXIT_PATH (head)) 896 if (EXIT_PATH (head))
905 { 897 {
906 if (tmp->type == PLAYER) 898 if (tmp->type == PLAYER)
1005 } 997 }
1006 998
1007 cast_spell (op, op, op->stats.sp ? op->stats.sp : rndm (1, 8), spell, NULL); 999 cast_spell (op, op, op->stats.sp ? op->stats.sp : rndm (1, 8), spell, NULL);
1008} 1000}
1009 1001
1010/* move_player_mover: this function takes a "player mover" as an 1002/* move_player_mover: this function takes a "player mover" as an
1011 * argument, and performs the function of a player mover, which is: 1003 * argument, and performs the function of a player mover, which is:
1012 * 1004 *
1013 * a player mover finds any players that are sitting on it. It 1005 * a player mover finds any players that are sitting on it. It
1014 * moves them in the op->stats.sp direction. speed is how often it'll move. 1006 * moves them in the op->stats.sp direction. speed is how often it'll move.
1015 * If attacktype is nonzero it will paralyze the player. If lifesave is set, 1007 * If attacktype is nonzero it will paralyze the player. If lifesave is set,
1017 * it'll paralyze the victim for hp*his speed/op->speed 1009 * it'll paralyze the victim for hp*his speed/op->speed
1018 */ 1010 */
1019static void 1011static void
1020move_player_mover (object *op) 1012move_player_mover (object *op)
1021{ 1013{
1022 int dir = op->stats.sp; 1014 int dir = 0;
1023 sint16 nx, ny;
1024 maptile *m;
1025
1026 /* Determine direction now for random movers so we do the right thing */
1027 if (!dir)
1028 dir = rndm (1, 8);
1029 1015
1030 for (object *victim = op->ms ().bot; victim; victim = victim->above) 1016 for (object *victim = op->ms ().bot; victim; victim = victim->above)
1031 { 1017 {
1032 if (QUERY_FLAG (victim, FLAG_ALIVE) && !QUERY_FLAG (victim, FLAG_WIZPASS) && 1018 if (victim->flag [FLAG_ALIVE]
1019 && !victim->flag [FLAG_WIZPASS]
1033 (victim->move_type & op->move_type || !victim->move_type)) 1020 && (victim->move_type & op->move_type || !victim->move_type))
1021 {
1022 if (op->flag [FLAG_LIFESAVE] && op->stats.hp-- < 0)
1034 { 1023 {
1024 op->destroy ();
1025 return;
1026 }
1027
1028 /* Determine direction only once so we do the right thing */
1029 // why is it the right thing, though?
1030 if (!dir)
1031 dir = op->stats.sp ? op->stats.sp : rndm (1, 8);
1032
1033 sint16 nx = op->x + DIRX (dir);
1034 sint16 ny = op->y + DIRY (dir);
1035 maptile *m = op->map;
1036 if (get_map_flags (m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP)
1037 {
1038 LOG (llevError, "move_player_mover: Trying to push player off the map! map=%s (%d, %d)\n", &m->path, op->x, op->y);
1039 return;
1040 }
1035 1041
1036 if (victim->head) 1042 if (victim->head)
1037 victim = victim->head; 1043 victim = victim->head;
1038 1044
1039 if (QUERY_FLAG (op, FLAG_LIFESAVE) && op->stats.hp-- < 0)
1040 {
1041 op->remove ();
1042 return;
1043 }
1044
1045 nx = op->x + freearr_x[dir];
1046 ny = op->y + freearr_y[dir];
1047 m = op->map;
1048 if (get_map_flags (m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP)
1049 {
1050 LOG (llevError, "move_player_mover: Trying to push player off the map! map=%s (%d, %d)\n", &m->path, op->x, op->y);
1051 return;
1052 }
1053
1054 if (should_director_abort (op, victim)) 1045 if (should_director_abort (op, victim))
1055 return; 1046 return;
1056 1047
1057 for (object *nextmover = m->at (nx, ny).bot; nextmover; nextmover = nextmover->above) 1048 for (object *nextmover = m->at (nx, ny).bot; nextmover; nextmover = nextmover->above)
1058 { 1049 {
1059 if (nextmover->type == PLAYERMOVER) 1050 if (nextmover->type == PLAYERMOVER)
1060 nextmover->speed_left = -.99f; 1051 nextmover->speed_left = -.99f;
1061 1052
1062 if (QUERY_FLAG (nextmover, FLAG_ALIVE)) 1053 if (nextmover->flag [FLAG_ALIVE])
1063 op->speed_left = -1.1f; /* wait until the next thing gets out of the way */ 1054 op->speed_left = -1.1f; /* wait until the next thing gets out of the way */
1064 } 1055 }
1065 1056
1066 if (victim->type == PLAYER) 1057 if (victim->type == PLAYER)
1067 { 1058 {
1079 } 1070 }
1080 else 1071 else
1081 return; 1072 return;
1082 } 1073 }
1083 else 1074 else
1084 move_object (victim, dir); 1075 victim->move (dir);
1085 1076
1086 if (!op->stats.maxsp && op->attacktype) 1077 if (!op->stats.maxsp && op->attacktype)
1087 op->stats.maxsp = 2; 1078 op->stats.maxsp = 2;
1088 1079
1089 if (op->attacktype) 1080 if (op->attacktype)
1090 { /* flag to paralyze the player */ 1081 { /* flag to paralyze the player */
1091 victim->speed_left = max (-5.f, -fabs (op->stats.maxsp * victim->speed / op->speed)); 1082 victim->speed_left = max (-5.f, -op->stats.maxsp * victim->speed / op->speed);
1092 } 1083 }
1093 } 1084 }
1094 } 1085 }
1095} 1086}
1096 1087
1134 break; 1125 break;
1135 } 1126 }
1136 } 1127 }
1137} 1128}
1138 1129
1139/* move_creator (by peterm) 1130/* move_creator (by peterm)
1140 * it has the creator object create it's other_arch right on top of it. 1131 * it has the creator object create it's other_arch right on top of it.
1141 * connected: what will trigger it 1132 * connected: what will trigger it
1142 * hp: how many times it may create before stopping 1133 * hp: how many times it may create before stopping
1143 * lifesave: if set, it'll never disappear but will go on creating 1134 * lifesave: if set, it'll never disappear but will go on creating
1144 * everytime it's triggered 1135 * everytime it's triggered
1152void 1143void
1153move_creator (object *creator) 1144move_creator (object *creator)
1154{ 1145{
1155 object *new_ob; 1146 object *new_ob;
1156 1147
1157 if (!QUERY_FLAG (creator, FLAG_LIFESAVE) && --creator->stats.hp < 0) 1148 if (!creator->flag [FLAG_LIFESAVE] && --creator->stats.hp < 0)
1158 { 1149 {
1159 creator->stats.hp = -1; 1150 creator->stats.hp = -1;
1160 return; 1151 return;
1161 } 1152 }
1162 1153
1166 int i; 1157 int i;
1167 object *ob_to_copy; 1158 object *ob_to_copy;
1168 1159
1169 /* select random object from inventory to copy */ 1160 /* select random object from inventory to copy */
1170 ob_to_copy = creator->inv; 1161 ob_to_copy = creator->inv;
1171 for (ob = creator->inv->below, i = 1; ob != NULL; ob = ob->below, i++) 1162 for (ob = creator->inv->below, i = 1; ob; ob = ob->below, i++)
1172 { 1163 {
1173 if (rndm (0, i) == 0) 1164 if (rndm (0, i) == 0)
1174 { 1165 {
1175 ob_to_copy = ob; 1166 ob_to_copy = ob;
1176 } 1167 }
1177 } 1168 }
1169
1178 new_ob = ob_to_copy->deep_clone (); 1170 new_ob = ob_to_copy->deep_clone ();
1179 CLEAR_FLAG (new_ob, FLAG_IS_A_TEMPLATE); 1171 new_ob->clr_flag (FLAG_IS_A_TEMPLATE);
1180 unflag_inv (new_ob, FLAG_IS_A_TEMPLATE); 1172 unflag_inv (new_ob, FLAG_IS_A_TEMPLATE);
1181 } 1173 }
1182 else 1174 else
1183 { 1175 {
1184 if (!creator->other_arch) 1176 if (!creator->other_arch)
1199 return; 1191 return;
1200 } 1192 }
1201 1193
1202 // for now lets try to identify everything generated here, it mostly 1194 // for now lets try to identify everything generated here, it mostly
1203 // happens automated, so this will at least fix many identify-experience holes 1195 // happens automated, so this will at least fix many identify-experience holes
1204 SET_FLAG (new_ob, FLAG_IDENTIFIED); 1196 if (new_ob->need_identify ())
1197 new_ob->set_flag (FLAG_IDENTIFIED);
1205 1198
1206 insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y); 1199 insert_ob_in_map_at (new_ob, creator->map, creator, 0, creator->x, creator->y);
1207 if (QUERY_FLAG (new_ob, FLAG_FREED)) 1200 if (new_ob->flag [FLAG_FREED])
1208 return; 1201 return;
1209 1202
1210 if (creator->slaying) 1203 if (creator->slaying)
1211 new_ob->name = new_ob->title = creator->slaying; 1204 new_ob->name = new_ob->title = creator->slaying;
1212} 1205}
1297} 1290}
1298 1291
1299void 1292void
1300process_object (object *op) 1293process_object (object *op)
1301{ 1294{
1302 if (expect_false (QUERY_FLAG (op, FLAG_IS_A_TEMPLATE))) 1295 if (ecb_expect_false (op->flag [FLAG_IS_A_TEMPLATE]))
1303 return; 1296 return;
1304 1297
1305 if (expect_false (INVOKE_OBJECT (TICK, op))) 1298 if (ecb_expect_false (INVOKE_OBJECT (TICK, op)))
1306 return; 1299 return;
1307 1300
1308 if (QUERY_FLAG (op, FLAG_MONSTER)) 1301 if (op->flag [FLAG_MONSTER])
1309 if (move_monster (op) || QUERY_FLAG (op, FLAG_FREED)) 1302 if (move_monster (op) || op->flag [FLAG_FREED])
1310 return; 1303 return;
1311 1304
1312 if (QUERY_FLAG (op, FLAG_ANIMATE) && op->anim_speed == 0) 1305 if (op->flag [FLAG_ANIMATE] && op->anim_speed == 0)
1313 { 1306 {
1314 animate_object (op, op->contr ? op->facing : op->direction); 1307 animate_object (op, op->contr ? op->facing : op->direction);
1315 1308
1316 if (QUERY_FLAG (op, FLAG_SEE_ANYWHERE)) 1309 if (op->flag [FLAG_SEE_ANYWHERE])
1317 make_sure_seen (op); 1310 make_sure_seen (op);
1318 } 1311 }
1319 1312
1320 if (expect_false ( 1313 if (ecb_expect_false (
1321 op->flag [FLAG_GENERATOR] 1314 op->flag [FLAG_GENERATOR]
1322 || op->flag [FLAG_CHANGING] 1315 || op->flag [FLAG_CHANGING]
1323 || op->flag [FLAG_IS_USED_UP] 1316 || op->flag [FLAG_IS_USED_UP]
1324 )) 1317 ))
1325 { 1318 {
1326 if (QUERY_FLAG (op, FLAG_CHANGING) && !op->state) 1319 if (op->flag [FLAG_CHANGING] && !op->state)
1327 { 1320 {
1328 change_object (op); 1321 change_object (op);
1329 return; 1322 return;
1330 } 1323 }
1331 1324
1332 if (QUERY_FLAG (op, FLAG_GENERATOR) && !QUERY_FLAG (op, FLAG_FRIENDLY)) 1325 if (op->flag [FLAG_GENERATOR] && !op->flag [FLAG_FRIENDLY])
1333 generate_monster (op); 1326 generate_monster (op);
1334 1327
1335 if (QUERY_FLAG (op, FLAG_IS_USED_UP) && --op->stats.food <= 0) 1328 if (op->flag [FLAG_IS_USED_UP] && --op->stats.food <= 0)
1336 { 1329 {
1337 if (QUERY_FLAG (op, FLAG_APPLIED)) 1330 if (op->flag [FLAG_APPLIED])
1338 remove_force (op); 1331 remove_force (op);
1339 else 1332 else
1340 { 1333 {
1341 op->remove (); // TODO: really necessary? 1334 op->remove (); // TODO: really necessary?
1342 1335
1343 if (QUERY_FLAG (op, FLAG_SEE_ANYWHERE)) 1336 if (op->flag [FLAG_SEE_ANYWHERE])
1344 make_sure_not_seen (op); 1337 make_sure_not_seen (op);
1345 1338
1346 op->drop_and_destroy (); 1339 op->drop_and_destroy ();
1347 } 1340 }
1348 1341
1484 1477
1485 case LAMP: 1478 case LAMP:
1486 case TORCH: 1479 case TORCH:
1487 move_lamp (op); 1480 move_lamp (op);
1488 break; 1481 break;
1489 }
1490}
1491 1482
1483 case PHYSICS: // hmm, bad naming
1484 move_physics (op);
1485 break;
1486 }
1487}
1488

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines