--- deliantra/server/server/move.C 2006/09/03 00:18:42 1.6 +++ deliantra/server/server/move.C 2006/09/10 15:59:57 1.7 @@ -1,6 +1,7 @@ + /* * static char *rcsid_move_c = - * "$Id: move.C,v 1.6 2006/09/03 00:18:42 root Exp $"; + * "$Id: move.C,v 1.7 2006/09/10 15:59:57 root Exp $"; */ /* @@ -28,7 +29,7 @@ #include #ifndef __CEXTRACT__ -#include +# include #endif #ifdef COZY_SERVER @@ -44,8 +45,10 @@ * removed and inserted objects even if they were unable to move. */ -int move_object(object *op, int dir) { - return move_ob(op, dir, op); +int +move_object (object *op, int dir) +{ + return move_ob (op, dir, op); } @@ -58,87 +61,91 @@ * move the object accordingly. This function is * very similiar to move_object. */ -int move_ob (object *op, int dir, object *originator) +int +move_ob (object *op, int dir, object *originator) { - sint16 newx = op->x+freearr_x[dir]; - sint16 newy = op->y+freearr_y[dir]; - object *tmp; - mapstruct *m; - int mflags; + sint16 newx = op->x + freearr_x[dir]; + sint16 newy = op->y + freearr_y[dir]; + object *tmp; + mapstruct *m; + int mflags; - if(op==NULL) { - LOG(llevError,"Trying to move NULL.\n"); - return 0; + if (op == NULL) + { + LOG (llevError, "Trying to move NULL.\n"); + return 0; } - m = op->map; - mflags = get_map_flags(m, &m, newx, newy, &newx, &newy); + m = op->map; + mflags = get_map_flags (m, &m, newx, newy, &newx, &newy); - /* If the space the player is trying to is out of the map, - * bail now - we know it can't work. - */ - if (mflags & P_OUT_OF_MAP) return 0; + /* If the space the player is trying to is out of the map, + * bail now - we know it can't work. + */ + if (mflags & P_OUT_OF_MAP) + return 0; - /* Is this space blocked? Players with wizpass are immune to - * this condition. - */ - if(blocked_link(op, m, newx, newy) && - !QUERY_FLAG(op, FLAG_WIZPASS)) - return 0; + /* Is this space blocked? Players with wizpass are immune to + * this condition. + */ + if (blocked_link (op, m, newx, newy) && !QUERY_FLAG (op, FLAG_WIZPASS)) + return 0; - /* 0.94.2 - we need to set the direction for the new animation code. - * it uses it to figure out face to use - I can't see it - * breaking anything, but it might. - */ - if(op->more != NULL && !move_ob(op->more, dir, op->more->head)) - return 0; + /* 0.94.2 - we need to set the direction for the new animation code. + * it uses it to figure out face to use - I can't see it + * breaking anything, but it might. + */ + if (op->more != NULL && !move_ob (op->more, dir, op->more->head)) + return 0; - op->direction = dir; + op->direction = dir; - if(op->will_apply&4) - check_earthwalls(op,m, newx,newy); - if(op->will_apply&8) - check_doors(op,m, newx,newy); - - /* 0.94.1 - I got a stack trace that showed it crash with remove_ob trying - * to remove a removed object, and this function was the culprit. A possible - * guess I have is that check_doors above ran into a trap, killing the - * monster. - * - * Unfortunately, it doesn't appear that the calling functions of move_object - * deal very well with op being killed, so all this might do is just - * migrate the problem someplace else. - */ - - if (QUERY_FLAG(op, FLAG_REMOVED)) { - LOG(llevDebug,"move_object: monster has been removed - will not process further\n"); - /* Was not successful, but don't want to try and move again */ - return 1; + if (op->will_apply & 4) + check_earthwalls (op, m, newx, newy); + if (op->will_apply & 8) + check_doors (op, m, newx, newy); + + /* 0.94.1 - I got a stack trace that showed it crash with remove_ob trying + * to remove a removed object, and this function was the culprit. A possible + * guess I have is that check_doors above ran into a trap, killing the + * monster. + * + * Unfortunately, it doesn't appear that the calling functions of move_object + * deal very well with op being killed, so all this might do is just + * migrate the problem someplace else. + */ + + if (QUERY_FLAG (op, FLAG_REMOVED)) + { + LOG (llevDebug, "move_object: monster has been removed - will not process further\n"); + /* Was not successful, but don't want to try and move again */ + return 1; } - /* If this is a tail portion, just want to tell caller that move is - * ok - the caller will deal with actual object removal/insertion - */ - if(op->head) - return 1; + /* If this is a tail portion, just want to tell caller that move is + * ok - the caller will deal with actual object removal/insertion + */ + if (op->head) + return 1; - remove_ob(op); + remove_ob (op); - /* we already have newx, newy, and m, so lets use them. - * In addition, this fixes potential crashes, because multipart object was - * on edge of map, +=x, +=y doesn't make correct coordinates. - */ - for(tmp = op; tmp != NULL; tmp = tmp->more) { - tmp->x += freearr_x[dir]; - tmp->y += freearr_y[dir]; - tmp->map = get_map_from_coord(tmp->map, &tmp->x, &tmp->y); + /* we already have newx, newy, and m, so lets use them. + * In addition, this fixes potential crashes, because multipart object was + * on edge of map, +=x, +=y doesn't make correct coordinates. + */ + for (tmp = op; tmp != NULL; tmp = tmp->more) + { + tmp->x += freearr_x[dir]; + tmp->y += freearr_y[dir]; + tmp->map = get_map_from_coord (tmp->map, &tmp->x, &tmp->y); } - /* insert_ob_in_map will deal with any tiling issues */ - insert_ob_in_map(op, m, originator,0); + /* insert_ob_in_map will deal with any tiling issues */ + insert_ob_in_map (op, m, originator, 0); - return 1; + return 1; } @@ -154,29 +161,32 @@ * Return value: 1 if object was destroyed, 0 otherwise. */ -int transfer_ob (object *op, int x, int y, int randomly, object *originator) +int +transfer_ob (object *op, int x, int y, int randomly, object *originator) { - int i; - object *tmp; + int i; + object *tmp; + + if (randomly) + i = find_free_spot (op, op->map, x, y, 0, SIZEOFFREE); + else + i = find_first_free_spot (op, op->map, x, y); + + if (i == -1) + return 0; /* No free spot */ + + if (op->head != NULL) + op = op->head; + remove_ob (op); + for (tmp = op; tmp != NULL; tmp = tmp->more) + tmp->x = x + freearr_x[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.x), + tmp->y = y + freearr_y[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.y); - if (randomly) - i = find_free_spot (op,op->map,x,y,0,SIZEOFFREE); - else - i = find_first_free_spot(op,op->map,x,y); - - if (i==-1) - return 0; /* No free spot */ - - if(op->head!=NULL) - op=op->head; - remove_ob(op); - for(tmp=op;tmp!=NULL;tmp=tmp->more) - tmp->x=x+freearr_x[i]+(tmp->arch==NULL?0:tmp->arch->clone.x), - tmp->y=y+freearr_y[i]+(tmp->arch==NULL?0:tmp->arch->clone.y); - - tmp = insert_ob_in_map(op,op->map,originator,0); - if (tmp) return 0; - else return 1; + tmp = insert_ob_in_map (op, op->map, originator, 0); + if (tmp) + return 0; + else + return 1; } /* @@ -191,98 +201,107 @@ * be used close to each other and not have the player put to the * one of another type. */ -int teleport (object *teleporter, uint8 tele_type, object *user) +int +teleport (object *teleporter, uint8 tele_type, object *user) { - object *altern; - int i,j,k,nrofalt=0; - object *other_teleporter, *tmp; - mapstruct *m; - sint16 sx, sy; - - if(user==NULL) return 0; - if(user->head!=NULL) - user=user->head; - - /* Find all other teleporters within range. This range - * should really be setable by some object attribute instead of - * using hard coded values. - */ - for(i= -5;i<6;i++) - for(j= -5;j<6;j++) { - if(i==0&&j==0) - continue; - /* Perhaps this should be extended to support tiled maps */ - if(OUT_OF_REAL_MAP(teleporter->map,teleporter->x+i,teleporter->y+j)) - continue; - other_teleporter=get_map_ob(teleporter->map, - teleporter->x+i,teleporter->y+j); + object *altern; + int i, j, k, nrofalt = 0; + object *other_teleporter, *tmp; + mapstruct *m; + sint16 sx, sy; - while (other_teleporter) { - if (other_teleporter->type == tele_type) break; - other_teleporter = other_teleporter->above; - } - if (other_teleporter && !(RANDOM() % ++nrofalt)) - altern = other_teleporter; - } + if (user == NULL) + return 0; + if (user->head != NULL) + user = user->head; - if(!nrofalt) { - LOG(llevError,"No alternative teleporters around!\n"); - return 0; + /* Find all other teleporters within range. This range + * should really be setable by some object attribute instead of + * using hard coded values. + */ + for (i = -5; i < 6; i++) + for (j = -5; j < 6; j++) + { + if (i == 0 && j == 0) + continue; + /* Perhaps this should be extended to support tiled maps */ + if (OUT_OF_REAL_MAP (teleporter->map, teleporter->x + i, teleporter->y + j)) + continue; + other_teleporter = get_map_ob (teleporter->map, teleporter->x + i, teleporter->y + j); + + while (other_teleporter) + { + if (other_teleporter->type == tele_type) + break; + other_teleporter = other_teleporter->above; + } + if (other_teleporter && !(RANDOM () % ++nrofalt)) + altern = other_teleporter; + } + + if (!nrofalt) + { + LOG (llevError, "No alternative teleporters around!\n"); + return 0; } - other_teleporter=altern; - k=find_free_spot(user,other_teleporter->map, - other_teleporter->x,other_teleporter->y,1,9); - - /* if k==-1, unable to find a free spot. If this is shop - * mat that the player is using, find someplace to move - * the player - otherwise, player can get trapped in the shops - * that appear in random dungeons. We basically just make - * sure the space isn't no pass (eg wall), and don't care - * about is alive. - */ - if (k==-1) { - if (tele_type == SHOP_MAT && user->type == PLAYER) { - for (k=1; k<9; k++) { - if (get_map_flags(other_teleporter->map, &m, - other_teleporter->x + freearr_x[k], - other_teleporter->y + freearr_y[k], &sx,&sy) & - P_OUT_OF_MAP) continue; + other_teleporter = altern; + k = find_free_spot (user, other_teleporter->map, other_teleporter->x, other_teleporter->y, 1, 9); + + /* if k==-1, unable to find a free spot. If this is shop + * mat that the player is using, find someplace to move + * the player - otherwise, player can get trapped in the shops + * that appear in random dungeons. We basically just make + * sure the space isn't no pass (eg wall), and don't care + * about is alive. + */ + if (k == -1) + { + if (tele_type == SHOP_MAT && user->type == PLAYER) + { + for (k = 1; k < 9; k++) + { + if (get_map_flags (other_teleporter->map, &m, + other_teleporter->x + freearr_x[k], other_teleporter->y + freearr_y[k], &sx, &sy) & P_OUT_OF_MAP) + continue; - if (!OB_TYPE_MOVE_BLOCK(user, GET_MAP_MOVE_BLOCK(m, sx, sy))) break; + if (!OB_TYPE_MOVE_BLOCK (user, GET_MAP_MOVE_BLOCK (m, sx, sy))) + break; } - if (k==9) { - LOG(llevError,"Shop mat %s (%d, %d) is in solid rock?\n", - &other_teleporter->name, other_teleporter->x, other_teleporter->y); - return 0; + if (k == 9) + { + LOG (llevError, "Shop mat %s (%d, %d) is in solid rock?\n", + &other_teleporter->name, other_teleporter->x, other_teleporter->y); + return 0; } } - else return 0; + else + return 0; } - remove_ob(user); + remove_ob (user); - /* Update location for the object */ - for(tmp=user;tmp!=NULL;tmp=tmp->more) { - tmp->x=other_teleporter->x+freearr_x[k]+ - (tmp->arch==NULL?0:tmp->arch->clone.x); - tmp->y=other_teleporter->y+freearr_y[k]+ - (tmp->arch==NULL?0:tmp->arch->clone.y); + /* Update location for the object */ + for (tmp = user; tmp != NULL; tmp = tmp->more) + { + tmp->x = other_teleporter->x + freearr_x[k] + (tmp->arch == NULL ? 0 : tmp->arch->clone.x); + tmp->y = other_teleporter->y + freearr_y[k] + (tmp->arch == NULL ? 0 : tmp->arch->clone.y); } - tmp = insert_ob_in_map(user,other_teleporter->map,NULL,0); - return (tmp == NULL); + tmp = insert_ob_in_map (user, other_teleporter->map, NULL, 0); + return (tmp == NULL); } -void recursive_roll(object *op,int dir,object *pusher) { - if(!roll_ob(op,dir,pusher)) { - new_draw_info_format(NDI_UNIQUE, 0, pusher, - "You fail to push the %s.",query_name(op)); - return; - } - (void) move_ob(pusher,dir,pusher); - new_draw_info_format(NDI_BLACK, 0, pusher, - "You move the %s.",query_name(op)); +void +recursive_roll (object *op, int dir, object *pusher) +{ + if (!roll_ob (op, dir, pusher)) + { + new_draw_info_format (NDI_UNIQUE, 0, pusher, "You fail to push the %s.", query_name (op)); + return; + } + (void) move_ob (pusher, dir, pusher); + new_draw_info_format (NDI_BLACK, 0, pusher, "You move the %s.", query_name (op)); return; } @@ -295,37 +314,41 @@ * Returns 1 if object does not fit, 0 if it does. */ -int try_fit (object *op, mapstruct *m, int x, int y) +int +try_fit (object *op, mapstruct *m, int x, int y) { - object *tmp, *more; - sint16 tx, ty; - int mflags; - mapstruct *m2; + object *tmp, *more; + sint16 tx, ty; + int mflags; + mapstruct *m2; - if (op->head) - op = op->head; + if (op->head) + op = op->head; - for (more = op; more ; more = more->more) { - tx = x + more->x - op->x; - ty = y + more->y - op->y; + for (more = op; more; more = more->more) + { + tx = x + more->x - op->x; + ty = y + more->y - op->y; - mflags = get_map_flags(m, &m2, tx, ty, &tx, &ty); + mflags = get_map_flags (m, &m2, tx, ty, &tx, &ty); - if (mflags & P_OUT_OF_MAP) - return 1; + if (mflags & P_OUT_OF_MAP) + return 1; - for (tmp = get_map_ob (m2, tx, ty); tmp; tmp=tmp->above) { - if (tmp->head == op || tmp == op) - continue; + for (tmp = get_map_ob (m2, tx, ty); tmp; tmp = tmp->above) + { + if (tmp->head == op || tmp == op) + continue; - if ((QUERY_FLAG(tmp,FLAG_ALIVE) && tmp->type!=DOOR)) - return 1; + if ((QUERY_FLAG (tmp, FLAG_ALIVE) && tmp->type != DOOR)) + return 1; - if (OB_MOVE_BLOCK(op, tmp)) return 1; + if (OB_MOVE_BLOCK (op, tmp)) + return 1; } } - return 0; + return 0; } /* @@ -334,161 +357,159 @@ * Support for rolling multipart objects is questionable. */ -int roll_ob(object *op,int dir, object *pusher) { - object *tmp; - sint16 x, y; - int flags; - mapstruct *m; - MoveType move_block; - - if (op->head) - op = op->head; - - x=op->x+freearr_x[dir]; - y=op->y+freearr_y[dir]; - - if(!QUERY_FLAG(op,FLAG_CAN_ROLL) || - (op->weight && - random_roll(0, op->weight/50000-1, pusher, PREFER_LOW) > pusher->stats.Str)) - return 0; +int +roll_ob (object *op, int dir, object *pusher) +{ + object *tmp; + sint16 x, y; + int flags; + mapstruct *m; + MoveType move_block; - m = op->map; - flags = get_map_flags(m, &m, x, y, &x, &y); + if (op->head) + op = op->head; - if (flags & (P_OUT_OF_MAP | P_IS_ALIVE)) - return 0; + x = op->x + freearr_x[dir]; + y = op->y + freearr_y[dir]; + + if (!QUERY_FLAG (op, FLAG_CAN_ROLL) || (op->weight && random_roll (0, op->weight / 50000 - 1, pusher, PREFER_LOW) > pusher->stats.Str)) + return 0; - move_block = GET_MAP_MOVE_BLOCK(m, x, y); + m = op->map; + flags = get_map_flags (m, &m, x, y, &x, &y); - /* If the target space is not blocked, no need to look at the objects on it */ - if ((op->move_type & move_block) == op->move_type) { - for (tmp=get_map_ob(m, x, y); tmp!=NULL; tmp=tmp->above) { - if (tmp->head == op) + if (flags & (P_OUT_OF_MAP | P_IS_ALIVE)) + return 0; + + move_block = GET_MAP_MOVE_BLOCK (m, x, y); + + /* If the target space is not blocked, no need to look at the objects on it */ + if ((op->move_type & move_block) == op->move_type) + { + for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above) + { + if (tmp->head == op) continue; - if (OB_MOVE_BLOCK(op, tmp) && !roll_ob(tmp,dir,pusher)) + if (OB_MOVE_BLOCK (op, tmp) && !roll_ob (tmp, dir, pusher)) return 0; } } - if (try_fit (op, m, x, y)) - return 0; + if (try_fit (op, m, x, y)) + return 0; - remove_ob(op); - for(tmp=op; tmp!=NULL; tmp=tmp->more) - tmp->x+=freearr_x[dir],tmp->y+=freearr_y[dir]; - insert_ob_in_map(op,op->map,pusher,0); - return 1; + remove_ob (op); + for (tmp = op; tmp != NULL; tmp = tmp->more) + tmp->x += freearr_x[dir], tmp->y += freearr_y[dir]; + insert_ob_in_map (op, op->map, pusher, 0); + return 1; } /* returns 1 if pushing invokes a attack, 0 when not */ -int push_ob(object *who, int dir, object *pusher) { - int str1, str2; - object *owner; - - if (who->head != NULL) - who = who->head; - owner = get_owner(who); - - /* Wake up sleeping monsters that may be pushed */ - CLEAR_FLAG(who,FLAG_SLEEP); - - /* player change place with his pets or summoned creature */ - /* TODO: allow multi arch pushing. Can't be very difficult */ - if (who->more == NULL +int +push_ob (object *who, int dir, object *pusher) +{ + int str1, str2; + object *owner; + + if (who->head != NULL) + who = who->head; + owner = get_owner (who); + + /* Wake up sleeping monsters that may be pushed */ + CLEAR_FLAG (who, FLAG_SLEEP); + + /* player change place with his pets or summoned creature */ + /* TODO: allow multi arch pushing. Can't be very difficult */ + if (who->more == NULL #ifdef COZY_SERVER - && - ( - (owner && owner->contr && pusher->contr - && same_party (owner->contr->party, pusher->contr->party)) - || owner == pusher - ) + && ((owner && owner->contr && pusher->contr && same_party (owner->contr->party, pusher->contr->party)) || owner == pusher) #else - && owner == pusher + && owner == pusher #endif - ) { - int temp; - mapstruct *m; - - remove_ob(who); - remove_ob(pusher); - temp = pusher->x; - pusher->x = who->x; - who->x = temp; - - temp = pusher->y; - pusher->y = who->y; - who->y = temp; - - m = pusher->map; - pusher->map = who->map; - who->map = m; + ) + { + int temp; + mapstruct *m; - insert_ob_in_map (who,who->map,pusher,0); - insert_ob_in_map (pusher,pusher->map,pusher,0); - return 0; + remove_ob (who); + remove_ob (pusher); + temp = pusher->x; + pusher->x = who->x; + who->x = temp; + + temp = pusher->y; + pusher->y = who->y; + who->y = temp; + + m = pusher->map; + pusher->map = who->map; + who->map = m; + + insert_ob_in_map (who, who->map, pusher, 0); + insert_ob_in_map (pusher, pusher->map, pusher, 0); + return 0; } - /* We want ONLY become enemy of evil, unaggressive monster. We must RUN in them */ - /* In original we have here a unaggressive check only - that was the reason why */ - /* we so often become an enemy of friendly monsters... */ - /* funny: was they set to unaggressive 0 (= not so nice) they don't attack */ - - if(owner != pusher && pusher->type == PLAYER && who->type != PLAYER && - !QUERY_FLAG(who,FLAG_FRIENDLY)&& !QUERY_FLAG(who,FLAG_NEUTRAL)) { - if(pusher->contr->run_on) /* only when we run */ { - new_draw_info_format(NDI_UNIQUE, 0, pusher, - "You start to attack %s !!", &who->name); - CLEAR_FLAG(who,FLAG_UNAGGRESSIVE); /* the sucker don't like you anymore */ - who->enemy = pusher; - return 1; + /* We want ONLY become enemy of evil, unaggressive monster. We must RUN in them */ + /* In original we have here a unaggressive check only - that was the reason why */ + /* we so often become an enemy of friendly monsters... */ + /* funny: was they set to unaggressive 0 (= not so nice) they don't attack */ + + if (owner != pusher && pusher->type == PLAYER && who->type != PLAYER && + !QUERY_FLAG (who, FLAG_FRIENDLY) && !QUERY_FLAG (who, FLAG_NEUTRAL)) + { + if (pusher->contr->run_on) /* only when we run */ + { + new_draw_info_format (NDI_UNIQUE, 0, pusher, "You start to attack %s !!", &who->name); + CLEAR_FLAG (who, FLAG_UNAGGRESSIVE); /* the sucker don't like you anymore */ + who->enemy = pusher; + return 1; } - else + else { - new_draw_info_format(NDI_UNIQUE, 0, pusher, - "You avoid attacking %s.", &who->name); + new_draw_info_format (NDI_UNIQUE, 0, pusher, "You avoid attacking %s.", &who->name); } } - /* now, lets test stand still. we NEVER can push stand_still monsters. */ - if(QUERY_FLAG(who,FLAG_STAND_STILL)) + /* now, lets test stand still. we NEVER can push stand_still monsters. */ + if (QUERY_FLAG (who, FLAG_STAND_STILL)) { - new_draw_info_format(NDI_UNIQUE, 0, pusher, - "You can't push %s.", &who->name); - return 0; + new_draw_info_format (NDI_UNIQUE, 0, pusher, "You can't push %s.", &who->name); + return 0; } - - /* This block is basically if you are pushing friendly but - * non pet creaturs. - * It basically does a random strength comparision to - * determine if you can push someone around. Note that - * this pushes the other person away - its not a swap. - */ - - str1 = (who->stats.Str>0?who->stats.Str:who->level); - str2 = (pusher->stats.Str>0?pusher->stats.Str:pusher->level); - if(QUERY_FLAG(who,FLAG_WIZ) || - random_roll(str1, str1/2+str1*2, who, PREFER_HIGH) >= - random_roll(str2, str2/2+str2*2, pusher, PREFER_HIGH) || - !move_object(who,dir)) - { - if (who ->type == PLAYER) { - new_draw_info_format(NDI_UNIQUE, 0, who, - "%s tried to push you.", &pusher->name); + + /* This block is basically if you are pushing friendly but + * non pet creaturs. + * It basically does a random strength comparision to + * determine if you can push someone around. Note that + * this pushes the other person away - its not a swap. + */ + + str1 = (who->stats.Str > 0 ? who->stats.Str : who->level); + str2 = (pusher->stats.Str > 0 ? pusher->stats.Str : pusher->level); + if (QUERY_FLAG (who, FLAG_WIZ) || + random_roll (str1, str1 / 2 + str1 * 2, who, PREFER_HIGH) >= + random_roll (str2, str2 / 2 + str2 * 2, pusher, PREFER_HIGH) || !move_object (who, dir)) + { + if (who->type == PLAYER) + { + new_draw_info_format (NDI_UNIQUE, 0, who, "%s tried to push you.", &pusher->name); } - return 0; + return 0; } - /* If we get here, the push succeeded. - * Let everyone know the status. - */ - if (who->type == PLAYER) { - new_draw_info_format(NDI_UNIQUE, 0, who, - "%s pushed you.", &pusher->name); - } - if (pusher->type == PLAYER) { - new_draw_info_format(NDI_UNIQUE, 0, pusher, - "You pushed %s back.", &who->name); + /* If we get here, the push succeeded. + * Let everyone know the status. + */ + if (who->type == PLAYER) + { + new_draw_info_format (NDI_UNIQUE, 0, who, "%s pushed you.", &pusher->name); } - - return 1; + if (pusher->type == PLAYER) + { + new_draw_info_format (NDI_UNIQUE, 0, pusher, "You pushed %s back.", &who->name); + } + + return 1; }