100 u->u.rail.first_engine = (v == u) ? INVALID_VEHICLE : first_engine; |
98 u->u.rail.first_engine = (v == u) ? INVALID_VEHICLE : first_engine; |
101 |
99 |
102 if (rvi_u->visual_effect != 0) { |
100 if (rvi_u->visual_effect != 0) { |
103 u->u.rail.cached_vis_effect = rvi_u->visual_effect; |
101 u->u.rail.cached_vis_effect = rvi_u->visual_effect; |
104 } else { |
102 } else { |
105 if (rvi_u->flags & RVI_WAGON || u->subtype == TS_Artic_Part) { |
103 if (IsTrainWagon(u) || IsArticulatedPart(u)) { |
106 // Wagons and articulated parts have no effect by default |
104 // Wagons and articulated parts have no effect by default |
107 u->u.rail.cached_vis_effect = 0x40; |
105 u->u.rail.cached_vis_effect = 0x40; |
108 } else if (rvi_u->engclass == 0) { |
106 } else if (rvi_u->engclass == 0) { |
109 // Steam is offset by -4 units |
107 // Steam is offset by -4 units |
110 u->u.rail.cached_vis_effect = 4; |
108 u->u.rail.cached_vis_effect = 4; |
748 v->date_of_last_service = _date; |
750 v->date_of_last_service = _date; |
749 v->build_year = _cur_year; |
751 v->build_year = _cur_year; |
750 v->type = VEH_Train; |
752 v->type = VEH_Train; |
751 v->cur_image = 0xAC2; |
753 v->cur_image = 0xAC2; |
752 |
754 |
|
755 v->subtype = 0; |
|
756 SetFrontEngine(v); |
|
757 SetTrainEngine(v); |
|
758 |
753 v->u.rail.shortest_platform[0] = 255; |
759 v->u.rail.shortest_platform[0] = 255; |
754 v->u.rail.shortest_platform[1] = 0; |
760 v->u.rail.shortest_platform[1] = 0; |
755 |
761 |
756 VehiclePositionChanged(v); |
762 VehiclePositionChanged(v); |
757 |
763 |
758 if (rvi->flags & RVI_MULTIHEAD && !HASBIT(p2, 0)) { |
764 if (rvi->flags & RVI_MULTIHEAD && !HASBIT(p2, 0)) { |
|
765 SetMultiheaded(v); |
759 AddRearEngineToMultiheadedTrain(vl[0], vl[1], true); |
766 AddRearEngineToMultiheadedTrain(vl[0], vl[1], true); |
|
767 /* Now we need to link the front and rear engines together |
|
768 * other_multiheaded_part is the pointer that links to the other half of the engine |
|
769 * vl[0] is the front and vl[1] is the rear |
|
770 */ |
|
771 vl[0]->u.rail.other_multiheaded_part = vl[1]; |
|
772 vl[1]->u.rail.other_multiheaded_part = vl[0]; |
760 } else { |
773 } else { |
761 AddArticulatedParts(rvi, vl); |
774 AddArticulatedParts(rvi, vl); |
762 } |
775 } |
763 |
776 |
764 TrainConsistChanged(v); |
777 TrainConsistChanged(v); |
851 } |
865 } |
852 } |
866 } |
853 } |
867 } |
854 |
868 |
855 return NULL; |
869 return NULL; |
|
870 } |
|
871 |
|
872 /* |
|
873 * add a vehicle v behind vehicle dest |
|
874 * use this function since it sets flags as needed |
|
875 */ |
|
876 static void AddWagonToConsist(Vehicle *v, Vehicle *dest) |
|
877 { |
|
878 UnlinkWagon(v, GetFirstVehicleInChain(v)); |
|
879 if (dest == NULL) return; |
|
880 |
|
881 v->next = dest->next; |
|
882 dest->next = v; |
|
883 ClearFreeWagon(v); |
|
884 ClearFrontEngine(v); |
|
885 } |
|
886 |
|
887 /* |
|
888 * move around on the train so rear engines are placed correctly according to the other engines |
|
889 * always call with the front engine |
|
890 */ |
|
891 static void NormaliseTrainConsist(Vehicle *v) |
|
892 { |
|
893 Vehicle *u; |
|
894 |
|
895 if (IsFreeWagon(v)) return; |
|
896 |
|
897 assert(IsFrontEngine(v)); |
|
898 |
|
899 for(; v != NULL; v = GetNextVehicle(v)) { |
|
900 if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue; |
|
901 |
|
902 /* make sure that there are no free cars before next engine */ |
|
903 for(u = v; u->next != NULL && !IsTrainEngine(u->next); u = u->next); |
|
904 |
|
905 if (u == v->u.rail.other_multiheaded_part) continue; |
|
906 AddWagonToConsist(v->u.rail.other_multiheaded_part, u); |
|
907 |
|
908 } |
856 } |
909 } |
857 |
910 |
858 /** Move a rail vehicle around inside the depot. |
911 /** Move a rail vehicle around inside the depot. |
859 * @param x,y unused |
912 * @param x,y unused |
860 * @param p1 various bitstuffed elements |
913 * @param p1 various bitstuffed elements |
865 int32 CmdMoveRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
918 int32 CmdMoveRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
866 { |
919 { |
867 VehicleID s = GB(p1, 0, 16); |
920 VehicleID s = GB(p1, 0, 16); |
868 VehicleID d = GB(p1, 16, 16); |
921 VehicleID d = GB(p1, 16, 16); |
869 Vehicle *src, *dst, *src_head, *dst_head; |
922 Vehicle *src, *dst, *src_head, *dst_head; |
870 bool is_loco; |
|
871 |
923 |
872 if (!IsVehicleIndex(s)) return CMD_ERROR; |
924 if (!IsVehicleIndex(s)) return CMD_ERROR; |
873 |
925 |
874 src = GetVehicle(s); |
926 src = GetVehicle(s); |
875 |
927 |
876 if (src->type != VEH_Train) return CMD_ERROR; |
928 if (src->type != VEH_Train) return CMD_ERROR; |
877 |
|
878 is_loco = !(RailVehInfo(src->engine_type)->flags & RVI_WAGON) && IS_FIRSTHEAD_SPRITE(src->spritenum); |
|
879 |
929 |
880 // if nothing is selected as destination, try and find a matching vehicle to drag to. |
930 // if nothing is selected as destination, try and find a matching vehicle to drag to. |
881 if (d == INVALID_VEHICLE) { |
931 if (d == INVALID_VEHICLE) { |
882 dst = NULL; |
932 dst = NULL; |
883 if (!is_loco) dst = FindGoodVehiclePos(src); |
933 if (!IsTrainEngine(src)) dst = FindGoodVehiclePos(src); |
884 } else { |
934 } else { |
885 dst = GetVehicle(d); |
935 dst = GetVehicle(d); |
886 } |
936 } |
887 |
937 |
888 // if an articulated part is being handled, deal with its parent vehicle |
938 // if an articulated part is being handled, deal with its parent vehicle |
889 while (src->subtype == TS_Artic_Part) src = GetPrevVehicleInChain(src); |
939 while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src); |
890 if (dst != NULL) { |
940 if (dst != NULL) { |
891 while (dst->subtype == TS_Artic_Part) dst = GetPrevVehicleInChain(dst); |
941 while (IsArticulatedPart(dst)) dst = GetPrevVehicleInChain(dst); |
892 } |
942 } |
893 |
943 |
894 // don't move the same vehicle.. |
944 // don't move the same vehicle.. |
895 if (src == dst) return 0; |
945 if (src == dst) return 0; |
896 |
946 |
905 dst_head = GetFirstVehicleInChain(dst); |
955 dst_head = GetFirstVehicleInChain(dst); |
906 // Now deal with articulated part of destination wagon |
956 // Now deal with articulated part of destination wagon |
907 dst = GetLastEnginePart(dst); |
957 dst = GetLastEnginePart(dst); |
908 } |
958 } |
909 |
959 |
910 /* clear the ->first cache */ |
960 if (dst != NULL && IsMultiheaded(dst) && !IsTrainEngine(dst) && IsTrainWagon(src)) { |
911 { |
961 /* We are moving a wagon to the rear part of a multiheaded engine */ |
912 Vehicle *u; |
962 if (dst->next == NULL) { |
913 |
963 /* It's the last one, so we will add the wagon just before the rear engine */ |
914 for (u = src_head; u != NULL; u = u->next) u->first = NULL; |
964 dst = GetPrevVehicleInChain(dst); |
915 for (u = dst_head; u != NULL; u = u->next) u->first = NULL; |
965 // if dst is NULL, it means that dst got a rear multiheaded engine as first engine. We can't use that |
916 } |
966 if (dst == NULL) return CMD_ERROR; |
|
967 } else { |
|
968 /* there are more units on this train, so we will add the wagon after the next one*/ |
|
969 dst = dst->next; |
|
970 } |
|
971 } |
|
972 |
|
973 if (IsTrainEngine(src) && dst_head != NULL) { |
|
974 /* we need to make sure that we didn't place it between a pair of multiheaded engines */ |
|
975 Vehicle *u, *engine = NULL; |
|
976 |
|
977 for(u = dst_head; u != NULL; u = u->next) { |
|
978 if (IsTrainEngine(u) && IsMultiheaded(u) && u->u.rail.other_multiheaded_part != NULL) { |
|
979 engine = u; |
|
980 } |
|
981 if (engine != NULL && engine->u.rail.other_multiheaded_part == u) { |
|
982 engine = NULL; |
|
983 } |
|
984 if (u == dst) { |
|
985 if (engine != NULL) { |
|
986 dst = engine->u.rail.other_multiheaded_part; |
|
987 } |
|
988 break; |
|
989 } |
|
990 |
|
991 } |
|
992 } |
|
993 |
|
994 if (IsMultiheaded(src) && !IsTrainEngine(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR); |
917 |
995 |
918 /* check if all vehicles in the source train are stopped inside a depot */ |
996 /* check if all vehicles in the source train are stopped inside a depot */ |
919 if (CheckTrainStoppedInDepot(src_head) < 0) return CMD_ERROR; |
997 if (CheckTrainStoppedInDepot(src_head) < 0) return CMD_ERROR; |
920 |
998 |
921 /* check if all the vehicles in the dest train are stopped, |
999 /* check if all the vehicles in the dest train are stopped, |
922 * and that the length of the dest train is no longer than XXX vehicles */ |
1000 * and that the length of the dest train is no longer than XXX vehicles */ |
923 if (dst_head != NULL) { |
1001 if (dst_head != NULL) { |
924 int num = CheckTrainStoppedInDepot(dst_head); |
1002 int num = CheckTrainStoppedInDepot(dst_head); |
925 if (num < 0) return CMD_ERROR; |
1003 if (num < 0) return CMD_ERROR; |
926 |
1004 |
927 if (num > (_patches.mammoth_trains ? 100 : 9) && dst_head->subtype == TS_Front_Engine ) |
1005 if (num > (_patches.mammoth_trains ? 100 : 9) && IsFrontEngine(dst_head)) |
928 return_cmd_error(STR_8819_TRAIN_TOO_LONG); |
1006 return_cmd_error(STR_8819_TRAIN_TOO_LONG); |
929 |
|
930 // if it's a multiheaded vehicle we're dragging to, drag to the vehicle before.. |
|
931 while (IS_CUSTOM_SECONDHEAD_SPRITE(dst->spritenum) || ( |
|
932 !is_custom_sprite(dst->spritenum) && _engine_sprite_add[dst->spritenum] != 0) |
|
933 ) { |
|
934 Vehicle *v = GetPrevVehicleInChain(dst); |
|
935 if (v == NULL || src == v) break; |
|
936 dst = v; |
|
937 } |
|
938 |
1007 |
939 assert(dst_head->tile == src_head->tile); |
1008 assert(dst_head->tile == src_head->tile); |
940 } |
1009 } |
941 |
1010 |
942 // when moving all wagons, we can't have the same src_head and dst_head |
1011 // when moving all wagons, we can't have the same src_head and dst_head |
943 if (HASBIT(p2, 0) && src_head == dst_head) return 0; |
1012 if (HASBIT(p2, 0) && src_head == dst_head) return 0; |
944 |
1013 |
945 // moving a loco to a new line?, then we need to assign a unitnumber. |
1014 // moving a loco to a new line?, then we need to assign a unitnumber. |
946 if (dst == NULL && src->subtype != TS_Front_Engine && is_loco) { |
1015 if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) { |
947 UnitID unit_num = GetFreeUnitNumber(VEH_Train); |
1016 UnitID unit_num = GetFreeUnitNumber(VEH_Train); |
948 if (unit_num > _patches.max_trains) |
1017 if (unit_num > _patches.max_trains) |
949 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
1018 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
950 |
1019 |
951 if (flags & DC_EXEC) |
1020 if (flags & DC_EXEC) |
975 src_head = UnlinkWagon(src, src_head); |
1049 src_head = UnlinkWagon(src, src_head); |
976 GetLastEnginePart(src)->next = NULL; |
1050 GetLastEnginePart(src)->next = NULL; |
977 } |
1051 } |
978 |
1052 |
979 if (dst == NULL) { |
1053 if (dst == NULL) { |
980 // move the train to an empty line. for locomotives, we set the type to 0. for wagons, 4. |
1054 // move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4. |
981 if (is_loco) { |
1055 if (IsTrainEngine(src)) { |
982 if (src->subtype != TS_Front_Engine) { |
1056 if (!IsFrontEngine(src)) { |
983 // setting the type to 0 also involves setting up the orders field. |
1057 // setting the type to 0 also involves setting up the orders field. |
984 src->subtype = TS_Front_Engine; |
1058 SetFrontEngine(src); |
985 assert(src->orders == NULL); |
1059 assert(src->orders == NULL); |
986 src->num_orders = 0; |
1060 src->num_orders = 0; |
987 } |
1061 } |
988 } else { |
1062 } else { |
989 src->subtype = TS_Free_Car; |
1063 SetFreeWagon(src); |
990 } |
1064 } |
991 dst_head = src; |
1065 dst_head = src; |
992 } else { |
1066 } else { |
993 if (src->subtype == TS_Front_Engine) { |
1067 if (IsFrontEngine(src)) { |
994 // the vehicle was previously a loco. need to free the order list and delete vehicle windows etc. |
1068 // the vehicle was previously a loco. need to free the order list and delete vehicle windows etc. |
995 DeleteWindowById(WC_VEHICLE_VIEW, src->index); |
1069 DeleteWindowById(WC_VEHICLE_VIEW, src->index); |
996 DeleteVehicleOrders(src); |
1070 DeleteVehicleOrders(src); |
997 } |
1071 } |
998 |
1072 |
999 src->subtype = TS_Not_First; |
1073 ClearFrontEngine(src); |
|
1074 ClearFreeWagon(src); |
1000 src->unitnumber = 0; // doesn't occupy a unitnumber anymore. |
1075 src->unitnumber = 0; // doesn't occupy a unitnumber anymore. |
1001 |
1076 |
1002 // link in the wagon(s) in the chain. |
1077 // link in the wagon(s) in the chain. |
1003 { |
1078 { |
1004 Vehicle *v; |
1079 Vehicle *v; |
1006 for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v)); |
1081 for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v)); |
1007 GetLastEnginePart(v)->next = dst->next; |
1082 GetLastEnginePart(v)->next = dst->next; |
1008 } |
1083 } |
1009 dst->next = src; |
1084 dst->next = src; |
1010 } |
1085 } |
|
1086 if (src->u.rail.other_multiheaded_part != NULL) { |
|
1087 if (src->u.rail.other_multiheaded_part == src_head) { |
|
1088 src_head = src_head->next; |
|
1089 } |
|
1090 AddWagonToConsist(src->u.rail.other_multiheaded_part, src); |
|
1091 } |
|
1092 |
|
1093 if (HASBIT(p2, 0) && src_head != NULL && src_head != src) { |
|
1094 /* if we stole a rear multiheaded engine, we better give it back to the front end */ |
|
1095 Vehicle *engine = NULL, *u; |
|
1096 for (u = src_head; u != NULL; u = u->next) { |
|
1097 if (IsMultiheaded(u)) { |
|
1098 if (IsTrainEngine(u)) { |
|
1099 engine = u; |
|
1100 continue; |
|
1101 } |
|
1102 /* we got the rear engine to match with the front one */ |
|
1103 engine = NULL; |
|
1104 } |
|
1105 } |
|
1106 if (engine != NULL && engine->u.rail.other_multiheaded_part != NULL) { |
|
1107 AddWagonToConsist(engine->u.rail.other_multiheaded_part, engine); |
|
1108 // previous line set the front engine to the old front. We need to clear that |
|
1109 engine->u.rail.other_multiheaded_part->first = NULL; |
|
1110 } |
|
1111 } |
1011 |
1112 |
1012 /* If there is an engine behind first_engine we moved away, it should become new first_engine |
1113 /* If there is an engine behind first_engine we moved away, it should become new first_engine |
1013 * To do this, CmdMoveRailVehicle must be called once more |
1114 * To do this, CmdMoveRailVehicle must be called once more |
1014 * since we set p2 to a condition that makes the statement false, we can't loop forever with this one */ |
1115 * we can't loop forever here because next time we reach this line we will have a front engine */ |
1015 if (make_new_front && new_front != NULL && !(HASBIT(p2, 0))) { |
1116 if (src_head != NULL && !IsFrontEngine(src_head) && IsTrainEngine(src_head)) { |
1016 if (!(RailVehInfo(new_front->engine_type)->flags & RVI_WAGON)) { |
1117 CmdMoveRailVehicle(x, y, flags, src_head->index | (INVALID_VEHICLE << 16), 1); |
1017 CmdMoveRailVehicle(x, y, flags, new_front->index | (INVALID_VEHICLE << 16), 1); |
1118 src_head = NULL; // don't do anything more to this train since the new call will do it |
1018 } |
|
1019 } |
1119 } |
1020 |
1120 |
1021 if (src_head) { |
1121 if (src_head) { |
|
1122 NormaliseTrainConsist(src_head); |
1022 TrainConsistChanged(src_head); |
1123 TrainConsistChanged(src_head); |
1023 if (src_head->subtype == TS_Front_Engine) { |
1124 if (IsFrontEngine(src_head)) { |
1024 UpdateTrainAcceleration(src_head); |
1125 UpdateTrainAcceleration(src_head); |
1025 InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index); |
1126 InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index); |
1026 /* Update the refit button and window */ |
1127 /* Update the refit button and window */ |
1027 InvalidateWindow(WC_VEHICLE_REFIT, src_head->index); |
1128 InvalidateWindow(WC_VEHICLE_REFIT, src_head->index); |
1028 InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, 12); |
1129 InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, 12); |
1030 /* Update the depot window */ |
1131 /* Update the depot window */ |
1031 InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile); |
1132 InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile); |
1032 }; |
1133 }; |
1033 |
1134 |
1034 if (dst_head) { |
1135 if (dst_head) { |
|
1136 NormaliseTrainConsist(dst_head); |
1035 TrainConsistChanged(dst_head); |
1137 TrainConsistChanged(dst_head); |
1036 if (dst_head->subtype == TS_Front_Engine) { |
1138 if (IsFrontEngine(dst_head)) { |
1037 UpdateTrainAcceleration(dst_head); |
1139 UpdateTrainAcceleration(dst_head); |
1038 InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index); |
1140 InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index); |
1039 /* Update the refit button and window */ |
1141 /* Update the refit button and window */ |
1040 InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, 12); |
1142 InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, 12); |
1041 InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index); |
1143 InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index); |
1070 v->vehstatus ^= VS_STOPPED; |
1172 v->vehstatus ^= VS_STOPPED; |
1071 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
1173 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
1072 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1174 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1073 } |
1175 } |
1074 return 0; |
1176 return 0; |
1075 } |
|
1076 |
|
1077 /** |
|
1078 * Search for a matching rear-engine of a dual-headed train. |
|
1079 * Do this as if you would find matching parentheses. If a new |
|
1080 * engine is 'started', first 'close' that before 'closing' our |
|
1081 * searched engine |
|
1082 */ |
|
1083 Vehicle* GetRearEngine(const Vehicle* v) |
|
1084 { |
|
1085 Vehicle *u; |
|
1086 int en_count = 1; |
|
1087 |
|
1088 for (u = v->next; u != NULL; u = u->next) { |
|
1089 if (u->engine_type == v->engine_type) { // find matching engine |
|
1090 en_count += (IS_FIRSTHEAD_SPRITE(u->spritenum)) ? +1 : -1; |
|
1091 |
|
1092 if (en_count == 0) return (Vehicle *)u; |
|
1093 } |
|
1094 } |
|
1095 return NULL; |
|
1096 } |
1177 } |
1097 |
1178 |
1098 /** Sell a (single) train wagon/engine. |
1179 /** Sell a (single) train wagon/engine. |
1099 * @param x,y unused |
1180 * @param x,y unused |
1100 * @param p1 the wagon/engine index |
1181 * @param p1 the wagon/engine index |
1106 * all wagons of the same type will go on the same line. Used by the AI currently |
1187 * all wagons of the same type will go on the same line. Used by the AI currently |
1107 */ |
1188 */ |
1108 int32 CmdSellRailWagon(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
1189 int32 CmdSellRailWagon(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
1109 { |
1190 { |
1110 Vehicle *v, *tmp, *first; |
1191 Vehicle *v, *tmp, *first; |
|
1192 Vehicle *new_f = NULL; |
1111 int32 cost = 0; |
1193 int32 cost = 0; |
1112 |
1194 |
1113 if (!IsVehicleIndex(p1) || p2 > 2) return CMD_ERROR; |
1195 if (!IsVehicleIndex(p1) || p2 > 2) return CMD_ERROR; |
1114 |
1196 |
1115 v = GetVehicle(p1); |
1197 v = GetVehicle(p1); |
1116 |
1198 |
1117 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1199 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1118 |
1200 |
1119 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1201 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1120 |
1202 |
1121 while (v->subtype == TS_Artic_Part) v = GetPrevVehicleInChain(v); |
1203 while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v); |
1122 first = GetFirstVehicleInChain(v); |
1204 first = GetFirstVehicleInChain(v); |
1123 |
1205 |
1124 // make sure the vehicle is stopped in the depot |
1206 // make sure the vehicle is stopped in the depot |
1125 if (CheckTrainStoppedInDepot(first) < 0) return CMD_ERROR; |
1207 if (CheckTrainStoppedInDepot(first) < 0) return CMD_ERROR; |
1126 |
1208 |
|
1209 if (IsMultiheaded(v) && !IsTrainEngine(v)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR); |
|
1210 |
1127 if (flags & DC_EXEC) { |
1211 if (flags & DC_EXEC) { |
1128 if (v == first && first->subtype == TS_Front_Engine) { |
1212 if (v == first && IsFrontEngine(first)) { |
1129 DeleteWindowById(WC_VEHICLE_VIEW, first->index); |
1213 DeleteWindowById(WC_VEHICLE_VIEW, first->index); |
1130 } |
1214 } |
1131 if (IsLocalPlayer() && (p1 == 1 || !(RailVehInfo(v->engine_type)->flags & RVI_WAGON))) { |
1215 if (IsLocalPlayer() && (p1 == 1 || !(RailVehInfo(v->engine_type)->flags & RVI_WAGON))) { |
1132 InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train); |
1216 InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train); |
1133 } |
1217 } |
1139 case 0: case 2: { /* Delete given wagon */ |
1223 case 0: case 2: { /* Delete given wagon */ |
1140 bool switch_engine = false; // update second wagon to engine? |
1224 bool switch_engine = false; // update second wagon to engine? |
1141 byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes |
1225 byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes |
1142 |
1226 |
1143 /* 1. Delete the engine, if it is dualheaded also delete the matching |
1227 /* 1. Delete the engine, if it is dualheaded also delete the matching |
1144 * rear engine of the loco (from the point of deletion onwards) */ |
1228 * rear engine of the loco (from the point of deletion onwards) */ |
1145 Vehicle* rear = (RailVehInfo(v->engine_type)->flags & RVI_MULTIHEAD) ? GetRearEngine(v) : NULL; |
1229 Vehicle *rear = (IsMultiheaded(v) && |
|
1230 IsTrainEngine(v)) ? v->u.rail.other_multiheaded_part : NULL; |
|
1231 |
1146 if (rear != NULL) { |
1232 if (rear != NULL) { |
1147 cost -= v->value; |
1233 cost -= rear->value; |
1148 if (flags & DC_EXEC) { |
1234 if (flags & DC_EXEC) { |
1149 v = UnlinkWagon(rear, v); |
1235 UnlinkWagon(rear, first); |
1150 DeleteVehicle(rear); |
1236 DeleteVehicle(rear); |
1151 } |
1237 } |
1152 } |
1238 } |
1153 |
1239 |
1154 /* 2. We are selling the first engine, some special action might be required |
1240 /* 2. We are selling the first engine, some special action might be required |
1155 * here, so take attention */ |
1241 * here, so take attention */ |
1156 if ((flags & DC_EXEC) && v == first) { |
1242 if ((flags & DC_EXEC) && v == first) { |
1157 Vehicle *new_f = GetNextVehicle(first); |
1243 new_f = GetNextVehicle(first); |
1158 |
1244 |
1159 /* 2.1 If the first wagon is sold, update the first-> pointers to NULL */ |
1245 /* 2.1 If the first wagon is sold, update the first-> pointers to NULL */ |
1160 for (tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL; |
1246 for (tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL; |
1161 |
1247 |
1162 /* 2.2 If there are wagons present after the deleted front engine, check |
1248 /* 2.2 If there are wagons present after the deleted front engine, check |
1163 * if the second wagon (which will be first) is an engine. If it is one, |
1249 * if the second wagon (which will be first) is an engine. If it is one, |
1164 * promote it as a new train, retaining the unitnumber, orders */ |
1250 * promote it as a new train, retaining the unitnumber, orders */ |
1165 if (new_f != NULL) { |
1251 if (new_f != NULL) { |
1166 if (!(RailVehInfo(new_f->engine_type)->flags & RVI_WAGON) && IS_FIRSTHEAD_SPRITE(new_f->spritenum)) { |
1252 if (IsTrainEngine(new_f)) { |
1167 switch_engine = true; |
1253 switch_engine = true; |
1168 /* Copy important data from the front engine */ |
1254 /* Copy important data from the front engine */ |
1169 new_f->unitnumber = first->unitnumber; |
1255 new_f->unitnumber = first->unitnumber; |
1170 new_f->current_order = first->current_order; |
1256 new_f->current_order = first->current_order; |
1171 new_f->cur_order_index = first->cur_order_index; |
1257 new_f->cur_order_index = first->cur_order_index; |
1183 first = UnlinkWagon(v, first); |
1269 first = UnlinkWagon(v, first); |
1184 DeleteVehicle(v); |
1270 DeleteVehicle(v); |
1185 |
1271 |
1186 /* 4 If the second wagon was an engine, update it to front_engine |
1272 /* 4 If the second wagon was an engine, update it to front_engine |
1187 * which UnlinkWagon() has changed to TS_Free_Car */ |
1273 * which UnlinkWagon() has changed to TS_Free_Car */ |
1188 if (switch_engine) first->subtype = TS_Front_Engine; |
1274 if (switch_engine) SetFrontEngine(first); |
1189 |
1275 |
1190 /* 5. If the train still exists, update its acceleration, window, etc. */ |
1276 /* 5. If the train still exists, update its acceleration, window, etc. */ |
1191 if (first != NULL) { |
1277 if (first != NULL) { |
|
1278 NormaliseTrainConsist(first); |
1192 TrainConsistChanged(first); |
1279 TrainConsistChanged(first); |
1193 if (first->subtype == TS_Front_Engine) { |
1280 if (IsFrontEngine(first)) { |
1194 InvalidateWindow(WC_VEHICLE_DETAILS, first->index); |
1281 InvalidateWindow(WC_VEHICLE_DETAILS, first->index); |
1195 InvalidateWindow(WC_VEHICLE_REFIT, first->index); |
1282 InvalidateWindow(WC_VEHICLE_REFIT, first->index); |
1196 UpdateTrainAcceleration(first); |
1283 UpdateTrainAcceleration(first); |
1197 } |
1284 } |
1198 } |
1285 } |
1199 |
1286 |
1200 |
1287 |
1201 /* (6.) Borked AI. If it sells an engine it expects all wagons lined |
1288 /* (6.) Borked AI. If it sells an engine it expects all wagons lined |
1202 * up on a new line to be added to the newly built loco. Replace it is. |
1289 * up on a new line to be added to the newly built loco. Replace it is. |
1203 * Totally braindead cause building a new engine adds all loco-less |
1290 * Totally braindead cause building a new engine adds all loco-less |
1204 * engines to its train anyways */ |
1291 * engines to its train anyways */ |
1205 if (p2 == 2 && ori_subtype == TS_Front_Engine) { |
1292 if (p2 == 2 && HASBIT(ori_subtype, Train_Front)) { |
1206 for (v = first; v != NULL; v = tmp) { |
1293 for (v = first; v != NULL; v = tmp) { |
1207 tmp = GetNextVehicle(v); |
1294 tmp = GetNextVehicle(v); |
1208 DoCommandByTile(v->tile, v->index | INVALID_VEHICLE << 16, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
1295 DoCommandByTile(v->tile, v->index | INVALID_VEHICLE << 16, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
1209 } |
1296 } |
1210 } |
1297 } |
1211 } |
1298 } |
1212 } break; |
1299 } break; |
1213 case 1: { /* Delete wagon and all wagons after it given certain criteria */ |
1300 case 1: { /* Delete wagon and all wagons after it given certain criteria */ |
1214 /* 1. Count the number for first and rear engines for dualheads |
1301 /* Start deleting every vehicle after the selected one |
1215 * to be able to deduce which ones go with which ones */ |
1302 * If we encounter a matching rear-engine to a front-engine |
1216 int enf_count = 0; |
1303 * earlier in the chain (before deletion), leave it alone */ |
1217 int enr_count = 0; |
|
1218 for (tmp = first; tmp != NULL; tmp = GetNextVehicle(tmp)) { |
|
1219 if (RailVehInfo(tmp->engine_type)->flags & RVI_MULTIHEAD) |
|
1220 (IS_FIRSTHEAD_SPRITE(tmp->spritenum)) ? enf_count++ : enr_count++; |
|
1221 } |
|
1222 |
|
1223 /* 2. Start deleting every vehicle after the selected one |
|
1224 * If we encounter a matching rear-engine to a front-engine |
|
1225 * earlier in the chain (before deletion), leave it alone */ |
|
1226 for (; v != NULL; v = tmp) { |
1304 for (; v != NULL; v = tmp) { |
1227 tmp = GetNextVehicle(v); |
1305 tmp = GetNextVehicle(v); |
1228 |
1306 |
1229 if (RailVehInfo(v->engine_type)->flags & RVI_MULTIHEAD) { |
1307 if (IsMultiheaded(v)) { |
1230 if (IS_FIRSTHEAD_SPRITE(v->spritenum)) { |
1308 if (IsTrainEngine(v)) { |
1231 /* Always delete newly encountered front-engines */ |
1309 /* We got a front engine of a multiheaded set. Now we will sell the rear end too */ |
1232 enf_count--; |
1310 Vehicle *rear = v->u.rail.other_multiheaded_part; |
1233 } else if (enr_count > enf_count) { |
1311 |
1234 /* More rear engines than front engines means this rear-engine does |
1312 if (rear != NULL) { |
1235 * not belong to any front-engine; delete */ |
1313 cost -= rear->value; |
1236 enr_count--; |
1314 if (flags & DC_EXEC) { |
1237 } else { |
1315 first = UnlinkWagon(rear, first); |
1238 /* Otherwise leave it alone */ |
1316 DeleteVehicle(rear); |
|
1317 } |
|
1318 } |
|
1319 } else if (v->u.rail.other_multiheaded_part != NULL) { |
|
1320 /* The front to this engine is earlier in this train. Do nothing */ |
1239 continue; |
1321 continue; |
1240 } |
1322 } |
1241 } |
1323 } |
1242 |
1324 |
1243 cost -= v->value; |
1325 cost -= v->value; |
2618 |
2703 |
2619 case MP_STREET: |
2704 case MP_STREET: |
2620 // tracks over roads, do owner check of tracks |
2705 // tracks over roads, do owner check of tracks |
2621 return |
2706 return |
2622 IsTileOwner(tile, v->owner) && ( |
2707 IsTileOwner(tile, v->owner) && ( |
2623 v->subtype != TS_Front_Engine || |
2708 !IsFrontEngine(v) || |
2624 IsCompatibleRail(v->u.rail.railtype, GB(_m[tile].m4, 0, 4)) |
2709 IsCompatibleRail(v->u.rail.railtype, GB(_m[tile].m4, 0, 4)) |
2625 ); |
2710 ); |
2626 |
2711 |
2627 default: |
2712 default: |
2628 return true; |
2713 return true; |
2629 } |
2714 } |
2630 |
2715 |
2631 return |
2716 return |
2632 IsTileOwner(tile, v->owner) && ( |
2717 IsTileOwner(tile, v->owner) && ( |
2633 v->subtype != TS_Front_Engine || |
2718 !IsFrontEngine(v) || |
2634 IsCompatibleRail(v->u.rail.railtype, GetRailType(tile)) |
2719 IsCompatibleRail(v->u.rail.railtype, GetRailType(tile)) |
2635 ); |
2720 ); |
2636 } |
2721 } |
2637 |
2722 |
2638 typedef struct { |
2723 typedef struct { |
2776 if (!(coll->vehstatus & VS_CRASHED)) |
2861 if (!(coll->vehstatus & VS_CRASHED)) |
2777 //two drivers + passangers killed in train coll (if it was not crashed already) |
2862 //two drivers + passangers killed in train coll (if it was not crashed already) |
2778 num += 2 + CountPassengersInTrain(coll); |
2863 num += 2 + CountPassengersInTrain(coll); |
2779 |
2864 |
2780 SetVehicleCrashed(v); |
2865 SetVehicleCrashed(v); |
2781 if (coll->subtype == TS_Front_Engine) SetVehicleCrashed(coll); |
2866 if (IsFrontEngine(coll)) SetVehicleCrashed(coll); |
2782 |
2867 |
2783 SetDParam(0, num); |
2868 SetDParam(0, num); |
2784 AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL, |
2869 AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL, |
2785 NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0), |
2870 NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0), |
2786 v->index, |
2871 v->index, |
2968 if (r&0x8){ |
3053 if (r&0x8){ |
2969 //debug("%x & 0x8", r); |
3054 //debug("%x & 0x8", r); |
2970 goto invalid_rail; |
3055 goto invalid_rail; |
2971 } |
3056 } |
2972 |
3057 |
2973 if (v->subtype == TS_Front_Engine) v->load_unload_time_rem = 0; |
3058 if (IsFrontEngine(v)) v->load_unload_time_rem = 0; |
2974 |
3059 |
2975 if (!(r&0x4)) { |
3060 if (!(r&0x4)) { |
2976 v->tile = gp.new_tile; |
3061 v->tile = gp.new_tile; |
2977 v->u.rail.track = chosen_track; |
3062 v->u.rail.track = chosen_track; |
2978 assert(v->u.rail.track); |
3063 assert(v->u.rail.track); |
2979 } |
3064 } |
2980 |
3065 |
2981 if (v->subtype == TS_Front_Engine) |
3066 if (IsFrontEngine(v)) |
2982 TrainMovedChangeSignals(gp.new_tile, enterdir); |
3067 TrainMovedChangeSignals(gp.new_tile, enterdir); |
2983 |
3068 |
2984 /* Signals can only change when the first |
3069 /* Signals can only change when the first |
2985 * (above) or the last vehicle moves. */ |
3070 * (above) or the last vehicle moves. */ |
2986 if (v->next == NULL) |
3071 if (v->next == NULL) |
3431 if (_age_cargo_skip_counter == 0 && v->cargo_days != 0xff) |
3516 if (_age_cargo_skip_counter == 0 && v->cargo_days != 0xff) |
3432 v->cargo_days++; |
3517 v->cargo_days++; |
3433 |
3518 |
3434 v->tick_counter++; |
3519 v->tick_counter++; |
3435 |
3520 |
3436 if (v->subtype == TS_Front_Engine) { |
3521 if (IsFrontEngine(v)) { |
3437 TrainLocoHandler(v, false); |
3522 TrainLocoHandler(v, false); |
3438 |
3523 |
3439 // make sure vehicle wasn't deleted. |
3524 // make sure vehicle wasn't deleted. |
3440 if (v->type == VEH_Train && v->subtype == TS_Front_Engine) |
3525 if (v->type == VEH_Train && IsFrontEngine(v)) |
3441 TrainLocoHandler(v, true); |
3526 TrainLocoHandler(v, true); |
3442 } else if (v->subtype == TS_Free_Car && HASBITS(v->vehstatus, VS_CRASHED)) { |
3527 } else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) { |
3443 // Delete flooded standalone wagon |
3528 // Delete flooded standalone wagon |
3444 if (++v->u.rail.crash_anim_pos >= 4400) |
3529 if (++v->u.rail.crash_anim_pos >= 4400) |
3445 DeleteVehicle(v); |
3530 DeleteVehicle(v); |
3446 } |
3531 } |
3447 } |
3532 } |