[CF-Devel] Summary of the last 2 day's diffs
Peter Mardahl
peterm at alfven.EECS.Berkeley.EDU
Tue Nov 7 20:12:13 CST 2000
? 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 ----
More information about the crossfire
mailing list