ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/button.C
Revision: 1.36
Committed: Sun Jul 1 05:00:17 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.35: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.36 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 pippijn 1.27 *
4 root 1.33 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.27 *
8 root 1.36 * Crossfire TRT 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 3 of the License, or
11     * (at your option) any later version.
12 pippijn 1.27 *
13 root 1.36 * 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 pippijn 1.27 *
18 root 1.36 * You should have received a copy of the GNU General Public License
19     * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 root 1.33 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 pippijn 1.27 */
23 elmex 1.1
24     #include <global.h>
25     #include <funcpoint.h>
26    
27     /*
28     * This code is no longer highly inefficient 8)
29     */
30    
31     /*
32 elmex 1.3 * 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 elmex 1.1 */
37 root 1.7 void
38     activate_connection_link (objectlink * ol, bool state, object *source = 0)
39 elmex 1.3 {
40     for (; ol; ol = ol->next)
41     {
42 root 1.12 if (!ol->ob)
43 elmex 1.3 {
44 root 1.12 LOG (llevError, "Internal error in activate_connection_link.\n");
45 elmex 1.3 continue;
46     }
47 root 1.12
48 elmex 1.3 /* 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 elmex 1.1
56 elmex 1.3 if (QUERY_FLAG (ol->ob, FLAG_FREED))
57     return;
58 root 1.19
59     object *tmp = ol->ob;
60 root 1.2
61 elmex 1.3 /* 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 root 1.2
67 elmex 1.3 switch (tmp->type)
68     {
69 root 1.19 case GATE:
70     case HOLE:
71     tmp->value = tmp->stats.maxsp ? !state : state;
72 root 1.20 tmp->set_speed (0.5);
73 root 1.19 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 root 1.35 tmp->set_speed (tmp->arch->speed);
108     tmp->value = tmp->arch->value;
109 root 1.19 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 root 1.32 for (object *part = tmp->more; part; part = part->more)
115 root 1.19 {
116 root 1.32 part->value = tmp->value;
117     part->stats.sp = tmp->stats.sp;
118     part->stats.hp = tmp->stats.hp;
119     part->set_speed (tmp->speed);
120 root 1.19 }
121     break;
122 root 1.7
123 root 1.19 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 root 1.32
132 root 1.19 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 root 1.32 head = ab->head_ ();
256 root 1.7 /* 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.32
264 root 1.7 if (tmp->value)
265     any_down = 1;
266 elmex 1.3 }
267     }
268 root 1.7 if (any_down) /* If any other buttons were down, force this to remain down */
269     op->value = 1;
270 elmex 1.1
271 root 1.7 /* If this button hasn't changed, don't do anything */
272     if (op->value != old_value)
273     {
274     SET_ANIMATION (op, op->value);
275     update_object (op, UP_OBJ_FACE);
276     push_button (op); /* Make all other buttons the same */
277 elmex 1.1 }
278     }
279    
280 root 1.7 void
281     use_trigger (object *op)
282 elmex 1.1 {
283 root 1.7 /* Toggle value */
284     op->value = !op->value;
285     push_button (op);
286 elmex 1.1 }
287    
288     /*
289     * Note: animate_object should be used instead of this,
290     * but it can't handle animations in the 8 directions
291     */
292 root 1.7 void
293     animate_turning (object *op) /* only one part objects */
294 elmex 1.1 {
295 root 1.7 if (++op->state >= NUM_ANIMATIONS (op) / 8)
296     op->state = 0;
297     SET_ANIMATION (op, (op->stats.sp - 1) * NUM_ANIMATIONS (op) / 8 + op->state);
298     update_object (op, UP_OBJ_FACE);
299 elmex 1.1 }
300    
301     #define ARCH_SACRIFICE(xyz) ((xyz)->slaying)
302     #define NROF_SACRIFICE(xyz) ((uint32)(xyz)->stats.food)
303    
304     /* Returns true if the sacrifice meets the needs of the altar.
305     *
306     * Function put in (0.92.1) so that identify altars won't grab money
307     * unnecessarily - we can see if there is sufficient money, see if something
308     * needs to be identified, and then remove money if needed.
309     *
310     * 0.93.4: Linked objects (ie, objects that are connected) can not be
311     * sacrificed. This fixes a bug of trying to put multiple altars/related
312     * objects on the same space that take the same sacrifice.
313     */
314 root 1.7
315     int
316     check_altar_sacrifice (const object *altar, const object *sacrifice)
317 elmex 1.1 {
318 root 1.7 if (!QUERY_FLAG (sacrifice, FLAG_ALIVE) && !QUERY_FLAG (sacrifice, FLAG_IS_LINKED) && sacrifice->type != PLAYER)
319     {
320 root 1.34 if ((ARCH_SACRIFICE (altar) == sacrifice->arch->archname
321     || ARCH_SACRIFICE (altar) == sacrifice->name
322     || ARCH_SACRIFICE (altar) == sacrifice->slaying
323     || (!strcmp (ARCH_SACRIFICE (altar), query_base_name (sacrifice, 0))))
324 root 1.7 && NROF_SACRIFICE (altar) <= (sacrifice->nrof ? sacrifice->nrof : 1))
325     return 1;
326 root 1.17
327 root 1.7 if (strcmp (ARCH_SACRIFICE (altar), "money") == 0
328     && sacrifice->type == MONEY && sacrifice->nrof * sacrifice->value >= NROF_SACRIFICE (altar))
329     return 1;
330     }
331 root 1.17
332 elmex 1.1 return 0;
333     }
334    
335     /*
336     * operate_altar checks if sacrifice was accepted and removes sacrificed
337     * objects. If sacrifice was succeed return 1 else 0. Might be better to
338     * call check_altar_sacrifice (above) than depend on the return value,
339     * since operate_altar will remove the sacrifice also.
340     *
341     * If this function returns 1, '*sacrifice' is modified to point to the
342     * remaining sacrifice, or is set to NULL if the sacrifice was used up.
343     */
344 root 1.7 int
345     operate_altar (object *altar, object **sacrifice)
346 elmex 1.1 {
347 root 1.7 if (!altar->map)
348     {
349     LOG (llevError, "BUG: operate_altar(): altar has no map\n");
350     return 0;
351     }
352 elmex 1.1
353     if (!altar->slaying || altar->value)
354     return 0;
355    
356 root 1.7 if (!check_altar_sacrifice (altar, *sacrifice))
357 elmex 1.1 return 0;
358    
359     /* check_altar_sacrifice should have already verified that enough money
360     * has been dropped.
361     */
362 root 1.7 if (!strcmp (ARCH_SACRIFICE (altar), "money"))
363     {
364     int number = NROF_SACRIFICE (altar) / (*sacrifice)->value;
365 elmex 1.1
366 root 1.7 /* Round up any sacrifices. Altars don't make change either */
367     if (NROF_SACRIFICE (altar) % (*sacrifice)->value)
368     number++;
369 root 1.9
370 root 1.7 *sacrifice = decrease_ob_nr (*sacrifice, number);
371     }
372 elmex 1.1 else
373 root 1.7 *sacrifice = decrease_ob_nr (*sacrifice, NROF_SACRIFICE (altar));
374    
375 elmex 1.1 if (altar->msg)
376 root 1.7 new_info_map (NDI_BLACK, altar->map, altar->msg);
377 root 1.9
378 elmex 1.1 return 1;
379     }
380    
381 root 1.7 void
382     trigger_move (object *op, int state) /* 1 down and 0 up */
383 elmex 1.1 {
384 root 1.7 op->stats.wc = state;
385     if (state)
386     {
387     use_trigger (op);
388 root 1.20 op->set_speed (op->stats.exp > 0 ? 1. / op->stats.exp : 1.);
389 root 1.7 op->speed_left = -1;
390     }
391     else
392     {
393     use_trigger (op);
394 root 1.20 op->set_speed (0);
395 elmex 1.1 }
396     }
397    
398    
399     /*
400     * cause != NULL: something has moved on top of op
401     *
402     * cause == NULL: nothing has moved, we have been called from
403     * animate_trigger().
404     *
405     * TRIGGER_ALTAR: Returns 1 if 'cause' was destroyed, 0 if not.
406     *
407     * TRIGGER: Returns 1 if handle could be moved, 0 if not.
408     *
409     * TRIGGER_BUTTON, TRIGGER_PEDESTAL: Returns 0.
410     */
411 root 1.7 int
412     check_trigger (object *op, object *cause)
413 elmex 1.1 {
414 root 1.7 object *tmp;
415     int push = 0, tot = 0;
416     int in_movement = op->stats.wc || op->speed;
417 elmex 1.1
418 root 1.7 switch (op->type)
419     {
420 root 1.2 case TRIGGER_BUTTON:
421 root 1.7 if (op->weight > 0)
422     {
423     if (cause)
424     {
425     for (tmp = op->above; tmp; tmp = tmp->above)
426     /* Comment reproduced from update_buttons(): */
427     /* Basically, if the move_type matches that on what the
428     * button wants, we count it. The second check is so that
429     * objects that don't move (swords, etc) will count. Note that
430     * this means that more work is needed to make buttons
431     * that are only triggered by flying objects.
432     */
433    
434     if ((tmp->move_type & op->move_on) || tmp->move_type == 0)
435     {
436     tot += tmp->weight * (tmp->nrof ? tmp->nrof : 1) + tmp->carrying;
437     }
438     if (tot >= op->weight)
439 root 1.2 push = 1;
440 root 1.7 if (op->stats.ac == push)
441     return 0;
442     op->stats.ac = push;
443     if (NUM_ANIMATIONS (op) > 1)
444     {
445     SET_ANIMATION (op, push);
446     update_object (op, UP_OBJ_FACE);
447 elmex 1.1 }
448 root 1.7 if (in_movement || !push)
449     return 0;
450 root 1.2 }
451 root 1.7 trigger_move (op, push);
452 root 1.2 }
453 root 1.7 return 0;
454 root 1.2
455     case TRIGGER_PEDESTAL:
456 root 1.7 if (cause)
457     {
458     for (tmp = op->above; tmp; tmp = tmp->above)
459     {
460 root 1.32 object *head = tmp->head_ ();
461 root 1.7
462     /* See comment in TRIGGER_BUTTON about move_types */
463     if (((head->move_type & op->move_on) || head->move_type == 0)
464     && (head->race == op->slaying || (!strcmp (op->slaying, "player") && head->type == PLAYER)))
465     {
466     push = 1;
467     break;
468 root 1.2 }
469     }
470 root 1.32
471 root 1.7 if (op->stats.ac == push)
472     return 0;
473 root 1.32
474 root 1.7 op->stats.ac = push;
475 root 1.32
476 root 1.7 if (NUM_ANIMATIONS (op) > 1)
477     {
478     SET_ANIMATION (op, push);
479     update_object (op, UP_OBJ_FACE);
480 elmex 1.1 }
481 root 1.32
482 root 1.7 update_object (op, UP_OBJ_FACE);
483 root 1.32
484 root 1.7 if (in_movement || !push)
485     return 0;
486 root 1.2 }
487 root 1.32
488 root 1.7 trigger_move (op, push);
489     return 0;
490 root 1.2
491     case TRIGGER_ALTAR:
492 root 1.7 if (cause)
493     {
494     if (in_movement)
495     return 0;
496 root 1.32
497 root 1.7 if (operate_altar (op, &cause))
498     {
499     if (NUM_ANIMATIONS (op) > 1)
500     {
501     SET_ANIMATION (op, 1);
502     update_object (op, UP_OBJ_FACE);
503 elmex 1.1 }
504 root 1.32
505 root 1.7 if (op->last_sp >= 0)
506     {
507     trigger_move (op, 1);
508     if (op->last_sp > 0)
509 root 1.2 op->last_sp = -op->last_sp;
510     }
511 root 1.7 else
512     {
513     /* for trigger altar with last_sp, the ON/OFF
514     * status (-> +/- value) is "simulated":
515     */
516     op->value = !op->value;
517     trigger_move (op, 1);
518     op->last_sp = -op->last_sp;
519     op->value = !op->value;
520 root 1.2 }
521 root 1.32
522 root 1.7 return cause == NULL;
523     }
524     else
525 root 1.32 return 0;
526 root 1.7 }
527     else
528     {
529     if (NUM_ANIMATIONS (op) > 1)
530     {
531     SET_ANIMATION (op, 0);
532     update_object (op, UP_OBJ_FACE);
533 root 1.2 }
534 root 1.7
535     /* If trigger_altar has "last_sp > 0" set on the map,
536     * it will push the connected value only once per sacrifice.
537     * Otherwise (default), the connected value will be
538     * pushed twice: First by sacrifice, second by reset! -AV
539     */
540     if (!op->last_sp)
541     trigger_move (op, 0);
542     else
543     {
544     op->stats.wc = 0;
545     op->value = !op->value;
546 root 1.20 op->set_speed (0);
547 root 1.2 }
548     }
549 root 1.7 return 0;
550 root 1.2
551     case TRIGGER:
552 root 1.7 if (cause)
553     {
554     if (in_movement)
555     return 0;
556 root 1.20
557 root 1.7 push = 1;
558 root 1.2 }
559 root 1.20
560 root 1.7 if (NUM_ANIMATIONS (op) > 1)
561     {
562     SET_ANIMATION (op, push);
563     update_object (op, UP_OBJ_FACE);
564 elmex 1.1 }
565 root 1.20
566 root 1.7 trigger_move (op, push);
567     return 1;
568 elmex 1.1
569 root 1.2 default:
570 root 1.7 LOG (llevDebug, "Unknown trigger type: %s (%d)\n", &op->name, op->type);
571     return 0;
572 elmex 1.1 }
573     }
574    
575 root 1.7 void
576 root 1.11 add_button_link (object *button, maptile *map, int connected)
577 root 1.7 {
578 elmex 1.1 oblinkpt *obp;
579 root 1.7 objectlink *ol = get_objectlink ();
580    
581     if (!map)
582     {
583     LOG (llevError, "Tried to add button-link without map.\n");
584     return;
585     }
586 elmex 1.1
587 root 1.19 button->path_attuned = connected; /* peterm: I need this so I can rebuild
588     a connected map from a template map. */
589 elmex 1.1
590 root 1.7 SET_FLAG (button, FLAG_IS_LINKED);
591 elmex 1.1
592     ol->ob = button;
593    
594 root 1.19 for (obp = map->buttons; obp && obp->value != connected; obp = obp->next)
595     ;
596 elmex 1.1
597 root 1.7 if (obp)
598     {
599     ol->next = obp->link;
600     obp->link = ol;
601     }
602     else
603     {
604     obp = get_objectlinkpt ();
605     obp->value = connected;
606    
607     obp->next = map->buttons;
608     map->buttons = obp;
609     obp->link = ol;
610     }
611 elmex 1.1 }
612    
613     /*
614     * Remove the object from the linked lists of buttons in the map.
615     * This is only needed by editors.
616     */
617    
618 root 1.7 void
619     remove_button_link (object *op)
620     {
621 elmex 1.1 oblinkpt *obp;
622     objectlink **olp, *ol;
623    
624 root 1.7 if (op->map == NULL)
625     {
626     LOG (llevError, "remove_button_link() in object without map.\n");
627     return;
628     }
629 root 1.12
630 root 1.7 if (!QUERY_FLAG (op, FLAG_IS_LINKED))
631     {
632     LOG (llevError, "remove_button_linked() in unlinked object.\n");
633     return;
634     }
635 root 1.12
636 elmex 1.1 for (obp = op->map->buttons; obp; obp = obp->next)
637     for (olp = &obp->link; (ol = *olp); olp = &ol->next)
638 root 1.7 if (ol->ob == op)
639     {
640    
641 elmex 1.1 /* LOG(llevDebug, "Removed link %d in button %s and map %s.\n",
642     obp->value, op->name, op->map->path);
643     */
644 root 1.7 *olp = ol->next;
645 root 1.12 delete ol;
646 root 1.7 return;
647     }
648 root 1.12
649 root 1.7 LOG (llevError, "remove_button_linked(): couldn't find object.\n");
650     CLEAR_FLAG (op, FLAG_IS_LINKED);
651 elmex 1.1 }
652 elmex 1.3
653     /*
654     * Gets the objectlink for this connection from the map.
655     */
656 root 1.7 oblinkpt *
657 root 1.11 get_connection_links (maptile *map, long connection)
658 elmex 1.3 {
659 root 1.7 for (oblinkpt * obp = map->buttons; obp; obp = obp->next)
660 elmex 1.3 if (obp->value == connection)
661     return obp;
662 root 1.12
663 elmex 1.3 return 0;
664     }
665    
666 elmex 1.1 /*
667     * Return the first objectlink in the objects linked to this one
668     */
669    
670 root 1.7 oblinkpt *
671     get_button_links (const object *button)
672     {
673 elmex 1.1 oblinkpt *obp;
674     objectlink *ol;
675    
676     if (!button->map)
677     return NULL;
678 root 1.12
679 elmex 1.1 for (obp = button->map->buttons; obp; obp = obp->next)
680     for (ol = obp->link; ol; ol = ol->next)
681 root 1.12 if (ol->ob == button)
682 elmex 1.3 return obp;
683 root 1.12
684 elmex 1.1 return NULL;
685     }
686    
687     /*
688     * Made as a separate function to increase efficiency
689     */
690    
691 root 1.7 int
692     get_button_value (const object *button)
693     {
694 elmex 1.1 oblinkpt *obp;
695     objectlink *ol;
696    
697     if (!button->map)
698     return 0;
699     for (obp = button->map->buttons; obp; obp = obp->next)
700     for (ol = obp->link; ol; ol = ol->next)
701 root 1.12 if (ol->ob == button)
702 elmex 1.1 return obp->value;
703     return 0;
704     }
705    
706     /* This routine makes monsters who are
707     * standing on the 'mood floor' change their
708     * disposition if it is different.
709     * If floor is to be triggered must have
710     * a speed of zero (default is 1 for all
711     * but the charm floor type).
712     * by b.t. thomas@nomad.astro.psu.edu
713     */
714    
715 root 1.7 void
716     do_mood_floor (object *op, object *source)
717     {
718     if (!source)
719     source = op;
720    
721 root 1.28 mapspace &ms = op->ms ();
722    
723     if (!(ms.flags () & P_IS_ALIVE))
724     return;
725    
726     object *tmp;
727    
728     for (tmp = ms.top; tmp; tmp = tmp->below)
729 root 1.7 if (QUERY_FLAG (tmp, FLAG_MONSTER))
730     break;
731    
732     /* doesn't effect players, and if there is a player on this space, won't also
733     * be a monster here.
734     */
735 root 1.28 //TODO: have players really FLAG_MONSTER? kept it for safety
736 root 1.7 if (!tmp || tmp->type == PLAYER)
737     return;
738    
739     switch (op->last_sp)
740     {
741 root 1.8 case 0: /* furious--make all monsters mad */
742     if (QUERY_FLAG (tmp, FLAG_UNAGGRESSIVE))
743     CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE);
744 root 1.28
745 root 1.8 if (QUERY_FLAG (tmp, FLAG_FRIENDLY))
746     {
747     tmp->attack_movement = 0;
748     /* lots of checks here, but want to make sure we don't
749     * dereference a null value
750     */
751 root 1.29 if (tmp->type == GOLEM
752     && tmp->owner
753     && tmp->owner->type == PLAYER
754 root 1.31 && tmp->owner->contr->golem == tmp)
755     tmp->owner->contr->golem = 0;
756 root 1.13
757 root 1.8 tmp->owner = 0;
758 root 1.29
759     remove_friendly_object (tmp);
760 root 1.8 }
761     break;
762 root 1.28
763 root 1.8 case 1: /* angry -- get neutral monsters mad */
764     if (QUERY_FLAG (tmp, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (tmp, FLAG_FRIENDLY))
765     CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE);
766     break;
767 root 1.28
768 root 1.8 case 2: /* calm -- pacify unfriendly monsters */
769 root 1.28 SET_FLAG (tmp, FLAG_UNAGGRESSIVE);
770 root 1.8 break;
771 root 1.28
772 root 1.8 case 3: /* make all monsters fall asleep */
773 root 1.28 SET_FLAG (tmp, FLAG_SLEEP);
774 root 1.8 break;
775 root 1.28
776 root 1.8 case 4: /* charm all monsters */
777     if (op == source)
778     break; /* only if 'connected' */
779    
780 root 1.28 if (object *pl = source->ms ().player ())
781     {
782     tmp->set_owner (pl);
783     SET_FLAG (tmp, FLAG_MONSTER);
784 root 1.7
785 root 1.28 tmp->stats.exp = 0;
786 root 1.17
787 root 1.28 add_friendly_object (tmp);
788     tmp->attack_movement = PETMOVE;
789     }
790     break;
791 root 1.17
792 root 1.30 case 6: // kill monsters
793 root 1.28 if (!QUERY_FLAG (tmp, FLAG_FRIENDLY))
794     break;
795 root 1.17
796 root 1.28 // FALL THROUGH
797 root 1.30 case 5: // kill all alives
798     if (!tmp->flag [FLAG_PRECIOUS])
799     {
800     get_archetype ("burnout")->insert_at (tmp, source);
801     tmp->destroy ();
802     }
803 root 1.8 break;
804 elmex 1.1
805 root 1.8 default:
806     break;
807 elmex 1.1 }
808     }
809    
810     /* this function returns the object it matches, or NULL if non.
811     * It will descend through containers to find the object.
812     * slaying = match object slaying flag
813     * race = match object archetype name flag
814     * hp = match object type (excpt type '0'== PLAYER)
815     */
816 root 1.7 object *
817     check_inv_recursive (object *op, const object *trig)
818 elmex 1.1 {
819 root 1.7 object *tmp, *ret = NULL;
820    
821     /* First check the object itself. */
822     if ((trig->stats.hp && (op->type == trig->stats.hp))
823 elmex 1.16 || (trig->slaying && (op->slaying == trig->slaying))
824 root 1.34 || (trig->race && (op->arch->archname == trig->race)))
825 root 1.7 return op;
826 elmex 1.1
827 root 1.7 for (tmp = op->inv; tmp; tmp = tmp->below)
828     {
829     if (tmp->inv)
830     {
831     ret = check_inv_recursive (tmp, trig);
832     if (ret)
833     return ret;
834 root 1.2 }
835 root 1.7 else if ((trig->stats.hp && (tmp->type == trig->stats.hp))
836 elmex 1.16 || (trig->slaying && (tmp->slaying == trig->slaying))
837 root 1.34 || (trig->race && (tmp->arch->archname == trig->race)))
838 root 1.7 return tmp;
839 elmex 1.1 }
840 root 1.7 return NULL;
841 elmex 1.1 }
842    
843     /* check_inv(), a function to search the inventory,
844     * of a player and then based on a set of conditions,
845     * the square will activate connected items.
846     * Monsters can't trigger this square (for now)
847     * Values are: last_sp = 1/0 obj/no obj triggers
848     * last_heal = 1/0 remove/dont remove obj if triggered
849     * -b.t. (thomas@nomad.astro.psu.edu
850 elmex 1.16 *
851     * Tue Dec 19 15:34:00 CET 2006 elmex: changed the function to ignore op
852     * because the check-inventory semantic essentially only applies when
853     * something is above the inventory checker.
854     * The semantic prior this change was: trigger if something has moved on or off
855     * and has a matching item. Imagine what happens if someone steps on the inventory
856     * checker with a matching item, has it, activates the connection, throws the item
857     * away, and then leaves the inventory checker. That would've caused an always-enabled
858     * state in the inventory checker. This won't happen anymore now.
859     *
860 elmex 1.26 * Wed Jan 10 11:34:26 CET 2007 elmex: fixed this function, we now check
861     * whether op is on this mapspace or not, because the value (1|0) depends
862     * on this information. also make sure to only push_button if op has
863     * a matching item (because when we do a push_button with value=0 timed gates
864     * will still open)! (i hope i got the semantics right this time)
865     *
866 elmex 1.1 */
867 root 1.7 void
868 elmex 1.16 check_inv (object *op, object *trig)
869 root 1.7 {
870 elmex 1.16 trig->value = 0; // deactivate if none of the following conditions apply
871    
872 elmex 1.26 object *pl = trig->ms ().player ();
873     object *match = check_inv_recursive (op, trig);
874    
875     // elmex: a note about (pl == op):
876     // if pl == 0 then the player has left this space
877     // if pl != 0 then a player is on this mapspace, but then
878     // we still have to check whether it's the player that triggered
879     // this inv-checker, because if not, then the op left this inv-checker
880     // and we have to set the value to 0
881    
882     if (match && trig->last_sp) // match == having
883 root 1.18 {
884 elmex 1.26 if (trig->last_heal)
885     decrease_ob (match);
886 root 1.18
887 elmex 1.26 trig->value = (pl == op ? 1 : 0); // 1 if matching player entered, and 0 if he left
888     push_button (trig);
889     }
890     else if (!match && !trig->last_sp) // match == not having
891     {
892     trig->value = (pl == op ? 1 : 0); // 1 if matching player entered, and 0 if he left
893     push_button (trig);
894 root 1.18 }
895 elmex 1.1 }
896