452 DoCheckTunnelInWay(tile,z,1) && |
452 DoCheckTunnelInWay(tile,z,1) && |
453 DoCheckTunnelInWay(tile,z,2) && |
453 DoCheckTunnelInWay(tile,z,2) && |
454 DoCheckTunnelInWay(tile,z,3); |
454 DoCheckTunnelInWay(tile,z,3); |
455 } |
455 } |
456 |
456 |
457 static byte _build_tunnel_bh; |
|
458 static byte _build_tunnel_railtype; |
|
459 |
|
460 static int32 DoBuildTunnel(int x, int y, int x2, int y2, uint32 flags, uint exc_tile) |
|
461 { |
|
462 TileIndex end_tile; |
|
463 int direction; |
|
464 int32 cost, ret; |
|
465 TileInfo ti; |
|
466 uint z; |
|
467 |
|
468 if ((uint)x > MapMaxX() * 16 - 1 || (uint)y > MapMaxY() * 16 - 1) |
|
469 return CMD_ERROR; |
|
470 |
|
471 /* check if valid, and make sure that (x,y) is smaller than (x2,y2) */ |
|
472 direction = 0; |
|
473 if (x == x2) { |
|
474 if (y == y2) return_cmd_error(STR_5008_CANNOT_START_AND_END_ON); |
|
475 direction++; |
|
476 if (y > y2) { |
|
477 intswap(y,y2); |
|
478 intswap(x,x2); |
|
479 exc_tile |= 2; |
|
480 } |
|
481 } else if (y == y2) { |
|
482 if (x > x2) { |
|
483 intswap(y,y2); |
|
484 intswap(x,x2); |
|
485 exc_tile |= 2; |
|
486 } |
|
487 } else { |
|
488 return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN); |
|
489 } |
|
490 |
|
491 cost = 0; |
|
492 |
|
493 FindLandscapeHeight(&ti, x2, y2); |
|
494 end_tile = ti.tile; |
|
495 z = ti.z; |
|
496 |
|
497 if (exc_tile != 3) { |
|
498 if ((direction ? 9U : 12U) != ti.tileh) |
|
499 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
|
500 ret = DoCommandByTile(ti.tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
|
501 if (CmdFailed(ret)) return CMD_ERROR; |
|
502 cost += ret; |
|
503 } |
|
504 cost += _price.build_tunnel; |
|
505 |
|
506 for (;;) { |
|
507 if (direction) y2-=16; else x2-=16; |
|
508 |
|
509 if (x2 == x && y2 == y) break; |
|
510 |
|
511 FindLandscapeHeight(&ti, x2, y2); |
|
512 if (ti.z <= z) return CMD_ERROR; |
|
513 |
|
514 if (!_cheats.crossing_tunnels.value && !CheckTunnelInWay(ti.tile, z)) |
|
515 return CMD_ERROR; |
|
516 |
|
517 cost += _price.build_tunnel; |
|
518 cost += (cost >> 3); |
|
519 |
|
520 if (cost >= 400000000) cost = 400000000; |
|
521 } |
|
522 |
|
523 FindLandscapeHeight(&ti, x2, y2); |
|
524 if (ti.z != z) return CMD_ERROR; |
|
525 |
|
526 if (exc_tile != 1) { |
|
527 if ((direction ? 6U : 3U) != ti.tileh) |
|
528 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
|
529 |
|
530 ret = DoCommandByTile(ti.tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
|
531 if (CmdFailed(ret)) return CMD_ERROR; |
|
532 cost += ret; |
|
533 } |
|
534 |
|
535 if (flags & DC_EXEC) { |
|
536 ModifyTile(ti.tile, |
|
537 MP_SETTYPE(MP_TUNNELBRIDGE) | |
|
538 MP_MAP3LO | MP_MAPOWNER_CURRENT | MP_MAP5, |
|
539 _build_tunnel_railtype, /* map3lo */ |
|
540 ((_build_tunnel_bh << 1) | 2) - direction /* map5 */ |
|
541 ); |
|
542 |
|
543 ModifyTile(end_tile, |
|
544 MP_SETTYPE(MP_TUNNELBRIDGE) | |
|
545 MP_MAP3LO | MP_MAPOWNER_CURRENT | MP_MAP5, |
|
546 _build_tunnel_railtype, /* map3lo */ |
|
547 (_build_tunnel_bh << 1) | (direction ? 3:0)/* map5 */ |
|
548 ); |
|
549 |
|
550 UpdateSignalsOnSegment(end_tile, direction?7:1); |
|
551 } |
|
552 |
|
553 return cost + _price.build_tunnel; |
|
554 } |
|
555 |
457 |
556 /** Build Tunnel. |
458 /** Build Tunnel. |
557 * @param x,y start tile coord of tunnel |
459 * @param x,y start tile coord of tunnel |
558 * @param p1 railtype, 0x200 for road tunnel |
460 * @param p1 railtype, 0x200 for road tunnel |
559 * @param p2 unused |
461 * @param p2 unused |
560 */ |
462 */ |
561 int32 CmdBuildTunnel(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
463 int32 CmdBuildTunnel(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
562 { |
464 { |
563 TileInfo ti, tiorg; |
465 TileIndexDiff delta; |
564 int direction; |
466 TileIndex start_tile; |
565 uint z; |
467 TileIndex end_tile; |
566 static const int8 _build_tunnel_coord_mod[4+1] = { -16, 0, 16, 0, -16 }; |
468 DiagDirection direction; |
567 static const byte _build_tunnel_tileh[4] = {3, 9, 12, 6}; |
469 uint start_tileh; |
568 TileIndex excavated_tile; |
470 uint end_tileh; |
569 |
471 uint start_z; |
570 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
472 uint end_z; |
|
473 int32 cost; |
|
474 int32 ret; |
|
475 |
|
476 _build_tunnel_endtile = 0; |
571 |
477 |
572 if (p1 != 0x200 && !ValParamRailtype(p1)) return CMD_ERROR; |
478 if (p1 != 0x200 && !ValParamRailtype(p1)) return CMD_ERROR; |
573 |
479 |
574 _build_tunnel_railtype = GB(p1, 0, 8); |
480 start_tile = TileVirtXY(x, y); |
575 _build_tunnel_bh = GB(p1, 8, 8); |
481 start_tileh = GetTileSlope(start_tile, &start_z); |
576 |
482 |
577 _build_tunnel_endtile = 0; |
483 switch (start_tileh) { |
578 excavated_tile = 0; |
484 case 3: direction = DIAGDIR_SW; break; |
579 |
485 case 6: direction = DIAGDIR_SE; break; |
580 FindLandscapeHeight(&tiorg, x, y); |
486 case 9: direction = DIAGDIR_NW; break; |
581 |
487 case 12: direction = DIAGDIR_NE; break; |
582 if (!EnsureNoVehicle(tiorg.tile)) |
488 default: return_cmd_error(STR_500B_SITE_UNSUITABLE_FOR_TUNNEL); |
583 return CMD_ERROR; |
489 } |
584 |
490 |
585 if (!(direction=0, tiorg.tileh == 12) && |
491 ret = DoCommandByTile(start_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
586 !(direction++, tiorg.tileh == 6) && |
492 if (CmdFailed(ret)) return ret; |
587 !(direction++, tiorg.tileh == 3) && |
493 cost = _price.build_tunnel + ret; |
588 !(direction++, tiorg.tileh == 9)) { |
494 |
589 return_cmd_error(STR_500B_SITE_UNSUITABLE_FOR_TUNNEL); |
495 delta = TileOffsByDir(direction); |
590 } |
496 end_tile = start_tile; |
591 |
497 for (;;) { |
592 z = tiorg.z; |
498 end_tile += delta; |
593 do { |
499 end_tileh = GetTileSlope(end_tile, &end_z); |
594 x += _build_tunnel_coord_mod[direction]; |
500 |
595 y += _build_tunnel_coord_mod[direction+1]; |
501 if (start_z == end_z) break; |
596 FindLandscapeHeight(&ti, x, y); |
502 |
597 } while (z != ti.z); |
503 if (!_cheats.crossing_tunnels.value && !CheckTunnelInWay(end_tile, start_z)) { |
598 _build_tunnel_endtile = ti.tile; |
504 return CMD_ERROR; |
599 |
505 } |
600 |
506 |
601 if (!EnsureNoVehicle(ti.tile)) return CMD_ERROR; |
507 cost += _price.build_tunnel; |
602 |
508 cost += cost >> 3; |
603 if (ti.tileh != _build_tunnel_tileh[direction]) { |
509 if (cost >= 400000000) cost = 400000000; |
604 if (CmdFailed(DoCommandByTile(ti.tile, ti.tileh & ~_build_tunnel_tileh[direction], 0, flags, CMD_TERRAFORM_LAND))) |
510 } |
605 return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND); |
511 |
606 excavated_tile = 1; |
512 // if the command fails from here on we want the end tile to be highlighted |
607 } |
513 _build_tunnel_endtile = end_tile; |
608 |
514 |
609 return DoBuildTunnel(x, y, tiorg.x, tiorg.y, flags, excavated_tile); |
515 // slope of end tile must be complementary to the slope of the start tile |
|
516 if (end_tileh != (15 ^ start_tileh)) { |
|
517 ret = DoCommandByTile(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND); |
|
518 if (CmdFailed(ret)) return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND); |
|
519 } else { |
|
520 ret = DoCommandByTile(end_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
|
521 if (CmdFailed(ret)) return ret; |
|
522 cost += ret; |
|
523 } |
|
524 cost += _price.build_tunnel; |
|
525 |
|
526 if (flags & DC_EXEC) { |
|
527 SetTileType(start_tile, MP_TUNNELBRIDGE); |
|
528 SetTileOwner(start_tile, _current_player); |
|
529 _m[start_tile].m3 = GB(p1, 0, 4); // rail type (if any) |
|
530 _m[start_tile].m5 = (GB(p1, 9, 1) << 2) | direction; // transport type and entrance direction |
|
531 |
|
532 SetTileType(end_tile, MP_TUNNELBRIDGE); |
|
533 SetTileOwner(end_tile, _current_player); |
|
534 _m[end_tile].m3 = GB(p1, 0, 4); // rail type (if any) |
|
535 _m[end_tile].m5 = (GB(p1, 9, 1) << 2) | (direction ^ 2); // transport type and entrance direction |
|
536 |
|
537 if (GB(p1, 9, 1) == 0) UpdateSignalsOnSegment(start_tile, direction << 1); |
|
538 } |
|
539 |
|
540 return cost; |
610 } |
541 } |
611 |
542 |
612 TileIndex CheckTunnelBusy(TileIndex tile, uint *length) |
543 TileIndex CheckTunnelBusy(TileIndex tile, uint *length) |
613 { |
544 { |
614 uint z = GetTileZ(tile); |
545 uint z = GetTileZ(tile); |