ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/button.C
Revision: 1.31
Committed: Mon Apr 30 04:25:29 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.30: +2 -2 lines
Log Message:
This is the first rough cut of the skill use system (use the STABLE tag).

Details will likely change, and combat skills do not work very well, but
it works quite well.

Players no longer have a shoottype or range slots, instead, each player
has these members:

   combat_skill/combat_ob  the currently selected skill (and weapon)
                           for direct attacks.
   ranged_skill/ranged_ob  the currently selected ranged skill (and
                           bow/spell/item)
   golem                   the currently-controlled golem, if any.

File Contents

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