train_cmd.c
branchcustombridgeheads
changeset 5630 abc40525bd50
parent 5622 2f0cb276d32a
child 5637 30d8850ae4fe
equal deleted inserted replaced
5629:7cb2c58f4a7c 5630:abc40525bd50
  3027 	byte chosen_track;
  3027 	byte chosen_track;
  3028 	byte old_z;
  3028 	byte old_z;
  3029 
  3029 
  3030 	/* For every vehicle after and including the given vehicle */
  3030 	/* For every vehicle after and including the given vehicle */
  3031 	for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) {
  3031 	for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) {
       
  3032 
       
  3033 		bool in_tunnel_or_bridge = (v->u.rail.track == 0x40);
       
  3034 		bool entering_new_tile;
       
  3035 
  3032 		BeginVehicleMove(v);
  3036 		BeginVehicleMove(v);
  3033 
  3037 
  3034 		if (v->u.rail.track != 0x40) {
  3038 		entering_new_tile = !GetNewVehiclePos(v, &gp);
       
  3039 
       
  3040 		if (in_tunnel_or_bridge) {
       
  3041 			uint32 res;
       
  3042 			/* in tunnel or on a bridge */
       
  3043 
       
  3044 			SetSpeedLimitOnBridge(v);
       
  3045 
       
  3046 			if (!(IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) || !((res = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y)) & 0x4)) {
       
  3047 				/* stay in tunnel/bridge wormhole */
       
  3048 				v->x_pos = gp.x;
       
  3049 				v->y_pos = gp.y;
       
  3050 				VehiclePositionChanged(v);
       
  3051 				if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
       
  3052 				continue;
       
  3053 			}
       
  3054 			/* left tunnel/bridge wormhole */
       
  3055 			dir = v->direction;
       
  3056 			enterdir = INVALID_DIAGDIR;
       
  3057 			if (IsBridgeTile(gp.new_tile) && res & 0x4) {
       
  3058 				/* ok we have just left the bridge (because the status was "onbridge" before and we got
       
  3059 				a return value of 4 from VehicleEnterTile. we know the enterdir from the bridge ramp
       
  3060 				direction, and act as if we entered the tile normally (hence the goto) */
       
  3061 				dir = v->direction;
       
  3062 				enterdir = ReverseDiagDir(GetBridgeRampDirection(gp.new_tile));
       
  3063 				in_tunnel_or_bridge = false;
       
  3064 			}
       
  3065 		} else {
  3035 			/* Not inside tunnel */
  3066 			/* Not inside tunnel */
  3036 			if (GetNewVehiclePos(v, &gp)) {
  3067 			if (!entering_new_tile) {
  3037 				/* Staying in the old tile */
  3068 				/* Staying in the old tile */
  3038 				if (v->u.rail.track == 0x80) {
  3069 				if (v->u.rail.track == 0x80) {
  3039 					/* inside depot */
  3070 					/* inside depot */
  3040 					gp.x = v->x_pos;
  3071 					gp.x = v->x_pos;
  3041 					gp.y = v->y_pos;
  3072 					gp.y = v->y_pos;
  3059 						v->current_order.flags = 0;
  3090 						v->current_order.flags = 0;
  3060 						InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
  3091 						InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
  3061 					}
  3092 					}
  3062 				}
  3093 				}
  3063 			} else {
  3094 			} else {
  3064 				/* A new tile is about to be entered. */
  3095 				/* A new tile is about to be entered normally (not from bridge wormhole to ramp) */
  3065 
       
  3066 				byte bits;
       
  3067 				/* Determine what direction we're entering the new tile from */
  3096 				/* Determine what direction we're entering the new tile from */
  3068 				dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile);
  3097 				dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile);
  3069 				enterdir = DirToDiagDir(dir);
  3098 				enterdir = DirToDiagDir(dir);
  3070 				assert(enterdir==0 || enterdir==1 || enterdir==2 || enterdir==3);
  3099 				assert(enterdir==0 || enterdir==1 || enterdir==2 || enterdir==3);
  3071 new_tile:
  3100 			}
  3072 
  3101 		}
  3073 				/* Get the status of the tracks in the new tile and mask
  3102 		if (entering_new_tile && !in_tunnel_or_bridge) {
  3074 				 * away the bits that aren't reachable. */
  3103 			/* A new tile is about to be entered. */
  3075 				ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL) & _reachable_tracks[enterdir];
  3104 			byte bits;
  3076 
  3105 
  3077 				/* Combine the from & to directions.
  3106 			/* Get the status of the tracks in the new tile and mask
  3078 				 * Now, the lower byte contains the track status, and the byte at bit 16 contains
  3107 			 * away the bits that aren't reachable. */
  3079 				 * the signal status. */
  3108 			ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL) & _reachable_tracks[enterdir];
  3080 				tracks = ts | (ts >> 8);
  3109 
  3081 				bits = tracks & 0xFF;
  3110 			/* Combine the from & to directions.
  3082 				if ((_patches.new_pathfinding_all || _patches.yapf.rail_use_yapf) && _patches.forbid_90_deg && prev == NULL) {
  3111 			 * Now, the lower byte contains the track status, and the byte at bit 16 contains
  3083 					/* We allow wagons to make 90 deg turns, because forbid_90_deg
  3112 			 * the signal status. */
  3084 					 * can be switched on halfway a turn */
  3113 			tracks = ts | (ts >> 8);
  3085 					bits &= ~TrackCrossesTracks(FIND_FIRST_BIT(v->u.rail.track));
  3114 			bits = tracks & 0xFF;
       
  3115 			if ((_patches.new_pathfinding_all || _patches.yapf.rail_use_yapf) && _patches.forbid_90_deg && prev == NULL) {
       
  3116 				/* We allow wagons to make 90 deg turns, because forbid_90_deg
       
  3117 				 * can be switched on halfway a turn */
       
  3118 				bits &= ~TrackCrossesTracks(FIND_FIRST_BIT(v->u.rail.track));
       
  3119 			}
       
  3120 
       
  3121 			if (bits == 0) {
       
  3122 				DEBUG(misc, 2, "%x == 0", bits);
       
  3123 				goto invalid_rail;
       
  3124 			}
       
  3125 
       
  3126 			/* Check if the new tile contrains tracks that are compatible
       
  3127 			 * with the current train, if not, bail out. */
       
  3128 			if (!CheckCompatibleRail(v, gp.new_tile)) {
       
  3129 				DEBUG(misc, 2, "!CheckCompatibleRail(%p, %x)", v, gp.new_tile);
       
  3130 				goto invalid_rail;
       
  3131 			}
       
  3132 
       
  3133 			if (prev == NULL) {
       
  3134 				/* Currently the locomotive is active. Determine which one of the
       
  3135 				 * available tracks to choose */
       
  3136 				chosen_track = 1 << ChooseTrainTrack(v, gp.new_tile, enterdir, bits);
       
  3137 				assert(chosen_track & tracks);
       
  3138 
       
  3139 				/* Check if it's a red signal and that force proceed is not clicked. */
       
  3140 				if ( (tracks>>16)&chosen_track && v->u.rail.force_proceed == 0) goto red_light;
       
  3141 			} else {
       
  3142 				static byte _matching_tracks[8] = {0x30, 1, 0xC, 2, 0x30, 1, 0xC, 2};
       
  3143 
       
  3144 				/* The wagon is active, simply follow the prev vehicle. */
       
  3145 				chosen_track = (byte)(_matching_tracks[GetDirectionToVehicle(prev, gp.x, gp.y)] & bits);
       
  3146 			}
       
  3147 
       
  3148 			/* make sure chosen track is a valid track */
       
  3149 			assert(chosen_track==1 || chosen_track==2 || chosen_track==4 || chosen_track==8 || chosen_track==16 || chosen_track==32);
       
  3150 
       
  3151 			/* Update XY to reflect the entrance to the new tile, and select the direction to use */
       
  3152 			{
       
  3153 				const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir];
       
  3154 				gp.x = (gp.x & ~0xF) | b[0];
       
  3155 				gp.y = (gp.y & ~0xF) | b[1];
       
  3156 				chosen_dir = b[2];
       
  3157 			}
       
  3158 
       
  3159 			/* Call the landscape function and tell it that the vehicle entered the tile */
       
  3160 			r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
       
  3161 			if (r & 0x8) {
       
  3162 				DEBUG(misc, 2, "%x & 0x8 (new tile)", r);
       
  3163 				goto invalid_rail;
       
  3164 			}
       
  3165 
       
  3166 			if (IsLevelCrossingTile(v->tile) && v->next == NULL) {
       
  3167 				UnbarCrossing(v->tile);
       
  3168 				MarkTileDirtyByTile(v->tile);
       
  3169 			}
       
  3170 
       
  3171 			if (IsFrontEngine(v)) v->load_unload_time_rem = 0;
       
  3172 
       
  3173 			if (!(r&0x4)) {
       
  3174 				v->tile = gp.new_tile;
       
  3175 
       
  3176 				if (GetTileRailType(gp.new_tile, chosen_track) != GetTileRailType(gp.old_tile, v->u.rail.track)) {
       
  3177 					TrainPowerChanged(GetFirstVehicleInChain(v));
  3086 				}
  3178 				}
  3087 
  3179 
  3088 				if (bits == 0) {
  3180 				v->u.rail.track = chosen_track;
  3089 					DEBUG(misc, 2, "%x == 0", bits);
  3181 				assert(v->u.rail.track);
  3090 					goto invalid_rail;
  3182 			}
  3091 				}
  3183 
  3092 
  3184 			if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir);
  3093 				/* Check if the new tile contrains tracks that are compatible
  3185 
  3094 				 * with the current train, if not, bail out. */
  3186 			/* Signals can only change when the first
  3095 				if (!CheckCompatibleRail(v, gp.new_tile)) {
  3187 			 * (above) or the last vehicle moves. */
  3096 					DEBUG(misc, 2, "!CheckCompatibleRail(%p, %x)", v, gp.new_tile);
  3188 			if (v->next == NULL)
  3097 					goto invalid_rail;
  3189 				TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
  3098 				}
  3190 
  3099 
  3191 			if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir);
  3100 				if (prev == NULL) {
  3192 
  3101 					/* Currently the locomotive is active. Determine which one of the
  3193 			v->direction = chosen_dir;
  3102 					 * available tracks to choose */
       
  3103 					chosen_track = 1 << ChooseTrainTrack(v, gp.new_tile, enterdir, bits);
       
  3104 					assert(chosen_track & tracks);
       
  3105 
       
  3106 					/* Check if it's a red signal and that force proceed is not clicked. */
       
  3107 					if ( (tracks>>16)&chosen_track && v->u.rail.force_proceed == 0) goto red_light;
       
  3108 				} else {
       
  3109 					static byte _matching_tracks[8] = {0x30, 1, 0xC, 2, 0x30, 1, 0xC, 2};
       
  3110 
       
  3111 					/* The wagon is active, simply follow the prev vehicle. */
       
  3112 					chosen_track = (byte)(_matching_tracks[GetDirectionToVehicle(prev, gp.x, gp.y)] & bits);
       
  3113 				}
       
  3114 
       
  3115 				/* make sure chosen track is a valid track */
       
  3116 				assert(chosen_track==1 || chosen_track==2 || chosen_track==4 || chosen_track==8 || chosen_track==16 || chosen_track==32);
       
  3117 
       
  3118 				/* Update XY to reflect the entrance to the new tile, and select the direction to use */
       
  3119 				{
       
  3120 					const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir];
       
  3121 					gp.x = (gp.x & ~0xF) | b[0];
       
  3122 					gp.y = (gp.y & ~0xF) | b[1];
       
  3123 					chosen_dir = b[2];
       
  3124 				}
       
  3125 
       
  3126 				/* Call the landscape function and tell it that the vehicle entered the tile */
       
  3127 				r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
       
  3128 				if (r & 0x8) {
       
  3129 					DEBUG(misc, 2, "%x & 0x8 (new tile)", r);
       
  3130 					goto invalid_rail;
       
  3131 				}
       
  3132 
       
  3133 				if (IsLevelCrossingTile(v->tile) && v->next == NULL) {
       
  3134 					UnbarCrossing(v->tile);
       
  3135 					MarkTileDirtyByTile(v->tile);
       
  3136 				}
       
  3137 
       
  3138 				if (IsFrontEngine(v)) v->load_unload_time_rem = 0;
       
  3139 
       
  3140 				if (!(r&0x4)) {
       
  3141 					v->tile = gp.new_tile;
       
  3142 
       
  3143 					if (GetTileRailType(gp.new_tile, chosen_track) != GetTileRailType(gp.old_tile, v->u.rail.track)) {
       
  3144 						TrainPowerChanged(GetFirstVehicleInChain(v));
       
  3145 					}
       
  3146 
       
  3147 					v->u.rail.track = chosen_track;
       
  3148 					assert(v->u.rail.track);
       
  3149 				}
       
  3150 
       
  3151 				if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir);
       
  3152 
       
  3153 				/* Signals can only change when the first
       
  3154 				 * (above) or the last vehicle moves. */
       
  3155 				if (v->next == NULL)
       
  3156 					TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
       
  3157 
       
  3158 				if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir);
       
  3159 
       
  3160 				v->direction = chosen_dir;
       
  3161 			}
       
  3162 		} else {
       
  3163 			uint32 res;
       
  3164 			/* in tunnel on on a bridge */
       
  3165 			GetNewVehiclePos(v, &gp);
       
  3166 
       
  3167 			SetSpeedLimitOnBridge(v);
       
  3168 
       
  3169 			if (!(IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) || !((res = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y)) & 0x4)) {
       
  3170 				v->x_pos = gp.x;
       
  3171 				v->y_pos = gp.y;
       
  3172 				VehiclePositionChanged(v);
       
  3173 				if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
       
  3174 				continue;
       
  3175 			}
       
  3176 
       
  3177 			if (IsBridgeTile(gp.new_tile) && res & 0x4) {
       
  3178 				/* ok we have just left the bridge (because the status was "onbridge" before and we got
       
  3179 				   a return value of 4 from VehicleEnterTile. we know the enterdir from the bridge ramp
       
  3180 				   direction, and act as if we entered the tile normally (hence the goto) */
       
  3181 				enterdir = ReverseDiagDir(GetBridgeRampDirection(gp.new_tile));
       
  3182 				goto new_tile;
       
  3183 			}
       
  3184 		}
  3194 		}
  3185 
  3195 
  3186 		/* update image of train, as well as delta XY */
  3196 		/* update image of train, as well as delta XY */
  3187 		newdir = GetNewVehicleDirection(v, gp.x, gp.y);
  3197 		newdir = GetNewVehicleDirection(v, gp.x, gp.y);
  3188 		UpdateTrainDeltaXY(v, newdir);
  3198 		UpdateTrainDeltaXY(v, newdir);