00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00034 #include <global.h>
00035 #ifndef __CEXTRACT__
00036 #include <sproto.h>
00037 #endif
00038
00039 static int roll_ob(object *op, int dir, object *pusher);
00040
00053 int move_object(object *op, int dir) {
00054 return move_ob(op, dir, op);
00055 }
00056
00072 int move_ob(object *op, int dir, object *originator) {
00073 sint16 newx = op->x+freearr_x[dir];
00074 sint16 newy = op->y+freearr_y[dir];
00075 object *tmp;
00076 mapstruct *m;
00077 int mflags;
00078
00079 if (op == NULL) {
00080 LOG(llevError, "Trying to move NULL.\n");
00081 return 0;
00082 }
00083
00084 m = op->map;
00085 mflags = get_map_flags(m, &m, newx, newy, &newx, &newy);
00086
00087
00088
00089
00090 if (mflags&P_OUT_OF_MAP)
00091 return 0;
00092
00093
00094
00095
00096
00097 if (blocked_link(op, m, newx, newy)
00098 && !QUERY_FLAG(op, FLAG_WIZPASS))
00099 return 0;
00100
00101
00102
00103
00104
00105 if (op->more != NULL && !move_ob(op->more, dir, op->more->head))
00106 return 0;
00107
00108 op->direction = dir;
00109
00110 if (op->will_apply&WILL_APPLY_EARTHWALL)
00111 check_earthwalls(op, m, newx, newy);
00112 if (op->will_apply&WILL_APPLY_DOOR)
00113 check_doors(op, m, newx, newy);
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 if (QUERY_FLAG(op, FLAG_REMOVED)) {
00126 LOG(llevDebug, "move_object: monster has been removed - will not process further\n");
00127
00128 return 1;
00129 }
00130
00131
00132
00133
00134 if (op->head)
00135 return 1;
00136
00137 remove_ob(op);
00138
00139
00140
00141
00142
00143 for (tmp = op; tmp != NULL; tmp = tmp->more) {
00144 tmp->x += freearr_x[dir];
00145 tmp->y += freearr_y[dir];
00146 tmp->map = get_map_from_coord(tmp->map, &tmp->x, &tmp->y);
00147 }
00148
00149
00150 insert_ob_in_map(op, m, originator, 0);
00151
00152
00153 if (op->type == PLAYER) {
00154 esrv_map_scroll(&op->contr->socket, freearr_x[dir], freearr_y[dir]);
00155 op->contr->socket.update_look = 1;
00156 op->contr->socket.look_position = 0;
00157 } else if (op->type == TRANSPORT) {
00158 object *pl;
00159
00160 for (pl = op->inv; pl; pl = pl->below) {
00161 if (pl->type == PLAYER) {
00162 pl->contr->do_los = 1;
00163 pl->map = op->map;
00164 pl->x = op->x;
00165 pl->y = op->y;
00166 esrv_map_scroll(&pl->contr->socket, freearr_x[dir], freearr_y[dir]);
00167 pl->contr->socket.update_look = 1;
00168 pl->contr->socket.look_position = 0;
00169 }
00170 }
00171 }
00172
00173 return 1;
00174 }
00175
00197 int transfer_ob(object *op, int x, int y, int randomly, object *originator) {
00198 int i;
00199 object *tmp;
00200
00201 if (randomly)
00202 i = find_free_spot(op, op->map, x, y, 0, SIZEOFFREE);
00203 else
00204 i = find_first_free_spot(op, op->map, x, y);
00205
00206 if (i == -1)
00207 return 0;
00208
00209 if (op->head != NULL)
00210 op = op->head;
00211 remove_ob(op);
00212 for (tmp = op; tmp != NULL; tmp = tmp->more)
00213 tmp->x = x+freearr_x[i]+(tmp->arch == NULL ? 0 : tmp->arch->clone.x),
00214 tmp->y = y+freearr_y[i]+(tmp->arch == NULL ? 0 : tmp->arch->clone.y);
00215
00216 tmp = insert_ob_in_map(op, op->map, originator, 0);
00217 if (op && op->type == PLAYER)
00218 map_newmap_cmd(&op->contr->socket);
00219 if (tmp)
00220 return 0;
00221 else
00222 return 1;
00223 }
00224
00244 int teleport(object *teleporter, uint8 tele_type, object *user) {
00245 object *altern[120];
00246 int i, j, k, nrofalt = 0;
00247 object *other_teleporter, *tmp;
00248 mapstruct *m;
00249 sint16 sx, sy;
00250
00251 if (user == NULL)
00252 return 0;
00253 if (user->head != NULL)
00254 user = user->head;
00255
00256
00257
00258
00259
00260 for (i = -5; i < 6; i++)
00261 for (j = -5; j < 6; j++) {
00262 if (i == 0 && j == 0)
00263 continue;
00264
00265 if (OUT_OF_REAL_MAP(teleporter->map, teleporter->x+i, teleporter->y+j))
00266 continue;
00267 other_teleporter = GET_MAP_OB(teleporter->map, teleporter->x+i, teleporter->y+j);
00268
00269 while (other_teleporter) {
00270 if (other_teleporter->type == tele_type)
00271 break;
00272 other_teleporter = other_teleporter->above;
00273 }
00274 if (other_teleporter)
00275 altern[nrofalt++] = other_teleporter;
00276 }
00277
00278 if (!nrofalt) {
00279 LOG(llevError, "No alternative teleporters around!\n");
00280 return 0;
00281 }
00282
00283 other_teleporter = altern[RANDOM()%nrofalt];
00284 k = find_free_spot(user, other_teleporter->map, other_teleporter->x, other_teleporter->y, 1, 9);
00285
00286
00287
00288
00289
00290
00291
00292
00293 if (k == -1) {
00294 if (tele_type == SHOP_MAT && user->type == PLAYER) {
00295 for (k = 1; k < 9; k++) {
00296 if (get_map_flags(other_teleporter->map, &m,
00297 other_teleporter->x+freearr_x[k],
00298 other_teleporter->y+freearr_y[k], &sx, &sy)&P_OUT_OF_MAP)
00299 continue;
00300
00301 if (!OB_TYPE_MOVE_BLOCK(user, GET_MAP_MOVE_BLOCK(m, sx, sy)))
00302 break;
00303
00304 }
00305 if (k == 9) {
00306 LOG(llevError, "Shop mat %s (%d, %d) is in solid rock?\n", other_teleporter->name, other_teleporter->x, other_teleporter->y);
00307
00308
00309
00310
00311 k = 0;
00312 }
00313 } else
00314 return 0;
00315 }
00316
00317 remove_ob(user);
00318
00319
00320 for (tmp = user; tmp != NULL; tmp = tmp->more) {
00321 tmp->x = other_teleporter->x+freearr_x[k]+(tmp->arch == NULL ? 0 : tmp->arch->clone.x);
00322 tmp->y = other_teleporter->y+freearr_y[k]+(tmp->arch == NULL ? 0 : tmp->arch->clone.y);
00323 }
00324 tmp = insert_ob_in_map(user, other_teleporter->map, NULL, 0);
00325 if (tmp && tmp->type == PLAYER)
00326 map_newmap_cmd(&tmp->contr->socket);
00327 return (tmp == NULL);
00328 }
00329
00340 void recursive_roll(object *op, int dir, object *pusher) {
00341 char name[MAX_BUF];
00342
00343 query_name(op, name, MAX_BUF);
00344 if (!roll_ob(op, dir, pusher)) {
00345 draw_ext_info_format(NDI_UNIQUE, 0, pusher, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE,
00346 "You fail to push the %s.",
00347 "You fail to push the %s.",
00348 name);
00349 return;
00350 }
00351 (void)move_ob(pusher, dir, pusher);
00352 draw_ext_info_format(NDI_BLACK, 0, pusher, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00353 "You move the %s.",
00354 "You move the %s.",
00355 name);
00356 return;
00357 }
00358
00380 static int try_fit(object *op, mapstruct *m, int x, int y) {
00381 object *tmp, *more;
00382 sint16 tx, ty;
00383 int mflags;
00384 mapstruct *m2;
00385
00386 if (op->head)
00387 op = op->head;
00388
00389 for (more = op; more; more = more->more) {
00390 tx = x+more->x-op->x;
00391 ty = y+more->y-op->y;
00392
00393 mflags = get_map_flags(m, &m2, tx, ty, &tx, &ty);
00394
00395 if (mflags&P_OUT_OF_MAP)
00396 return 1;
00397
00398 for (tmp = GET_MAP_OB(m2, tx, ty); tmp; tmp = tmp->above) {
00399 if (tmp->head == op || tmp == op)
00400 continue;
00401
00402 if ((QUERY_FLAG(tmp, FLAG_ALIVE) && tmp->type != DOOR))
00403 return 1;
00404
00405 if (OB_MOVE_BLOCK(op, tmp))
00406 return 1;
00407
00408 }
00409 }
00410 return 0;
00411 }
00412
00432 static int roll_ob(object *op, int dir, object *pusher) {
00433 object *tmp;
00434 sint16 x, y;
00435 int flags;
00436 mapstruct *m;
00437 MoveType move_block;
00438
00439 if (op->head)
00440 op = op->head;
00441
00442 x = op->x+freearr_x[dir];
00443 y = op->y+freearr_y[dir];
00444
00445 if (!QUERY_FLAG(op, FLAG_CAN_ROLL)
00446 || (op->weight && random_roll(0, op->weight/50000-1, pusher, PREFER_LOW) > pusher->stats.Str))
00447 return 0;
00448
00449 m = op->map;
00450 flags = get_map_flags(m, &m, x, y, &x, &y);
00451
00452 if (flags&(P_OUT_OF_MAP|P_IS_ALIVE))
00453 return 0;
00454
00455 move_block = GET_MAP_MOVE_BLOCK(m, x, y);
00456
00457
00458 if ((op->move_type&move_block) == op->move_type) {
00459 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) {
00460 if (tmp->head == op)
00461 continue;
00462 if (OB_MOVE_BLOCK(op, tmp) && !roll_ob(tmp, dir, pusher))
00463 return 0;
00464 }
00465 }
00466 if (try_fit(op, m, x, y))
00467 return 0;
00468
00469 remove_ob(op);
00470 for (tmp = op; tmp != NULL; tmp = tmp->more)
00471 tmp->x += freearr_x[dir],
00472 tmp->y += freearr_y[dir];
00473 insert_ob_in_map(op, op->map, pusher, 0);
00474 return 1;
00475 }
00476
00492 int push_ob(object *who, int dir, object *pusher) {
00493 int str1, str2;
00494 object *owner;
00495
00496 if (who->head != NULL)
00497 who = who->head;
00498 owner = get_owner(who);
00499
00500
00501 CLEAR_FLAG(who, FLAG_SLEEP);
00502
00503
00504
00505 if (who->more == NULL
00506 && (owner == pusher || (owner != NULL && owner->type == PLAYER && owner->contr->party != NULL && owner->contr->party == pusher->contr->party))) {
00507 int temp;
00508 mapstruct *m;
00509
00510 remove_ob(who);
00511 remove_ob(pusher);
00512 temp = pusher->x;
00513 pusher->x = who->x;
00514 who->x = temp;
00515
00516 temp = pusher->y;
00517 pusher->y = who->y;
00518 who->y = temp;
00519
00520 m = pusher->map;
00521 pusher->map = who->map;
00522 who->map = m;
00523
00524 insert_ob_in_map(who, who->map, pusher, 0);
00525 insert_ob_in_map(pusher, pusher->map, pusher, 0);
00526
00527
00528
00529
00530
00531 if (pusher->type == PLAYER) {
00532 esrv_map_scroll(&pusher->contr->socket, freearr_x[dir], freearr_y[dir]);
00533 pusher->contr->socket.update_look = 1;
00534 pusher->contr->socket.look_position = 0;
00535 }
00536 return 0;
00537 }
00538
00539
00540
00541
00542
00543 if (owner != pusher
00544 && pusher->type == PLAYER
00545 && who->type != PLAYER
00546 && !QUERY_FLAG(who, FLAG_FRIENDLY)&& !QUERY_FLAG(who, FLAG_NEUTRAL)) {
00547 if (pusher->contr->run_on) {
00548 draw_ext_info_format(NDI_UNIQUE, 0, pusher,
00549 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE,
00550 "You start to attack %s !!",
00551 "You start to attack %s !!",
00552 who->name);
00553 CLEAR_FLAG(who, FLAG_UNAGGRESSIVE);
00554 who->enemy = pusher;
00555 return 1;
00556 } else {
00557 draw_ext_info_format(NDI_UNIQUE, 0, pusher,
00558 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE,
00559 "You avoid attacking %s.",
00560 "You avoid attacking %s.",
00561 who->name);
00562 }
00563 }
00564
00565
00566 if (QUERY_FLAG(who, FLAG_STAND_STILL)) {
00567 draw_ext_info_format(NDI_UNIQUE, 0, pusher,
00568 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE,
00569 "You can't push %s.",
00570 "You can't push %s.",
00571 who->name);
00572 return 0;
00573 }
00574
00575
00576
00577
00578
00579
00580
00581
00582 str1 = (who->stats.Str > 0 ? who->stats.Str : who->level);
00583 str2 = (pusher->stats.Str > 0 ? pusher->stats.Str : pusher->level);
00584 if (QUERY_FLAG(who, FLAG_WIZ)
00585 || random_roll(str1, str1/2+str1*2, who, PREFER_HIGH) >= random_roll(str2, str2/2+str2*2, pusher, PREFER_HIGH)
00586 || !move_object(who, dir)) {
00587 if (who->type == PLAYER) {
00588 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_VICTIM, MSG_TYPE_VICTIM_WAS_PUSHED,
00589 "%s tried to push you.",
00590 "%s tried to push you.",
00591 pusher->name);
00592 }
00593 return 0;
00594 }
00595
00596
00597
00598
00599 if (who->type == PLAYER) {
00600 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_VICTIM, MSG_TYPE_VICTIM_WAS_PUSHED,
00601 "%s pushed you.",
00602 "%s pushed you.",
00603 pusher->name);
00604 }
00605 if (pusher->type == PLAYER) {
00606 draw_ext_info_format(NDI_UNIQUE, 0, pusher, MSG_TYPE_VICTIM, MSG_TYPE_VICTIM_WAS_PUSHED,
00607 "You pushed %s back.",
00608 "You pushed %s back.",
00609 who->name);
00610 }
00611
00612 return 1;
00613 }
00614
00626 int move_to(object *op, int x, int y) {
00627 int direction;
00628
00629 if (op->x == x && op->y == y)
00630 return 0;
00631
00632 if (GET_MAP_FLAGS(op->map, x, y)&P_OUT_OF_MAP)
00633 return 2;
00634
00635 direction = compute_path(op, GET_MAP_OB(op->map, x, y), -1);
00636 if (direction == -1)
00637 return 2;
00638
00639
00640 move_ob(op, direction, op);
00641 return 1;
00642 }