27 |
27 |
28 RAIL_DEPOT_TRACK_MASK = 1, |
28 RAIL_DEPOT_TRACK_MASK = 1, |
29 RAIL_DEPOT_DIR = 3, |
29 RAIL_DEPOT_DIR = 3, |
30 RAIL_DEPOT_UNUSED_BITS = 0x3C, |
30 RAIL_DEPOT_UNUSED_BITS = 0x3C, |
31 |
31 |
32 RAIL_TYPE_CHECKPOINT = 0xC4, |
32 RAIL_TYPE_WAYPOINT = 0xC4, |
33 RAIL_CHECKPOINT_TRACK_MASK = 1, |
33 RAIL_WAYPOINT_TRACK_MASK = 1, |
34 RAIL_CHECKPOINT_UNUSED_BITS = 0x3E, |
34 RAIL_WAYPOINT_UNUSED_BITS = 0x3E, |
35 }; |
35 }; |
36 |
36 |
37 #define IS_RAIL_DEPOT(x) (((x) & (RAIL_TYPE_DEPOT|RAIL_DEPOT_UNUSED_BITS)) == RAIL_TYPE_DEPOT) |
37 #define IS_RAIL_DEPOT(x) (((x) & (RAIL_TYPE_DEPOT|RAIL_DEPOT_UNUSED_BITS)) == RAIL_TYPE_DEPOT) |
38 #define IS_RAIL_CHECKPOINT(x) (((x) & (RAIL_TYPE_CHECKPOINT|RAIL_CHECKPOINT_UNUSED_BITS)) == RAIL_TYPE_CHECKPOINT) |
38 #define IS_RAIL_WAYPOINT(x) (((x) & (RAIL_TYPE_WAYPOINT|RAIL_WAYPOINT_UNUSED_BITS)) == RAIL_TYPE_WAYPOINT) |
39 |
39 |
40 /* Format of rail map5 byte. |
40 /* Format of rail map5 byte. |
41 * 00 abcdef => Normal rail |
41 * 00 abcdef => Normal rail |
42 * 01 abcdef => Rail with signals |
42 * 01 abcdef => Rail with signals |
43 * 10 ?????? => Unused |
43 * 10 ?????? => Unused |
661 } |
661 } |
662 |
662 |
663 return cost + _price.build_train_depot; |
663 return cost + _price.build_train_depot; |
664 } |
664 } |
665 |
665 |
666 static void MakeDefaultCheckpointName(Checkpoint *cp) |
666 static void MakeDefaultWaypointName(Waypoint *cp) |
667 { |
667 { |
668 int townidx = ClosestTownFromTile(cp->xy, (uint)-1)->index; |
668 int townidx = ClosestTownFromTile(cp->xy, (uint)-1)->index; |
669 Checkpoint *cc; |
669 Waypoint *cc; |
670 bool used_checkpoint[64]; |
670 bool used_waypoint[64]; |
671 int i; |
671 int i; |
672 |
672 |
673 memset(used_checkpoint, 0, sizeof(used_checkpoint)); |
673 memset(used_waypoint, 0, sizeof(used_waypoint)); |
674 |
674 |
675 // find an unused checkpoint number belonging to this town |
675 // find an unused waypoint number belonging to this town |
676 for(cc = _checkpoints; cc != endof(_checkpoints); cc++) { |
676 for(cc = _waypoints; cc != endof(_waypoints); cc++) { |
677 if (cc->xy && cc->town_or_string & 0xC000 && (cc->town_or_string & 0xFF) == townidx) |
677 if (cc->xy && cc->town_or_string & 0xC000 && (cc->town_or_string & 0xFF) == townidx) |
678 used_checkpoint[(cc->town_or_string >> 8) & 0x3F] = true; |
678 used_waypoint[(cc->town_or_string >> 8) & 0x3F] = true; |
679 } |
679 } |
680 |
680 |
681 for(i=0; used_checkpoint[i] && i!=lengthof(used_checkpoint)-1; i++) {} |
681 for(i=0; used_waypoint[i] && i!=lengthof(used_waypoint)-1; i++) {} |
682 cp->town_or_string = 0xC000 + (i << 8) + townidx; |
682 cp->town_or_string = 0xC000 + (i << 8) + townidx; |
683 } |
683 } |
684 |
684 |
685 // find a deleted checkpoint close to a tile. |
685 // find a deleted waypoint close to a tile. |
686 static Checkpoint *FindDeletedCheckpointCloseTo(uint tile) |
686 static Waypoint *FindDeletedWaypointCloseTo(uint tile) |
687 { |
687 { |
688 Checkpoint *cp,*best = NULL; |
688 Waypoint *cp,*best = NULL; |
689 uint thres = 8, cur_dist; |
689 uint thres = 8, cur_dist; |
690 |
690 |
691 for(cp = _checkpoints; cp != endof(_checkpoints); cp++) { |
691 for(cp = _waypoints; cp != endof(_waypoints); cp++) { |
692 if (cp->deleted && cp->xy) { |
692 if (cp->deleted && cp->xy) { |
693 cur_dist = GetTileDist(tile, cp->xy); |
693 cur_dist = GetTileDist(tile, cp->xy); |
694 if (cur_dist < thres) { |
694 if (cur_dist < thres) { |
695 thres = cur_dist; |
695 thres = cur_dist; |
696 best = cp; |
696 best = cp; |
723 if (tileh != 0) { |
723 if (tileh != 0) { |
724 if (!_patches.build_on_slopes || tileh & 0x10 || !(tileh & (0x3 << dir)) || !(tileh & ~(0x3 << dir))) |
724 if (!_patches.build_on_slopes || tileh & 0x10 || !(tileh & (0x3 << dir)) || !(tileh & ~(0x3 << dir))) |
725 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED); |
725 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED); |
726 } |
726 } |
727 |
727 |
728 // check if there is an already existing, deleted, checkpoint close to us that we can reuse. |
728 // check if there is an already existing, deleted, waypoint close to us that we can reuse. |
729 cp = FindDeletedCheckpointCloseTo(tile); |
729 cp = FindDeletedWaypointCloseTo(tile); |
730 if (cp == NULL) { |
730 if (cp == NULL) { |
731 cp = AllocateCheckpoint(); |
731 cp = AllocateWaypoint(); |
732 if (cp == NULL) return CMD_ERROR; |
732 if (cp == NULL) return CMD_ERROR; |
733 cp->town_or_string = 0; |
733 cp->town_or_string = 0; |
734 } |
734 } |
735 |
735 |
736 if (flags & DC_EXEC) { |
736 if (flags & DC_EXEC) { |
737 ModifyTile(tile, MP_MAP5, RAIL_TYPE_CHECKPOINT | dir); |
737 ModifyTile(tile, MP_MAP5, RAIL_TYPE_WAYPOINT | dir); |
738 if (p1 & 0x100) { |
738 if (p1 & 0x100) { |
739 // custom graphics |
739 // custom graphics |
740 _map3_lo[tile] |= 16; |
740 _map3_lo[tile] |= 16; |
741 _map3_hi[tile] = p1 & 0xff; |
741 _map3_hi[tile] = p1 & 0xff; |
742 } |
742 } |
743 |
743 |
744 cp->deleted = 0; |
744 cp->deleted = 0; |
745 cp->xy = tile; |
745 cp->xy = tile; |
746 |
746 |
747 if (cp->town_or_string == 0) MakeDefaultCheckpointName(cp); else RedrawCheckpointSign(cp); |
747 if (cp->town_or_string == 0) MakeDefaultWaypointName(cp); else RedrawWaypointSign(cp); |
748 UpdateCheckpointSign(cp); |
748 UpdateWaypointSign(cp); |
749 RedrawCheckpointSign(cp); |
749 RedrawWaypointSign(cp); |
750 SetSignalsOnBothDir(tile, dir ? 2 : 1); |
750 SetSignalsOnBothDir(tile, dir ? 2 : 1); |
751 } |
751 } |
752 |
752 |
753 return _price.build_train_depot; |
753 return _price.build_train_depot; |
754 } |
754 } |
755 |
755 |
756 static void DoDeleteCheckpoint(Checkpoint *cp) |
756 static void DoDeleteWaypoint(Waypoint *cp) |
757 { |
757 { |
758 cp->xy = 0; |
758 cp->xy = 0; |
759 DeleteCommandFromVehicleSchedule(((cp-_checkpoints) << 8) + OT_GOTO_CHECKPOINT); |
759 DeleteCommandFromVehicleSchedule(((cp-_waypoints) << 8) + OT_GOTO_WAYPOINT); |
760 if (~cp->town_or_string & 0xC000) DeleteName(cp->town_or_string); |
760 if (~cp->town_or_string & 0xC000) DeleteName(cp->town_or_string); |
761 RedrawCheckpointSign(cp); |
761 RedrawWaypointSign(cp); |
762 } |
762 } |
763 |
763 |
764 // delete checkpoints after a while |
764 // delete waypoints after a while |
765 void CheckpointsDailyLoop() |
765 void WaypointsDailyLoop() |
766 { |
766 { |
767 Checkpoint *cp; |
767 Waypoint *cp; |
768 for(cp = _checkpoints; cp != endof(_checkpoints); cp++) { |
768 for(cp = _waypoints; cp != endof(_waypoints); cp++) { |
769 if (cp->deleted && !--cp->deleted) { |
769 if (cp->deleted && !--cp->deleted) { |
770 DoDeleteCheckpoint(cp); |
770 DoDeleteWaypoint(cp); |
771 } |
771 } |
772 } |
772 } |
773 } |
773 } |
774 |
774 |
775 static int32 RemoveTrainCheckpoint(uint tile, uint32 flags, bool justremove) |
775 static int32 RemoveTrainWaypoint(uint tile, uint32 flags, bool justremove) |
776 { |
776 { |
777 Checkpoint *cp; |
777 Waypoint *cp; |
778 |
778 |
779 // make sure it's a checkpoint |
779 // make sure it's a waypoint |
780 if (!IS_TILETYPE(tile, MP_RAILWAY) || !IS_RAIL_CHECKPOINT(_map5[tile])) |
780 if (!IS_TILETYPE(tile, MP_RAILWAY) || !IS_RAIL_WAYPOINT(_map5[tile])) |
781 return CMD_ERROR; |
781 return CMD_ERROR; |
782 |
782 |
783 if (!CheckTileOwnership(tile) && !(_current_player==17)) |
783 if (!CheckTileOwnership(tile) && !(_current_player==17)) |
784 return CMD_ERROR; |
784 return CMD_ERROR; |
785 |
785 |
786 if (!EnsureNoVehicle(tile)) |
786 if (!EnsureNoVehicle(tile)) |
787 return CMD_ERROR; |
787 return CMD_ERROR; |
788 |
788 |
789 if (flags & DC_EXEC) { |
789 if (flags & DC_EXEC) { |
790 int direction = _map5[tile] & RAIL_CHECKPOINT_TRACK_MASK; |
790 int direction = _map5[tile] & RAIL_WAYPOINT_TRACK_MASK; |
791 |
791 |
792 // mark the checkpoint deleted |
792 // mark the waypoint deleted |
793 for(cp=_checkpoints; cp->xy != (TileIndex)tile; cp++) {} |
793 for(cp=_waypoints; cp->xy != (TileIndex)tile; cp++) {} |
794 cp->deleted = 30; // let it live for this many days before we do the actual deletion. |
794 cp->deleted = 30; // let it live for this many days before we do the actual deletion. |
795 RedrawCheckpointSign(cp); |
795 RedrawWaypointSign(cp); |
796 |
796 |
797 if (justremove) { |
797 if (justremove) { |
798 ModifyTile(tile, MP_MAP5, 1<<direction); |
798 ModifyTile(tile, MP_MAP5, 1<<direction); |
799 _map3_lo[tile] &= ~16; |
799 _map3_lo[tile] &= ~16; |
800 _map3_hi[tile] = 0; |
800 _map3_hi[tile] = 0; |
805 } |
805 } |
806 |
806 |
807 return _price.remove_train_depot; |
807 return _price.remove_train_depot; |
808 } |
808 } |
809 |
809 |
810 int32 CmdRemoveTrainCheckpoint(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
810 int32 CmdRemoveTrainWaypoint(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
811 { |
811 { |
812 uint tile = TILE_FROM_XY(x,y); |
812 uint tile = TILE_FROM_XY(x,y); |
813 return RemoveTrainCheckpoint(tile, flags, true); |
813 return RemoveTrainWaypoint(tile, flags, true); |
814 } |
814 } |
815 |
815 |
816 |
816 |
817 // p1 = id of checkpoint |
817 // p1 = id of waypoint |
818 int32 CmdRenameCheckpoint(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
818 int32 CmdRenameWaypoint(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
819 { |
819 { |
820 Checkpoint *cp; |
820 Waypoint *cp; |
821 StringID str; |
821 StringID str; |
822 |
822 |
823 if (_decode_parameters[0] != 0) { |
823 if (_decode_parameters[0] != 0) { |
824 str = AllocateName((byte*)_decode_parameters, 0); |
824 str = AllocateName((byte*)_decode_parameters, 0); |
825 if (str == 0) return CMD_ERROR; |
825 if (str == 0) return CMD_ERROR; |
826 |
826 |
827 if (flags & DC_EXEC) { |
827 if (flags & DC_EXEC) { |
828 cp = &_checkpoints[p1]; |
828 cp = &_waypoints[p1]; |
829 if (~cp->town_or_string & 0xC000) DeleteName(cp->town_or_string); |
829 if (~cp->town_or_string & 0xC000) DeleteName(cp->town_or_string); |
830 cp->town_or_string = str; |
830 cp->town_or_string = str; |
831 UpdateCheckpointSign(cp); |
831 UpdateWaypointSign(cp); |
832 MarkWholeScreenDirty(); |
832 MarkWholeScreenDirty(); |
833 } else { |
833 } else { |
834 DeleteName(str); |
834 DeleteName(str); |
835 } |
835 } |
836 } else { |
836 } else { |
837 if (flags & DC_EXEC) { |
837 if (flags & DC_EXEC) { |
838 cp = &_checkpoints[p1]; |
838 cp = &_waypoints[p1]; |
839 if (~cp->town_or_string & 0xC000) DeleteName(cp->town_or_string); |
839 if (~cp->town_or_string & 0xC000) DeleteName(cp->town_or_string); |
840 MakeDefaultCheckpointName(cp); |
840 MakeDefaultWaypointName(cp); |
841 UpdateCheckpointSign(cp); |
841 UpdateWaypointSign(cp); |
842 MarkWholeScreenDirty(); |
842 MarkWholeScreenDirty(); |
843 } |
843 } |
844 } |
844 } |
845 return 0; |
845 return 0; |
846 } |
846 } |
1530 MAYBE_DRAW_SIGNAL(3, 0x4FF, 10); |
1530 MAYBE_DRAW_SIGNAL(3, 0x4FF, 10); |
1531 MAYBE_DRAW_SIGNAL(2, 0x501, 11); |
1531 MAYBE_DRAW_SIGNAL(2, 0x501, 11); |
1532 } |
1532 } |
1533 } |
1533 } |
1534 } else { |
1534 } else { |
1535 /* draw depots / checkpoints */ |
1535 /* draw depots / waypoints */ |
1536 const byte *s; |
1536 const byte *s; |
1537 const DrawTrackSeqStruct *drss; |
1537 const DrawTrackSeqStruct *drss; |
1538 byte type = m5 & 0x3F; // 0-3: depots, 4-5: checkpoints |
1538 byte type = m5 & 0x3F; // 0-3: depots, 4-5: waypoints |
1539 |
1539 |
1540 if (!(m5 & (RAIL_TYPE_MASK&~RAIL_TYPE_SPECIAL))) |
1540 if (!(m5 & (RAIL_TYPE_MASK&~RAIL_TYPE_SPECIAL))) |
1541 return; |
1541 return; |
1542 |
1542 |
1543 if (ti->tileh != 0) { DrawFoundation(ti, ti->tileh); } |
1543 if (ti->tileh != 0) { DrawFoundation(ti, ti->tileh); } |
1544 |
1544 |
1545 if (!IS_RAIL_DEPOT(m5) && IS_RAIL_CHECKPOINT(m5) && _map3_lo[ti->tile]&16) { |
1545 if (!IS_RAIL_DEPOT(m5) && IS_RAIL_WAYPOINT(m5) && _map3_lo[ti->tile]&16) { |
1546 // look for customization |
1546 // look for customization |
1547 DrawTileSprites *cust = GetCustomStation('WAYP', _map3_hi[ti->tile]); |
1547 DrawTileSprites *cust = GetCustomStation('WAYP', _map3_hi[ti->tile]); |
1548 |
1548 |
1549 if (cust) { |
1549 if (cust) { |
1550 DrawTileSeqStruct const *seq; |
1550 DrawTileSeqStruct const *seq; |
1618 if (image & 0x8000) image |= ormod; |
1618 if (image & 0x8000) image |= ormod; |
1619 DrawSprite(image + railtype, x + pt.x, y + pt.y); |
1619 DrawSprite(image + railtype, x + pt.x, y + pt.y); |
1620 } |
1620 } |
1621 } |
1621 } |
1622 |
1622 |
1623 void DrawCheckpointSprite(int x, int y, int stat_id) |
1623 void DrawWaypointSprite(int x, int y, int stat_id) |
1624 { |
1624 { |
1625 // TODO: We should use supersets with cargo-id FF, if available. --pasky |
1625 // TODO: We should use supersets with cargo-id FF, if available. --pasky |
1626 DrawTileSprites *cust = GetCustomStation('WAYP', stat_id); |
1626 DrawTileSprites *cust = GetCustomStation('WAYP', stat_id); |
1627 DrawTileSeqStruct const *seq; |
1627 DrawTileSeqStruct const *seq; |
1628 uint32 ormod, img; |
1628 uint32 ormod, img; |