00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00034 #include <global.h>
00035 #include <sproto.h>
00036
00037 static objectlink *get_button_links(const object *button);
00038
00052 void trigger_connected(objectlink *ol, object *cause, const int state) {
00053 object *tmp;
00054
00055 for (; ol; ol = ol->next) {
00056 if (!ol->ob || ol->ob->count != ol->id) {
00057 LOG(llevError, "Internal error in trigger_connect. No object associated with link id (%d) (cause='%s'.\n", ol->id, (cause && cause->name) ? cause->name : "");
00058 continue;
00059 }
00060
00061
00062
00063
00064
00065
00066
00067
00068 if (QUERY_FLAG(ol->ob, FLAG_FREED))
00069 return;
00070 tmp = ol->ob;
00071
00072
00073 if (state && !QUERY_FLAG(tmp, FLAG_ACTIVATE_ON_PUSH))
00074 continue;
00075 if (!state && !QUERY_FLAG(tmp, FLAG_ACTIVATE_ON_RELEASE))
00076 continue;
00077
00078
00079
00080
00081
00082
00083 if (execute_event(tmp, EVENT_TRIGGER, cause, NULL, NULL, SCRIPT_FIX_ALL) != 0)
00084 continue;
00085
00086 switch (tmp->type) {
00087 case GATE:
00088 case HOLE:
00089 tmp->value = tmp->stats.maxsp ? !state : state;
00090 tmp->speed = 0.5;
00091 update_ob_speed(tmp);
00092 break;
00093
00094 case CF_HANDLE:
00095 SET_ANIMATION(tmp, (tmp->value = tmp->stats.maxsp ? !state : state));
00096 update_object(tmp, UP_OBJ_FACE);
00097 break;
00098
00099 case SIGN:
00100 if (!tmp->stats.food || tmp->last_eat < tmp->stats.food) {
00101 ext_info_map(NDI_UNIQUE|NDI_NAVY, tmp->map,
00102 MSG_TYPE_SIGN, MSG_SUBTYPE_NONE,
00103 tmp->msg, tmp->msg);
00104 if (tmp->stats.food)
00105 tmp->last_eat++;
00106 }
00107 break;
00108
00109 case ALTAR:
00110 tmp->value = 1;
00111 SET_ANIMATION(tmp, tmp->value);
00112 update_object(tmp, UP_OBJ_FACE);
00113 break;
00114
00115 case BUTTON:
00116 case PEDESTAL:
00117 tmp->value = state;
00118 SET_ANIMATION(tmp, tmp->value);
00119 update_object(tmp, UP_OBJ_FACE);
00120 break;
00121
00122 case TIMED_GATE:
00123 tmp->speed = tmp->arch->clone.speed;
00124 update_ob_speed(tmp);
00125 tmp->value = tmp->arch->clone.value;
00126 tmp->stats.sp = 1;
00127 tmp->stats.hp = tmp->stats.maxhp;
00128
00129
00130
00131 for (tmp = tmp->more; tmp != NULL; tmp = tmp->more) {
00132 tmp->speed = tmp->head->speed;
00133 tmp->value = tmp->head->value;
00134 tmp->stats.sp = tmp->head->stats.sp;
00135 tmp->stats.hp = tmp->head->stats.hp;
00136 update_ob_speed(tmp);
00137 }
00138 break;
00139
00140 case DIRECTOR:
00141 case FIREWALL:
00142 if (!QUERY_FLAG(tmp, FLAG_ANIMATE)&&tmp->type == FIREWALL)
00143 move_firewall(tmp);
00144 else {
00145 if ((tmp->stats.sp += tmp->stats.maxsp) > 8)
00146 tmp->stats.sp = ((tmp->stats.sp-1)%8)+1;
00147 animate_turning(tmp);
00148 }
00149 break;
00150
00151 default:
00152 ob_trigger(tmp, cause, state);
00153 }
00154 }
00155 }
00156
00165 void push_button(object *op) {
00166
00167 trigger_connected(get_button_links(op), op, op->value);
00168 }
00169
00178 void update_button(object *op) {
00179 object *ab, *tmp, *head;
00180 int tot, any_down = 0, old_value = op->value;
00181 objectlink *ol;
00182
00183
00184 for (ol = get_button_links(op); ol; ol = ol->next) {
00185 if (!ol->ob || ol->ob->count != ol->id) {
00186 LOG(llevDebug, "Internal error in update_button (%s).\n", op->name);
00187 continue;
00188 }
00189
00190 tmp = ol->ob;
00191 if (tmp->type == BUTTON) {
00192 for (ab = tmp->above, tot = 0; ab != NULL; ab = ab->above)
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 if ((ab->move_type&tmp->move_on) || ab->move_type == 0)
00207 tot += ab->weight*(ab->nrof ? ab->nrof : 1)+ab->carrying;
00208
00209 tmp->value = (tot >= tmp->weight) ? 1 : 0;
00210 if (tmp->value)
00211 any_down = 1;
00212 } else if (tmp->type == PEDESTAL) {
00213 tmp->value = 0;
00214 for (ab = tmp->above; ab != NULL; ab = ab->above) {
00215 head = ab->head ? ab->head : ab;
00216
00217 if (((head->move_type&tmp->move_on) || ab->move_type == 0)
00218 && (head->race == tmp->slaying
00219 || ((head->type == SPECIAL_KEY) && (head->slaying == tmp->slaying))
00220 || (!strcmp(tmp->slaying, "player") && head->type == PLAYER)))
00221 tmp->value = 1;
00222 }
00223 if (tmp->value)
00224 any_down = 1;
00225 }
00226 }
00227 if (any_down)
00228 op->value = 1;
00229
00230
00231 if (op->value != old_value) {
00232 SET_ANIMATION(op, op->value);
00233 update_object(op, UP_OBJ_FACE);
00234 push_button(op);
00235 }
00236 }
00237
00241 void update_buttons(mapstruct *m) {
00242 objectlink *ol;
00243 oblinkpt *obp;
00244
00245 for (obp = m->buttons; obp; obp = obp->next)
00246 for (ol = obp->link; ol; ol = ol->next) {
00247 if (!ol->ob || ol->ob->count != ol->id) {
00248 LOG(llevError, "Internal error in update_button (%s (%dx%d):%d, connected %ld).\n",
00249 ol->ob ? ol->ob->name : "null",
00250 ol->ob ? ol->ob->x : -1,
00251 ol->ob ? ol->ob->y : -1,
00252 ol->id,
00253 obp->value);
00254 continue;
00255 }
00256 if (ol->ob->type == BUTTON || ol->ob->type == PEDESTAL) {
00257 update_button(ol->ob);
00258 break;
00259 }
00260 }
00261 }
00262
00268 void use_trigger(object *op) {
00269
00270 op->value = !op->value;
00271 push_button(op);
00272 }
00273
00284 void animate_turning(object *op) {
00285 if (++op->state >= NUM_ANIMATIONS(op)/8)
00286 op->state = 0;
00287 SET_ANIMATION(op, (op->stats.sp-1)*NUM_ANIMATIONS(op)/8+op->state);
00288 update_object(op, UP_OBJ_FACE);
00289 }
00290
00291 #define ARCH_SACRIFICE(xyz) ((xyz)->slaying)
00292 #define NROF_SACRIFICE(xyz) ((uint32)(xyz)->stats.food)
00293
00305 static int matches_sacrifice(const object *altar, const object *sacrifice) {
00306 char name[MAX_BUF];
00307
00308 if (QUERY_FLAG(sacrifice, FLAG_ALIVE)
00309 || QUERY_FLAG(sacrifice, FLAG_IS_LINKED)
00310 || sacrifice->type == PLAYER)
00311 return 0;
00312
00313 query_base_name(sacrifice, 0, name, MAX_BUF);
00314 if (ARCH_SACRIFICE(altar) == sacrifice->arch->name
00315 || ARCH_SACRIFICE(altar) == sacrifice->name
00316 || ARCH_SACRIFICE(altar) == sacrifice->slaying
00317 || (!strcmp(ARCH_SACRIFICE(altar), name)))
00318 return 1;
00319
00320 if (strcmp(ARCH_SACRIFICE(altar), "money") == 0
00321 && sacrifice->type == MONEY)
00322 return 1;
00323
00324 return 0;
00325 }
00326
00355 int check_altar_sacrifice(const object *altar, const object *sacrifice, int remove_others, int *toremove) {
00356 int money;
00357 object *tmp;
00358 int wanted, rest;
00359 object *above;
00360
00361 if (!matches_sacrifice(altar, sacrifice))
00362
00363
00364 return 0;
00365
00366
00367 if (QUERY_FLAG(sacrifice, FLAG_UNPAID)) {
00368 return 0;
00369 }
00370
00371 money = (strcmp(ARCH_SACRIFICE(altar), "money") == 0) ? 1 : 0;
00372
00373
00374 if (money && sacrifice->nrof*sacrifice->value >= NROF_SACRIFICE(altar)) {
00375 if (toremove) {
00376 *toremove = NROF_SACRIFICE(altar)/sacrifice->value;
00377
00378 if (NROF_SACRIFICE(altar)%sacrifice->value)
00379 (*toremove)++;
00380 }
00381 return 1;
00382 }
00383
00384 if (!money && NROF_SACRIFICE(altar) <= (sacrifice->nrof ? sacrifice->nrof : 1)) {
00385 if (toremove)
00386 *toremove = NROF_SACRIFICE(altar);
00387 return 1;
00388 }
00389
00390 if (money) {
00391 wanted = NROF_SACRIFICE(altar)-sacrifice->nrof*sacrifice->value;
00392 } else {
00393 wanted = NROF_SACRIFICE(altar)-(sacrifice->nrof ? sacrifice->nrof : 1);
00394 }
00395 rest = wanted;
00396
00397
00398
00399
00400 for (tmp = altar->above; tmp != NULL && wanted > 0; tmp = tmp->above) {
00401 if (tmp == sacrifice || !matches_sacrifice(altar, tmp))
00402 continue;
00403 if (money)
00404 wanted -= tmp->nrof*tmp->value;
00405 else
00406 wanted -= (tmp->nrof ? tmp->nrof : 1);
00407 }
00408
00409 if (wanted > 0)
00410
00411 return 0;
00412
00413
00414
00415
00416 if (toremove)
00417 *toremove = sacrifice->nrof ? sacrifice->nrof : 1;
00418
00419 if (!remove_others)
00420 return 1;
00421
00422
00423 for (tmp = altar->above; tmp != NULL && rest > 0; tmp = above) {
00424 above = tmp->above;
00425 if (tmp == sacrifice || !matches_sacrifice(altar, tmp))
00426 continue;
00427 if (money) {
00428 wanted = tmp->nrof*tmp->value;
00429 if (rest > wanted) {
00430 remove_ob(tmp);
00431 rest -= wanted;
00432 } else {
00433 wanted = rest/tmp->value;
00434 if (rest%tmp->value)
00435 wanted++;
00436 decrease_ob_nr(tmp, wanted);
00437 return 1;
00438 }
00439 } else
00440 if (rest > (tmp->nrof ? tmp->nrof : 1)) {
00441 rest -= (tmp->nrof ? tmp->nrof : 1);
00442 remove_ob(tmp);
00443 } else {
00444 decrease_ob_nr(tmp, rest);
00445 return 1;
00446 }
00447 }
00448
00449
00450 LOG(llevError, "check_altar_sacrifice on %s: found objects to sacrifice, but couldn't remove them??\n", altar->map->path);
00451 return 1;
00452 }
00453
00470 int operate_altar(object *altar, object **sacrifice) {
00471 int number;
00472
00473 if (!altar->map) {
00474 LOG(llevError, "BUG: operate_altar(): altar has no map\n");
00475 return 0;
00476 }
00477
00478 if (!altar->slaying || altar->value)
00479 return 0;
00480
00481 if (!check_altar_sacrifice(altar, *sacrifice, 1, &number))
00482 return 0;
00483
00484
00485 *sacrifice = decrease_ob_nr(*sacrifice, number);
00486
00487 if (altar->msg)
00488 ext_info_map(NDI_BLACK, altar->map, MSG_TYPE_DIALOG, MSG_TYPE_DIALOG_ALTAR, altar->msg, altar->msg);
00489 return 1;
00490 }
00491
00495 static void trigger_move(object *op, int state) {
00496 op->stats.wc = state;
00497 if (state) {
00498 use_trigger(op);
00499 if (op->stats.exp > 0)
00500 op->speed = 1.0/op->stats.exp;
00501 else
00502 op->speed = 1.0;
00503 update_ob_speed(op);
00504 op->speed_left = -1;
00505 } else {
00506 use_trigger(op);
00507 op->speed = 0;
00508 update_ob_speed(op);
00509 }
00510 }
00511
00525 int check_trigger(object *op, object *cause) {
00526 object *tmp;
00527 int push = 0, tot = 0;
00528 int in_movement = op->stats.wc || op->speed;
00529
00530 switch (op->type) {
00531 case TRIGGER_BUTTON:
00532 if (op->weight > 0) {
00533 if (cause) {
00534 for (tmp = op->above; tmp; tmp = tmp->above)
00535
00536
00537
00538
00539
00540
00541
00542 if ((tmp->move_type&op->move_on) || tmp->move_type == 0) {
00543 tot += tmp->weight*(tmp->nrof ? tmp->nrof : 1)+tmp->carrying;
00544 }
00545 if (tot >= op->weight)
00546 push = 1;
00547 if (op->stats.ac == push)
00548 return 0;
00549 op->stats.ac = push;
00550 if (NUM_ANIMATIONS(op) > 1) {
00551 SET_ANIMATION(op, push);
00552 update_object(op, UP_OBJ_FACE);
00553 }
00554 if (in_movement || !push)
00555 return 0;
00556 }
00557 trigger_move(op, push);
00558 }
00559 return 0;
00560
00561 case TRIGGER_PEDESTAL:
00562 if (cause) {
00563 for (tmp = op->above; tmp; tmp = tmp->above) {
00564 object *head = tmp->head ? tmp->head : tmp;
00565
00566
00567 if (((head->move_type&op->move_on) || head->move_type == 0)
00568 && (head->race == op->slaying || (!strcmp(op->slaying, "player") && head->type == PLAYER))) {
00569 push = 1;
00570 break;
00571 }
00572 }
00573 if (op->stats.ac == push)
00574 return 0;
00575 op->stats.ac = push;
00576 if (NUM_ANIMATIONS(op) > 1) {
00577 SET_ANIMATION(op, push);
00578 update_object(op, UP_OBJ_FACE);
00579 }
00580 if (in_movement || !push)
00581 return 0;
00582 }
00583 trigger_move(op, push);
00584 return 0;
00585
00586 case TRIGGER_ALTAR:
00587 if (cause) {
00588 if (in_movement)
00589 return 0;
00590 if (operate_altar(op, &cause)) {
00591 if (NUM_ANIMATIONS(op) > 1) {
00592 SET_ANIMATION(op, 1);
00593 update_object(op, UP_OBJ_FACE);
00594 }
00595
00596 if (op->last_sp >= 0) {
00597 trigger_move(op, 1);
00598 if (op->last_sp > 0)
00599 op->last_sp = -op->last_sp;
00600 } else {
00601
00602
00603
00604 op->value = !op->value;
00605 trigger_move(op, 1);
00606 op->last_sp = -op->last_sp;
00607 op->value = !op->value;
00608 }
00609 return cause == NULL;
00610 } else {
00611 return 0;
00612 }
00613 } else {
00614 if (NUM_ANIMATIONS(op) > 1) {
00615 SET_ANIMATION(op, 0);
00616 update_object(op, UP_OBJ_FACE);
00617 }
00618
00619
00620
00621
00622
00623
00624 if (!op->last_sp)
00625 trigger_move(op, 0);
00626 else {
00627 op->stats.wc = 0;
00628 op->value = !op->value;
00629 op->speed = 0;
00630 update_ob_speed(op);
00631 }
00632 }
00633 return 0;
00634
00635 case TRIGGER:
00636 if (cause) {
00637 if (in_movement)
00638 return 0;
00639 push = 1;
00640 }
00641 if (NUM_ANIMATIONS(op) > 1) {
00642 SET_ANIMATION(op, push);
00643 update_object(op, UP_OBJ_FACE);
00644 }
00645 trigger_move(op, push);
00646 return 1;
00647
00648 default:
00649 LOG(llevDebug, "Unknown trigger type: %s (%d)\n", op->name, op->type);
00650 return 0;
00651 }
00652 }
00653
00663 void add_button_link(object *button, mapstruct *map, int connected) {
00664 oblinkpt *obp;
00665 objectlink *ol = get_objectlink();
00666
00667 if (!map) {
00668 LOG(llevError, "Tried to add button-link without map.\n");
00669 free_objectlink(ol);
00670 return;
00671 }
00672
00673 SET_FLAG(button, FLAG_IS_LINKED);
00674
00675 ol->ob = button;
00676 ol->id = button->count;
00677
00678 for (obp = map->buttons; obp && obp->value != connected; obp = obp->next)
00679 ;
00680
00681 if (obp) {
00682 ol->next = obp->link;
00683 obp->link = ol;
00684 } else {
00685 obp = get_objectlinkpt();
00686 obp->value = connected;
00687
00688 obp->next = map->buttons;
00689 map->buttons = obp;
00690 obp->link = ol;
00691 }
00692 }
00693
00700 void remove_button_link(object *op) {
00701 oblinkpt *obp;
00702 objectlink **olp, *ol;
00703
00704 if (op->map == NULL) {
00705 LOG(llevError, "remove_button_link() in object without map.\n");
00706 return;
00707 }
00708 if (!QUERY_FLAG(op, FLAG_IS_LINKED)) {
00709 LOG(llevError, "remove_button_linked() in unlinked object.\n");
00710 return;
00711 }
00712
00713 for (obp = op->map->buttons; obp; obp = obp->next)
00714 for (olp = &obp->link; (ol = *olp); olp = &ol->next)
00715 if (ol->ob == op) {
00716
00717
00718
00719 *olp = ol->next;
00720 free(ol);
00721 return;
00722 }
00723 LOG(llevError, "remove_button_linked(): couldn't find object.\n");
00724 CLEAR_FLAG(op, FLAG_IS_LINKED);
00725 }
00726
00734 static objectlink *get_button_links(const object *button) {
00735 oblinkpt *obp;
00736 objectlink *ol;
00737
00738 if (!button->map)
00739 return NULL;
00740
00741 for (obp = button->map->buttons; obp; obp = obp->next)
00742 for (ol = obp->link; ol; ol = ol->next)
00743 if (ol->ob == button && ol->id == button->count)
00744 return obp->link;
00745 return NULL;
00746 }
00747
00756 int get_button_value(const object *button) {
00757 oblinkpt *obp;
00758 objectlink *ol;
00759
00760 if (!button->map)
00761 return 0;
00762
00763 for (obp = button->map->buttons; obp; obp = obp->next)
00764 for (ol = obp->link; ol; ol = ol->next)
00765 if (ol->ob == button && ol->id == button->count)
00766 return obp->value;
00767 return 0;
00768 }
00769
00788 object *check_inv_recursive(object *op, const object *trig) {
00789 object *tmp, *ret = NULL;
00790
00791
00792 if ((!trig->stats.hp || (op->type == trig->stats.hp))
00793 && (!trig->slaying || (op->slaying == trig->slaying))
00794 && (!trig->race || (op->arch->name == trig->race))
00795 && (!trig->title || (op->title == trig->title)))
00796 return op;
00797
00798 for (tmp = op->inv; tmp; tmp = tmp->below) {
00799 if (tmp->inv) {
00800 ret = check_inv_recursive(tmp, trig);
00801 if (ret)
00802 return ret;
00803 } else if ((!trig->stats.hp || (tmp->type == trig->stats.hp))
00804 && (!trig->slaying || (tmp->slaying == trig->slaying))
00805 && (!trig->race || (tmp->arch->name == trig->race))
00806 && (!trig->title || (tmp->title == trig->title)))
00807 return tmp;
00808 }
00809
00810 return NULL;
00811 }
00812
00828 void check_inv(object *op, object *trig) {
00829 object *match;
00830
00831 if (op->type != PLAYER)
00832 return;
00833
00834 match = check_inv_recursive(op, trig);
00835 if (match && trig->last_sp) {
00836 if (trig->last_heal)
00837 decrease_ob(match);
00838 use_trigger(trig);
00839 } else if (!match && !trig->last_sp)
00840 use_trigger(trig);
00841 }
00842
00853 void verify_button_links(const mapstruct *map) {
00854 oblinkpt *obp;
00855 objectlink *ol;
00856
00857 if (!map)
00858 return;
00859
00860 for (obp = map->buttons; obp; obp = obp->next) {
00861 for (ol = obp->link; ol; ol = ol->next) {
00862 if (ol->id != ol->ob->count)
00863 LOG(llevError, "verify_button_links: object %s on list is corrupt (%d!=%d)\n", ol->ob->name, ol->id, ol->ob->count);
00864 }
00865 }
00866 }