version 1.2 | | version 1.3 |
---|
| | |
/* | | /* |
* static char *rcsid_button_c = | | * static char *rcsid_button_c = |
* "$Id: button.c,v 1.2 1999/07/13 06:02:41 cvs Exp $"; | | * "$Id: button.c,v 1.3 2000/05/26 09:50:45 jec Exp $"; |
*/ | | */ |
| | |
/* | | /* |
| | |
*/ | | */ |
| | |
void update_button(object *op) { | | void update_button(object *op) { |
object *ab,*tmp; | | object *ab,*tmp,*head; |
int tot,any_down=0, old_value=op->value; | | int tot,any_down=0, old_value=op->value; |
objectlink *ol; | | objectlink *ol; |
| | |
| | |
} else if (tmp->type == PEDESTAL) { | | } else if (tmp->type == PEDESTAL) { |
tmp->value = 0; | | tmp->value = 0; |
for(ab=tmp->above; ab!=NULL; ab=ab->above) { | | for(ab=tmp->above; ab!=NULL; ab=ab->above) { |
if(ab->head!=NULL) | | head = ab->head ? ab->head : ab; |
ab=ab->head; | | if ( (!QUERY_FLAG(head,FLAG_FLYING) || |
if ( (!QUERY_FLAG(ab,FLAG_FLYING) || | | |
QUERY_FLAG(tmp,FLAG_FLY_ON)) && | | QUERY_FLAG(tmp,FLAG_FLY_ON)) && |
(ab->race==tmp->slaying || | | (head->race==tmp->slaying || |
((ab->type==SPECIAL_KEY) && (ab->slaying==tmp->slaying)) || | | ((head->type==SPECIAL_KEY) && (head->slaying==tmp->slaying)) || |
(!strcmp (tmp->slaying, "player") && | | (!strcmp (tmp->slaying, "player") && |
ab->type == PLAYER))) | | head->type == PLAYER))) |
tmp->value = 1; | | tmp->value = 1; |
} | | } |
if(tmp->value) | | if(tmp->value) |
| | |
#define ARCH_SACRIFICE(xyz) ((xyz)->slaying) | | #define ARCH_SACRIFICE(xyz) ((xyz)->slaying) |
#define NROF_SACRIFICE(xyz) ((xyz)->stats.food) | | #define NROF_SACRIFICE(xyz) ((xyz)->stats.food) |
| | |
/* Returns that object if it meets the sacrifice needs of the altar. | | /* Returns true if the sacrifice meets the needs of the altar. |
* If no object meets the needs, return NULL. | | * |
* Function put in (0.92.1) so that identify altars won't grab money | | * Function put in (0.92.1) so that identify altars won't grab money |
* unnecessarily - we can see if there is sufficient money, see if something | | * unnecessarily - we can see if there is sufficient money, see if something |
* needs to be identified, and then remove money if needed. (via check_altar) | | * needs to be identified, and then remove money if needed. |
* Check_altar uses this function also. | | * |
* 0.93.4: Linked objects (ie, objects that are connected) can not be | | * 0.93.4: Linked objects (ie, objects that are connected) can not be |
* sacrificed. This fixes a bug of trying to put multiple altars/related | | * sacrificed. This fixes a bug of trying to put multiple altars/related |
* objects on the same space that take the same sacrifice. | | * objects on the same space that take the same sacrifice. |
*/ | | */ |
| | |
object *check_altar_sacrifice(object *altar) | | int check_altar_sacrifice (object *altar, object *sacrifice) |
{ | | { |
object *op; | | if ( ! QUERY_FLAG (sacrifice, FLAG_ALIVE) |
| | && ! QUERY_FLAG (sacrifice, FLAG_IS_LINKED) |
for (op=altar->above; op; op=op->above) | | && sacrifice->type != PLAYER) |
if (!QUERY_FLAG(op,FLAG_ALIVE) && !QUERY_FLAG(op,FLAG_IS_LINKED) && | | { |
op->type != PLAYER) { | | if ((ARCH_SACRIFICE(altar) == sacrifice->arch->name || |
if ((ARCH_SACRIFICE(altar) == op->arch->name || | | ARCH_SACRIFICE(altar) == sacrifice->name || |
ARCH_SACRIFICE(altar) == op->name || | | ARCH_SACRIFICE(altar) == sacrifice->slaying) |
ARCH_SACRIFICE(altar) == op->slaying) | | && NROF_SACRIFICE(altar) <= (sacrifice->nrof?sacrifice->nrof:1)) |
&& NROF_SACRIFICE(altar) <= (op->nrof?op->nrof:1)) | | return 1; |
return op; | | if (strcmp (ARCH_SACRIFICE(altar), "money") == 0 |
if (!strcmp(ARCH_SACRIFICE(altar), "money") && | | && sacrifice->type == MONEY |
op->type==MONEY && op->nrof*op->value>=NROF_SACRIFICE(altar)) | | && sacrifice->nrof * sacrifice->value >= NROF_SACRIFICE(altar)) |
return op; | | return 1; |
} | | } |
return NULL; | | return 0; |
} | | } |
| | |
| | |
/* | | /* |
* check_altar checks if sacrifice was accepted and removes sacrificed | | * operate_altar checks if sacrifice was accepted and removes sacrificed |
* objects. If sacrifice was succeed return 1 else 0 Might be better to | | * objects. If sacrifice was succeed return 1 else 0. Might be better to |
* call check_altar_sacrifice (above) than depend on the return value, | | * call check_altar_sacrifice (above) than depend on the return value, |
* since check_altar will remove the sacrifice also. | | * since operate_altar will remove the sacrifice also. |
* | | * |
* Don't really like the name of this functin, operate_altar might be better - | | * If this function returns 1, '*sacrifice' is modified to point to the |
* we aren't really checking it, since it will remove the sacrifice | | * remaining sacrifice, or is set to NULL if the sacrifice was used up. |
*/ | | */ |
| | |
int check_altar (object *altar) | | int operate_altar (object *altar, object **sacrifice) |
{ | | { |
object *op; | | object *op; |
| | |
| | if ( ! altar->map) { |
| | LOG (llevError, "BUG: operate_altar(): altar has no map\n"); |
| | return 0; |
| | } |
| | |
if (!altar->slaying || altar->value) | | if (!altar->slaying || altar->value) |
return 0; | | return 0; |
| | |
op=check_altar_sacrifice(altar); | | if ( ! check_altar_sacrifice (altar, *sacrifice)) |
if (!op) | | |
return 0; | | return 0; |
| | |
/* get_altar_sacrifice should have already verified that enough money | | /* check_altar_sacrifice should have already verified that enough money |
* has been dropped. | | * has been dropped. |
*/ | | */ |
if (!strcmp(ARCH_SACRIFICE(altar), "money")) { | | if (!strcmp(ARCH_SACRIFICE(altar), "money")) { |
int number=NROF_SACRIFICE(altar)/op->value; | | int number=NROF_SACRIFICE(altar) / (*sacrifice)->value; |
| | |
/* Round up any sacrifices. Altars don't make change either */ | | /* Round up any sacrifices. Altars don't make change either */ |
if (NROF_SACRIFICE(altar)%op->value) number++; | | if (NROF_SACRIFICE(altar) % (*sacrifice)->value) number++; |
decrease_ob_nr (op, number); | | *sacrifice = decrease_ob_nr (*sacrifice, number); |
} | | } |
else | | else |
decrease_ob_nr (op, NROF_SACRIFICE(altar)); | | *sacrifice = decrease_ob_nr (*sacrifice, NROF_SACRIFICE(altar)); |
| | |
for (op = get_map_ob(altar->map,altar->x,altar->y); | | if (altar->msg) |
op && op->type != PLAYER; op=op->above); | | (*info_map_func) (NDI_BLACK, altar->map, altar->msg); |
if (op && altar->msg) | | |
(*info_map_func) (NDI_BLACK, op->map, altar->msg); | | |
return 1; | | return 1; |
} | | } |
| | |
void trigger_move (object *op, int state) /* 1 down and 0 up */ | | void trigger_move (object *op, int state) /* 1 down and 0 up */ |
{ | | { |
op->stats.wc = state; | | op->stats.wc = state; |
SET_ANIMATION(op,op->stats.wc); | | |
update_object(op); | | |
if (state) { | | if (state) { |
| | |
/* Push button now does it all. */ | | |
use_trigger(op); | | use_trigger(op); |
| | op->speed = 1.0 / op->arch->clone.stats.exp; |
op->speed = op->arch->clone.speed; | | |
update_ob_speed(op); | | update_ob_speed(op); |
op->speed_left = -1; | | op->speed_left = -1; |
} else { | | } else { |
| | use_trigger(op); |
op->speed = 0; | | op->speed = 0; |
update_ob_speed(op); | | update_ob_speed(op); |
} | | } |
} | | } |
| | |
void check_trigger (object *op) { | | |
| | /* |
| | * cause != NULL: something has moved on top of op |
| | * |
| | * cause == NULL: nothing has moved, we have been called from |
| | * animate_trigger(). |
| | * |
| | * TRIGGER_ALTAR: Returns 1 if 'cause' was destroyed, 0 if not. |
| | * |
| | * TRIGGER: Returns 1 if handle could be moved, 0 if not. |
| | * |
| | * TRIGGER_BUTTON, TRIGGER_PEDESTAL: Returns 0. |
| | */ |
| | int check_trigger (object *op, object *cause) |
| | { |
object *tmp; | | object *tmp; |
int push = 0, tot = 0; | | int push = 0, tot = 0; |
| | int in_movement = op->stats.wc || op->speed; |
| | |
switch (op->type) { | | switch (op->type) { |
case TRIGGER_BUTTON: | | case TRIGGER_BUTTON: |
if (op->weight > 0) { | | if (op->weight > 0) { |
| | if (cause) { |
for(tmp=op->above; tmp; tmp=tmp->above) | | for(tmp=op->above; tmp; tmp=tmp->above) |
if(!QUERY_FLAG(tmp,FLAG_FLYING)) | | if(!QUERY_FLAG(tmp,FLAG_FLYING)) |
tot += tmp->weight * (tmp->nrof ? tmp->nrof : 1) + tmp->carrying; | | tot += tmp->weight * (tmp->nrof ? tmp->nrof : 1) |
| | + tmp->carrying; |
if (tot >= op->weight) | | if (tot >= op->weight) |
push = 1; | | push = 1; |
if (!push || op->stats.wc == 0) | | if (op->stats.ac == push) |
| | return 0; |
| | op->stats.ac = push; |
| | SET_ANIMATION (op, push); |
| | update_object (op); |
| | if (in_movement || ! push) |
| | return 0; |
| | } |
trigger_move (op, push); | | trigger_move (op, push); |
} | | } |
return; | | return 0; |
| | |
case TRIGGER_PEDESTAL: | | case TRIGGER_PEDESTAL: |
| | if (cause) { |
for(tmp=op->above; tmp; tmp=tmp->above) { | | for(tmp=op->above; tmp; tmp=tmp->above) { |
if(tmp->head!=NULL) | | object *head = tmp->head ? tmp->head : tmp; |
tmp=tmp->head; | | if ((!QUERY_FLAG(head,FLAG_FLYING) || QUERY_FLAG(op,FLAG_FLY_ON)) |
if ( (!QUERY_FLAG(tmp,FLAG_FLYING) || QUERY_FLAG(op,FLAG_FLY_ON)) | | && (head->race==op->slaying || |
&& (tmp->race==op->slaying || | | (!strcmp (op->slaying, "player") && head->type == PLAYER))) |
(!strcmp (op->slaying, "player") && tmp->type == PLAYER))) | | { |
push = 1; | | push = 1; |
| | break; |
| | } |
| | } |
| | if (op->stats.ac == push) |
| | return 0; |
| | op->stats.ac = push; |
| | SET_ANIMATION (op, push); |
| | update_object(op); |
| | if (in_movement || ! push) |
| | return 0; |
} | | } |
if (!push || op->stats.wc == 0) | | |
trigger_move(op, push); | | trigger_move(op, push); |
return; | | return 0; |
| | |
case TRIGGER_ALTAR: | | case TRIGGER_ALTAR: |
if (op->stats.wc == 0) | | if (cause) { |
trigger_move (op, op->speed == 0 ? check_altar(op) : 0); | | if (in_movement) |
return; | | return 0; |
| | if (operate_altar (op, &cause)) { |
| | SET_ANIMATION (op, 1); |
| | update_object(op); |
| | trigger_move (op, 1); |
| | return cause == NULL; |
| | } else { |
| | return 0; |
| | } |
| | } else { |
| | SET_ANIMATION (op, 0); |
| | update_object(op); |
| | trigger_move (op, 0); |
| | } |
| | return 0; |
| | |
case TRIGGER: | | case TRIGGER: |
if (op->stats.wc == 0) /* handle-trigger */ | | if (cause) { |
trigger_move (op, op->speed == 0 ? 1 : 0); | | if (in_movement) |
return; | | return 0; |
| | push = 1; |
| | } |
| | SET_ANIMATION (op, push); |
| | update_object(op); |
| | trigger_move (op, push); |
| | return 1; |
| | |
default: | | default: |
LOG(llevDebug, "Unknown trigger type: %s (%d)\n", op->name, op->type); | | LOG(llevDebug, "Unknown trigger type: %s (%d)\n", op->name, op->type); |
| | return 0; |
} | | } |
} | | } |
| | |