ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/button.C
Revision: 1.20
Committed: Tue Dec 26 08:54:58 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.19: +10 -16 lines
Log Message:
replace update_ob_speed by ->set_speed

File Contents

# Content
1 /*
2 CrossFire, A Multiplayer game for X-windows
3
4 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
5 Copyright (C) 1992 Frank Tore Johansen
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 The authors can be reached via e-mail at <crossfire@schmorp.de>
22 */
23
24 #include <global.h>
25 #include <funcpoint.h>
26
27 /*
28 * This code is no longer highly inefficient 8)
29 */
30
31 /*
32 * elmex:
33 * This function takes a objectlink list with all the objects are going to be activated.
34 * state is a true/false flag that will actiavte objects that have FLAG_ACTIVATE_ON_PUSH/RELEASE set.
35 * The source argument can be 0 or the source object for this activation.
36 */
37 void
38 activate_connection_link (objectlink * ol, bool state, object *source = 0)
39 {
40 for (; ol; ol = ol->next)
41 {
42 if (!ol->ob)
43 {
44 LOG (llevError, "Internal error in activate_connection_link.\n");
45 continue;
46 }
47
48 /* a button link object can become freed when the map is saving. As
49 * a map is saved, objects are removed and freed, and if an object is
50 * on top of a button, this function is eventually called. If a map
51 * is getting moved out of memory, the status of buttons and levers
52 * probably isn't important - it will get sorted out when the map is
53 * re-loaded. As such, just exit this function if that is the case.
54 */
55
56 if (QUERY_FLAG (ol->ob, FLAG_FREED))
57 return;
58
59 object *tmp = ol->ob;
60
61 /* if the criteria isn't appropriate, don't do anything */
62 if (state && !QUERY_FLAG (tmp, FLAG_ACTIVATE_ON_PUSH))
63 continue;
64 if (!state && !QUERY_FLAG (tmp, FLAG_ACTIVATE_ON_RELEASE))
65 continue;
66
67 switch (tmp->type)
68 {
69 case GATE:
70 case HOLE:
71 tmp->value = tmp->stats.maxsp ? !state : state;
72 tmp->set_speed (0.5);
73 break;
74
75 case CF_HANDLE:
76 SET_ANIMATION (tmp, (tmp->value = tmp->stats.maxsp ? !state : state));
77 update_object (tmp, UP_OBJ_FACE);
78 break;
79
80 case SIGN:
81 if (!tmp->stats.food || tmp->last_eat < tmp->stats.food)
82 {
83 new_info_map (NDI_UNIQUE | NDI_NAVY, tmp->map, tmp->msg);
84 if (tmp->stats.food)
85 tmp->last_eat++;
86 }
87 break;
88
89 case ALTAR:
90 tmp->value = 1;
91 SET_ANIMATION (tmp, tmp->value);
92 update_object (tmp, UP_OBJ_FACE);
93 break;
94
95 case BUTTON:
96 case PEDESTAL:
97 tmp->value = state;
98 SET_ANIMATION (tmp, tmp->value);
99 update_object (tmp, UP_OBJ_FACE);
100 break;
101
102 case MOOD_FLOOR:
103 do_mood_floor (tmp, source);
104 break;
105
106 case TIMED_GATE:
107 tmp->set_speed (tmp->arch->clone.speed);
108 tmp->value = tmp->arch->clone.value;
109 tmp->stats.sp = 1;
110 tmp->stats.hp = tmp->stats.maxhp;
111 /* Handle multipart gates. We copy the value for the other parts
112 * from the head - this ensures that the data will consistent
113 */
114 for (tmp = tmp->more; tmp; tmp = tmp->more)
115 {
116 tmp->value = tmp->head->value;
117 tmp->stats.sp = tmp->head->stats.sp;
118 tmp->stats.hp = tmp->head->stats.hp;
119 tmp->set_speed (tmp->head->speed);
120 }
121 break;
122
123 case DIRECTOR:
124 case FIREWALL:
125 if (!QUERY_FLAG (tmp, FLAG_ANIMATE) && tmp->type == FIREWALL)
126 move_firewall (tmp);
127 else
128 {
129 if ((tmp->stats.sp += tmp->stats.maxsp) > 8) /* next direction */
130 tmp->stats.sp = ((tmp->stats.sp - 1) % 8) + 1;
131 animate_turning (tmp);
132 }
133 break;
134
135 case TELEPORTER:
136 move_teleporter (tmp);
137 break;
138
139 case CREATOR:
140 move_creator (tmp);
141 break;
142
143 case TRIGGER_MARKER:
144 move_marker (tmp);
145 break;
146
147 case DUPLICATOR:
148 move_duplicator (tmp);
149 break;
150 }
151 }
152 }
153
154 /*
155 * elmex:
156 * This is the new push_button function, it got split up so that
157 * you can activate connections without a button now!
158 * old but still valid comment:
159 *
160 * Push the specified object. This can affect other buttons/gates/handles
161 * altars/pedestals/holes in the whole map.
162 * Changed the routine to loop through _all_ objects.
163 * Better hurry with that linked list...
164 *
165 */
166 void
167 push_button (object *op)
168 {
169 oblinkpt *obp = get_button_links (op);
170
171 if (!obp)
172 return;
173
174 if (INVOKE_MAP (TRIGGER, op->map, ARG_INT64 (obp->value), ARG_INT (op->value)))
175 return;
176
177 activate_connection_link (obp->link, op->value, op);
178 }
179
180 /*
181 * elmex:
182 * This activates a connection, similar to push_button (object *op) but it takes
183 * only a map, a connection value and a true or false flag that indicated whether
184 * the connection was 'state' or 'released'. So that you can activate objects
185 * who have FLAG_ACTIVATE_ON_PUSH/RELEASE set properly.
186 *
187 */
188 void
189 activate_connection (maptile *map, long connection, bool state)
190 {
191 if (INVOKE_MAP (TRIGGER, map, ARG_INT64 (connection), ARG_INT (state)))
192 return;
193
194 oblinkpt *obp = get_connection_links (map, connection);
195
196 if (obp)
197 activate_connection_link (obp->link, state);
198 }
199
200 /*
201 * Updates everything connected with the button op.
202 * After changing the state of a button, this function must be called
203 * to make sure that all gates and other buttons connected to the
204 * button reacts to the (eventual) change of state.
205 */
206 void
207 update_button (object *op)
208 {
209 object *ab, *tmp, *head;
210 int tot, any_down = 0, old_value = op->value;
211 oblinkpt *obp = 0;
212 objectlink *ol;
213
214 obp = get_button_links (op);
215 /* LOG(llevDebug, "update_button: %s (%d)\n", op->name, op->count); */
216 if (obp)
217 for (ol = obp->link; ol; ol = ol->next)
218 {
219 if (!ol->ob)
220 {
221 LOG (llevDebug, "Internal error in update_button (%s).\n", &op->name);
222 continue;
223 }
224
225 tmp = ol->ob;
226 if (tmp->type == BUTTON)
227 {
228 for (ab = tmp->above, tot = 0; ab != NULL; ab = ab->above)
229 /* Bug? The pedestal code below looks for the head of
230 * the object, this bit doesn't. I'd think we should check
231 * for head here also. Maybe it also makese sense to
232 * make the for ab=tmp->above loop common, and alter
233 * behaviour based on object within that loop?
234 */
235
236 /* Basically, if the move_type matches that on what the
237 * button wants, we count it. The second check is so that
238 * objects don't move (swords, etc) will count. Note that
239 * this means that more work is needed to make buttons
240 * that are only triggered by flying objects.
241 */
242 if ((ab->move_type & tmp->move_on) || ab->move_type == 0)
243 tot += ab->weight * (ab->nrof ? ab->nrof : 1) + ab->carrying;
244
245 tmp->value = (tot >= tmp->weight) ? 1 : 0;
246 if (tmp->value)
247 any_down = 1;
248 }
249 else if (tmp->type == PEDESTAL)
250 {
251 tmp->value = 0;
252 for (ab = tmp->above; ab != NULL; ab = ab->above)
253 {
254 head = ab->head ? ab->head : ab;
255 /* Same note regarding move_type for buttons above apply here. */
256 if (((head->move_type & tmp->move_on) || ab->move_type == 0) &&
257 (head->race == tmp->slaying ||
258 ((head->type == SPECIAL_KEY) && (head->slaying == tmp->slaying)) ||
259 (!strcmp (tmp->slaying, "player") && head->type == PLAYER)))
260 tmp->value = 1;
261 }
262 if (tmp->value)
263 any_down = 1;
264 }
265 }
266 if (any_down) /* If any other buttons were down, force this to remain down */
267 op->value = 1;
268
269 /* If this button hasn't changed, don't do anything */
270 if (op->value != old_value)
271 {
272 SET_ANIMATION (op, op->value);
273 update_object (op, UP_OBJ_FACE);
274 push_button (op); /* Make all other buttons the same */
275 }
276 }
277
278 /*
279 * Updates every button on the map (by calling update_button() for them).
280 */
281
282 void
283 update_buttons (maptile *m)
284 {
285 objectlink *ol;
286 oblinkpt *obp;
287
288 for (obp = m->buttons; obp; obp = obp->next)
289 for (ol = obp->link; ol; ol = ol->next)
290 {
291 if (!ol->ob)
292 {
293 LOG (llevError, "Internal error in update_button (%s (%dx%d), connected %ld).\n",
294 ol->ob ? (const char *) ol->ob->name : "null", ol->ob ? ol->ob->x : -1, ol->ob ? ol->ob->y : -1, obp->value);
295 continue;
296 }
297
298 if (ol->ob->type == BUTTON || ol->ob->type == PEDESTAL)
299 {
300 update_button (ol->ob);
301 break;
302 }
303 }
304 }
305
306 void
307 use_trigger (object *op)
308 {
309
310 /* Toggle value */
311 op->value = !op->value;
312 push_button (op);
313 }
314
315 /*
316 * Note: animate_object should be used instead of this,
317 * but it can't handle animations in the 8 directions
318 */
319
320 void
321 animate_turning (object *op) /* only one part objects */
322 {
323 if (++op->state >= NUM_ANIMATIONS (op) / 8)
324 op->state = 0;
325 SET_ANIMATION (op, (op->stats.sp - 1) * NUM_ANIMATIONS (op) / 8 + op->state);
326 update_object (op, UP_OBJ_FACE);
327 }
328
329 #define ARCH_SACRIFICE(xyz) ((xyz)->slaying)
330 #define NROF_SACRIFICE(xyz) ((uint32)(xyz)->stats.food)
331
332 /* Returns true if the sacrifice meets the needs of the altar.
333 *
334 * Function put in (0.92.1) so that identify altars won't grab money
335 * unnecessarily - we can see if there is sufficient money, see if something
336 * needs to be identified, and then remove money if needed.
337 *
338 * 0.93.4: Linked objects (ie, objects that are connected) can not be
339 * sacrificed. This fixes a bug of trying to put multiple altars/related
340 * objects on the same space that take the same sacrifice.
341 */
342
343 int
344 check_altar_sacrifice (const object *altar, const object *sacrifice)
345 {
346 if (!QUERY_FLAG (sacrifice, FLAG_ALIVE) && !QUERY_FLAG (sacrifice, FLAG_IS_LINKED) && sacrifice->type != PLAYER)
347 {
348 if ((ARCH_SACRIFICE (altar) == sacrifice->arch->name ||
349 ARCH_SACRIFICE (altar) == sacrifice->name ||
350 ARCH_SACRIFICE (altar) == sacrifice->slaying ||
351 (!strcmp (ARCH_SACRIFICE (altar), query_base_name (sacrifice, 0))))
352 && NROF_SACRIFICE (altar) <= (sacrifice->nrof ? sacrifice->nrof : 1))
353 return 1;
354
355 if (strcmp (ARCH_SACRIFICE (altar), "money") == 0
356 && sacrifice->type == MONEY && sacrifice->nrof * sacrifice->value >= NROF_SACRIFICE (altar))
357 return 1;
358 }
359
360 return 0;
361 }
362
363 /*
364 * operate_altar checks if sacrifice was accepted and removes sacrificed
365 * objects. If sacrifice was succeed return 1 else 0. Might be better to
366 * call check_altar_sacrifice (above) than depend on the return value,
367 * since operate_altar will remove the sacrifice also.
368 *
369 * If this function returns 1, '*sacrifice' is modified to point to the
370 * remaining sacrifice, or is set to NULL if the sacrifice was used up.
371 */
372 int
373 operate_altar (object *altar, object **sacrifice)
374 {
375 if (!altar->map)
376 {
377 LOG (llevError, "BUG: operate_altar(): altar has no map\n");
378 return 0;
379 }
380
381 if (!altar->slaying || altar->value)
382 return 0;
383
384 if (!check_altar_sacrifice (altar, *sacrifice))
385 return 0;
386
387 /* check_altar_sacrifice should have already verified that enough money
388 * has been dropped.
389 */
390 if (!strcmp (ARCH_SACRIFICE (altar), "money"))
391 {
392 int number = NROF_SACRIFICE (altar) / (*sacrifice)->value;
393
394 /* Round up any sacrifices. Altars don't make change either */
395 if (NROF_SACRIFICE (altar) % (*sacrifice)->value)
396 number++;
397
398 *sacrifice = decrease_ob_nr (*sacrifice, number);
399 }
400 else
401 *sacrifice = decrease_ob_nr (*sacrifice, NROF_SACRIFICE (altar));
402
403 if (altar->msg)
404 new_info_map (NDI_BLACK, altar->map, altar->msg);
405
406 return 1;
407 }
408
409 void
410 trigger_move (object *op, int state) /* 1 down and 0 up */
411 {
412 op->stats.wc = state;
413 if (state)
414 {
415 use_trigger (op);
416 op->set_speed (op->stats.exp > 0 ? 1. / op->stats.exp : 1.);
417 op->speed_left = -1;
418 }
419 else
420 {
421 use_trigger (op);
422 op->set_speed (0);
423 }
424 }
425
426
427 /*
428 * cause != NULL: something has moved on top of op
429 *
430 * cause == NULL: nothing has moved, we have been called from
431 * animate_trigger().
432 *
433 * TRIGGER_ALTAR: Returns 1 if 'cause' was destroyed, 0 if not.
434 *
435 * TRIGGER: Returns 1 if handle could be moved, 0 if not.
436 *
437 * TRIGGER_BUTTON, TRIGGER_PEDESTAL: Returns 0.
438 */
439 int
440 check_trigger (object *op, object *cause)
441 {
442 object *tmp;
443 int push = 0, tot = 0;
444 int in_movement = op->stats.wc || op->speed;
445
446 switch (op->type)
447 {
448 case TRIGGER_BUTTON:
449 if (op->weight > 0)
450 {
451 if (cause)
452 {
453 for (tmp = op->above; tmp; tmp = tmp->above)
454 /* Comment reproduced from update_buttons(): */
455 /* Basically, if the move_type matches that on what the
456 * button wants, we count it. The second check is so that
457 * objects that don't move (swords, etc) will count. Note that
458 * this means that more work is needed to make buttons
459 * that are only triggered by flying objects.
460 */
461
462 if ((tmp->move_type & op->move_on) || tmp->move_type == 0)
463 {
464 tot += tmp->weight * (tmp->nrof ? tmp->nrof : 1) + tmp->carrying;
465 }
466 if (tot >= op->weight)
467 push = 1;
468 if (op->stats.ac == push)
469 return 0;
470 op->stats.ac = push;
471 if (NUM_ANIMATIONS (op) > 1)
472 {
473 SET_ANIMATION (op, push);
474 update_object (op, UP_OBJ_FACE);
475 }
476 if (in_movement || !push)
477 return 0;
478 }
479 trigger_move (op, push);
480 }
481 return 0;
482
483 case TRIGGER_PEDESTAL:
484 if (cause)
485 {
486 for (tmp = op->above; tmp; tmp = tmp->above)
487 {
488 object *head = tmp->head ? tmp->head : tmp;
489
490 /* See comment in TRIGGER_BUTTON about move_types */
491 if (((head->move_type & op->move_on) || head->move_type == 0)
492 && (head->race == op->slaying || (!strcmp (op->slaying, "player") && head->type == PLAYER)))
493 {
494 push = 1;
495 break;
496 }
497 }
498 if (op->stats.ac == push)
499 return 0;
500 op->stats.ac = push;
501 if (NUM_ANIMATIONS (op) > 1)
502 {
503 SET_ANIMATION (op, push);
504 update_object (op, UP_OBJ_FACE);
505 }
506 update_object (op, UP_OBJ_FACE);
507 if (in_movement || !push)
508 return 0;
509 }
510 trigger_move (op, push);
511 return 0;
512
513 case TRIGGER_ALTAR:
514 if (cause)
515 {
516 if (in_movement)
517 return 0;
518 if (operate_altar (op, &cause))
519 {
520 if (NUM_ANIMATIONS (op) > 1)
521 {
522 SET_ANIMATION (op, 1);
523 update_object (op, UP_OBJ_FACE);
524 }
525 if (op->last_sp >= 0)
526 {
527 trigger_move (op, 1);
528 if (op->last_sp > 0)
529 op->last_sp = -op->last_sp;
530 }
531 else
532 {
533 /* for trigger altar with last_sp, the ON/OFF
534 * status (-> +/- value) is "simulated":
535 */
536 op->value = !op->value;
537 trigger_move (op, 1);
538 op->last_sp = -op->last_sp;
539 op->value = !op->value;
540 }
541 return cause == NULL;
542 }
543 else
544 {
545 return 0;
546 }
547 }
548 else
549 {
550 if (NUM_ANIMATIONS (op) > 1)
551 {
552 SET_ANIMATION (op, 0);
553 update_object (op, UP_OBJ_FACE);
554 }
555
556 /* If trigger_altar has "last_sp > 0" set on the map,
557 * it will push the connected value only once per sacrifice.
558 * Otherwise (default), the connected value will be
559 * pushed twice: First by sacrifice, second by reset! -AV
560 */
561 if (!op->last_sp)
562 trigger_move (op, 0);
563 else
564 {
565 op->stats.wc = 0;
566 op->value = !op->value;
567 op->set_speed (0);
568 }
569 }
570 return 0;
571
572 case TRIGGER:
573 if (cause)
574 {
575 if (in_movement)
576 return 0;
577
578 push = 1;
579 }
580
581 if (NUM_ANIMATIONS (op) > 1)
582 {
583 SET_ANIMATION (op, push);
584 update_object (op, UP_OBJ_FACE);
585 }
586
587 trigger_move (op, push);
588 return 1;
589
590 default:
591 LOG (llevDebug, "Unknown trigger type: %s (%d)\n", &op->name, op->type);
592 return 0;
593 }
594 }
595
596 void
597 add_button_link (object *button, maptile *map, int connected)
598 {
599 oblinkpt *obp;
600 objectlink *ol = get_objectlink ();
601
602 if (!map)
603 {
604 LOG (llevError, "Tried to add button-link without map.\n");
605 return;
606 }
607
608 button->path_attuned = connected; /* peterm: I need this so I can rebuild
609 a connected map from a template map. */
610
611 SET_FLAG (button, FLAG_IS_LINKED);
612
613 ol->ob = button;
614
615 for (obp = map->buttons; obp && obp->value != connected; obp = obp->next)
616 ;
617
618 if (obp)
619 {
620 ol->next = obp->link;
621 obp->link = ol;
622 }
623 else
624 {
625 obp = get_objectlinkpt ();
626 obp->value = connected;
627
628 obp->next = map->buttons;
629 map->buttons = obp;
630 obp->link = ol;
631 }
632 }
633
634 /*
635 * Remove the object from the linked lists of buttons in the map.
636 * This is only needed by editors.
637 */
638
639 void
640 remove_button_link (object *op)
641 {
642 oblinkpt *obp;
643 objectlink **olp, *ol;
644
645 if (op->map == NULL)
646 {
647 LOG (llevError, "remove_button_link() in object without map.\n");
648 return;
649 }
650
651 if (!QUERY_FLAG (op, FLAG_IS_LINKED))
652 {
653 LOG (llevError, "remove_button_linked() in unlinked object.\n");
654 return;
655 }
656
657 for (obp = op->map->buttons; obp; obp = obp->next)
658 for (olp = &obp->link; (ol = *olp); olp = &ol->next)
659 if (ol->ob == op)
660 {
661
662 /* LOG(llevDebug, "Removed link %d in button %s and map %s.\n",
663 obp->value, op->name, op->map->path);
664 */
665 *olp = ol->next;
666 delete ol;
667 return;
668 }
669
670 LOG (llevError, "remove_button_linked(): couldn't find object.\n");
671 CLEAR_FLAG (op, FLAG_IS_LINKED);
672 }
673
674 /*
675 * Gets the objectlink for this connection from the map.
676 */
677 oblinkpt *
678 get_connection_links (maptile *map, long connection)
679 {
680 for (oblinkpt * obp = map->buttons; obp; obp = obp->next)
681 if (obp->value == connection)
682 return obp;
683
684 return 0;
685 }
686
687 /*
688 * Return the first objectlink in the objects linked to this one
689 */
690
691 oblinkpt *
692 get_button_links (const object *button)
693 {
694 oblinkpt *obp;
695 objectlink *ol;
696
697 if (!button->map)
698 return NULL;
699
700 for (obp = button->map->buttons; obp; obp = obp->next)
701 for (ol = obp->link; ol; ol = ol->next)
702 if (ol->ob == button)
703 return obp;
704
705 return NULL;
706 }
707
708 /*
709 * Made as a separate function to increase efficiency
710 */
711
712 int
713 get_button_value (const object *button)
714 {
715 oblinkpt *obp;
716 objectlink *ol;
717
718 if (!button->map)
719 return 0;
720 for (obp = button->map->buttons; obp; obp = obp->next)
721 for (ol = obp->link; ol; ol = ol->next)
722 if (ol->ob == button)
723 return obp->value;
724 return 0;
725 }
726
727 /* This routine makes monsters who are
728 * standing on the 'mood floor' change their
729 * disposition if it is different.
730 * If floor is to be triggered must have
731 * a speed of zero (default is 1 for all
732 * but the charm floor type).
733 * by b.t. thomas@nomad.astro.psu.edu
734 */
735
736 void
737 do_mood_floor (object *op, object *source)
738 {
739 object *tmp;
740 object *tmp2;
741
742 if (!source)
743 source = op;
744
745 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp; tmp = tmp->above)
746 if (QUERY_FLAG (tmp, FLAG_MONSTER))
747 break;
748
749 /* doesn't effect players, and if there is a player on this space, won't also
750 * be a monster here.
751 */
752 if (!tmp || tmp->type == PLAYER)
753 return;
754
755 switch (op->last_sp)
756 {
757 case 0: /* furious--make all monsters mad */
758 if (QUERY_FLAG (tmp, FLAG_UNAGGRESSIVE))
759 CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE);
760 if (QUERY_FLAG (tmp, FLAG_FRIENDLY))
761 {
762 CLEAR_FLAG (tmp, FLAG_FRIENDLY);
763 remove_friendly_object (tmp);
764 tmp->attack_movement = 0;
765 /* lots of checks here, but want to make sure we don't
766 * dereference a null value
767 */
768 if (tmp->type == GOLEM && tmp->owner && tmp->owner->type == PLAYER && tmp->owner->contr->ranges[range_golem] == tmp)
769 tmp->owner->contr->ranges[range_golem] = 0;
770
771 tmp->owner = 0;
772 }
773 break;
774 case 1: /* angry -- get neutral monsters mad */
775 if (QUERY_FLAG (tmp, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (tmp, FLAG_FRIENDLY))
776 CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE);
777 break;
778 case 2: /* calm -- pacify unfriendly monsters */
779 if (!QUERY_FLAG (tmp, FLAG_UNAGGRESSIVE))
780 SET_FLAG (tmp, FLAG_UNAGGRESSIVE);
781 break;
782 case 3: /* make all monsters fall asleep */
783 if (!QUERY_FLAG (tmp, FLAG_SLEEP))
784 SET_FLAG (tmp, FLAG_SLEEP);
785 break;
786 case 4: /* charm all monsters */
787 if (op == source)
788 break; /* only if 'connected' */
789
790 for (tmp2 = GET_MAP_OB (source->map, source->x, source->y); /* finding an owner */
791 tmp2->type != PLAYER; tmp2 = tmp2->above)
792 if (tmp2->above == NULL)
793 break;
794
795 if (tmp2->type != PLAYER)
796 break;
797
798 tmp->set_owner (tmp2);
799 SET_FLAG (tmp, FLAG_MONSTER);
800
801 tmp->stats.exp = 0;
802 SET_FLAG (tmp, FLAG_FRIENDLY);
803
804 add_friendly_object (tmp);
805 tmp->attack_movement = PETMOVE;
806 break;
807
808 default:
809 break;
810 }
811 }
812
813 /* this function returns the object it matches, or NULL if non.
814 * It will descend through containers to find the object.
815 * slaying = match object slaying flag
816 * race = match object archetype name flag
817 * hp = match object type (excpt type '0'== PLAYER)
818 */
819 object *
820 check_inv_recursive (object *op, const object *trig)
821 {
822 object *tmp, *ret = NULL;
823
824 /* First check the object itself. */
825 if ((trig->stats.hp && (op->type == trig->stats.hp))
826 || (trig->slaying && (op->slaying == trig->slaying))
827 || (trig->race && (op->arch->name == trig->race)))
828 return op;
829
830 for (tmp = op->inv; tmp; tmp = tmp->below)
831 {
832 if (tmp->inv)
833 {
834 ret = check_inv_recursive (tmp, trig);
835 if (ret)
836 return ret;
837 }
838 else if ((trig->stats.hp && (tmp->type == trig->stats.hp))
839 || (trig->slaying && (tmp->slaying == trig->slaying))
840 || (trig->race && (tmp->arch->name == trig->race)))
841 return tmp;
842 }
843 return NULL;
844 }
845
846 /* check_inv(), a function to search the inventory,
847 * of a player and then based on a set of conditions,
848 * the square will activate connected items.
849 * Monsters can't trigger this square (for now)
850 * Values are: last_sp = 1/0 obj/no obj triggers
851 * last_heal = 1/0 remove/dont remove obj if triggered
852 * -b.t. (thomas@nomad.astro.psu.edu
853 *
854 * Tue Dec 19 15:34:00 CET 2006 elmex: changed the function to ignore op
855 * because the check-inventory semantic essentially only applies when
856 * something is above the inventory checker.
857 * The semantic prior this change was: trigger if something has moved on or off
858 * and has a matching item. Imagine what happens if someone steps on the inventory
859 * checker with a matching item, has it, activates the connection, throws the item
860 * away, and then leaves the inventory checker. That would've caused an always-enabled
861 * state in the inventory checker. This won't happen anymore now.
862 *
863 */
864 void
865 check_inv (object *op, object *trig)
866 {
867 trig->value = 0; // deactivate if none of the following conditions apply
868
869 if (object *pl = trig->ms ().player ())
870 {
871 object *match = check_inv_recursive (pl, trig);
872
873 if (match && trig->last_sp) // match == having
874 {
875 if (trig->last_heal)
876 decrease_ob (match);
877
878 trig->value = 1;
879 }
880 else if (!match && !trig->last_sp) // match == not having
881 trig->value = 1;
882 }
883
884 push_button (trig);
885 }
886