version 1.148 | | version 1.149 |
---|
| | |
/* | | /* |
* static char *rcsid_apply_c = | | * static char *rcsid_apply_c = |
* "$Id: apply.c,v 1.148 2005/10/28 19:08:53 akirschbaum Exp $"; | | * "$Id: apply.c,v 1.149 2005/11/16 08:16:08 mwedel Exp $"; |
*/ | | */ |
/* | | /* |
CrossFire, A Multiplayer game for X-windows | | CrossFire, A Multiplayer game for X-windows |
| | |
tmp->below = sack->inv; | | tmp->below = sack->inv; |
tmp->above = NULL; | | tmp->above = NULL; |
sack->inv = tmp; | | sack->inv = tmp; |
SET_FLAG (sack, FLAG_WALK_OFF); /* trying force closing it */ | | sack->move_off = MOVE_ALL; /* trying force closing it */ |
SET_FLAG (sack, FLAG_FLY_OFF); | | |
} else { | | } else { |
CLEAR_FLAG (sack, FLAG_WALK_OFF); | | sack->move_off = 0; |
CLEAR_FLAG (sack, FLAG_FLY_OFF); | | |
tmp = sack->inv; | | tmp = sack->inv; |
if (tmp && tmp->type == CLOSE_CON) { | | if (tmp && tmp->type == CLOSE_CON) { |
remove_ob(tmp); | | remove_ob(tmp); |
| | |
| | |
if (op->container && QUERY_FLAG(sack, FLAG_APPLIED)) { | | if (op->container && QUERY_FLAG(sack, FLAG_APPLIED)) { |
if (op->container->env != op) { /* if container is on the ground */ | | if (op->container->env != op) { /* if container is on the ground */ |
CLEAR_FLAG (op->container, FLAG_WALK_OFF); | | op->container->move_off = 0; |
CLEAR_FLAG (op->container, FLAG_FLY_OFF); | | |
} | | } |
/* Lauwenmark: Handle for plugin close event */ | | /* Lauwenmark: Handle for plugin close event */ |
if (execute_event(tmp, EVENT_CLOSE,op,NULL,NULL,SCRIPT_FIX_ALL)!=0) | | if (execute_event(tmp, EVENT_CLOSE,op,NULL,NULL,SCRIPT_FIX_ALL)!=0) |
return 1; | | return 1; |
| | |
new_draw_info_format(NDI_UNIQUE, 0, op, "You close %s.", | | new_draw_info_format(NDI_UNIQUE, 0, op, "You close %s.", |
query_name(op->container)); | | query_name(op->container)); |
CLEAR_FLAG(op->container, FLAG_APPLIED); | | CLEAR_FLAG(op->container, FLAG_APPLIED); |
| | |
return 0; | | return 0; |
} | | } |
/* set these so when the player walks off, we can unapply the sack */ | | /* set these so when the player walks off, we can unapply the sack */ |
SET_FLAG (sack, FLAG_WALK_OFF); /* trying force closing it */ | | sack->move_off = MOVE_ALL; /* trying force closing it */ |
SET_FLAG (sack, FLAG_FLY_OFF); | | |
| | |
CLEAR_FLAG (sack, FLAG_APPLIED); | | CLEAR_FLAG (sack, FLAG_APPLIED); |
new_draw_info_format(NDI_UNIQUE, 0, op, "You open %s.", query_name(sack)); | | new_draw_info_format(NDI_UNIQUE, 0, op, "You open %s.", query_name(sack)); |
| | |
for (tmp=op->inv; tmp; tmp=next) { | | for (tmp=op->inv; tmp; tmp=next) { |
next = tmp->below; | | next = tmp->below; |
if (QUERY_FLAG(tmp, FLAG_UNPAID)) { | | if (QUERY_FLAG(tmp, FLAG_UNPAID)) { |
int i = find_free_spot (tmp->arch, op->map, op->x, op->y, 1, 9); | | int i = find_free_spot (tmp, op->map, op->x, op->y, 1, 9); |
| | |
remove_ob(tmp); | | remove_ob(tmp); |
if (i==-1) i=0; | | if (i==-1) i=0; |
| | |
if (QUERY_FLAG(op, FLAG_UNPAID) || !QUERY_FLAG(op, FLAG_ALIVE)) { | | if (QUERY_FLAG(op, FLAG_UNPAID) || !QUERY_FLAG(op, FLAG_ALIVE)) { |
| | |
/* Somebody dropped an unpaid item, just move to an adjacent place. */ | | /* Somebody dropped an unpaid item, just move to an adjacent place. */ |
int i = find_free_spot (op->arch, op->map, op->x, op->y, 1, 9); | | int i = find_free_spot (op, op->map, op->x, op->y, 1, 9); |
if (i != -1) { | | if (i != -1) { |
rv = transfer_ob (op, op->x + freearr_x[i], op->y + freearr_y[i], 0, | | rv = transfer_ob (op, op->x + freearr_x[i], op->y + freearr_y[i], 0, |
shop_mat); | | shop_mat); |
| | |
* they are not on the mat anymore | | * they are not on the mat anymore |
*/ | | */ |
| | |
int i = find_free_spot (op->arch, op->map, op->x, op->y, 1, 9); | | int i = find_free_spot (op, op->map, op->x, op->y, 1, 9); |
if(i == -1) { | | if(i == -1) { |
LOG (llevError, "Internal shop-mat problem.\n"); | | LOG (llevError, "Internal shop-mat problem.\n"); |
} else { | | } else { |
| | |
| | |
if (sign->stats.food) { | | if (sign->stats.food) { |
if (sign->last_eat >= sign->stats.food) { | | if (sign->last_eat >= sign->stats.food) { |
if (!QUERY_FLAG (sign, FLAG_WALK_ON) && !QUERY_FLAG (sign, FLAG_FLY_ON)) | | if (!sign->move_on) |
new_draw_info (NDI_UNIQUE, 0, op, "You cannot read it anymore."); | | new_draw_info (NDI_UNIQUE, 0, op, "You cannot read it anymore."); |
return; | | return; |
} | | } |
| | |
} | | } |
| | |
/* Sign or magic mouth? Do we need to see it, or does it talk to us? | | /* Sign or magic mouth? Do we need to see it, or does it talk to us? |
* No way to know for sure. | | * No way to know for sure. The presumption is basically that if |
* | | * move_on is zero, it needs to be manually applied (doesn't talk |
* This check fails for signs with FLAG_WALK_ON/FLAG_FLY_ON. Checking | | * to us). |
* for FLAG_INVISIBLE instead of FLAG_WALK_ON/FLAG_FLY_ON would fail | | */ |
* for magic mouths that have been made visible. | | if (QUERY_FLAG (op, FLAG_BLIND) && ! QUERY_FLAG (op, FLAG_WIZ) && !sign->move_on) { |
*/ | | |
if (QUERY_FLAG (op, FLAG_BLIND) && ! QUERY_FLAG (op, FLAG_WIZ) | | |
&& ! QUERY_FLAG (sign, FLAG_WALK_ON) | | |
&& ! QUERY_FLAG (sign, FLAG_FLY_ON)) | | |
{ | | |
new_draw_info (NDI_UNIQUE, 0, op, | | new_draw_info (NDI_UNIQUE, 0, op, |
"You are unable to read while blind."); | | "You are unable to read while blind."); |
return; | | return; |
| | |
| | |
| | |
/** | | /** |
* 'victim' moves onto 'trap' (trap has FLAG_WALK_ON or FLAG_FLY_ON set) or | | * 'victim' moves onto 'trap' |
* 'victim' leaves 'trap' (trap has FLAG_WALK_OFF or FLAG_FLY_OFF) set. | | * 'victim' leaves 'trap' |
| | * effect is determined by move_on/move_off of trap and move_type of victime. |
* | | * |
* originator: Player, monster or other object that caused 'victim' to move | | * originator: Player, monster or other object that caused 'victim' to move |
* onto 'trap'. Will receive messages caused by this action. May be NULL. | | * onto 'trap'. Will receive messages caused by this action. May be NULL. |
| | |
{ | | { |
static int recursion_depth = 0; | | static int recursion_depth = 0; |
/* move_apply() is the most likely candidate for causing unwanted and | | /* move_apply() is the most likely candidate for causing unwanted and |
* possibly unlimited recursion. */ | | * possibly unlimited recursion. |
| | */ |
/* The following was changed because it was causing perfeclty correct | | /* The following was changed because it was causing perfeclty correct |
maps to fail. 1) it's not an error to recurse: | | * maps to fail. 1) it's not an error to recurse: |
rune detonates, summoning monster. monster lands on nearby rune. | | * rune detonates, summoning monster. monster lands on nearby rune. |
nearby rune detonates. This sort of recursion is expected and | | * nearby rune detonates. This sort of recursion is expected and |
proper. This code was causing needless crashes. */ | | * proper. This code was causing needless crashes. |
| | */ |
if (recursion_depth >= 500) { | | if (recursion_depth >= 500) { |
LOG (llevDebug, "WARNING: move_apply(): aborting recursion " | | LOG (llevDebug, "WARNING: move_apply(): aborting recursion " |
"[trap arch %s, name %s; victim arch %s, name %s]\n", | | "[trap arch %s, name %s; victim arch %s, name %s]\n", |
| | |
return; | | return; |
} | | } |
recursion_depth++; | | recursion_depth++; |
if (trap->head) | | if (trap->head) trap=trap->head; |
trap=trap->head; | | |
/* Lauwenmark: Handle for plugin trigger event */ | | /* Lauwenmark: Handle for plugin trigger event */ |
if (execute_event(trap, EVENT_TRIGGER,originator,victim,NULL,SCRIPT_FIX_ALL)!=0) | | if (execute_event(trap, EVENT_TRIGGER,originator,victim,NULL,SCRIPT_FIX_ALL)!=0) |
return; | | return; |
switch (trap->type) | | |
{ | | switch (trap->type) { |
case PLAYERMOVER: | | case PLAYERMOVER: |
if (trap->attacktype && (trap->level || victim->type!=PLAYER) && | | if (trap->attacktype && (trap->level || victim->type!=PLAYER) && |
!should_director_abort(trap, victim)) { | | !should_director_abort(trap, victim)) { |
if (!trap->stats.maxsp) trap->stats.maxsp=2.0; | | if (!trap->stats.maxsp) trap->stats.maxsp=2.0; |
| | |
/* Is this correct? From the docs, it doesn't look like it | | /* Is this correct? From the docs, it doesn't look like it |
* should be divided by trap->speed | | * should be divided by trap->speed |
*/ | | */ |
victim->speed_left = -FABS(trap->stats.maxsp*victim->speed/trap->speed); | | victim->speed_left = -FABS(trap->stats.maxsp*victim->speed/trap->speed); |
| | |
/* Just put in some sanity check. I think there is a bug in the | | /* Just put in some sanity check. I think there is a bug in the |
* above with some objects have zero speed, and thus the player | | * above with some objects have zero speed, and thus the player |
* getting permanently paralyzed. | | * getting permanently paralyzed. |
*/ | | */ |
if (victim->speed_left<-50.0) victim->speed_left=-50.0; | | if (victim->speed_left<-50.0) victim->speed_left=-50.0; |
/* LOG(llevDebug, "apply, playermove, player speed_left=%f\n", | | /* LOG(llevDebug, "apply, playermove, player speed_left=%f\n", victim->speed_left);*/ |
victim->speed_left);*/ | | |
} | | } |
goto leave; | | goto leave; |
| | |
| | |
if (trap->inv == NULL) | | if (trap->inv == NULL) |
goto leave; | | goto leave; |
/* fallthrough */ | | /* fallthrough */ |
| | |
case ARROW: | | case ARROW: |
| | |
/* bad bug: monster throw a object, make a step forwards, step on object , | | /* bad bug: monster throw a object, make a step forwards, step on object , |
* trigger this here and get hit by own missile - and will be own enemy. | | * trigger this here and get hit by own missile - and will be own enemy. |
* Victim then is his own enemy and will start to kill herself (this is | | * Victim then is his own enemy and will start to kill herself (this is |
* removed) but we have not synced victim and his missile. To avoid senseless | | * removed) but we have not synced victim and his missile. To avoid senseless |
* action, we avoid hits here */ | | * action, we avoid hits here |
if ((QUERY_FLAG (victim, FLAG_ALIVE) && trap->speed) && | | */ |
trap->owner != victim) | | if ((QUERY_FLAG (victim, FLAG_ALIVE) && trap->speed) && trap->owner != victim) |
hit_with_arrow (trap, victim); | | hit_with_arrow (trap, victim); |
goto leave; | | goto leave; |
| | |
| | |
case SPELL_EFFECT: | | case SPELL_EFFECT: |
apply_spell_effect(trap, victim); | | apply_spell_effect(trap, victim); |
goto leave; | | goto leave; |
| | |
case TRAPDOOR: | | case TRAPDOOR: |
{ | | { |
int max, sound_was_played; | | int max, sound_was_played; |
object *ab; | | object *ab, *ab_next; |
if(!trap->value) { | | if(!trap->value) { |
int tot; | | int tot; |
for(ab=trap->above,tot=0;ab!=NULL;ab=ab->above) | | for(ab=trap->above,tot=0;ab!=NULL;ab=ab->above) |
if(!QUERY_FLAG(ab,FLAG_FLYING)) | | if ((ab->move_type && trap->move_on) || ab->move_type==0) |
tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying; | | tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying; |
| | |
if(!(trap->value=(tot>trap->weight)?1:0)) | | if(!(trap->value=(tot>trap->weight)?1:0)) |
goto leave; | | goto leave; |
| | |
SET_ANIMATION(trap, trap->value); | | SET_ANIMATION(trap, trap->value); |
update_object(trap,UP_OBJ_FACE); | | update_object(trap,UP_OBJ_FACE); |
} | | } |
for (ab = trap->above, max=100, sound_was_played = 0; | | |
--max && ab && ! QUERY_FLAG (ab, FLAG_FLYING); ab=ab->above) | | for (ab = trap->above, max=100, sound_was_played = 0; --max && ab; ab=ab_next) { |
{ | | /* need to set this up, since if we do transfer the object, |
| | * ab->above would be bogus |
| | */ |
| | ab_next = ab->above; |
| | |
| | if ((ab->move_type && trap->move_on) || ab->move_type==0) { |
if ( ! sound_was_played) { | | if ( ! sound_was_played) { |
play_sound_map(trap->map, trap->x, trap->y, SOUND_FALL_HOLE); | | play_sound_map(trap->map, trap->x, trap->y, SOUND_FALL_HOLE); |
sound_was_played = 1; | | sound_was_played = 1; |
| | |
new_draw_info(NDI_UNIQUE, 0,ab,"You fall into a trapdoor!"); | | new_draw_info(NDI_UNIQUE, 0,ab,"You fall into a trapdoor!"); |
transfer_ob(ab,(int)EXIT_X(trap),(int)EXIT_Y(trap),0,ab); | | transfer_ob(ab,(int)EXIT_X(trap),(int)EXIT_Y(trap),0,ab); |
} | | } |
| | } |
goto leave; | | goto leave; |
} | | } |
| | |
| | |
case CONVERTER: | | case CONVERTER: |
if (convert_item (victim, trap) < 0) { | | if (convert_item (victim, trap) < 0) { |
object *op; | | object *op; |
| | |
new_draw_info_format(NDI_UNIQUE, 0, originator, | | new_draw_info_format(NDI_UNIQUE, 0, originator, "The %s seems to be broken!", query_name(trap)); |
"The %s seems to be broken!", | | |
query_name(trap)); | | |
| | |
op = get_archetype("burnout"); | | op = get_archetype("burnout"); |
if (op != NULL) { | | if (op != NULL) { |
| | |
/* Hole not open? */ | | /* Hole not open? */ |
if(trap->stats.wc > 0) | | if(trap->stats.wc > 0) |
goto leave; | | goto leave; |
| | |
/* Is this a multipart monster and not the head? If so, return. | | /* Is this a multipart monster and not the head? If so, return. |
* Processing will happen if the head runs into the pit | | * Processing will happen if the head runs into the pit |
*/ | | */ |
if (victim->head) | | if (victim->head) |
goto leave; | | goto leave; |
| | |
play_sound_map (victim->map, victim->x, victim->y, SOUND_FALL_HOLE); | | play_sound_map (victim->map, victim->x, victim->y, SOUND_FALL_HOLE); |
new_draw_info (NDI_UNIQUE, 0, victim, "You fall through the hole!\n"); | | new_draw_info (NDI_UNIQUE, 0, victim, "You fall through the hole!\n"); |
transfer_ob (victim, EXIT_X (trap), EXIT_Y (trap), 1, victim); | | transfer_ob (victim, EXIT_X (trap), EXIT_Y (trap), 1, victim); |
| | |
/* Basically, don't show exits leading to random maps the | | /* Basically, don't show exits leading to random maps the |
* players output. | | * players output. |
*/ | | */ |
if (trap->msg && strncmp(EXIT_PATH(trap),"/!",2) | | if (trap->msg && strncmp(EXIT_PATH(trap),"/!",2) && strncmp(EXIT_PATH(trap), "/random/", 8)) |
&& strncmp(EXIT_PATH(trap), "/random/", 8)) | | |
new_draw_info (NDI_NAVY, 0, victim, trap->msg); | | new_draw_info (NDI_NAVY, 0, victim, trap->msg); |
enter_exit (victim, trap); | | enter_exit (victim, trap); |
} | | } |
| | |
case SIGN: | | case SIGN: |
if (victim->type != PLAYER && trap->stats.food > 0) | | if (victim->type != PLAYER && trap->stats.food > 0) |
goto leave; /* monsters musn't apply magic_mouths with counters */ | | goto leave; /* monsters musn't apply magic_mouths with counters */ |
| | |
apply_sign (victim, trap, 1); | | apply_sign (victim, trap, 1); |
goto leave; | | goto leave; |
| | |
| | |
| | |
case RUNE: | | case RUNE: |
case TRAP: | | case TRAP: |
if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE)) | | if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE)) { |
spring_trap(trap, victim); | | spring_trap(trap, victim); |
| | } |
goto leave; | | goto leave; |
| | |
default: | | default: |
| | |
{ | | { |
int tmp; | | int tmp; |
| | |
if (op->env == NULL && QUERY_FLAG (pl, FLAG_FLYING)) | | if (op->env == NULL && (pl->move_type & MOVE_FLYING)) { |
{ | | |
/* player is flying and applying object not in inventory */ | | /* player is flying and applying object not in inventory */ |
if ( ! QUERY_FLAG (pl, FLAG_WIZ) | | if ( ! QUERY_FLAG (pl, FLAG_WIZ) && !(op->move_type & MOVE_FLYING)) { |
&& ! QUERY_FLAG (op, FLAG_FLYING) | | |
&& ! QUERY_FLAG (op, FLAG_FLY_ON)) | | |
{ | | |
new_draw_info (NDI_UNIQUE, 0, pl, "But you are floating high " | | new_draw_info (NDI_UNIQUE, 0, pl, "But you are floating high " |
"above the ground!"); | | "above the ground!"); |
return 0; | | return 0; |
| | |
floors++; | | floors++; |
else if (floors > 0) | | else if (floors > 0) |
return; /* process only floor objects after first floor object */ | | return; /* process only floor objects after first floor object */ |
if ( ! tmp->invisible || QUERY_FLAG (tmp, FLAG_WALK_ON) | | |
|| QUERY_FLAG (tmp, FLAG_FLY_ON)) | | /* If it is visible, player can apply it. If it is applied by |
{ | | * person moving on it, also activate. Added code to make it |
| | * so that at least one of players movement types be that which |
| | * the item needs. |
| | */ |
| | if ( ! tmp->invisible || (tmp->move_on & pl->move_type)) { |
if (player_apply (pl, tmp, 0, 1) == 1) | | if (player_apply (pl, tmp, 0, 1) == 1) |
return; | | return; |
} | | } |