? config.log ? config.cache ? config.status ? Makefile ? common/Makefile ? crossedit/Makefile ? crossedit/crossedit ? crossedit/Cnv/Makefile ? crossedit/Cnv/test ? crossedit/bitmaps/Makefile ? crossedit/doc/Makefile ? crossedit/include/Makefile ? doc/Makefile ? doc/playbook/Makefile ? doc/playbook-html/Makefile ? doc/spoiler/Makefile ? doc/spoiler-html/Makefile ? include/Makefile ? include/autoconf.h ? lib/Makefile ? random_maps/Makefile ? random_maps/random_map ? server/Makefile ? server/crossfire ? socket/Makefile ? utils/Makefile Index: CHANGES =================================================================== RCS file: /home/cvs/CVS/crossfire/CHANGES,v retrieving revision 1.131 retrieving revision 1.133 diff -c -r1.131 -r1.133 *** CHANGES 2000/11/04 06:40:50 1.131 --- CHANGES 2000/11/07 00:43:29 1.133 *************** *** 18,23 **** --- 18,163 ---- else. With this, include the file(s) that you changed. ------------------------------------------------------------------------------ + PeterM: 2000-11-06 + server/spell_util.c crash bug removed from move ball lightning: + ball lightning mover improved in general. --PeterM + + -------------------------------------------- + --- BEGIN stop_item() / attack fix patch --- Jan Echternach 2000-11-06 + -------------------------------------------- + + Summary of this patch: Provide new stop_item() function for properly + handling "moving" items on a map (flying arrows, thrown objects, + active cones); obsoletes the workarounds. Fix some attack bugs (with + possible server crashes) - many attackers attacked while being + removed, even though much code could only handle the attacker being on + the same map as the victim (not even the attacker being in the + victim's inventory, e.g. poison). + + common/object.c: insert_ob_in_map(): Call check_walk_on() after + update_object() because the latter needs to update some very + important flags used by a lot of code before this code is called + by check_walk_on(). + + common/object.c: get_split_ob(): Completed support for splitting + removed objects. + + common/object.c: decrease_ob_nr(): Rewrote this function: Added + support for removed objects. Removing an object completely didn't + always update the environment's weight properly. Removing an amount + of 0 from an object with nrof == 0 destroyed the object. Improved + performance a bit (don't need to update the player's weight if an + object below the player is modified). + + server/apply.c: move_apply(): Added recursion limit. + + server/apply.c: move_apply(): THROWN_OBJ and ARROW: Use new + hit_with_arrow() function. + + server/apply.c: move_apply(): FBULLET and BULLET: Call + check_fired_arch() only when the victim blocks the square (FLAG_NO_PASS + or FLAG_ALIVE). + + server/attack.c: save_throw_object(): Use new stop_item() function + before trying to modify an object. Added originator to all + insert_ob_in_map() calls. + + server/attack.c: hit_map(): Added log message if the hitter is not on + a map. Added was_destroyed() check after calling save_throw_object(). + + server/attack.c: get_attack_mode() and abort_attack(): New functions + to determine the type of attack (simple or full attack). + + server/attack.c: attack_ob(): Now only attack_ob_simple() with default + damage and weapon class values. + + server/attack.c: attack_ob_simple(): Contains most of old attack_ob(), + but takes damage and weapon class as parameters, needed for + hit_with_arrow(). Uses get_attack_mode() and abort_attack() to + support new "simple" attack mode. + + server/attack.c: stick_arrow() and hit_with_arrow(): Moved those parts + of old stop_arrow() and move_arrow() that dealt with attacking a + victim over here. + + server/attack.c: hit_player(): Uses get_attack_mode() and + abort_attack() to support new "simple" attack mode. + + server/attack.c: paralyze_player(): Use insert_ob_in_map_simple() + instead of insert_ob_in_map() because the callers are not prepared for + this function triggering any complex machinery, and + insert_ob_in_map_simple() should be enough for plain visual effects. + + server/attack.c: thrown_item_effect(): Don't need to deal with thrown + objects, hit_with_arrow() already does everything necessary. + + server/attack.c: adj_attackroll(): Added log message if hitter and + victim are not on the same map. + + server/c_object.c: Fixed two typos in "can't pick up xxx" messages. + + server/c_object.c: pick_up_object(): Removed can_pick() check because + pick_up() already checks this. Added support for picking up removed + objects because the stop_item() in pick_up() can now call us with + removed objects. Moved FLAG_STARTEQUIP check to pick_up(). Fixed + weight limit lookup for monsters that have strength > MAX_STAT. + + server/c_object.c: pick_up(): Use new stop_item() function. + + server/player.c: fire_bow() and server/skills.c: do_throw(): Removed + FLAG_NO_PICK workaround for flying objects. stop_item() now handles + this correctly. + + server/rune.c: spring_trap(): Fix unlimited trap recursion. Since + traps are triggered by move_apply(), the result of triggering a trap + may trigger the trap again before it is deactivated. + + server/rune.c: spring_trap(): Runes that don't cast spells can only be + triggered by living objects. + + server/spell_effect.c: move_cancellation(): Don't call hit_map() with + a removed attacker. + + server/spell_util.c: cast_cone(): Only print warning message about + cones that don't have FLAG_FLY/WALK_ON if the cone does any damage. + + server/spell_util.c: move_cone(): Removed workaround for cones in ice + cubes. stop_item() now handles this correctly. + + server/spell_util.c: explode_object(): Rewrote this function: New + interface - exploding object must not be removed when the function is + called, it must have an other_arch (i.e. it must be able to explode), + and it will be gone for sure when the function terminates. Removed + some code with no effect. Don't call any attack functions with + removed attackers. + + server/spell_util.c: check_fired_arch(): Rewrote this function. + + server/spell_util.c: move_fired_arch(): Rewrote most of this function: + Don't attack with removed attackers. Call check_fired_arch() instead + of duplicating its code. + + server/spell_util.c: move_ball_lightning(): Don't attack with removed + attackers. Rewrote the movement algorithm to simplify this task. + + server/time.c: stop_item() and fix_stopped_item: New functions. + + server/time.c: fix_stopped_arrow(): Contains most of the old + stop_arrow() function. Unlike stop_arrow(), it takes an arrow that is + not removed. Removed FLACK_NO_PICK workaround. + + server/time.c: stop_arrow(): Stops arrows and thrown objects and puts + them on the map. Sticking objects into targets is no longer handled + by stop_arrow(), but by hit_with_arrow(). + + server/time.c: move_arrow(): Don't attack with removed attackers. + + socket/item.c: esrv_move_object(): Removed misleading comment. + + ------------------------------------------ + --- END stop_item() / attack fix patch --- Jan Echternach 2000-11-06 + ------------------------------------------ + server/time.c: Add call to esrv_update_item to update the face for the client after the player chooses a class. MSW 11/3/2000 Index: common/object.c =================================================================== RCS file: /home/cvs/CVS/crossfire/common/object.c,v retrieving revision 1.8 retrieving revision 1.9 diff -c -r1.8 -r1.9 *** common/object.c 2000/06/27 03:34:34 1.8 --- common/object.c 2000/11/06 23:06:47 1.9 *************** *** 1,6 **** /* * static char *rcsid_object_c = ! * "$Id: object.c,v 1.8 2000/06/27 03:34:34 cvs Exp $"; */ /* --- 1,6 ---- /* * static char *rcsid_object_c = ! * "$Id: object.c,v 1.9 2000/11/06 23:06:47 jec Exp $"; */ /* *************** *** 1476,1495 **** else set_map_ob(op->map,op->x,op->y,op); /* Tell the map that we're here */ - /* Only check this if we are the head of the object */ - if (!op->head) { - mapstruct *map=op->map; - if (check_walk_on(op, originator)) - return NULL; - - /* If we are a multi part object, lets work our way through the check - * walk on's. - */ - for (tmp=op->more; tmp!=NULL; tmp=tmp->more) - if (check_walk_on (op, originator)) - return NULL; - - } if(op->type==PLAYER) op->contr->do_los=1; for(tmp=get_map_ob(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above) --- 1476,1481 ---- *************** *** 1512,1520 **** --- 1498,1525 ---- #endif /* Don't know if moving this to the end will break anything. However, * we want to have update_look set above before calling this. + * + * check_walk_on() must be after this because code called from + * check_walk_on() depends on correct map flags (so functions like + * blocked() and wall() work properly), and these flags are updated by + * update_object(). */ update_object(op); + /* Only check this if we are the head of the object */ + if ( ! op->head) { + mapstruct *map=op->map; + if (check_walk_on(op, originator)) + return NULL; + + /* If we are a multi part object, lets work our way through the check + * walk on's. + */ + for (tmp=op->more; tmp!=NULL; tmp=tmp->more) + if (check_walk_on (op, originator)) + return NULL; + } + return op; } *************** *** 1528,1533 **** --- 1533,1539 ---- object *get_split_ob(object *orig_ob,int nr) { object *newob; + int is_removed = (QUERY_FLAG (orig_ob, FLAG_REMOVED) != 0); if(orig_ob->nrof<nr) { sprintf(errmsg,"There are only %d %ss.", *************** *** 1537,1546 **** newob=get_object(); copy_object(orig_ob,newob); if((orig_ob->nrof-=nr)<1) { ! remove_ob(orig_ob); free_object(orig_ob); } ! else if(!QUERY_FLAG(orig_ob,FLAG_REMOVED)){ if(orig_ob->env!=NULL) sub_weight (orig_ob->env,orig_ob->weight*nr); if (orig_ob->env == NULL && orig_ob->map->in_memory!=MAP_IN_MEMORY) { --- 1543,1553 ---- newob=get_object(); copy_object(orig_ob,newob); if((orig_ob->nrof-=nr)<1) { ! if ( ! is_removed) ! remove_ob(orig_ob); free_object(orig_ob); } ! else if ( ! is_removed) { if(orig_ob->env!=NULL) sub_weight (orig_ob->env,orig_ob->weight*nr); if (orig_ob->env == NULL && orig_ob->map->in_memory!=MAP_IN_MEMORY) { *************** *** 1562,1625 **** * Return value: 'op' if something is left, NULL if the amount reached 0 */ ! object *decrease_ob_nr(object *op,int i) { ! object *tmp; ! ! /* nrof is split out into a long so it is handled ok on 64 bit machines. ! * I think it might work to just do op->nrof-=i and cast that to an sint32 ! * to see if it is negative. But if so, we might as well just nrof in ! * the object structure an sint32, since that would still set a maximum ! * value. ! */ ! long nrof=op->nrof; ! nrof -= i; ! if (nrof<0) nrof=0; ! op->nrof = nrof; ! ! if(!op->nrof) { ! op->nrof=0; /* just to be sure that remove_ob handles weight properly */ ! /* We don't have remove object send delete to the new client, because ! * in many areas, more intelligent strategies are employed. However, if ! * we are decreasing the number, we can be sure that the object is gone ! * for good, so send a delete down the line. Need to check for ! * environment before we call remove_ob, since that deletes the ! * environment. ! */ ! if(op->env!=NULL) { ! tmp=is_player_inv (op->env); ! if(tmp!=NULL) { ! (*esrv_del_item_func)(tmp->contr, op->count); ! (*esrv_update_item_func)(UPD_WEIGHT, tmp, tmp); ! } ! } else { ! for(tmp=op->above;tmp!=NULL;tmp=tmp->above) ! if(tmp->type==PLAYER) { ! (*esrv_del_item_func)(tmp->contr, op->count); ! (*esrv_update_item_func)(UPD_WEIGHT, tmp, tmp); ! } } ! remove_ob(op); ! free_object(op); ! return NULL; ! } ! else ! if(op->env!=NULL) { ! sub_weight(op->env,op->weight*i); ! tmp=is_player_inv (op->env); ! if(tmp!=NULL) { ! (*esrv_send_item_func)(tmp, op); ! (*esrv_update_item_func)(UPD_WEIGHT, tmp, tmp); ! } } else { ! for(tmp=op->above;tmp!=NULL;tmp=tmp->above) ! if(tmp->type==PLAYER) { ! (*esrv_send_item_func)(tmp, op); ! (*esrv_update_item_func)(UPD_WEIGHT, tmp, tmp); ! } } - return op; } /* --- 1569,1630 ---- * Return value: 'op' if something is left, NULL if the amount reached 0 */ ! object *decrease_ob_nr (object *op, int i) { ! object *tmp; ! if (i == 0) /* objects with op->nrof require this check */ ! return op; ! ! if (i > op->nrof) ! i = op->nrof; ! ! if (QUERY_FLAG (op, FLAG_REMOVED)) ! { ! op->nrof -= i; } ! else if (op->env != NULL) ! { ! tmp = is_player_inv (op->env); ! if (i < op->nrof) { ! sub_weight (op->env, op->weight * i); ! op->nrof -= i; ! if (tmp) { ! (*esrv_send_item_func) (tmp, op); ! (*esrv_update_item_func) (UPD_WEIGHT, tmp, tmp); ! } ! } else { ! remove_ob (op); ! op->nrof = 0; ! if (tmp) { ! (*esrv_del_item_func) (tmp->contr, op->count); ! (*esrv_update_item_func) (UPD_WEIGHT, tmp, tmp); ! } ! } ! } ! else ! { ! if (i < op->nrof) { ! op->nrof -= i; ! } else { ! remove_ob (op); ! op->nrof = 0; ! } ! for (tmp = op->above; tmp != NULL; tmp = tmp->above) ! if (tmp->type == PLAYER) { ! if (op->nrof) ! (*esrv_send_item_func) (tmp, op); ! else ! (*esrv_del_item_func) (tmp->contr, op->count); ! } ! } ! ! if (op->nrof) { ! return op; } else { ! free_object (op); ! return NULL; } } /* Index: include/sproto.h =================================================================== RCS file: /home/cvs/CVS/crossfire/include/sproto.h,v retrieving revision 1.16 retrieving revision 1.17 diff -c -r1.16 -r1.17 *** include/sproto.h 2000/10/30 22:09:59 1.16 --- include/sproto.h 2000/11/06 23:06:47 1.17 *************** *** 45,53 **** extern void apply_lighter ( object *who, object *lighter ); extern void scroll_failure ( object *op, int failure, int power ); extern int did_make_save_item ( object *op, int type ); ! extern void save_throw_object ( object *op, int type ); extern int hit_map ( object *op, int dir, int type ); extern int attack_ob ( object *op, object *hitter ); extern void tear_down_wall ( object *op ); extern int hit_player_attacktype ( object *op, object *hitter, int dam, uint32 attacktype, int magic ); extern int hit_player ( object *op, int dam, object *hitter, int type ); --- 45,54 ---- extern void apply_lighter ( object *who, object *lighter ); extern void scroll_failure ( object *op, int failure, int power ); extern int did_make_save_item ( object *op, int type ); ! extern void save_throw_object ( object *op, int type, object *originator ); extern int hit_map ( object *op, int dir, int type ); extern int attack_ob ( object *op, object *hitter ); + extern object *hit_with_arrow ( object *op, object *victim ); extern void tear_down_wall ( object *op ); extern int hit_player_attacktype ( object *op, object *hitter, int dam, uint32 attacktype, int magic ); extern int hit_player ( object *op, int dam, object *hitter, int type ); *************** *** 57,63 **** extern void blind_player ( object *op, object *hitter, int dam ); extern void paralyze_player ( object *op, object *hitter, int dam ); extern void deathstrike_player ( object *op, object *hitter, int *dam ); - extern object *thrown_item_effect ( object *hitter, object *victim ); extern int adj_attackroll ( object *hitter, object *target ); extern int is_aimed_missile ( object *op ); extern int checkbanned ( char *login, char *host ); --- 58,63 ---- *************** *** 124,130 **** extern int command_rskill ( object *pl, char *params ); extern int command_apply ( object *op, char *params ); extern int sack_can_hold ( object *pl, object *sack, object *op, int nrof ); - extern void pick_up_object ( object *pl, object *op, object *tmp, int nrof ); extern void pick_up ( object *op, object *alt ); extern int command_take ( object *op, char *params ); extern void put_object_in_sack ( object *op, object *sack, object *tmp, long nrof ); --- 124,129 ---- *************** *** 576,582 **** extern void move_golem ( object *op ); extern void control_golem ( object *op, int dir ); extern void move_missile ( object *op ); ! extern int explode_object ( object *op ); extern void check_fired_arch ( object *op ); extern void move_fired_arch ( object *op ); extern void drain_rod_charge ( object *rod ); --- 575,581 ---- extern void move_golem ( object *op ); extern void control_golem ( object *op, int dir ); extern void move_missile ( object *op ); ! extern void explode_object ( object *op ); extern void check_fired_arch ( object *op ); extern void move_fired_arch ( object *op ); extern void drain_rod_charge ( object *rod ); *************** *** 618,624 **** extern void move_detector ( object *op ); extern void animate_trigger ( object *op ); extern void move_hole ( object *op ); ! extern void stop_arrow ( object *op, object *tmp ); extern void move_arrow ( object *op ); extern void change_object ( object *op ); extern void move_teleporter ( object *op ); --- 617,624 ---- extern void move_detector ( object *op ); extern void animate_trigger ( object *op ); extern void move_hole ( object *op ); ! extern object *stop_item ( object *op ); ! extern object *fix_stopped_arrow ( object *op ); extern void move_arrow ( object *op ); extern void change_object ( object *op ); extern void move_teleporter ( object *op ); Index: server/apply.c =================================================================== RCS file: /home/cvs/CVS/crossfire/server/apply.c,v retrieving revision 1.21 retrieving revision 1.22 diff -c -r1.21 -r1.22 *** server/apply.c 2000/10/30 22:09:59 1.21 --- server/apply.c 2000/11/06 23:06:47 1.22 *************** *** 1,6 **** /* * static char *rcsid_apply_c = ! * "$Id: apply.c,v 1.21 2000/10/30 22:09:59 jec Exp $"; */ /* CrossFire, A Multiplayer game for X-windows --- 1,6 ---- /* * static char *rcsid_apply_c = ! * "$Id: apply.c,v 1.22 2000/11/06 23:06:47 jec Exp $"; */ /* CrossFire, A Multiplayer game for X-windows *************** *** 1085,1090 **** --- 1085,1102 ---- */ void move_apply (object *trap, object *victim, object *originator) { + static int recursion_depth = 0; + + /* move_apply() is the most likely candidate for causing unwanted and + * possibly unlimited recursion. */ + if (recursion_depth >= 5) { + LOG (llevError, "WARNING: move_apply(): aborting recursion " + "[trap arch %s, name %s; victim arch %s, name %s]\n", + trap->arch->name, trap->name, victim->arch->name, victim->name); + return; + } + recursion_depth++; + switch (trap->type) { case PLAYERMOVER: *************** *** 1101,1131 **** if (victim->speed_left<-50.0) victim->speed_left=-50.0; /* fprintf(stderr,"apply, playermove, player speed_left=%f\n", victim->speed_left);*/ } ! return; case SPINNER: if(victim->direction) { victim->direction=absdir(victim->direction-trap->stats.sp); update_turn_face(victim); } ! return; case DIRECTOR: if(victim->direction) { victim->direction=trap->stats.sp; update_turn_face(victim); } ! return; case BUTTON: case PEDESTAL: update_button(trap); ! return; case ALTAR: /* sacrifice victim on trap */ apply_altar (trap, victim, originator); ! return; case MMISSILE: if (QUERY_FLAG (victim, FLAG_ALIVE)) { --- 1113,1143 ---- if (victim->speed_left<-50.0) victim->speed_left=-50.0; /* fprintf(stderr,"apply, playermove, player speed_left=%f\n", victim->speed_left);*/ } ! goto leave; case SPINNER: if(victim->direction) { victim->direction=absdir(victim->direction-trap->stats.sp); update_turn_face(victim); } ! goto leave; case DIRECTOR: if(victim->direction) { victim->direction=trap->stats.sp; update_turn_face(victim); } ! goto leave; case BUTTON: case PEDESTAL: update_button(trap); ! goto leave; case ALTAR: /* sacrifice victim on trap */ apply_altar (trap, victim, originator); ! goto leave; case MMISSILE: if (QUERY_FLAG (victim, FLAG_ALIVE)) { *************** *** 1136,1166 **** free_object (trap); } } ! return; case THROWN_OBJ: case ARROW: ! if(QUERY_FLAG(victim, FLAG_ALIVE)&&trap->speed) { ! tag_t trap_tag = trap->count; ! if(attack_ob(victim,trap)) { ! /* There can be cases where a monster 'kills' an arrow. Typically ! * happens for things like black puddings that have hitback properties. ! */ ! if ( ! was_destroyed (trap, trap_tag)) { ! remove_ob(trap); ! stop_arrow(trap,victim); ! } ! } ! } ! return; case CANCELLATION: case BALL_LIGHTNING: if (QUERY_FLAG (victim, FLAG_ALIVE)) hit_player (victim, trap->stats.dam, trap, trap->attacktype); else if (victim->material) ! save_throw_object (victim, trap->attacktype); ! return; case CONE: if(QUERY_FLAG(victim, FLAG_ALIVE)&&trap->speed) { --- 1148,1171 ---- free_object (trap); } } ! goto leave; case THROWN_OBJ: + if (trap->inv == NULL) + goto leave; + /* fallthrough */ case ARROW: ! if (QUERY_FLAG (victim, FLAG_ALIVE) && trap->speed) ! hit_with_arrow (trap, victim); ! goto leave; case CANCELLATION: case BALL_LIGHTNING: if (QUERY_FLAG (victim, FLAG_ALIVE)) hit_player (victim, trap->stats.dam, trap, trap->attacktype); else if (victim->material) ! save_throw_object (victim, trap->attacktype, trap); ! goto leave; case CONE: if(QUERY_FLAG(victim, FLAG_ALIVE)&&trap->speed) { *************** *** 1168,1179 **** if (attacktype) hit_player(victim,trap->stats.dam,trap,attacktype); } ! return; case FBULLET: case BULLET: ! check_fired_arch(trap); ! return; case TRAPDOOR: { --- 1173,1186 ---- if (attacktype) hit_player(victim,trap->stats.dam,trap,attacktype); } ! goto leave; case FBULLET: case BULLET: ! if (QUERY_FLAG (victim, FLAG_NO_PASS) ! || QUERY_FLAG (victim, FLAG_ALIVE)) ! check_fired_arch (trap); ! goto leave; case TRAPDOOR: { *************** *** 1185,1191 **** if(!QUERY_FLAG(ab,FLAG_FLYING)) tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying; if(!(trap->value=(tot>trap->weight)?1:0)) ! return; SET_ANIMATION(trap, trap->value); update_object(trap); } --- 1192,1198 ---- if(!QUERY_FLAG(ab,FLAG_FLYING)) tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying; if(!(trap->value=(tot>trap->weight)?1:0)) ! goto leave; SET_ANIMATION(trap, trap->value); update_object(trap); } *************** *** 1199,1238 **** 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); } ! return; } case CONVERTER: convert_item (victim, trap); ! return; case TRIGGER_BUTTON: case TRIGGER_PEDESTAL: case TRIGGER_ALTAR: check_trigger (trap, victim); ! return; case DEEP_SWAMP: walk_on_deep_swamp (trap, victim); ! return; case CHECK_INV: check_inv (victim, trap); ! return; case HOLE: /* Hole not open? */ if(trap->stats.wc > 0) ! return; /* Is this a multipart monster and not the head? If so, return. * Processing will happen if the head runs into the pit */ if (victim->head) ! return; 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"); transfer_ob (victim, EXIT_X (trap), EXIT_Y (trap), 1, victim); ! return; case EXIT: if (victim->type == PLAYER && EXIT_PATH (trap)) { --- 1206,1245 ---- 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); } ! goto leave; } case CONVERTER: convert_item (victim, trap); ! goto leave; case TRIGGER_BUTTON: case TRIGGER_PEDESTAL: case TRIGGER_ALTAR: check_trigger (trap, victim); ! goto leave; case DEEP_SWAMP: walk_on_deep_swamp (trap, victim); ! goto leave; case CHECK_INV: check_inv (victim, trap); ! goto leave; case HOLE: /* Hole not open? */ if(trap->stats.wc > 0) ! goto leave; /* Is this a multipart monster and not the head? If so, return. * Processing will happen if the head runs into the pit */ if (victim->head) ! goto leave; 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"); transfer_ob (victim, EXIT_X (trap), EXIT_Y (trap), 1, victim); ! goto leave; case EXIT: if (victim->type == PLAYER && EXIT_PATH (trap)) { *************** *** 1240,1285 **** new_draw_info (NDI_NAVY, 0, victim, trap->msg); enter_exit (victim, trap); } ! return; case ENCOUNTER: #ifdef RANDOM_ENCOUNTERS if (victim->type == PLAYER && QUERY_FLAG (trap, FLAG_IS_FLOOR)) random_encounter (victim, trap); #endif ! return; case SHOP_MAT: apply_shop_mat (trap, victim); ! return; /* Drop a certain amount of gold, and have one item identified */ case IDENTIFY_ALTAR: apply_id_altar (victim, trap, originator); ! return; case SIGN: apply_sign (victim, trap); ! return; case CONTAINER: if (victim->type==PLAYER) (void) esrv_apply_container (victim, trap); else (void) apply_container (victim, trap); ! return; case RUNE: if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE)) spring_trap (trap, victim); ! return; default: LOG (llevDebug, "name %s, arch %s, type %d with fly/walk on/off not " "handled in move_apply()\n", trap->name, trap->arch->name, trap->type); ! return; } } --- 1247,1295 ---- new_draw_info (NDI_NAVY, 0, victim, trap->msg); enter_exit (victim, trap); } ! goto leave; case ENCOUNTER: #ifdef RANDOM_ENCOUNTERS if (victim->type == PLAYER && QUERY_FLAG (trap, FLAG_IS_FLOOR)) random_encounter (victim, trap); #endif ! goto leave; case SHOP_MAT: apply_shop_mat (trap, victim); ! goto leave; /* Drop a certain amount of gold, and have one item identified */ case IDENTIFY_ALTAR: apply_id_altar (victim, trap, originator); ! goto leave; case SIGN: apply_sign (victim, trap); ! goto leave; case CONTAINER: if (victim->type==PLAYER) (void) esrv_apply_container (victim, trap); else (void) apply_container (victim, trap); ! goto leave; case RUNE: if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE)) spring_trap (trap, victim); ! goto leave; default: LOG (llevDebug, "name %s, arch %s, type %d with fly/walk on/off not " "handled in move_apply()\n", trap->name, trap->arch->name, trap->type); ! goto leave; } + + leave: + recursion_depth--; } *************** *** 2509,2515 **** */ strcpy(item_name, item->name); ! save_throw_object(item,AT_FIRE); /* Change to check count and not freed, since the object pointer * may have gotten recycled */ --- 2519,2525 ---- */ strcpy(item_name, item->name); ! save_throw_object(item,AT_FIRE,who); /* Change to check count and not freed, since the object pointer * may have gotten recycled */ Index: server/attack.c =================================================================== RCS file: /home/cvs/CVS/crossfire/server/attack.c,v retrieving revision 1.17 retrieving revision 1.18 diff -c -r1.17 -r1.18 *** server/attack.c 2000/10/31 12:04:58 1.17 --- server/attack.c 2000/11/06 23:06:47 1.18 *************** *** 1,6 **** /* * static char *rcsid_attack_c = ! * "$Id: attack.c,v 1.17 2000/10/31 12:04:58 peterm Exp $"; */ /* CrossFire, A Multiplayer game for X-windows --- 1,6 ---- /* * static char *rcsid_attack_c = ! * "$Id: attack.c,v 1.18 2000/11/06 23:06:47 jec Exp $"; */ /* CrossFire, A Multiplayer game for X-windows *************** *** 86,98 **** * calling cancellation, etc.) */ ! void save_throw_object(object *op, int type) { ! ! if (!did_make_save_item(op, type)) { object *env=op->env; int x=op->x,y=op->y; mapstruct *m=op->map; /* Hacked the following so that type LIGHTER will work. * Also, objects which are potenital "lights" that are hit by * flame/elect attacks will be set to glow. "lights" are any --- 86,103 ---- * calling cancellation, etc.) */ ! void save_throw_object (object *op, int type, object *originator) ! { ! if ( ! did_make_save_item (op, type)) ! { object *env=op->env; int x=op->x,y=op->y; mapstruct *m=op->map; + op = stop_item (op); + if (op == NULL) + return; + /* Hacked the following so that type LIGHTER will work. * Also, objects which are potenital "lights" that are hit by * flame/elect attacks will be set to glow. "lights" are any *************** *** 105,111 **** &&op->other_arch&&op->glow_radius) { char *arch=op->other_arch->name; ! decrease_ob_nr(op,1); if((op = get_archetype(arch))!=NULL) { if(env) { op->x=env->x,op->y=env->y; --- 110,118 ---- &&op->other_arch&&op->glow_radius) { char *arch=op->other_arch->name; ! op = decrease_ob_nr (op, 1); ! if (op) ! fix_stopped_item (op, m, originator); if((op = get_archetype(arch))!=NULL) { if(env) { op->x=env->x,op->y=env->y; *************** *** 114,131 **** esrv_send_item(env, op); } else { op->x=x,op->y=y; ! insert_ob_in_map(op,m,NULL); } } return; } if(type&AT_CANCELLATION) { /* Cancellation. */ cancellation(op); return; } ! if(op->nrof>1) ! decrease_ob_nr(op,RANDOM()%op->nrof); ! else { if (op->env) { object *tmp= is_player_inv(op->env); --- 121,141 ---- esrv_send_item(env, op); } else { op->x=x,op->y=y; ! insert_ob_in_map(op,m,originator); } } return; } if(type&AT_CANCELLATION) { /* Cancellation. */ cancellation(op); + fix_stopped_item (op, m, originator); return; } ! if(op->nrof>1) { ! op = decrease_ob_nr(op,RANDOM()%op->nrof); ! if (op) ! fix_stopped_item (op, m, originator); ! } else { if (op->env) { object *tmp= is_player_inv(op->env); *************** *** 134,140 **** esrv_update_item(UPD_WEIGHT, tmp, tmp); } } ! remove_ob(op); free_object(op); } if(type&(AT_FIRE|AT_ELECTRICITY)) { --- 144,151 ---- esrv_update_item(UPD_WEIGHT, tmp, tmp); } } ! if ( ! QUERY_FLAG (op, FLAG_REMOVED)) ! remove_ob(op); free_object(op); } if(type&(AT_FIRE|AT_ELECTRICITY)) { *************** *** 144,150 **** insert_ob_in_ob(op,env); } else { op->x=x,op->y=y; ! insert_ob_in_map(op,m,NULL); } } return; --- 155,161 ---- insert_ob_in_ob(op,env); } else { op->x=x,op->y=y; ! insert_ob_in_map(op,m,originator); } } return; *************** *** 155,166 **** archetype *at = find_archetype("icecube"); if (at == NULL) return; if ((tmp = present_arch(at,op->map,op->x,op->y)) == NULL) { tmp = arch_to_object(at); tmp->x=op->x,tmp->y=op->y; ! insert_ob_in_map(tmp,op->map,NULL); } ! remove_ob(op); (void) insert_ob_in_ob(op,tmp); return; } --- 166,181 ---- archetype *at = find_archetype("icecube"); if (at == NULL) return; + op = stop_item (op); + if (op == NULL) + return; if ((tmp = present_arch(at,op->map,op->x,op->y)) == NULL) { tmp = arch_to_object(at); tmp->x=op->x,tmp->y=op->y; ! insert_ob_in_map(tmp,op->map,originator); } ! if ( ! QUERY_FLAG (op, FLAG_REMOVED)) ! remove_ob(op); (void) insert_ob_in_ob(op,tmp); return; } *************** *** 177,183 **** LOG (llevError, "BUG: hit_map(): free object\n"); return 0; } ! if (op->head) op=op->head; op_tag = op->count; --- 192,204 ---- LOG (llevError, "BUG: hit_map(): free object\n"); return 0; } ! ! if (QUERY_FLAG (op, FLAG_REMOVED) || op->env != NULL) { ! LOG (llevError, "BUG: hit_map(): hitter (arch %s, name %s) not on a map\n", ! op->arch->name, op->name); ! return 0; ! } ! if (op->head) op=op->head; op_tag = op->count; *************** *** 232,238 **** next_tag = next->count; if (QUERY_FLAG (tmp, FLAG_FREED)) { ! LOG (llevError, "BUG: hit_map(): found free object\n"); break; } --- 253,259 ---- next_tag = next->count; if (QUERY_FLAG (tmp, FLAG_FREED)) { ! LOG (llevError, "BUG: hit_map(): found freed object\n"); break; } *************** *** 248,254 **** if (was_destroyed (op, op_tag)) break; } else if (tmp->material) { ! save_throw_object(tmp,type); } } #ifdef NO_CONE_PROPOGATE --- 269,277 ---- if (was_destroyed (op, op_tag)) break; } else if (tmp->material) { ! save_throw_object(tmp,type,op); ! if (was_destroyed (op, op_tag)) ! break; } } #ifdef NO_CONE_PROPOGATE *************** *** 308,348 **** return &messages; } ! /* ! * attack_ob() returns 1 on a hit, and 0 on a miss. ! * op is what is being attacked, hitter is what is hitting (Arrow, player, ! * whatever) */ ! int attack_ob(object *op,object *hitter) { ! int roll,dam=0; char buf[MAX_BUF]; uint32 type; att_msg *msg; ! char *op_name; signed char luck=0; ! if(op->head!=NULL) ! op=op->head; ! if(op->name==NULL) { ! if(settings.debug >= llevDebug) { ! dump_object(op); ! LOG(llevDebug,"Object without name tried to attack.\n%s\n",errmsg); ! /* we don't NEED to print this a zillion times, so GIVE IT A NAME. */ ! op->name = add_string(op->arch->name); ! ! } ! if (QUERY_FLAG(op, FLAG_REMOVED) && !QUERY_FLAG(op, FLAG_FREED)) ! free_object(op); ! return 1; ! } /* * A little check to make it more difficult to dance forward and back * to avoid ever being hit by monsters. */ ! if (QUERY_FLAG(op, FLAG_MONSTER) && op->speed_left > -(FABS(op->speed))*0.3) { ! /* Decrease speed BEFORE calling process_object. Otherwise, an * infinite loop occurs, with process_object calling move_monster, * which then gets here again. By decreasing the speed before --- 331,408 ---- return &messages; } ! ! static int get_attack_mode (object **target, object **hitter, ! int *simple_attack) ! { ! if (QUERY_FLAG (*target, FLAG_FREED) || QUERY_FLAG (*hitter, FLAG_FREED)) { ! LOG (llevError, "BUG: get_attack_mode(): freed object\n"); ! return 1; ! } ! if ((*target)->head) ! *target = (*target)->head; ! if ((*hitter)->head) ! *hitter = (*hitter)->head; ! if ((*hitter)->env != NULL || (*target)->env != NULL) { ! *simple_attack = 1; ! return 0; ! } ! if (QUERY_FLAG (*target, FLAG_REMOVED) ! || QUERY_FLAG (*hitter, FLAG_REMOVED) ! || (*hitter)->map == NULL || (*hitter)->map != (*target)->map) ! { ! LOG (llevError, "BUG: hitter (arch %s, name %s) with no relation to " ! "target\n", (*hitter)->arch->name, (*hitter)->name); ! return 1; ! } ! *simple_attack = 0; ! return 0; ! } ! ! static int abort_attack (object *target, object *hitter, int simple_attack) ! { ! /* Check if target and hitter are still in a relation similar to the one ! * determined by get_attack_mode(). Returns true if the relation has changed. */ + int new_mode; ! if (hitter->env == target || target->env == hitter) ! new_mode = 1; ! else if (QUERY_FLAG (hitter, FLAG_REMOVED) ! || QUERY_FLAG (target, FLAG_REMOVED) ! || hitter->map == NULL || hitter->map != target->map) ! return 1; ! else ! new_mode = 0; ! return new_mode != simple_attack; ! } ! ! static void thrown_item_effect (object *, object *); ! ! static int attack_ob_simple (object *op, object *hitter, int base_dam, ! int base_wc) ! { ! int simple_attack, roll, dam=0; char buf[MAX_BUF]; uint32 type; att_msg *msg; ! char *op_name = NULL; signed char luck=0; + tag_t op_tag, hitter_tag; ! if (get_attack_mode (&op, &hitter, &simple_attack)) ! goto error; ! ! op_tag = op->count; ! hitter_tag = hitter->count; /* * A little check to make it more difficult to dance forward and back * to avoid ever being hit by monsters. */ ! if ( ! simple_attack && QUERY_FLAG (op, FLAG_MONSTER) ! && op->speed_left > -(FABS(op->speed))*0.3) ! { /* Decrease speed BEFORE calling process_object. Otherwise, an * infinite loop occurs, with process_object calling move_monster, * which then gets here again. By decreasing the speed before *************** *** 350,371 **** */ op->speed_left--; process_object(op); ! if (QUERY_FLAG(op, FLAG_FREED)) ! return 1; } add_refcount(op_name = op->name); - if(hitter->head!=NULL) - hitter=hitter->head; - if (hitter->name==NULL) { - if(settings.debug >= llevDebug) { - dump_object(hitter); - LOG(llevDebug,"Object without name tried to attack.\n%s\n",errmsg); - } - return 1; - } - /* BROKEN: the luck code. If you look carefully, luck has these effects: positive luck adds to the damage YOU take and to YOUR likelihood of getting HIT. This is intolerable. I am setting "luck" in this --- 410,422 ---- */ op->speed_left--; process_object(op); ! if (was_destroyed (op, op_tag) || was_destroyed (hitter, hitter_tag) ! || abort_attack (op, hitter, simple_attack)) ! goto error; } add_refcount(op_name = op->name); /* BROKEN: the luck code. If you look carefully, luck has these effects: positive luck adds to the damage YOU take and to YOUR likelihood of getting HIT. This is intolerable. I am setting "luck" in this *************** *** 382,392 **** roll=RANDOM()%20+1+luck; /* Adjust roll for various situations. */ ! roll += adj_attackroll(hitter,op); /* See if we hit the creature */ ! if(roll==(20+luck)||op->stats.ac>=hitter->stats.wc-roll) { ! int hitdam=hitter->stats.dam+luck; #ifdef CASTING_TIME if ((hitter->type == PLAYER)&&(hitter->casting > -1)){ hitter->casting = -1; --- 433,444 ---- roll=RANDOM()%20+1+luck; /* Adjust roll for various situations. */ ! if ( ! simple_attack) ! roll += adj_attackroll(hitter,op); /* See if we hit the creature */ ! if(roll==(20+luck)||op->stats.ac>=base_wc-roll) { ! int hitdam = base_dam + luck; #ifdef CASTING_TIME if ((hitter->type == PLAYER)&&(hitter->casting > -1)){ hitter->casting = -1; *************** *** 399,432 **** if (op->type == PLAYER) { new_draw_info(NDI_UNIQUE, 0,op,"You were hit and lost your spell!"); new_draw_info_format(NDI_ALL|NDI_UNIQUE,5,NULL, ! "%s was hit by %s and lost a spell.",op->name,hitter->name); } } #endif ! /* If you hit something, the victim should *always* wake up. ! * Before, invisible hitters could avoid doing this. ! * -b.t. */ ! if(QUERY_FLAG(op,FLAG_SLEEP)) CLEAR_FLAG(op,FLAG_SLEEP); ! ! /* If the victim can't see the attacker, it may alert others ! * for help. */ ! if(op->type!=PLAYER&&!can_see_enemy(op,hitter) ! &&!get_owner(op)&&RANDOM()%(op->stats.Int+1)) ! npc_call_help(op); ! ! /* if you were hidden and hit by a creature, you are discovered*/ ! if(op->hide && QUERY_FLAG(hitter,FLAG_ALIVE)) { ! make_visible(op); ! if(op->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,op, ! "You were hit by a wild attack. You are no longer hidden!"); ! } ! ! /* thrown items (hitter) will have various effects ! * when they hit the victim. For things like thrown daggers, ! * this sets 'hitter' to the actual dagger, and not the ! * wrapper object. ! */ ! if((hitter=thrown_item_effect(hitter,op))==NULL) goto leave; /* Need to do at least 1 damage, otherwise there is no point * to go further and it will cause FPE's below. --- 451,494 ---- if (op->type == PLAYER) { new_draw_info(NDI_UNIQUE, 0,op,"You were hit and lost your spell!"); new_draw_info_format(NDI_ALL|NDI_UNIQUE,5,NULL, ! "%s was hit by %s and lost a spell.",op_name,hitter->name); } } #endif ! if ( ! simple_attack) ! { ! /* If you hit something, the victim should *always* wake up. ! * Before, invisible hitters could avoid doing this. ! * -b.t. */ ! if (QUERY_FLAG (op, FLAG_SLEEP)) ! CLEAR_FLAG(op,FLAG_SLEEP); ! ! /* If the victim can't see the attacker, it may alert others ! * for help. */ ! if (op->type != PLAYER && ! can_see_enemy (op, hitter) ! && ! get_owner (op) && RANDOM() % (op->stats.Int + 1)) ! npc_call_help (op); ! ! /* if you were hidden and hit by a creature, you are discovered*/ ! if (op->hide && QUERY_FLAG (hitter, FLAG_ALIVE)) { ! make_visible (op); ! if (op->type == PLAYER) ! new_draw_info (NDI_UNIQUE, 0, op, ! "You were hit by a wild attack. " ! "You are no longer hidden!"); ! } ! ! /* thrown items (hitter) will have various effects ! * when they hit the victim. For things like thrown daggers, ! * this sets 'hitter' to the actual dagger, and not the ! * wrapper object. ! */ ! thrown_item_effect (hitter, op); ! if (was_destroyed (hitter, hitter_tag) ! || was_destroyed (op, op_tag) ! || abort_attack (op, hitter, simple_attack)) ! goto leave; ! } /* Need to do at least 1 damage, otherwise there is no point * to go further and it will cause FPE's below. *************** *** 436,453 **** type=hitter->attacktype; if(!type) type=AT_PHYSICAL; /* Handle monsters that hit back */ ! if (QUERY_FLAG(op, FLAG_HITBACK) && QUERY_FLAG(hitter, FLAG_ALIVE)) { if (op->attacktype & AT_ACID && hitter->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,hitter,"You are splashed by acid!\n"); hit_player(hitter, RANDOM()%(op->stats.dam+1), op, op->attacktype); ! if (QUERY_FLAG(op, FLAG_FREED)) goto leave; } /* In the new attack code, it should handle multiple attack * types in its area, so remove it from here. */ dam=hit_player(op, (RANDOM()%hitdam)+1, hitter, type); ! if (QUERY_FLAG(op, FLAG_FREED)) goto leave; } /* end of if hitter hit op */ /* if we missed, dam=0 */ --- 498,521 ---- type=hitter->attacktype; if(!type) type=AT_PHYSICAL; /* Handle monsters that hit back */ ! if ( ! simple_attack && QUERY_FLAG (op, FLAG_HITBACK) ! && QUERY_FLAG (hitter, FLAG_ALIVE)) ! { if (op->attacktype & AT_ACID && hitter->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,hitter,"You are splashed by acid!\n"); hit_player(hitter, RANDOM()%(op->stats.dam+1), op, op->attacktype); ! if (was_destroyed (op, op_tag) ! || was_destroyed (hitter, hitter_tag) ! || abort_attack (op, hitter, simple_attack)) ! goto leave; } /* In the new attack code, it should handle multiple attack * types in its area, so remove it from here. */ dam=hit_player(op, (RANDOM()%hitdam)+1, hitter, type); ! if (was_destroyed (op, op_tag) || was_destroyed (hitter, hitter_tag) ! || abort_attack (op, hitter, simple_attack)) goto leave; } /* end of if hitter hit op */ /* if we missed, dam=0 */ *************** *** 492,502 **** new_draw_info(NDI_BLACK, 0, hitter->owner, buf); } ! leave: ! free_string(op_name); return dam; } void tear_down_wall(object *op) { int perc=0; --- 560,698 ---- new_draw_info(NDI_BLACK, 0, hitter->owner, buf); } ! goto leave; ! ! error: ! dam = 1; ! goto leave; ! ! leave: ! if (op_name) ! free_string (op_name); return dam; } + int attack_ob (object *op, object *hitter) + { + if (hitter->head) + hitter = hitter->head; + return attack_ob_simple (op, hitter, hitter->stats.dam, hitter->stats.wc); + } + + /* op is the arrow, tmp is what is stopping the arrow. + * + * Returns 1 if op was inserted into tmp's inventory, 0 otherwise. + */ + static int stick_arrow (object *op, object *tmp) + { + /* If the missile hit a player, we insert it in their inventory. + * However, if the missile is heavy, we don't do so (assume it falls + * to the ground after a hit). What a good value for this is up to + * debate - 5000 is 5 kg, so arrows, knives, and other light weapons + * stick around. + */ + if (op->weight <= 5000 && tmp->stats.hp >= 0) { + if(tmp->head != NULL) + tmp = tmp->head; + remove_ob (op); + op = insert_ob_in_ob(op,tmp); + if (tmp->type== PLAYER) + esrv_send_item (tmp, op); + return 1; + } else + return 0; + } + + /* hit_with_arrow() disassembles the missile, attacks the victim and + * reassembles the missile. + * + * It returns a pointer to the reassembled missile, or NULL if the missile + * isn't available anymore. + */ + object *hit_with_arrow (object *op, object *victim) + { + object *container, *hitter; + int hit_something; + tag_t victim_tag, hitter_tag; + sint16 victim_x, victim_y; + + /* Disassemble missile */ + if (op->inv) { + container = op; + hitter = op->inv; + remove_ob (hitter); + insert_ob_in_map_simple (hitter, container->map); + /* Note that we now have an empty THROWN_OBJ on the map. Code that + * might be called until this THROWN_OBJ is either reassembled or + * removed at the end of this function must be able to deal with empty + * THROWN_OBJs. */ + } else { + container = NULL; + hitter = op; + } + + /* Try to hit victim */ + victim_x = victim->x; + victim_y = victim->y; + victim_tag = victim->count; + hitter_tag = hitter->count; + hit_something = attack_ob_simple (victim, hitter, op->stats.dam, + op->stats.wc); + /* Arrow attacks door, rune of summoning is triggered, demon is put on + * arrow, move_apply() calls this function, arrow sticks in demon, + * attack_ob_simple() returns, and we've got an arrow that still exists + * but is no longer on the map. Ugh. (Beware: Such things can happen at + * other places as well!) */ + if (was_destroyed (hitter, hitter_tag) || hitter->env != NULL) { + if (container) { + remove_ob (container); + free_object (container); + } + return NULL; + } + + /* Missile hit victim */ + if (hit_something) + { + /* Stop arrow */ + if (container == NULL) { + hitter = fix_stopped_arrow (hitter); + if (hitter == NULL) + return NULL; + } else { + remove_ob (container); + free_object (container); + } + + /* Try to stick arrow into victim */ + if ( ! was_destroyed (victim, victim_tag) + && stick_arrow (hitter, victim)) + return NULL; + + /* Else try to put arrow on victim's map square */ + if ((victim_x != hitter->x || victim_y != hitter->y) + && ! wall (hitter->map, victim_x, victim_y)) + { + remove_ob (hitter); + hitter->x = victim_x; + hitter->y = victim_y; + insert_ob_in_map (hitter, hitter->map, hitter); + } else { + /* Else leave arrow where it is */ + merge_ob (hitter, NULL); + } + return NULL; + } + + /* Missile missed victim - reassemble missile */ + if (container) { + remove_ob (hitter); + insert_ob_in_ob (hitter, container); + } + return op; + } + + void tear_down_wall(object *op) { int perc=0; *************** *** 743,768 **** char buf[MAX_BUF]; object *old_hitter=NULL; /* this is used in case of servant monsters */ int maxdam=0,ndam,attacktype=1,attacknum,magic=(type & AT_MAGIC); ! tag_t hitter_tag; ! if (QUERY_FLAG (op, FLAG_FREED) || QUERY_FLAG (hitter, FLAG_FREED)) { ! LOG (llevError, "BUG: hit_player(): freed object\n"); return 0; ! } hitter_tag = hitter->count; ! if(op->head!=NULL) { ! if(op->head==op) { ! LOG(llevError,"Recursive head error!\n"); ! return 0; ! } ! #if 0 ! /* To paralyze/slow a creature, we must hit its head with the attacktype. ! * If we are going to do this, this should probably be expanded. ! */ ! if(type&AT_PARALYZE || type&AT_SLOW) ! return 0; ! #else /* slow and paralyze must hit the head. But we don't want to just * return - we still need to process other attacks the spell still * might have. So just remove the paralyze and slow attacktypes, --- 939,958 ---- char buf[MAX_BUF]; object *old_hitter=NULL; /* this is used in case of servant monsters */ int maxdam=0,ndam,attacktype=1,attacknum,magic=(type & AT_MAGIC); ! int body_attack = op && op->head; /* Did we hit op's head? */ ! int simple_attack; ! tag_t op_tag, hitter_tag; ! if (get_attack_mode (&op, &hitter, &simple_attack)) return 0; ! ! if (QUERY_FLAG (op, FLAG_WIZ)) ! return 0; ! ! op_tag = op->count; hitter_tag = hitter->count; ! if (body_attack) { /* slow and paralyze must hit the head. But we don't want to just * return - we still need to process other attacks the spell still * might have. So just remove the paralyze and slow attacktypes, *************** *** 776,794 **** type &= ~(AT_PARALYZE | AT_SLOW); if (!type || type==AT_MAGIC) return 0; } - #endif - op=op->head; } ! if(op->type==DOOR && op->inv && op->inv->type==RUNE) { ! spring_trap(op->inv,hitter); ! if (was_destroyed (hitter, hitter_tag)) ! return 0; } ! /* If its already dead, or we're the wizard, don't attack it - no point */ ! if(QUERY_FLAG(op,FLAG_WIZ)||!QUERY_FLAG(op,FLAG_ALIVE)||op->stats.hp<0) return 0; #ifdef ATTACK_DEBUG LOG(llevDebug,"hit player: attacktype %d, dam %d\n", type, dam); --- 966,994 ---- type &= ~(AT_PARALYZE | AT_SLOW); if (!type || type==AT_MAGIC) return 0; } } ! if ( ! simple_attack && op->type == DOOR) { ! object *tmp; ! for (tmp = op->inv; tmp != NULL; tmp = tmp->below) ! if (tmp->type == RUNE) { ! spring_trap (tmp, hitter); ! if (was_destroyed (hitter, hitter_tag) ! || was_destroyed (op, op_tag) ! || abort_attack (op, hitter, simple_attack)) ! return 0; ! break; ! } } ! if ( ! QUERY_FLAG (op, FLAG_ALIVE) || op->stats.hp < 0) { ! /* FIXME: If a player is killed by a rune in a door, the ! * was_destroyed() check above doesn't return, and might get here. ! */ ! LOG (llevDebug, "victim (arch %s, name %s) already dead in " ! "hit_player()\n", op->arch->name, op->name); return 0; + } #ifdef ATTACK_DEBUG LOG(llevDebug,"hit player: attacktype %d, dam %d\n", type, dam); *************** *** 1212,1218 **** if((tmp=present(PARAIMAGE,op->map,op->x,op->y))==NULL) { tmp=clone_arch(PARAIMAGE); tmp->x=op->x,tmp->y=op->y; ! insert_ob_in_map(tmp,op->map,NULL); } op->speed_left-=(float)FABS(op->speed)*(dam*3); tmp->stats.food+=(signed short) (dam*3)/op->speed; --- 1412,1422 ---- if((tmp=present(PARAIMAGE,op->map,op->x,op->y))==NULL) { tmp=clone_arch(PARAIMAGE); tmp->x=op->x,tmp->y=op->y; ! /* We can't use insert_ob_in_map() (which can trigger various things) ! * unless a lot of was_destroyed() checks are added in our callers. ! * But this is just a simple visual effect anyway. ! */ ! insert_ob_in_map_simple(tmp,op->map); } op->speed_left-=(float)FABS(op->speed)*(dam*3); tmp->stats.food+=(signed short) (dam*3)/op->speed; *************** *** 1274,1295 **** /* thrown_item_effect() - handles any special effects of thrown * items (like attacking living creatures--a potion thrown at a ! * monster). We return the hitter item for further ! * possible (ie physical) attacks. Other posibilities ! * include spilling containers, and lighting stuff on fire ! * with thrown torches. */ ! object *thrown_item_effect( object *hitter, object *victim) { ! object *tmp=hitter; ! ! if(hitter->type==THROWN_OBJ) tmp = hitter->inv; ! if(!tmp) return hitter; if(!QUERY_FLAG(hitter,FLAG_ALIVE)) { ! switch (tmp->type) { case POTION: if(QUERY_FLAG(victim,FLAG_ALIVE)&&!QUERY_FLAG(victim,FLAG_UNDEAD) ! &&!(victim->immune&AT_MAGIC)) (void) apply_potion(victim,tmp); break; case FOOD: /* cursed food is (often) poisonous....but it won't 'explode' --- 1478,1494 ---- /* thrown_item_effect() - handles any special effects of thrown * items (like attacking living creatures--a potion thrown at a ! * monster). */ ! static void thrown_item_effect (object *hitter, object *victim) ! { ! tag_t tag = hitter->count; if(!QUERY_FLAG(hitter,FLAG_ALIVE)) { ! switch (hitter->type) { case POTION: if(QUERY_FLAG(victim,FLAG_ALIVE)&&!QUERY_FLAG(victim,FLAG_UNDEAD) ! &&!(victim->immune&AT_MAGIC)) (void) apply_potion(victim,hitter); break; case FOOD: /* cursed food is (often) poisonous....but it won't 'explode' *************** *** 1299,1320 **** break; case POISON: /* poison drinks */ if(QUERY_FLAG(victim,FLAG_ALIVE)&&!QUERY_FLAG(victim,FLAG_UNDEAD) ! &&!(victim->immune&AT_POISON)) apply_poison(victim,tmp); break; case CONTAINER: /* spill_container(victim,RANDOM()%(hitter->stats.dam+1)); */ break; - default: - break; } - #if 0 - /* glow objects (torches) are on fire.. */ - if(!tmp->type&&tmp->glow_radius>0) { - } - #endif } - - return tmp; } /* adj_attackroll() - adjustments to attacks by various conditions */ --- 1498,1510 ---- break; case POISON: /* poison drinks */ if(QUERY_FLAG(victim,FLAG_ALIVE)&&!QUERY_FLAG(victim,FLAG_UNDEAD) ! &&!(victim->immune&AT_POISON)) apply_poison(victim,hitter); break; case CONTAINER: /* spill_container(victim,RANDOM()%(hitter->stats.dam+1)); */ break; } } } /* adj_attackroll() - adjustments to attacks by various conditions */ *************** *** 1324,1331 **** int adjust=0; /* safety */ ! if(!target||!hitter||!hitter->map||!target->map||hitter->map!=target->map) return 0; /* aimed missiles use the owning object's sight */ if(is_aimed_missile(hitter)) { --- 1514,1524 ---- int adjust=0; /* safety */ ! if(!target||!hitter||!hitter->map||!target->map||hitter->map!=target->map) { ! LOG (llevError, "BUG: adj_attackroll(): hitter and target not on same " ! "map\n"); return 0; + } /* aimed missiles use the owning object's sight */ if(is_aimed_missile(hitter)) { Index: server/c_object.c =================================================================== RCS file: /home/cvs/CVS/crossfire/server/c_object.c,v retrieving revision 1.12 retrieving revision 1.13 diff -c -r1.12 -r1.13 *** server/c_object.c 2000/11/03 05:42:56 1.12 --- server/c_object.c 2000/11/06 23:06:47 1.13 *************** *** 1,6 **** /* * static char *rcsid_c_object_c = ! * "$Id: c_object.c,v 1.12 2000/11/03 05:42:56 cvs Exp $"; */ /* CrossFire, A Multiplayer game for X-windows --- 1,6 ---- /* * static char *rcsid_c_object_c = ! * "$Id: c_object.c,v 1.13 2000/11/06 23:06:47 jec Exp $"; */ /* CrossFire, A Multiplayer game for X-windows *************** *** 246,259 **** * tmp is the object to pick up, nrof is the number to * pick up (0 means all of them) */ ! void pick_up_object (object *pl, object *op, object *tmp, int nrof) { /* buf needs to be big (more than 256 chars) because you can get * very long item names. */ char buf[HUGE_BUF]; object *env=tmp->env; ! uint32 weight; /* IF the player is flying & trying to take the item out of a container * that is in his inventory, let him. tmp->env points to the container --- 246,260 ---- * tmp is the object to pick up, nrof is the number to * pick up (0 means all of them) */ ! static void pick_up_object (object *pl, object *op, object *tmp, int nrof) { /* buf needs to be big (more than 256 chars) because you can get * very long item names. */ char buf[HUGE_BUF]; object *env=tmp->env; ! uint32 weight, effective_weight_limit; ! int tmp_nrof = tmp->nrof ? tmp->nrof : 1; /* IF the player is flying & trying to take the item out of a container * that is in his inventory, let him. tmp->env points to the container *************** *** 265,302 **** new_draw_info(NDI_UNIQUE, 0,pl, "You are levitating, you can't reach the ground!"); return; } - if(!can_pick(pl,tmp)) { - if (tmp->name!=NULL) { - sprintf(buf,"You can't pick up a %s", tmp->name); - new_draw_info(NDI_UNIQUE, 0,pl, buf); - } - else - new_draw_info(NDI_UNIQUE, 0,pl,"You can't take that!"); - return; - } if (QUERY_FLAG (tmp, FLAG_NO_DROP)) return; if(QUERY_FLAG(tmp,FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) { new_draw_info(NDI_UNIQUE, 0,pl, "The object disappears in a puff of smoke!"); new_draw_info(NDI_UNIQUE, 0,pl, "It must have been an illusion."); if (pl->type==PLAYER) esrv_del_item (pl->contr, tmp->count); ! remove_ob(tmp); free_object(tmp); return; } - - /* startequip items are not allowed to be put into containers: */ - if (pl->type == PLAYER && op->type == CONTAINER && - QUERY_FLAG(tmp, FLAG_STARTEQUIP)) { - new_draw_info(NDI_UNIQUE, 0,pl,"This object cannot be put into containers!"); - return; - } ! if (nrof==0 || nrof>tmp->nrof) nrof=(tmp->nrof?tmp->nrof:1); /* Figure out how much weight this object will add to the player */ weight = tmp->weight * nrof; if (tmp->inv) weight += tmp->carrying * (100 - tmp->stats.Str) / 100; ! if ((pl->weight + pl->carrying +weight) > weight_limit[pl->stats.Str]) { new_draw_info(NDI_UNIQUE, 0,pl,"That item is too heavy for you to pick up."); return; } --- 266,293 ---- new_draw_info(NDI_UNIQUE, 0,pl, "You are levitating, you can't reach the ground!"); return; } if (QUERY_FLAG (tmp, FLAG_NO_DROP)) return; if(QUERY_FLAG(tmp,FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) { new_draw_info(NDI_UNIQUE, 0,pl, "The object disappears in a puff of smoke!"); new_draw_info(NDI_UNIQUE, 0,pl, "It must have been an illusion."); if (pl->type==PLAYER) esrv_del_item (pl->contr, tmp->count); ! if ( ! QUERY_FLAG (tmp, FLAG_REMOVED)) ! remove_ob (tmp); free_object(tmp); return; } ! if (nrof > tmp_nrof || nrof == 0) ! nrof = tmp_nrof; /* Figure out how much weight this object will add to the player */ weight = tmp->weight * nrof; if (tmp->inv) weight += tmp->carrying * (100 - tmp->stats.Str) / 100; ! if (pl->stats.Str <= MAX_STAT) ! effective_weight_limit = weight_limit[pl->stats.Str]; ! else ! effective_weight_limit = weight_limit[MAX_STAT]; ! if ((pl->weight + pl->carrying + weight) > effective_weight_limit) { new_draw_info(NDI_UNIQUE, 0,pl,"That item is too heavy for you to pick up."); return; } *************** *** 307,313 **** SET_FLAG(tmp, FLAG_WAS_WIZ); #endif ! if(nrof != tmp->nrof && !(nrof == 1 && tmp->nrof == 0)) { object *tmp2 = tmp; tag_t tmp2_tag = tmp2->count; tmp = get_split_ob (tmp, nrof); --- 298,304 ---- SET_FLAG(tmp, FLAG_WAS_WIZ); #endif ! if (nrof != tmp_nrof) { object *tmp2 = tmp; tag_t tmp2_tag = tmp2->count; tmp = get_split_ob (tmp, nrof); *************** *** 317,323 **** } /* Tell a client what happened rest of objects */ if (pl->type == PLAYER) { ! if (was_destroyed (tmp2, tmp2_tag)) esrv_del_item (pl->contr, tmp2_tag); else esrv_send_item (pl, tmp2); --- 308,314 ---- } /* Tell a client what happened rest of objects */ if (pl->type == PLAYER) { ! if (was_destroyed (tmp2, tmp2_tag)) esrv_del_item (pl->contr, tmp2_tag); else esrv_send_item (pl, tmp2); *************** *** 327,335 **** * - we are moving all the items from the container to elsewhere, * so it needs to be deleted. */ ! if (tmp->env && pl->type==PLAYER) ! esrv_del_item (pl->contr, tmp->count); ! remove_ob(tmp); /* Unlink it */ } if(QUERY_FLAG(tmp, FLAG_UNPAID)) (void) sprintf(buf,"%s will cost you %s.", query_name(tmp), --- 318,328 ---- * - we are moving all the items from the container to elsewhere, * so it needs to be deleted. */ ! if ( ! QUERY_FLAG (tmp, FLAG_REMOVED)) { ! if (tmp->env && pl->type==PLAYER) ! esrv_del_item (pl->contr, tmp->count); ! remove_ob(tmp); /* Unlink it */ ! } } if(QUERY_FLAG(tmp, FLAG_UNPAID)) (void) sprintf(buf,"%s will cost you %s.", query_name(tmp), *************** *** 360,377 **** void pick_up(object *op,object *alt) /* modified slightly to allow monsters use this -b.t. 5-31-95 */ { ! object *tmp=NULL; int count; ! if(alt) ! tmp=alt; ! else if(op->below==NULL || !can_pick(op, tmp)) { ! new_draw_info(NDI_UNIQUE, 0,op,"There is nothing to pick up here."); ! return; ! } else ! tmp=op->below; ! if (op->type==PLAYER && op->contr->count && op->contr->count <tmp->nrof) count=op->contr->count; else count=tmp->nrof; --- 353,394 ---- void pick_up(object *op,object *alt) /* modified slightly to allow monsters use this -b.t. 5-31-95 */ { ! int need_fix_tmp = 0; ! object *tmp; ! mapstruct *tmp_map; int count; + tag_t tag; ! /* Decide which object to pick. */ ! if (alt) ! { ! if ( ! can_pick (op, alt)) { ! new_draw_info_format (NDI_UNIQUE, 0, op, "You can't pick up a %s.", ! alt->name); ! goto leave; ! } ! tmp = alt; ! } ! else ! { ! if (op->below == NULL || ! can_pick (op, op->below)) { ! new_draw_info (NDI_UNIQUE, 0, op, ! "There is nothing to pick up here."); ! goto leave; ! } ! tmp = op->below; ! } ! ! /* Try to catch it. */ ! tmp_map = tmp->map; ! tmp = stop_item (tmp); ! if (tmp == NULL) ! goto leave; ! need_fix_tmp = 1; ! if ( ! can_pick (op, tmp)) ! goto leave; ! if (op->type==PLAYER) count=op->contr->count; else count=tmp->nrof; *************** *** 380,386 **** if (op->container) { alt = op->container; if (alt != tmp->env && !sack_can_hold (op, alt, tmp,count)) ! return; } else { /* non container pickup */ for (alt=op->inv; alt; alt=alt->below) if (alt->type==CONTAINER && QUERY_FLAG(alt, FLAG_APPLIED) && --- 397,403 ---- if (op->container) { alt = op->container; if (alt != tmp->env && !sack_can_hold (op, alt, tmp,count)) ! goto leave; } else { /* non container pickup */ for (alt=op->inv; alt; alt=alt->below) if (alt->type==CONTAINER && QUERY_FLAG(alt, FLAG_APPLIED) && *************** *** 405,415 **** #ifdef PICKUP_DEBUG printf ("Pick_up(): %s picks %s (%d) and inserts it %s.\n",op->name, tmp->name, op->contr->count, alt->name); #endif ! if(op->type==PLAYER) { ! pick_up_object(op, alt, tmp, op->contr->count); op->contr->count=0; ! } else ! pick_up_object(op, alt, tmp, tmp->nrof); } --- 422,448 ---- #ifdef PICKUP_DEBUG printf ("Pick_up(): %s picks %s (%d) and inserts it %s.\n",op->name, tmp->name, op->contr->count, alt->name); #endif ! ! /* startequip items are not allowed to be put into containers: */ ! if (op->type == PLAYER && alt->type == CONTAINER ! && QUERY_FLAG (tmp, FLAG_STARTEQUIP)) ! { ! new_draw_info (NDI_UNIQUE, 0, op, ! "This object cannot be put into containers!"); ! goto leave; ! } ! ! tag = tmp->count; ! pick_up_object (op, alt, tmp, count); ! if (was_destroyed (tmp, tag) || tmp->env) ! need_fix_tmp = 0; ! if (op->type == PLAYER) op->contr->count=0; ! goto leave; ! ! leave: ! if (need_fix_tmp) ! fix_stopped_item (tmp, tmp_map, op); } *************** *** 450,456 **** for (tmp=op->below; tmp!=NULL; tmp=tmp->next) if (!tmp->invisible) { char buf[MAX_BUF]; ! sprintf(buf,"You can't pick up a %s", tmp->name? tmp->name:"null"); new_draw_info(NDI_UNIQUE, 0,op, buf); break; --- 483,489 ---- for (tmp=op->below; tmp!=NULL; tmp=tmp->next) if (!tmp->invisible) { char buf[MAX_BUF]; ! sprintf(buf,"You can't pick up a %s.", tmp->name? tmp->name:"null"); new_draw_info(NDI_UNIQUE, 0,op, buf); break; Index: server/player.c =================================================================== RCS file: /home/cvs/CVS/crossfire/server/player.c,v retrieving revision 1.18 retrieving revision 1.19 diff -c -r1.18 -r1.19 *** server/player.c 2000/10/30 22:09:59 1.18 --- server/player.c 2000/11/06 23:06:47 1.19 *************** *** 1,6 **** /* * static char *rcsid_player_c = ! * "$Id: player.c,v 1.18 2000/10/30 22:09:59 jec Exp $"; */ /* --- 1,6 ---- /* * static char *rcsid_player_c = ! * "$Id: player.c,v 1.19 2000/11/06 23:06:47 jec Exp $"; */ /* *************** *** 974,980 **** arrow->level = SK_level (op); arrow->map = op->map; - SET_FLAG(arrow, FLAG_NO_PICK); SET_FLAG(arrow, FLAG_FLYING); SET_FLAG(arrow, FLAG_FLY_ON); SET_FLAG(arrow, FLAG_WALK_ON); --- 974,979 ---- Index: server/rune.c =================================================================== RCS file: /home/cvs/CVS/crossfire/server/rune.c,v retrieving revision 1.8 retrieving revision 1.9 diff -c -r1.8 -r1.9 *** server/rune.c 2000/06/09 00:17:22 1.8 --- server/rune.c 2000/11/06 23:06:47 1.9 *************** *** 1,6 **** /* * static char *rcsid_rune_c = ! * "$Id: rune.c,v 1.8 2000/06/09 00:17:22 cvs Exp $"; */ /* --- 1,6 ---- /* * static char *rcsid_rune_c = ! * "$Id: rune.c,v 1.9 2000/11/06 23:06:47 jec Exp $"; */ /* *************** *** 211,220 **** object *env; tag_t trap_tag = trap->count; ! trap->stats.hp--; /*decrement detcount */ /* get the spell number from the name in the slaying field, and set that as the spell to be cast. */ ! if((spell_in_rune=look_up_spell_by_name(NULL,trap->slaying))!=-1) trap->stats.sp=spell_in_rune; if(victim) if(victim->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,victim,trap->msg); /* Flash an image of the trap on the map so the poor sod * knows what hit him. */ --- 211,233 ---- object *env; tag_t trap_tag = trap->count; ! /* Prevent recursion */ ! if (trap->stats.hp <= 0) ! return; ! /* get the spell number from the name in the slaying field, and set that as the spell to be cast. */ ! if ((spell_in_rune = look_up_spell_by_name (NULL, trap->slaying)) != -1) ! trap->stats.sp=spell_in_rune; ! ! /* Only living objects can trigger runes that don't cast spells, as ! * doing direct damage to a non-living object doesn't work anyway. ! * Typical example is an arrow attacking a door. ! */ ! if ( ! QUERY_FLAG (victim, FLAG_ALIVE) && ! trap->stats.sp) ! return; ! ! trap->stats.hp--; /*decrement detcount */ if(victim) if(victim->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,victim,trap->msg); /* Flash an image of the trap on the map so the poor sod * knows what hit him. */ *************** *** 239,245 **** cast_spell(trap,trap,trap->direction,trap->stats.sp,1,spellNormal,NULL); } ! if(!trap->stats.hp) { trap->type=98; /* make the trap impotent */ trap->stats.food=20; /* make it stick around until its spells are gone */ SET_FLAG(trap,FLAG_IS_USED_UP); --- 252,258 ---- cast_spell(trap,trap,trap->direction,trap->stats.sp,1,spellNormal,NULL); } ! if (trap->stats.hp <= 0) { trap->type=98; /* make the trap impotent */ trap->stats.food=20; /* make it stick around until its spells are gone */ SET_FLAG(trap,FLAG_IS_USED_UP); Index: server/skills.c =================================================================== RCS file: /home/cvs/CVS/crossfire/server/skills.c,v retrieving revision 1.8 retrieving revision 1.9 diff -c -r1.8 -r1.9 *** server/skills.c 2000/06/09 12:01:47 1.8 --- server/skills.c 2000/11/06 23:06:47 1.9 *************** *** 1,6 **** /* * static char *rcsid_skills_c = ! * "$Id: skills.c,v 1.8 2000/06/09 12:01:47 jec Exp $"; */ /* CrossFire, A Multiplayer game for X-windows --- 1,6 ---- /* * static char *rcsid_skills_c = ! * "$Id: skills.c,v 1.9 2000/11/06 23:06:47 jec Exp $"; */ /* CrossFire, A Multiplayer game for X-windows *************** *** 1603,1609 **** throw_ob->speed_left = 0; throw_ob->map = op->map; - SET_FLAG(throw_ob, FLAG_NO_PICK); SET_FLAG(throw_ob, FLAG_FLYING); SET_FLAG(throw_ob, FLAG_FLY_ON); SET_FLAG(throw_ob, FLAG_WALK_ON); --- 1603,1608 ---- Index: server/spell_effect.c =================================================================== RCS file: /home/cvs/CVS/crossfire/server/spell_effect.c,v retrieving revision 1.24 retrieving revision 1.25 diff -c -r1.24 -r1.25 *** server/spell_effect.c 2000/10/20 19:19:39 1.24 --- server/spell_effect.c 2000/11/06 23:06:47 1.25 *************** *** 1,6 **** /* * static char *rcsid_spell_effect_c = ! * "$Id: spell_effect.c,v 1.24 2000/10/20 19:19:39 peterm Exp $"; */ --- 1,6 ---- /* * static char *rcsid_spell_effect_c = ! * "$Id: spell_effect.c,v 1.25 2000/11/06 23:06:47 jec Exp $"; */ *************** *** 1540,1551 **** if (at) for(i=1;i<9;i++) fire_arch(op,op,i,at,0,0); ! remove_ob(op); ! op->x=env->x; ! op->y=env->y; ! if(!explode_object(op)) /* Boom 8) */ ! LOG(llevError,"Error: bomb refused to go off.\n"); ! return; } --- 1540,1546 ---- if (at) for(i=1;i<9;i++) fire_arch(op,op,i,at,0,0); ! explode_object(op); } *************** *** 1586,1593 **** insert_ob_in_map(op,op->map,op); return; } ! hit_map(op, 0, op->attacktype); ! insert_ob_in_map(op,op->map,op); } void cancellation(object *op) --- 1581,1588 ---- insert_ob_in_map(op,op->map,op); return; } ! if ((op = insert_ob_in_map (op, op->map, op)) != NULL) ! hit_map (op, 0, op->attacktype); } void cancellation(object *op) Index: server/spell_util.c =================================================================== RCS file: /home/cvs/CVS/crossfire/server/spell_util.c,v retrieving revision 1.24 retrieving revision 1.26 diff -c -r1.24 -r1.26 *** server/spell_util.c 2000/10/31 22:11:46 1.24 --- server/spell_util.c 2000/11/07 00:43:30 1.26 *************** *** 1,6 **** /* * static char *rcsid_spell_util_c = ! * "$Id: spell_util.c,v 1.24 2000/10/31 22:11:46 peterm Exp $"; */ /* --- 1,6 ---- /* * static char *rcsid_spell_util_c = ! * "$Id: spell_util.c,v 1.26 2000/11/07 00:43:30 peterm Exp $"; */ /* *************** *** 1103,1109 **** if ( ! QUERY_FLAG (tmp, FLAG_FLYING)) LOG (llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", spell_arch->name); ! if ( ! QUERY_FLAG (tmp, FLAG_WALK_ON) || ! QUERY_FLAG (tmp, FLAG_FLY_ON)) LOG (llevDebug, "cast_cone(): arch %s doesn't have walk_on 1 and " "fly_on 1\n", spell_arch->name); insert_ob_in_map(tmp,op->map,op); --- 1103,1110 ---- if ( ! QUERY_FLAG (tmp, FLAG_FLYING)) LOG (llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", spell_arch->name); ! if (( ! QUERY_FLAG (tmp, FLAG_WALK_ON) || ! QUERY_FLAG (tmp, FLAG_FLY_ON)) ! && tmp->stats.dam) LOG (llevDebug, "cast_cone(): arch %s doesn't have walk_on 1 and " "fly_on 1\n", spell_arch->name); insert_ob_in_map(tmp,op->map,op); *************** *** 1115,1131 **** int i; tag_t tag; - if (op->env) { - /* handle flowers in icecubes */ - op->speed = 0; - update_ob_speed (op); - return; - } - /* if no map then hit_map will crash so just ignore object */ if (! op->map) { LOG(llevError,"Tried to move_cone object %s without a map.\n", op->name ? op->name : "unknown"); return; } --- 1116,1127 ---- int i; tag_t tag; /* if no map then hit_map will crash so just ignore object */ if (! op->map) { LOG(llevError,"Tried to move_cone object %s without a map.\n", op->name ? op->name : "unknown"); + op->speed = 0; + update_ob_speed (op); return; } *************** *** 1478,1524 **** } insert_ob_in_map(op,op->map,op); } - - int explode_object(object *op) { - object *tmp, *victim, *env; ! if(out_of_map(op->map,op->x,op->y)) /* peterm: check for out of map obj's.*/ ! { ! return 0; ! } ! for(env=op;env->env!=NULL;env=env->env); ! if (env->map == NULL) ! return 0; ! if(op->other_arch==NULL) ! return 0; ! tmp=arch_to_object(op->other_arch); ! /* peterm: Hack added to make objects be able to both hit for damage and ! then explode. */ ! if(op->attacktype){ ! for(victim=get_map_ob(op->map,op->x,op->y);victim!=NULL;victim=victim->above) ! if(QUERY_FLAG(victim,FLAG_ALIVE)) ! break; ! hit_map(op,0,op->attacktype); ! #if 0 ! /* Hit_map will also do a hit_player for us. Leaving this call in ! * effectively doubles the amount of damage the bullet is doing. ! */ ! /* Should hit_map also be doing this? Why call hit_player ! * again? Also, make sure victim has not been killed - it ! * is possible that hit_map killed the object. ! */ ! if(victim!=NULL && !QUERY_FLAG(victim,FLAG_FREED)) ! hit_player(victim,op->stats.dam,op,op->attacktype); ! #endif } /* peterm: hack added to make fireballs and other explosions level * dependent: */ - /* op->stats.sp stores the spell which made this object here. */ tmp->stats.dam += SP_level_dam_adjust(op,op,op->stats.sp); if(op->attacktype&AT_MAGIC) tmp->attacktype|=AT_MAGIC; --- 1474,1524 ---- } insert_ob_in_map(op,op->map,op); } ! void explode_object(object *op) ! { ! tag_t op_tag = op->count; ! object *tmp; ! mapstruct *map; ! if (op->other_arch == NULL) { ! LOG (llevError, "BUG: explode_object(): op without other_arch\n"); ! remove_ob (op); ! free_object (op); ! return; ! } ! if (op->env) { ! object *env; ! for (env = op; env->env != NULL; env = env->env) ; ! if (env->map == NULL || out_of_map (env->map, env->x, env->y)) { ! LOG (llevError, "BUG: explode_object(): env out of map\n"); ! remove_ob (op); ! free_object (op); ! return; } + remove_ob (op); + op->x = env->x; + op->y = env->y; + insert_ob_in_map_simple (op, env->map); + } else if (out_of_map (op->map, op->x, op->y)) { + LOG (llevError, "BUG: explode_object(): op out of map\n"); + remove_ob (op); + free_object (op); + return; + } + + if (op->attacktype) { + hit_map (op, 0, op->attacktype); + if (was_destroyed (op, op_tag)) + return; + } /* peterm: hack added to make fireballs and other explosions level * dependent: */ /* op->stats.sp stores the spell which made this object here. */ + tmp = arch_to_object (op->other_arch); tmp->stats.dam += SP_level_dam_adjust(op,op,op->stats.sp); if(op->attacktype&AT_MAGIC) tmp->attacktype|=AT_MAGIC; *************** *** 1526,1573 **** if(op->stats.hp) tmp->stats.hp=op->stats.hp; tmp->stats.maxhp=op->count; /* Unique ID */ ! tmp->x=env->x,tmp->y=env->y; #ifdef MULTIPLE_GODS /* needed for AT_HOLYWORD stuff -b.t. */ if(tmp->attacktype&AT_HOLYWORD||tmp->attacktype&AT_GODPOWER) ! if(!tailor_god_spell(tmp,op)) return 0; #endif ! if (wall(env->map,env->x,env->y)) ! tmp->x-=DIRX(env),tmp->y-=DIRY(env); ! if (out_of_map(env->map, env->x, env->y)) ! free_object(tmp); ! else ! insert_ob_in_map(tmp,env->map,op); ! free_object(op); ! return 1; } ! void check_fired_arch(object *op) { ! if(blocked(op->map,op->x,op->y)) { object *tmp; ! remove_ob(op); ! if(out_of_map(op->map,op->x,op->y)) { ! free_object(op); ! return; } ! if(explode_object(op)) ! return; ! for(tmp=get_map_ob(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above) ! if(QUERY_FLAG(tmp, FLAG_ALIVE)) ! break; ! if(tmp!=NULL) ! op->stats.dam-=hit_player(tmp,op->stats.dam,op,op->attacktype); ! if(blocked(op->map,op->x,op->y)) { ! free_object(op); ! return; } - insert_ob_in_map(op,op->map,op); - } } ! void move_fired_arch(object *op) { ! remove_ob(op); /* peterm: added to make comet leave a trail of burnouts it's an unadulterated hack, but the effect is cool. */ --- 1526,1588 ---- if(op->stats.hp) tmp->stats.hp=op->stats.hp; tmp->stats.maxhp=op->count; /* Unique ID */ ! tmp->x = op->x; ! tmp->y = op->y; #ifdef MULTIPLE_GODS /* needed for AT_HOLYWORD stuff -b.t. */ if(tmp->attacktype&AT_HOLYWORD||tmp->attacktype&AT_GODPOWER) ! if ( ! tailor_god_spell (tmp, op)) { ! remove_ob (op); ! free_object (op); ! return; ! } #endif ! /* Prevent recursion */ ! CLEAR_FLAG (op, FLAG_WALK_ON); ! CLEAR_FLAG (op, FLAG_FLY_ON); ! ! insert_ob_in_map (tmp, op->map, op); ! if ( ! was_destroyed (op, op_tag)) { ! remove_ob (op); ! free_object (op); ! } } ! void check_fired_arch (object *op) ! { ! tag_t op_tag = op->count, tmp_tag; object *tmp; ! int dam; ! ! if ( ! blocked (op->map, op->x, op->y)) ! return; ! ! if (op->other_arch) { ! explode_object (op); ! return; } ! ! for (tmp = get_map_ob (op->map,op->x,op->y); tmp != NULL; tmp = tmp->above) ! { ! if (QUERY_FLAG (tmp, FLAG_ALIVE)) { ! tmp_tag = tmp->count; ! dam = hit_player (tmp, op->stats.dam, op, op->attacktype); ! if (was_destroyed (op, op_tag) || ! was_destroyed (tmp, tmp_tag) ! || (op->stats.dam -= dam) < 0) ! { ! remove_ob (op); ! free_object(op); ! return; ! } ! } } } ! void move_fired_arch (object *op) ! { ! tag_t op_tag = op->count; ! int new_x, new_y; /* peterm: added to make comet leave a trail of burnouts it's an unadulterated hack, but the effect is cool. */ *************** *** 1576,1636 **** tmp1->x = op->x; tmp1->y = op->y; insert_ob_in_map(tmp1,op->map,op); } /* end addition. */ ! op->x+=DIRX(op),op->y+=DIRY(op); ! if(!op->direction||wall(op->map,op->x,op->y)) { ! if(explode_object(op)) ! return; ! free_object(op); ! return; } ! if(reflwall(op->map,op->x,op->y)) { ! op->direction=absdir(op->direction+4); ! if ((op = insert_ob_in_map(op,op->map,op)) != NULL) ! update_turn_face(op); ! return; } - if(blocked(op->map,op->x,op->y)) { - object *tmp; ! if(out_of_map(op->map,op->x,op->y)) { ! free_object(op); ! return; ! } ! ! if(explode_object(op)) ! return; ! ! for(tmp=get_map_ob(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above) ! if(QUERY_FLAG(tmp, FLAG_ALIVE)) ! break; ! ! if(tmp!=NULL) { ! /* Certain items, like speedballs, have attacktype ghosthit. ! * hit_player wants to remove the object after it hits the player. ! * Since it is already removed, just don't make it ghosthit, and ! * remove it here ! */ ! ! if (op->attacktype & AT_GHOSTHIT) { ! hit_player(tmp,op->stats.dam,op,(op->attacktype & ~AT_GHOSTHIT)); ! free_object(op); ! return; ! } ! else ! op->stats.dam-=hit_player(tmp,op->stats.dam,op,op->attacktype); ! } ! /* I guess this can be applicable if the object blocking the ! * space was destroyed? ! */ ! if(blocked(op->map,op->x,op->y)) { ! free_object(op); ! return; ! } ! } /* if space is blocked */ ! insert_ob_in_map(op,op->map,op); } --- 1591,1629 ---- tmp1->x = op->x; tmp1->y = op->y; insert_ob_in_map(tmp1,op->map,op); + if (was_destroyed (op, op_tag)) + return; } /* end addition. */ ! new_x = op->x + DIRX(op); ! new_y = op->y + DIRY(op); ! if (out_of_map (op->map, new_x, new_y)) { ! remove_ob (op); ! free_object (op); ! return; } ! if ( ! op->direction || wall (op->map, new_x, new_y)) { ! if (op->other_arch) { ! explode_object (op); ! } else { ! remove_ob (op); ! free_object (op); ! } ! return; } ! remove_ob (op); ! op->x = new_x; ! op->y = new_y; ! if ((op = insert_ob_in_map (op, op->map, op)) == NULL) ! return; ! if (reflwall (op->map, op->x, op->y)) { ! op->direction = absdir (op->direction + 4); ! update_turn_face (op); ! } else { ! check_fired_arch (op); ! } } *************** *** 1683,1727 **** /* peterm: ball lightning mover. */ /* ball lightning automatically seeks out a victim, if it sees any monsters close enough. */ - void move_ball_lightning(object *op) { ! int i,nx,ny,tx,ty,j,dam_save; object *owner; owner = get_owner(op); - remove_ob(op); /* Only those attuned to PATH_ELEC may use ball lightning with AT_GODPOWER */ ! if((!(owner->path_attuned & PATH_ELEC))&& (op->attacktype & AT_GODPOWER)) { free_object(op); new_draw_info_format(NDI_UNIQUE,0,owner,"The ball lightning dispells immediately. Perhaps you need attunement to the spell path?"); return; } ! nx=op->x+DIRX(op); ! ny=op->y+DIRY(op); ! ty=op->y; ! tx=op->x; /* the following logic makes sure that the ball ! doesn't move into a wall, and makes ! sure that it will move along a wall to try and ! get at it's victim. */ ! if(!wall(op->map, nx, ny)&&!blocks_view(op->map,nx,ny)) { ! tx=nx; ! ty=ny; } ! else ! { i=RANDOM()%2; ! if(i) { ! if(!wall(op->map,op->x,ny)&&!blocks_view(op->map,op->x,ny)) ty=ny; ! else if(!wall(op->map,nx,op->y)&&!blocks_view(op->map,nx,op->y)) tx=nx; ! } ! else { ! if(!wall(op->map,nx,op->y)&&!blocks_view(op->map,nx,op->y)) tx=nx; ! else if(!wall(op->map,op->x,ny)&&!blocks_view(op->map,op->x,ny)) ty=ny; ! } } ! op->y=ty; ! op->x=tx; insert_ob_in_map(op,op->map,op); dam_save = op->stats.dam; /* save the original dam: we do halfdam on --- 1676,1725 ---- /* peterm: ball lightning mover. */ /* ball lightning automatically seeks out a victim, if it sees any monsters close enough. */ void move_ball_lightning(object *op) { ! int i,nx,ny,tx,ty,j,dam_save,dir; object *owner; owner = get_owner(op); /* Only those attuned to PATH_ELEC may use ball lightning with AT_GODPOWER */ ! if(owner && (!(owner->path_attuned & PATH_ELEC))&& (op->attacktype & AT_GODPOWER)) { ! remove_ob(op); free_object(op); new_draw_info_format(NDI_UNIQUE,0,owner,"The ball lightning dispells immediately. Perhaps you need attunement to the spell path?"); return; } + + /* the following logic makes sure that the ball + doesn't move into a wall, and makes + sure that it will move along a wall to try and + get at it's victim. */ + dir = 0; ! if(!(RANDOM() %4)) ! j = RANDOM() %2; ! for(i = 1; i < 9; i++) { ! /* i bit 0: alters sign of offset ! * otther bits (i / 2): absolute value of offset ! */ ! ! int offset = ((i ^ j) & 1) ? (i / 2) : - (i / 2); ! int tmpdir = absdir (op->direction + offset); ! nx = op->x + freearr_x[tmpdir]; ! ny = op->y + freearr_y[tmpdir]; ! if ( ! wall (op->map, nx, ny) && ! blocks_view (op->map, nx, ny)) { ! dir = tmpdir; ! break; ! } } ! if (dir == 0) { ! nx = op->x; ! ny = op->y; } ! ! remove_ob(op); ! op->y=ny; ! op->x=nx; insert_ob_in_map(op,op->map,op); dam_save = op->stats.dam; /* save the original dam: we do halfdam on *************** *** 1731,1751 **** for(j=0;j<9;j++) { int hx,hy; /* hit these squares */ ! hx = tx+freearr_x[j]; hy = ty+freearr_y[j]; /* first, don't ever, ever hit the owner. Don't hit out of the map either.*/ ! if(! (owner->x==hx && owner->y==hy) && !out_of_map(op->map,hx,hy)) { ! op->x = hx; ! op->y = hy; if(j) op->stats.dam = dam_save/2; ! if(blocked(op->map,op->x,op->y)) hit_map(op,0,op->attacktype); } } /* restore to the center location and damage*/ - op->y = ty; - op->x = tx; op->stats.dam = dam_save; i=spell_find_dir(op->map,op->x,op->y,get_owner(op)); --- 1729,1745 ---- for(j=0;j<9;j++) { int hx,hy; /* hit these squares */ ! hx = nx+freearr_x[j]; hy = ny+freearr_y[j]; /* first, don't ever, ever hit the owner. Don't hit out of the map either.*/ ! if(! (owner && owner->x==hx && owner->y==hy) && !out_of_map(op->map,hx,hy)) { if(j) op->stats.dam = dam_save/2; ! if(blocked(op->map,hx,hy)) hit_map(op,j,op->attacktype); } } /* restore to the center location and damage*/ op->stats.dam = dam_save; i=spell_find_dir(op->map,op->x,op->y,get_owner(op)); *************** *** 1759,1764 **** --- 1753,1760 ---- op->direction=i; } } + + /* peterm: do LOS stuff for ball lightning. Go after the closest VISIBLE monster. Index: server/time.c =================================================================== RCS file: /home/cvs/CVS/crossfire/server/time.c,v retrieving revision 1.13 retrieving revision 1.14 diff -c -r1.13 -r1.14 *** server/time.c 2000/11/04 06:40:50 1.13 --- server/time.c 2000/11/06 23:06:47 1.14 *************** *** 1,6 **** /* * static char *rcsid_time_c = ! * "$Id: time.c,v 1.13 2000/11/04 06:40:50 cvs Exp $"; */ /* --- 1,6 ---- /* * static char *rcsid_time_c = ! * "$Id: time.c,v 1.14 2000/11/06 23:06:47 jec Exp $"; */ /* *************** *** 441,469 **** } ! /* stop_arrow() - what to do when a non-living flying object ! * has to stop. Sept 96 - I added in thrown object code in ! * here too. -b.t. ! * op is arrow, tmp is what is stopping the arrow (can be NULL) */ ! ! void stop_arrow(object *op,object *tmp) { ! if(wall(op->map,op->x,op->y)) ! op->x-=DIRX(op),op->y-=DIRY(op); ! if(wall(op->map, op->x, op->y)) { ! free_object(op); ! return; } if(RANDOM() % 100 < op->stats.food) { /* Small chance of breaking */ free_object(op); ! return; } op->direction=0; - CLEAR_FLAG(op, FLAG_NO_PICK); CLEAR_FLAG(op, FLAG_WALK_ON); CLEAR_FLAG(op, FLAG_FLY_ON); CLEAR_FLAG(op, FLAG_FLYING); --- 441,519 ---- } ! /* stop_item() returns a pointer to the stopped object. The stopped object ! * may or may not have been removed from maps or inventories. It will not ! * have been merged with other items. ! * ! * This function assumes that only items on maps need special treatment. ! * ! * If the object can't be stopped, or it was destroyed while trying to stop ! * it, NULL is returned. ! * ! * fix_stopped_item() should be used if the stopped item should be put on ! * the map. */ ! object *stop_item (object *op) ! { ! if (op->map == NULL) ! return op; ! switch (op->type) ! { ! case THROWN_OBJ: ! { ! object *payload = op->inv; ! if (payload == NULL) ! return NULL; ! remove_ob (payload); ! remove_ob (op); ! free_object (op); ! return payload; ! } ! ! case ARROW: ! if (op->speed >= MIN_ACTIVE_SPEED) ! op = fix_stopped_arrow (op); ! return op; ! ! case CONE: ! if (op->speed < MIN_ACTIVE_SPEED) { ! return op; ! } else { ! return NULL; ! } ! ! default: ! return op; } + } + /* fix_stopped_item() - put stopped item where stop_item() had found it. + * Inserts item into the old map, or merges it if it already is on the map. + * + * 'map' must be the value of op->map before stop_item() was called. + */ + void fix_stopped_item (object *op, mapstruct *map, object *originator) + { + if (map == NULL) + return; + if (QUERY_FLAG (op, FLAG_REMOVED)) + insert_ob_in_map (op, map, originator); + else if (op->type == ARROW) + merge_ob (op, NULL); /* only some arrows actually need this */ + } + + + object *fix_stopped_arrow (object *op) + { if(RANDOM() % 100 < op->stats.food) { /* Small chance of breaking */ + remove_ob (op); free_object(op); ! return NULL; } op->direction=0; CLEAR_FLAG(op, FLAG_WALK_ON); CLEAR_FLAG(op, FLAG_FLY_ON); CLEAR_FLAG(op, FLAG_FLYING); *************** *** 475,537 **** op->stats.sp = 0; op->stats.hp = 0; op->face=op->arch->clone.face; - - /* this happens for thrown objects, which 'carry' the - * real object in inventory. */ - if(op->inv) { - object *old=op,*new=op->inv; - remove_ob(op->inv); - new->map = old->map; - free_object(old); - op = new; - } - - /* If the missile hit a player, we insert it in their inventory. - * However, if the missile is heavy, we don't do so (assume it falls - * to the ground after a hit). What a good value for this is up to - * debate - 5000 is 5 kg, so arrows, knives, and other light weapons - * stick around. - */ - if(op->weight <= 5000 && tmp!=NULL&&tmp->stats.hp>=0) { - if(tmp->head != NULL) - tmp = tmp->head; - op = insert_ob_in_ob(op,tmp); - if (tmp->type== PLAYER) - esrv_send_item (tmp, op); - } else - insert_ob_in_map(op,op->map,op); op->owner=NULL; /* So that stopped arrows will be saved */ } /* Move an arrow along its course. op is the arrow or thrown object. */ void move_arrow(object *op) { object *tmp; if(op->map==NULL) { ! LOG(llevDebug,"Arrow had no map.\n"); remove_ob(op); free_object(op); return; } - remove_ob(op); - /* we need to stop thrown objects at some point. Like here. */ if(op->type==THROWN_OBJ) { if(op->last_sp-- < 0) { ! stop_arrow(op, NULL); return; } } ! if(wall(op->map,op->x+DIRX(op),op->y+DIRY(op))) { /* if the object doesn't reflect, stop the arrow from moving */ if(!QUERY_FLAG(op, FLAG_REFLECTING) || !(RANDOM()%20)) { ! stop_arrow(op,NULL); return; } else { /* object is reflected */ /* If one of the major directions (n,s,e,w), just reverse it */ --- 525,633 ---- op->stats.sp = 0; op->stats.hp = 0; op->face=op->arch->clone.face; op->owner=NULL; /* So that stopped arrows will be saved */ + update_object (op); + return op; } + /* stop_arrow() - what to do when a non-living flying object + * has to stop. Sept 96 - I added in thrown object code in + * here too. -b.t. + * + * Returns a pointer to the stopped object (which will have been removed + * from maps or inventories), or NULL if was destroyed. + */ + + static void stop_arrow (object *op) + { + if (op->inv) { + object *payload = op->inv; + remove_ob (payload); + insert_ob_in_map (payload, op->map, payload); + remove_ob (op); + free_object (op); + } else { + op = fix_stopped_arrow (op); + if (op) + merge_ob (op, NULL); + } + } /* Move an arrow along its course. op is the arrow or thrown object. */ void move_arrow(object *op) { object *tmp; + sint16 new_x, new_y; + int was_reflected; if(op->map==NULL) { ! LOG (llevError, "BUG: Arrow had no map.\n"); remove_ob(op); free_object(op); return; } /* we need to stop thrown objects at some point. Like here. */ if(op->type==THROWN_OBJ) { + if (op->inv == NULL) + return; if(op->last_sp-- < 0) { ! stop_arrow (op); return; } } + /* Calculate target map square */ + new_x = op->x + DIRX(op); + new_y = op->y + DIRY(op); + was_reflected = 0; + + /* See if there is any living object on target map square */ + tmp = out_of_map (op->map, new_x, new_y) + ? NULL : get_map_ob (op->map, new_x, new_y); + while (tmp != NULL && ! QUERY_FLAG (tmp, FLAG_ALIVE)) + tmp = tmp->above; + + if (tmp != NULL) + { + /* Found living object, but it is reflecting the missile. Update + * as below. + */ + if (QUERY_FLAG (tmp, FLAG_REFL_MISSILE)) + { + int number = op->face->number; + + op->direction = absdir (op->direction + 4); + op->state = 0; + if (GET_ANIM_ID (op)) { + number += 4; + if (number > GET_ANIMATION (op, 8)) + number -= 8; + op->face = &new_faces[number]; + } + if (wall (op->map, new_x, new_y)) { + /* Target is standing on a wall. Let arrow turn around before + * the wall. */ + new_x = op->x; + new_y = op->y; + } + was_reflected = 1; /* skip normal movement calculations */ + } + else + { + /* Attack the object. */ + op = hit_with_arrow (op, tmp); + if (op == NULL) + return; + } + } ! if ( ! was_reflected && wall (op->map, new_x, new_y)) ! { /* if the object doesn't reflect, stop the arrow from moving */ if(!QUERY_FLAG(op, FLAG_REFLECTING) || !(RANDOM()%20)) { ! stop_arrow (op); return; } else { /* object is reflected */ /* If one of the major directions (n,s,e,w), just reverse it */ *************** *** 566,572 **** else if(!right) op->direction=absdir(op->direction+1); else { /* is this possible? */ ! stop_arrow(op,NULL); return; } } --- 662,668 ---- else if(!right) op->direction=absdir(op->direction+1); else { /* is this possible? */ ! stop_arrow (op); return; } } *************** *** 577,624 **** } /* object is reflected */ } /* object ran into a wall */ ! op->x+=DIRX(op),op->y+=DIRY(op); ! tmp=get_map_ob(op->map,op->x,op->y); ! ! /* See if there is any living object on this space */ ! while(tmp!=NULL&&!QUERY_FLAG(tmp, FLAG_ALIVE)) ! tmp=tmp->above; ! ! /* Nothing alive? Insert arrow and return */ ! if(tmp==NULL) { ! insert_ob_in_map(op,op->map,op); ! return; ! } ! ! /* Found living object, but it is reflecting the missile. Update ! * as below. ! */ ! if (QUERY_FLAG(tmp, FLAG_REFL_MISSILE)) { ! int number = op->face->number; ! ! op->direction=absdir(op->direction+4),op->state=0; ! if(GET_ANIM_ID(op)) { ! number+=4; ! if(number > GET_ANIMATION(op, 8)) ! number-=8; ! op->face = &new_faces[number]; ! } ! insert_ob_in_map(op,op->map,op); ! return; ! } ! ! /* Attach the object. IF successful, stop the arrow */ ! if(attack_ob(tmp,op)) ! stop_arrow(op,tmp); ! else { ! /* if we miss, insert it back into the map. If no direction, ! * stop the arrow. ! */ ! if(op->direction) ! insert_ob_in_map(op,op->map,op); ! else ! stop_arrow(op,NULL); ! } } /* This routine doesnt seem to work for "inanimate" objects that --- 673,683 ---- } /* object is reflected */ } /* object ran into a wall */ ! /* Move the arrow. */ ! remove_ob (op); ! op->x = new_x; ! op->y = new_y; ! insert_ob_in_map (op, op->map, op); } /* This routine doesnt seem to work for "inanimate" objects that Index: socket/item.c =================================================================== RCS file: /home/cvs/CVS/crossfire/socket/item.c,v retrieving revision 1.6 retrieving revision 1.7 diff -c -r1.6 -r1.7 *** socket/item.c 2000/11/03 05:42:56 1.6 --- socket/item.c 2000/11/06 23:06:48 1.7 *************** *** 1,7 **** /* * static char *rcsid_item_c = ! * "$Id: item.c,v 1.6 2000/11/03 05:42:56 cvs Exp $"; */ /* --- 1,7 ---- /* * static char *rcsid_item_c = ! * "$Id: item.c,v 1.7 2000/11/06 23:06:48 jec Exp $"; */ /* *************** *** 710,717 **** } return; } else if (to == pl->count) { /* pick it up to the inventory */ - /* pick_up_object (pl, pl, op, nrof);*/ - /* Using pick_up will cause objects to get put into containers. */ pl->contr->count = nrof; pick_up(pl, op); return ; --- 710,715 ----