Crossfire Server, Trunk  R20513
button.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #include "global.h"
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "sproto.h"
25 
26 static objectlink *get_button_links(const object *button);
27 
41 void trigger_connected(objectlink *ol, object *cause, const int state) {
42  object *tmp;
43 
44  for (; ol; ol = ol->next) {
45  object *part;
46 
47  if (!ol->ob || ol->ob->count != ol->id) {
48  LOG(llevError, "Internal error in trigger_connect. No object associated with link id (%u) (cause='%s'.\n", ol->id, (cause && cause->name) ? cause->name : "");
49  continue;
50  }
51  /* a button link object can become freed when the map is saving. As
52  * a map is saved, objects are removed and freed, and if an object is
53  * on top of a button, this function is eventually called. If a map
54  * is getting moved out of memory, the status of buttons and levers
55  * probably isn't important - it will get sorted out when the map is
56  * re-loaded. As such, just exit this function if that is the case.
57  */
58 
59  if (QUERY_FLAG(ol->ob, FLAG_FREED))
60  return;
61  tmp = ol->ob;
62 
63  /* if the criteria isn't appropriate, don't do anything */
64  if (state && !QUERY_FLAG(tmp, FLAG_ACTIVATE_ON_PUSH))
65  continue;
66  if (!state && !QUERY_FLAG(tmp, FLAG_ACTIVATE_ON_RELEASE))
67  continue;
68 
69  /*
70  * (tchize) call the triggers of the activated object.
71  * tmp = activated object
72  * op is activator (aka button)
73  */
74  if (execute_event(tmp, EVENT_TRIGGER, cause, NULL, NULL, SCRIPT_FIX_ALL) != 0)
75  continue;
76 
77  switch (tmp->type) {
78  case GATE:
79  case HOLE:
80  tmp->value = tmp->stats.maxsp ? !state : state;
81  tmp->speed = 0.5;
83  break;
84 
85  case CF_HANDLE:
86  SET_ANIMATION(tmp, (tmp->value = tmp->stats.maxsp ? !state : state));
88  break;
89 
90  case SIGN:
91  if (!tmp->stats.food || tmp->last_eat < tmp->stats.food) {
94  tmp->msg);
95  if (tmp->stats.food)
96  tmp->last_eat++;
97  }
98  break;
99 
100  case ALTAR:
101  tmp->value = 1;
102  SET_ANIMATION(tmp, tmp->value);
104  break;
105 
106  case BUTTON:
107  case PEDESTAL:
108  tmp->value = state;
109  SET_ANIMATION(tmp, tmp->value);
111  break;
112 
113  case TIMED_GATE:
114  for (part = tmp; tmp != NULL; tmp = tmp->more) {
115  part->speed = tmp->arch->clone.speed;
116  part->value = tmp->arch->clone.value;
117  part->stats.sp = 1;
118  part->stats.hp = tmp->stats.maxhp;
119  object_update_speed(part);
120  }
121  break;
122 
123  case DIRECTOR:
124  if ((tmp->stats.sp += tmp->stats.maxsp) > 8) /* next direction */
125  tmp->stats.sp = ((tmp->stats.sp-1)%8)+1;
126  animate_turning(tmp);
127  break;
128  case FIREWALL:
129  // Since director is broken out, we don't need to check on firewall type now
130  if (!QUERY_FLAG(tmp, FLAG_ANIMATE)/* && tmp->type == FIREWALL*/)
131  move_firewall(tmp);
132  else {
133  if ((tmp->direction += tmp->stats.maxsp) > 8) /* next direction */
134  tmp->direction = ((tmp->direction-1)%8)+1;
135  animate_turning(tmp);
136  }
137  break;
138 
139 
140  default:
141  ob_trigger(tmp, cause, state);
142  }
143  }
144 }
145 
154 void push_button(object *op) {
155  /* LOG(llevDebug, "push_button: %s (%d)\n", op->name, op->count); */
157 }
158 
167 void update_button(object *op) {
168  object *tmp, *head;
169  int tot, any_down = 0, old_value = op->value;
170  objectlink *ol;
171 
172  /* LOG(llevDebug, "update_button: %s (%d)\n", op->name, op->count); */
173  for (ol = get_button_links(op); ol; ol = ol->next) {
174  if (!ol->ob || ol->ob->count != ol->id) {
175  LOG(llevDebug, "Internal error in update_button (%s).\n", op->name);
176  continue;
177  }
178 
179  tmp = ol->ob;
180  if (tmp->type == BUTTON) {
181  tot = 0;
182  FOR_ABOVE_PREPARE(tmp, ab)
183  /* Bug? The pedestal code below looks for the head of
184  * the object, this bit doesn't. I'd think we should check
185  * for head here also. Maybe it also makese sense to
186  * make the for ab=tmp->above loop common, and alter
187  * behaviour based on object within that loop?
188  */
189 
190  /* Basically, if the move_type matches that on what the
191  * button wants, we count it. The second check is so that
192  * objects don't move (swords, etc) will count. Note that
193  * this means that more work is needed to make buttons
194  * that are only triggered by flying objects.
195  */
196  if ((ab->move_type&tmp->move_on) || ab->move_type == 0)
197  tot += ab->weight*(ab->nrof ? ab->nrof : 1)+ab->carrying;
199 
200  tmp->value = (tot >= tmp->weight) ? 1 : 0;
201  if (tmp->value)
202  any_down = 1;
203  } else if (tmp->type == PEDESTAL) {
204  tmp->value = 0;
205  FOR_ABOVE_PREPARE(tmp, ab) {
206  head = ab->head ? ab->head : ab;
207  /* Same note regarding move_type for buttons above apply here. */
208  if (((head->move_type&tmp->move_on) || ab->move_type == 0)
209  && (head->race == tmp->slaying
210  || ((head->type == SPECIAL_KEY) && (head->slaying == tmp->slaying))
211  || (!strcmp(tmp->slaying, "player") && head->type == PLAYER)))
212  tmp->value = 1;
213  } FOR_ABOVE_FINISH();
214  if (tmp->value)
215  any_down = 1;
216  }
217  }
218  if (any_down) /* If any other buttons were down, force this to remain down */
219  op->value = 1;
220 
221  /* If this button hasn't changed, don't do anything */
222  if (op->value != old_value) {
223  SET_ANIMATION(op, op->value);
225  push_button(op); /* Make all other buttons the same */
226  }
227 }
228 
233  objectlink *ol;
234  oblinkpt *obp;
235 
236  for (obp = m->buttons; obp; obp = obp->next)
237  for (ol = obp->link; ol; ol = ol->next) {
238  if (!ol->ob || ol->ob->count != ol->id) {
239  LOG(llevError, "Internal error in update_button (%s (%dx%d):%u, connected %ld).\n",
240  ol->ob ? ol->ob->name : "null",
241  ol->ob ? ol->ob->x : -1,
242  ol->ob ? ol->ob->y : -1,
243  ol->id,
244  obp->value);
245  continue;
246  }
247  if (ol->ob->type == BUTTON || ol->ob->type == PEDESTAL) {
248  update_button(ol->ob);
249  break;
250  }
251  }
252 }
253 
259 void use_trigger(object *op) {
260  /* Toggle value */
261  op->value = !op->value;
262  push_button(op);
263 }
264 
275 void animate_turning(object *op) {
276  if (++op->state >= NUM_ANIMATIONS(op)/8)
277  op->state = 0;
278  // Firewalls use direction instead of sp to avoid issues involving the spell transference.
279  if (op->type == FIREWALL){
280  SET_ANIMATION(op, (op->direction-1)*NUM_ANIMATIONS(op)/8+op->state);
281  }
282  else {
283  SET_ANIMATION(op, (op->stats.sp-1)*NUM_ANIMATIONS(op)/8+op->state);
284  }
286 }
287 
288 #define ARCH_SACRIFICE(xyz) ((xyz)->slaying)
289 #define NROF_SACRIFICE(xyz) ((uint32_t)(xyz)->stats.food)
290 
302 static int matches_sacrifice(const object *altar, const object *sacrifice) {
303  char name[MAX_BUF];
304 
305  if ((QUERY_FLAG(sacrifice, FLAG_ALIVE) && object_get_value(altar, "accept_alive") == NULL)
306  || QUERY_FLAG(sacrifice, FLAG_IS_LINKED)
307  || sacrifice->type == PLAYER)
308  return 0;
309 
310  query_base_name(sacrifice, 0, name, MAX_BUF);
311  if (ARCH_SACRIFICE(altar) == sacrifice->arch->name
312  || ARCH_SACRIFICE(altar) == sacrifice->name
313  || ARCH_SACRIFICE(altar) == sacrifice->slaying
314  || (!strcmp(ARCH_SACRIFICE(altar), name)))
315  return 1;
316 
317  if (strcmp(ARCH_SACRIFICE(altar), "money") == 0
318  && sacrifice->type == MONEY)
319  return 1;
320 
321  return 0;
322 }
323 
352 int check_altar_sacrifice(const object *altar, const object *sacrifice, int remove_others, int *toremove) {
353  int money;
354  uint32_t wanted, rest;
355 
356  if (!matches_sacrifice(altar, sacrifice))
357  /* New dropped object doesn't match the altar, other objects already on top are not enough to
358  * activate altar, else they would have disappeared. */
359  return 0;
360 
361  /* Check item is paid for. */
362  if (QUERY_FLAG(sacrifice, FLAG_UNPAID)) {
363  return 0;
364  }
365 
366  money = (strcmp(ARCH_SACRIFICE(altar), "money") == 0) ? 1 : 0;
367 
368  /* Easy checks: newly dropped object is enough for sacrifice. */
369  if (money && sacrifice->nrof*sacrifice->value >= NROF_SACRIFICE(altar)) {
370  if (toremove) {
371  *toremove = NROF_SACRIFICE(altar)/sacrifice->value;
372  /* Round up any sacrifices. Altars don't make change either */
373  if (NROF_SACRIFICE(altar)%sacrifice->value)
374  (*toremove)++;
375  }
376  return 1;
377  }
378 
379  if (!money && NROF_SACRIFICE(altar) <= (sacrifice->nrof ? sacrifice->nrof : 1)) {
380  if (toremove)
381  *toremove = NROF_SACRIFICE(altar);
382  return 1;
383  }
384 
385  if (money) {
386  wanted = NROF_SACRIFICE(altar)-sacrifice->nrof*sacrifice->value;
387  } else {
388  wanted = NROF_SACRIFICE(altar)-(sacrifice->nrof ? sacrifice->nrof : 1);
389  }
390  rest = wanted;
391 
392  /* Ok, now we check if we got enough with other items.
393  * We only check items above altar, and not checking again sacrifice.
394  */
395  FOR_ABOVE_PREPARE(altar, tmp) {
396  if (wanted <= 0)
397  break;
398  if (tmp == sacrifice || !matches_sacrifice(altar, tmp))
399  continue;
400  if (money)
401  wanted -= tmp->nrof*tmp->value;
402  else
403  wanted -= (tmp->nrof ? tmp->nrof : 1);
404  } FOR_ABOVE_FINISH();
405 
406  if (wanted > 0)
407  /* Not enough value, let's bail out. */
408  return 0;
409 
410  /* From there on, we do have enough objects for the altar. */
411 
412  /* Last dropped object will be totally eaten in any case. */
413  if (toremove)
414  *toremove = sacrifice->nrof ? sacrifice->nrof : 1;
415 
416  if (!remove_others)
417  return 1;
418 
419  /* We loop again, this time to remove what we need. */
420  FOR_ABOVE_PREPARE(altar, tmp) {
421  if (rest <= 0)
422  break;
423  if (tmp == sacrifice || !matches_sacrifice(altar, tmp))
424  continue;
425  if (money) {
426  wanted = tmp->nrof*tmp->value;
427  if (rest > wanted) {
428  object_remove(tmp);
429  rest -= wanted;
430  } else {
431  wanted = rest/tmp->value;
432  if (rest%tmp->value)
433  wanted++;
434  object_decrease_nrof(tmp, wanted);
435  return 1;
436  }
437  } else
438  if (rest > (tmp->nrof ? tmp->nrof : 1)) {
439  rest -= (tmp->nrof ? tmp->nrof : 1);
440  object_remove(tmp);
441  } else {
442  object_decrease_nrof(tmp, rest);
443  return 1;
444  }
445  } FOR_ABOVE_FINISH();
446 
447  /* Something went wrong, we'll be nice and accept the sacrifice anyway. */
448  LOG(llevError, "check_altar_sacrifice on %s: found objects to sacrifice, but couldn't remove them??\n", altar->map->path);
449  return 1;
450 }
451 
468 int operate_altar(object *altar, object **sacrifice) {
469  int number;
470 
471  if (!altar->map) {
472  LOG(llevError, "BUG: operate_altar(): altar has no map\n");
473  return 0;
474  }
475 
476  if (!altar->slaying || altar->value)
477  return 0;
478 
479  if (!check_altar_sacrifice(altar, *sacrifice, 1, &number))
480  return 0;
481 
482  /* check_altar_sacrifice fills in number for us. */
483  *sacrifice = object_decrease_nrof(*sacrifice, number);
484 
485  if (altar->msg)
487  return 1;
488 }
489 
493 static void trigger_move(object *op, int state) { /* 1 down and 0 up */
494  op->stats.wc = state;
495  if (state) {
496  use_trigger(op);
497  if (op->stats.exp > 0) /* check sanity */
498  op->speed = 1.0/op->stats.exp;
499  else
500  op->speed = 1.0;
502  op->speed_left = -1;
503  } else {
504  use_trigger(op);
505  op->speed = 0;
507  }
508 }
509 
523 int check_trigger(object *op, object *cause) {
524  int push = 0, tot = 0;
525  int in_movement = op->stats.wc || op->speed;
526 
527  switch (op->type) {
528  case TRIGGER_BUTTON:
529  if (op->weight > 0) {
530  if (cause) {
531  FOR_ABOVE_PREPARE(op, tmp)
532  /* Comment reproduced from update_buttons():
533  * Basically, if the move_type matches that on what the
534  * button wants, we count it. The second check is so that
535  * objects that don't move (swords, etc) will count. Note that
536  * this means that more work is needed to make buttons
537  * that are only triggered by flying objects.
538  */
539  if ((tmp->move_type&op->move_on) || tmp->move_type == 0) {
540  tot += tmp->weight*(tmp->nrof ? tmp->nrof : 1)+tmp->carrying;
541  }
543  if (tot >= op->weight)
544  push = 1;
545  if (op->stats.ac == push)
546  return 0;
547  op->stats.ac = push;
548  if (NUM_ANIMATIONS(op) > 1) {
549  SET_ANIMATION(op, push);
551  }
552  if (in_movement || !push)
553  return 0;
554  }
555  trigger_move(op, push);
556  }
557  return 0;
558 
559  case TRIGGER_PEDESTAL:
560  if (cause) {
561  FOR_ABOVE_PREPARE(op, tmp) {
562  object *head = tmp->head ? tmp->head : tmp;
563 
564  /* See comment in TRIGGER_BUTTON about move_types */
565  if (((head->move_type&op->move_on) || head->move_type == 0)
566  && (head->race == op->slaying || (!strcmp(op->slaying, "player") && head->type == PLAYER))) {
567  push = 1;
568  break;
569  }
570  } FOR_ABOVE_FINISH();
571  if (op->stats.ac == push)
572  return 0;
573  op->stats.ac = push;
574  if (NUM_ANIMATIONS(op) > 1) {
575  SET_ANIMATION(op, push);
577  }
578  if (in_movement || !push)
579  return 0;
580  }
581  trigger_move(op, push);
582  return 0;
583 
584  case TRIGGER_ALTAR:
585  if (cause) {
586  if (in_movement)
587  return 0;
588  if (operate_altar(op, &cause)) {
589  if (NUM_ANIMATIONS(op) > 1) {
590  SET_ANIMATION(op, 1);
592  }
593 
594  if (op->last_sp >= 0) {
595  trigger_move(op, 1);
596  if (op->last_sp > 0)
597  op->last_sp = -op->last_sp;
598  } else {
599  /* for trigger altar with last_sp, the ON/OFF
600  * status (-> +/- value) is "simulated":
601  */
602  op->value = !op->value;
603  trigger_move(op, 1);
604  op->last_sp = -op->last_sp;
605  op->value = !op->value;
606  }
607  return cause == NULL;
608  } else {
609  return 0;
610  }
611  } else {
612  if (NUM_ANIMATIONS(op) > 1) {
613  SET_ANIMATION(op, 0);
615  }
616 
617  /* If trigger_altar has "last_sp > 0" set on the map,
618  * it will push the connected value only once per sacrifice.
619  * Otherwise (default), the connected value will be
620  * pushed twice: First by sacrifice, second by reset! -AV
621  */
622  if (!op->last_sp)
623  trigger_move(op, 0);
624  else {
625  op->stats.wc = 0;
626  op->value = !op->value;
627  op->speed = 0;
629  }
630  }
631  return 0;
632 
633  case TRIGGER:
634  if (cause) {
635  if (in_movement)
636  return 0;
637  push = 1;
638  }
639  if (NUM_ANIMATIONS(op) > 1) {
640  SET_ANIMATION(op, push);
642  }
643  trigger_move(op, push);
644  return 1;
645 
646  default:
647  LOG(llevDebug, "Unknown trigger type: %s (%d)\n", op->name, op->type);
648  return 0;
649  }
650 }
651 
661 void add_button_link(object *button, mapstruct *map, int connected) {
662  oblinkpt *obp;
663  objectlink *ol = get_objectlink();
664 
665  if (!map) {
666  LOG(llevError, "Tried to add button-link without map.\n");
667  free_objectlink(ol);
668  return;
669  }
670 
671  SET_FLAG(button, FLAG_IS_LINKED);
672 
673  ol->ob = button;
674  ol->id = button->count;
675 
676  for (obp = map->buttons; obp && obp->value != connected; obp = obp->next)
677  ;
678 
679  if (obp) {
680  ol->next = obp->link;
681  obp->link = ol;
682  } else {
683  obp = get_objectlinkpt();
684  obp->value = connected;
685 
686  obp->next = map->buttons;
687  map->buttons = obp;
688  obp->link = ol;
689  }
690 }
691 
698 void remove_button_link(object *op) {
699  oblinkpt *obp;
700  objectlink **olp, *ol;
701 
702  if (op->map == NULL) {
703  LOG(llevError, "remove_button_link() in object without map.\n");
704  return;
705  }
706  if (!QUERY_FLAG(op, FLAG_IS_LINKED)) {
707  LOG(llevError, "remove_button_linked() in unlinked object.\n");
708  return;
709  }
710 
711  for (obp = op->map->buttons; obp; obp = obp->next)
712  for (olp = &obp->link; (ol = *olp); olp = &ol->next)
713  if (ol->ob == op) {
714 /* LOG(llevDebug, "Removed link %d in button %s and map %s.\n",
715  obp->value, op->name, op->map->path);
716 */
717  *olp = ol->next;
718  free(ol);
719  return;
720  }
721  LOG(llevError, "remove_button_linked(): couldn't find object.\n");
723 }
724 
732 static objectlink *get_button_links(const object *button) {
733  oblinkpt *obp;
734  objectlink *ol;
735 
736  if (!button->map)
737  return NULL;
738 
739  for (obp = button->map->buttons; obp; obp = obp->next)
740  for (ol = obp->link; ol; ol = ol->next)
741  if (ol->ob == button && ol->id == button->count)
742  return obp->link;
743  return NULL;
744 }
745 
754 int get_button_value(const object *button) {
755  oblinkpt *obp;
756  objectlink *ol;
757 
758  if (!button->map)
759  return 0;
760 
761  for (obp = button->map->buttons; obp; obp = obp->next)
762  for (ol = obp->link; ol; ol = ol->next)
763  if (ol->ob == button && ol->id == button->count)
764  return obp->value;
765  return 0;
766 }
767 
786 object *check_inv_recursive(object *op, const object *trig) {
787  object *ret = NULL;
788 
789  /* First check the object itself. */
790  if ((!trig->stats.hp || (op->type == trig->stats.hp))
791  && (!trig->slaying || (op->slaying == trig->slaying))
792  && (!trig->race || (op->arch->name == trig->race))
793  && (!trig->title || (op->title == trig->title)))
794  return op;
795 
796  FOR_INV_PREPARE(op, tmp) {
797  if (tmp->inv) {
798  ret = check_inv_recursive(tmp, trig);
799  if (ret)
800  return ret;
801  } else if ((!trig->stats.hp || (tmp->type == trig->stats.hp))
802  && (!trig->slaying || (tmp->slaying == trig->slaying))
803  && (!trig->race || (tmp->arch->name == trig->race))
804  && (!trig->title || (tmp->title == trig->title)))
805  return tmp;
806  } FOR_INV_FINISH();
807 
808  return NULL;
809 }
810 
826 void check_inv(object *op, object *trig) {
827  object *match;
828 
829  if (op->type != PLAYER)
830  return;
831 
832  match = check_inv_recursive(op, trig);
833  if (match && trig->last_sp) {
834  if (trig->last_heal)
836  use_trigger(trig);
837  } else if (!match && !trig->last_sp)
838  use_trigger(trig);
839 }
840 
851 void verify_button_links(const mapstruct *map) {
852  oblinkpt *obp;
853  objectlink *ol;
854 
855  if (!map)
856  return;
857 
858  for (obp = map->buttons; obp; obp = obp->next) {
859  for (ol = obp->link; ol; ol = ol->next) {
860  if (ol->id != ol->ob->count)
861  LOG(llevError, "verify_button_links: object %s on list is corrupt (%u!=%u)\n", ol->ob->name, ol->id, ol->ob->count);
862  }
863  }
864 }
See Pedestal.
Definition: object.h:121
Error, serious thing.
Definition: logger.h:11
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:365
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:236
int8_t ac
Armour Class, how hard to hit, the lower the better.
Definition: living.h:37
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:519
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:316
MoveType move_type
Type of movement this object uses.
Definition: object.h:424
#define ARCH_SACRIFICE(xyz)
Definition: button.c:288
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:427
Used to link together several objects.
Definition: object.h:442
const char * race
Human, goblin, dragon, etc.
Definition: object.h:318
static void trigger_move(object *op, int state)
Definition: button.c:493
void push_button(object *op)
Push the specified object.
Definition: button.c:154
#define SET_FLAG(xyz, p)
Definition: define.h:223
#define NROF_SACRIFICE(xyz)
Definition: button.c:289
int32_t last_heal
Last healed.
Definition: object.h:357
void check_inv(object *op, object *trig)
Function to search the inventory, of a player and then based on a set of conditions, the square will activate connected items.
Definition: button.c:826
#define SET_ANIMATION(ob, newanim)
Definition: global.h:171
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
See Money.
Definition: object.h:137
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.c:722
object clone
An object from which to do object_copy()
Definition: object.h:470
#define MSG_TYPE_DIALOG
NPCs, magic mouths, and altars.
Definition: newclient.h:375
const char * slaying
Which race to do double damage to.
Definition: object.h:319
int32_t last_sp
As last_heal, but for spell points.
Definition: object.h:358
See Altar Trigger.
Definition: object.h:133
int64_t exp
Experience.
Definition: living.h:46
See Button Trigger.
Definition: object.h:132
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.c:1239
int16_t sp
Spell points.
Definition: living.h:41
#define FLAG_ACTIVATE_ON_PUSH
connected object is activated when &#39;pushed&#39;
Definition: define.h:371
#define NDI_BLACK
Definition: newclient.h:221
Global type definitions and header inclusions.
#define SCRIPT_FIX_ALL
Definition: global.h:361
long value
Used as connected value in buttons/gates.
Definition: object.h:453
tag_t id
ob&#39;s tag, in case it is removed.
Definition: object.h:445
int16_t maxsp
Max spell points.
Definition: living.h:42
Used to link together several object links.
Definition: object.h:451
int16_t hp
Hit Points.
Definition: living.h:39
struct oblnk * link
Items for this value.
Definition: object.h:452
#define NDI_NAVY
Definition: newclient.h:223
object * ob
Item to link to.
Definition: object.h:443
const char * title
Of foo, etc.
Definition: object.h:317
int16_t y
Position in the map for this object.
Definition: object.h:326
int16_t maxhp
Max hit points.
Definition: living.h:40
struct oblinkpt * next
Next value in the list.
Definition: object.h:454
See Sign & Magic Mouth.
Definition: object.h:211
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
static int matches_sacrifice(const object *altar, const object *sacrifice)
Helper function to check if the item matches altar&#39;s requested sacrifice.
Definition: button.c:302
float speed_left
How much speed is left to spend this round.
Definition: object.h:329
See Special Key.
Definition: object.h:124
int32_t weight
Attributes of the object.
Definition: object.h:365
#define FOR_ABOVE_FINISH()
Finishes FOR_ABOVE_PREPARE().
Definition: define.h:729
int check_altar_sacrifice(const object *altar, const object *sacrifice, int remove_others, int *toremove)
Checks whether the altar has enough to sacrifice.
Definition: button.c:352
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
void remove_button_link(object *op)
Remove the object from the linked lists of buttons in the map.
Definition: button.c:698
const char * name
The name of the object, obviously...
Definition: object.h:311
#define FOR_ABOVE_PREPARE(op_, it_)
Constructs a loop iterating over all objects above an object.
Definition: define.h:722
uint8_t state
How the object was last drawn (animation)
Definition: object.h:349
int operate_altar(object *altar, object **sacrifice)
Checks if sacrifice was accepted and removes sacrificed objects.
Definition: button.c:468
void trigger_connected(objectlink *ol, object *cause, const int state)
Trigger every object in an objectlink.
Definition: button.c:41
int8_t direction
Means the object is moving that way.
Definition: object.h:334
uint32_t nrof
How many of the objects.
Definition: object.h:333
void add_button_link(object *button, mapstruct *map, int connected)
Links specified object in the map.
Definition: button.c:661
void use_trigger(object *op)
Toggles the state of specified button.
Definition: button.c:259
void update_buttons(mapstruct *m)
Updates every button on the map (by calling update_button() for them).
Definition: button.c:232
float speed
The overall speed of this object.
Definition: object.h:328
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
See Handle Trigger.
Definition: object.h:129
#define MSG_TYPE_DIALOG_ALTAR
A message from an altar.
Definition: newclient.h:466
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
See Magic Wall.
Definition: object.h:168
oblinkpt * buttons
Linked list of linked lists of buttons.
Definition: map.h:354
int16_t x
Definition: object.h:326
#define FLAG_ACTIVATE_ON_RELEASE
connected object is activated when &#39;released&#39;
Definition: define.h:372
int32_t last_eat
How long since we last ate.
Definition: object.h:356
int8_t wc
Weapon Class, how skilled, the lower the better.
Definition: living.h:36
void move_firewall(object *op)
Move for FIREWALL.
Definition: main.c:330
unsigned int uint32_t
Definition: win32.h:162
See Player.
Definition: object.h:107
object * check_inv_recursive(object *op, const object *trig)
Checks object and its inventory for specific item.
Definition: button.c:786
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:242
See Altar.
Definition: object.h:122
object * object_decrease_nrof(object *op, uint32_t i)
Decreases a specified number from the amount of an object.
Definition: object.c:2505
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:28
#define NUM_ANIMATIONS(ob)
Definition: global.h:179
int get_button_value(const object *button)
Returns the first value linked to this button.
Definition: button.c:754
tag_t count
Unique object number for this object.
Definition: object.h:299
living stats
Str, Con, Dex, etc.
Definition: object.h:368
struct archt * arch
Pointer to archetype.
Definition: object.h:412
struct oblnk * next
Next item to link to.
Definition: object.h:444
See Button.
Definition: object.h:207
Only for debugging purposes.
Definition: logger.h:13
See Gate.
Definition: object.h:206
void verify_button_links(const mapstruct *map)
This does a minimal check of the button link consistency for object map.
Definition: button.c:851
void animate_turning(object *op)
Animates one step of object.
Definition: button.c:275
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
See Handle.
Definition: object.h:208
See Timed Gate.
Definition: object.h:128
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: main.c:364
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
void update_button(object *op)
Updates everything connected with the button op.
Definition: button.c:167
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
struct obj * head
Points to the main object of a large body.
Definition: object.h:296
#define MSG_SUBTYPE_NONE
Definition: newclient.h:398
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
See Pit.
Definition: object.h:209
int check_trigger(object *op, object *cause)
Definition: button.c:523
method_ret ob_trigger(object *op, object *cause, int state)
An object is triggered by another one.
Definition: ob_methods.c:127
static objectlink * get_button_links(const object *button)
Return the first objectlink in the objects linked to this one.
Definition: button.c:732
This is a game-map.
Definition: map.h:325
void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
Writes to everyone on the specified map.
Definition: main.c:325
void push(String_Array *array, const char *string)
Add a string to a String_Array struct.
Definition: bwp.c:310
struct obj * more
Pointer to the rest of a large body of objects.
Definition: object.h:295
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.c:1129
int32_t value
How much money it is worth (or contains)
Definition: object.h:350
See Director.
Definition: object.h:222
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
#define EVENT_TRIGGER
Button pushed, lever pulled, etc.
Definition: plugin.h:74
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
#define MSG_TYPE_SIGN
Definition: newclient.h:373
int32_t food
How much food in stomach.
Definition: living.h:47
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233