ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/button.C
Revision: 1.9
Committed: Wed Sep 13 23:42:23 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.8: +3 -4 lines
Log Message:
*** empty log message ***

File Contents

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