src/ship_cmd.cpp
branchcustombridgeheads
changeset 5649 55c8267c933f
parent 5643 3778051e8095
child 5650 aefc131bf5ce
equal deleted inserted replaced
5648:1608018c5ff2 5649:55c8267c933f
       
     1 /* $Id$ */
       
     2 
       
     3 #include "stdafx.h"
       
     4 #include "openttd.h"
       
     5 #include "ship.h"
       
     6 #include "table/strings.h"
       
     7 #include "functions.h"
       
     8 #include "map.h"
       
     9 #include "tile.h"
       
    10 #include "vehicle.h"
       
    11 #include "command.h"
       
    12 #include "pathfind.h"
       
    13 #include "station_map.h"
       
    14 #include "station.h"
       
    15 #include "news.h"
       
    16 #include "engine.h"
       
    17 #include "player.h"
       
    18 #include "sound.h"
       
    19 #include "npf.h"
       
    20 #include "depot.h"
       
    21 #include "vehicle_gui.h"
       
    22 #include "newgrf_engine.h"
       
    23 #include "water_map.h"
       
    24 #include "yapf/yapf.h"
       
    25 #include "debug.h"
       
    26 #include "newgrf_callbacks.h"
       
    27 #include "newgrf_text.h"
       
    28 #include "newgrf_sound.h"
       
    29 #include "date.h"
       
    30 
       
    31 static const uint16 _ship_sprites[] = {0x0E5D, 0x0E55, 0x0E65, 0x0E6D};
       
    32 static const byte _ship_sometracks[4] = {0x19, 0x16, 0x25, 0x2A};
       
    33 
       
    34 static byte GetTileShipTrackStatus(TileIndex tile)
       
    35 {
       
    36 	uint32 r = GetTileTrackStatus(tile, TRANSPORT_WATER);
       
    37 	return r | r >> 8;
       
    38 }
       
    39 
       
    40 void DrawShipEngine(int x, int y, EngineID engine, uint32 image_ormod)
       
    41 {
       
    42 	int spritenum = ShipVehInfo(engine)->image_index;
       
    43 
       
    44 	if (is_custom_sprite(spritenum)) {
       
    45 		int sprite = GetCustomVehicleIcon(engine, DIR_W);
       
    46 
       
    47 		if (sprite != 0) {
       
    48 			DrawSprite(sprite | image_ormod, x, y);
       
    49 			return;
       
    50 		}
       
    51 		spritenum = orig_ship_vehicle_info[engine - SHIP_ENGINES_INDEX].image_index;
       
    52 	}
       
    53 	DrawSprite((6 + _ship_sprites[spritenum]) | image_ormod, x, y);
       
    54 }
       
    55 
       
    56 int GetShipImage(const Vehicle* v, Direction direction)
       
    57 {
       
    58 	int spritenum = v->spritenum;
       
    59 
       
    60 	if (is_custom_sprite(spritenum)) {
       
    61 		int sprite = GetCustomVehicleSprite(v, direction);
       
    62 
       
    63 		if (sprite != 0) return sprite;
       
    64 		spritenum = orig_ship_vehicle_info[v->engine_type - SHIP_ENGINES_INDEX].image_index;
       
    65 	}
       
    66 	return _ship_sprites[spritenum] + direction;
       
    67 }
       
    68 
       
    69 static const Depot* FindClosestShipDepot(const Vehicle* v)
       
    70 {
       
    71 	const Depot* depot;
       
    72 	const Depot* best_depot = NULL;
       
    73 	uint dist;
       
    74 	uint best_dist = (uint)-1;
       
    75 	TileIndex tile;
       
    76 	TileIndex tile2 = v->tile;
       
    77 
       
    78 	if (_patches.new_pathfinding_all) {
       
    79 		NPFFoundTargetData ftd;
       
    80 		byte trackdir = GetVehicleTrackdir(v);
       
    81 		ftd = NPFRouteToDepotTrialError(v->tile, trackdir, TRANSPORT_WATER, v->owner, INVALID_RAILTYPE);
       
    82 		if (ftd.best_bird_dist == 0) {
       
    83 			best_depot = GetDepotByTile(ftd.node.tile); /* Found target */
       
    84 		} else {
       
    85 			best_depot = NULL; /* Did not find target */
       
    86 		}
       
    87 	} else {
       
    88 		FOR_ALL_DEPOTS(depot) {
       
    89 			tile = depot->xy;
       
    90 			if (IsTileDepotType(tile, TRANSPORT_WATER) && IsTileOwner(tile, v->owner)) {
       
    91 				dist = DistanceManhattan(tile, tile2);
       
    92 				if (dist < best_dist) {
       
    93 					best_dist = dist;
       
    94 					best_depot = depot;
       
    95 				}
       
    96 			}
       
    97 		}
       
    98 	}
       
    99 	return best_depot;
       
   100 }
       
   101 
       
   102 static void CheckIfShipNeedsService(Vehicle *v)
       
   103 {
       
   104 	const Depot* depot;
       
   105 
       
   106 	if (_patches.servint_ships == 0) return;
       
   107 	if (!VehicleNeedsService(v))     return;
       
   108 	if (v->vehstatus & VS_STOPPED)   return;
       
   109 
       
   110 	if (v->current_order.type == OT_GOTO_DEPOT &&
       
   111 			v->current_order.flags & OF_HALT_IN_DEPOT)
       
   112 		return;
       
   113 
       
   114 	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
       
   115 
       
   116 	if (IsShipInDepot(v)) {
       
   117 		VehicleServiceInDepot(v);
       
   118 		return;
       
   119 	}
       
   120 
       
   121 	depot = FindClosestShipDepot(v);
       
   122 
       
   123 	if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) {
       
   124 		if (v->current_order.type == OT_GOTO_DEPOT) {
       
   125 			v->current_order.type = OT_DUMMY;
       
   126 			v->current_order.flags = 0;
       
   127 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
   128 		}
       
   129 		return;
       
   130 	}
       
   131 
       
   132 	v->current_order.type = OT_GOTO_DEPOT;
       
   133 	v->current_order.flags = OF_NON_STOP;
       
   134 	v->current_order.dest = depot->index;
       
   135 	v->dest_tile = depot->xy;
       
   136 	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
   137 }
       
   138 
       
   139 void OnNewDay_Ship(Vehicle *v)
       
   140 {
       
   141 	int32 cost;
       
   142 
       
   143 	if ((++v->day_counter & 7) == 0)
       
   144 		DecreaseVehicleValue(v);
       
   145 
       
   146 	CheckVehicleBreakdown(v);
       
   147 	AgeVehicle(v);
       
   148 	CheckIfShipNeedsService(v);
       
   149 
       
   150 	CheckOrders(v);
       
   151 
       
   152 	if (v->vehstatus & VS_STOPPED) return;
       
   153 
       
   154 	cost = ShipVehInfo(v->engine_type)->running_cost * _price.ship_running / 364;
       
   155 	v->profit_this_year -= cost >> 8;
       
   156 
       
   157 	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
       
   158 	SubtractMoneyFromPlayerFract(v->owner, cost);
       
   159 
       
   160 	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
   161 	//we need this for the profit
       
   162 	InvalidateWindowClasses(WC_SHIPS_LIST);
       
   163 }
       
   164 
       
   165 static void HandleBrokenShip(Vehicle *v)
       
   166 {
       
   167 	if (v->breakdown_ctr != 1) {
       
   168 		v->breakdown_ctr = 1;
       
   169 		v->cur_speed = 0;
       
   170 
       
   171 		if (v->breakdowns_since_last_service != 255)
       
   172 			v->breakdowns_since_last_service++;
       
   173 
       
   174 		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
       
   175 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
   176 
       
   177 		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
       
   178 			SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
       
   179 				SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
       
   180 		}
       
   181 
       
   182 		if (!(v->vehstatus & VS_HIDDEN)) {
       
   183 			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
       
   184 			if (u != NULL) u->u.special.unk0 = v->breakdown_delay * 2;
       
   185 		}
       
   186 	}
       
   187 
       
   188 	if (!(v->tick_counter & 1)) {
       
   189 		if (!--v->breakdown_delay) {
       
   190 			v->breakdown_ctr = 0;
       
   191 			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
       
   192 		}
       
   193 	}
       
   194 }
       
   195 
       
   196 static void MarkShipDirty(Vehicle *v)
       
   197 {
       
   198 	v->cur_image = GetShipImage(v, v->direction);
       
   199 	MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
       
   200 }
       
   201 
       
   202 static void PlayShipSound(Vehicle *v)
       
   203 {
       
   204 	if (!PlayVehicleSound(v, VSE_START)) {
       
   205 		SndPlayVehicleFx(ShipVehInfo(v->engine_type)->sfx, v);
       
   206 	}
       
   207 }
       
   208 
       
   209 static void ProcessShipOrder(Vehicle *v)
       
   210 {
       
   211 	const Order *order;
       
   212 
       
   213 	switch (v->current_order.type) {
       
   214 		case OT_GOTO_DEPOT:
       
   215 			if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return;
       
   216 			if (v->current_order.flags & OF_SERVICE_IF_NEEDED &&
       
   217 					!VehicleNeedsService(v)) {
       
   218 				v->cur_order_index++;
       
   219 			}
       
   220 			break;
       
   221 
       
   222 		case OT_LOADING:
       
   223 		case OT_LEAVESTATION:
       
   224 			return;
       
   225 
       
   226 		default: break;
       
   227 	}
       
   228 
       
   229 	if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
       
   230 
       
   231 	order = GetVehicleOrder(v, v->cur_order_index);
       
   232 
       
   233 	if (order == NULL) {
       
   234 		v->current_order.type  = OT_NOTHING;
       
   235 		v->current_order.flags = 0;
       
   236 		v->dest_tile = 0;
       
   237 		return;
       
   238 	}
       
   239 
       
   240 	if (order->type  == v->current_order.type &&
       
   241 			order->flags == v->current_order.flags &&
       
   242 			order->dest  == v->current_order.dest)
       
   243 		return;
       
   244 
       
   245 	v->current_order = *order;
       
   246 
       
   247 	if (order->type == OT_GOTO_STATION) {
       
   248 		const Station *st;
       
   249 
       
   250 		if (order->dest == v->last_station_visited)
       
   251 			v->last_station_visited = INVALID_STATION;
       
   252 
       
   253 		st = GetStation(order->dest);
       
   254 		if (st->dock_tile != 0) {
       
   255 			v->dest_tile = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile)));
       
   256 		}
       
   257 	} else if (order->type == OT_GOTO_DEPOT) {
       
   258 		v->dest_tile = GetDepot(order->dest)->xy;
       
   259 	} else {
       
   260 		v->dest_tile = 0;
       
   261 	}
       
   262 
       
   263 	InvalidateVehicleOrder(v);
       
   264 
       
   265 	InvalidateWindowClasses(WC_SHIPS_LIST);
       
   266 }
       
   267 
       
   268 static void HandleShipLoading(Vehicle *v)
       
   269 {
       
   270 	if (v->current_order.type == OT_NOTHING) return;
       
   271 
       
   272 	if (v->current_order.type != OT_DUMMY) {
       
   273 		if (v->current_order.type != OT_LOADING) return;
       
   274 		if (--v->load_unload_time_rem) return;
       
   275 
       
   276 		if (CanFillVehicle(v) && (v->current_order.flags & OF_FULL_LOAD ||
       
   277 				(_patches.gradual_loading && !HASBIT(v->load_status, LS_LOADING_FINISHED)))) {
       
   278 			SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
       
   279 			if (LoadUnloadVehicle(v, false)) {
       
   280 				InvalidateWindow(WC_SHIPS_LIST, v->owner);
       
   281 				MarkShipDirty(v);
       
   282 			}
       
   283 			return;
       
   284 		}
       
   285 		PlayShipSound(v);
       
   286 
       
   287 		{
       
   288 			Order b = v->current_order;
       
   289 			v->current_order.type = OT_LEAVESTATION;
       
   290 			v->current_order.flags = 0;
       
   291 			if (!(b.flags & OF_NON_STOP)) return;
       
   292 		}
       
   293 	}
       
   294 
       
   295 	v->cur_order_index++;
       
   296 	InvalidateVehicleOrder(v);
       
   297 }
       
   298 
       
   299 static void UpdateShipDeltaXY(Vehicle *v, int dir)
       
   300 {
       
   301 #define MKIT(d,c,b,a) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
       
   302 	static const uint32 _delta_xy_table[8] = {
       
   303 		MKIT( -3,  -3,  6,  6),
       
   304 		MKIT(-16,  -3, 32,  6),
       
   305 		MKIT( -3,  -3,  6,  6),
       
   306 		MKIT( -3, -16,  6, 32),
       
   307 		MKIT( -3,  -3,  6,  6),
       
   308 		MKIT(-16,  -3, 32,  6),
       
   309 		MKIT( -3,  -3,  6,  6),
       
   310 		MKIT( -3, -16,  6, 32),
       
   311 	};
       
   312 #undef MKIT
       
   313 	uint32 x = _delta_xy_table[dir];
       
   314 	v->x_offs        = GB(x,  0, 8);
       
   315 	v->y_offs        = GB(x,  8, 8);
       
   316 	v->sprite_width  = GB(x, 16, 8);
       
   317 	v->sprite_height = GB(x, 24, 8);
       
   318 }
       
   319 
       
   320 void RecalcShipStuff(Vehicle *v)
       
   321 {
       
   322 	UpdateShipDeltaXY(v, v->direction);
       
   323 	v->cur_image = GetShipImage(v, v->direction);
       
   324 	MarkShipDirty(v);
       
   325 	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
       
   326 }
       
   327 
       
   328 static const TileIndexDiffC _ship_leave_depot_offs[] = {
       
   329 	{-1,  0},
       
   330 	{ 0, -1}
       
   331 };
       
   332 
       
   333 static void CheckShipLeaveDepot(Vehicle *v)
       
   334 {
       
   335 	TileIndex tile;
       
   336 	Axis axis;
       
   337 	uint m;
       
   338 
       
   339 	if (!IsShipInDepot(v)) return;
       
   340 
       
   341 	tile = v->tile;
       
   342 	axis = GetShipDepotAxis(tile);
       
   343 
       
   344 	// Check first side
       
   345 	if (_ship_sometracks[axis] & GetTileShipTrackStatus(TILE_ADD(tile, ToTileIndexDiff(_ship_leave_depot_offs[axis])))) {
       
   346 		m = (axis == AXIS_X) ? 0x101 : 0x207;
       
   347 	// Check second side
       
   348 	} else if (_ship_sometracks[axis + 2] & GetTileShipTrackStatus(TILE_ADD(tile, -2 * ToTileIndexDiff(_ship_leave_depot_offs[axis])))) {
       
   349 		m = (axis == AXIS_X) ? 0x105 : 0x203;
       
   350 	} else {
       
   351 		return;
       
   352 	}
       
   353 	v->direction    = GB(m, 0, 8);
       
   354 	v->u.ship.state = GB(m, 8, 8);
       
   355 	v->vehstatus &= ~VS_HIDDEN;
       
   356 
       
   357 	v->cur_speed = 0;
       
   358 	RecalcShipStuff(v);
       
   359 
       
   360 	PlayShipSound(v);
       
   361 	VehicleServiceInDepot(v);
       
   362 	InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
       
   363 	InvalidateWindowClasses(WC_SHIPS_LIST);
       
   364 }
       
   365 
       
   366 static bool ShipAccelerate(Vehicle *v)
       
   367 {
       
   368 	uint spd;
       
   369 	byte t;
       
   370 
       
   371 	spd = min(v->cur_speed + 1, v->max_speed);
       
   372 
       
   373 	//updates statusbar only if speed have changed to save CPU time
       
   374 	if (spd != v->cur_speed) {
       
   375 		v->cur_speed = spd;
       
   376 		if (_patches.vehicle_speed)
       
   377 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
   378 	}
       
   379 
       
   380 	// Decrease somewhat when turning
       
   381 	if (!(v->direction & 1)) spd = spd * 3 / 4;
       
   382 
       
   383 	if (spd == 0) return false;
       
   384 	if ((byte)++spd == 0) return true;
       
   385 
       
   386 	v->progress = (t = v->progress) - (byte)spd;
       
   387 
       
   388 	return (t < v->progress);
       
   389 }
       
   390 
       
   391 static int32 EstimateShipCost(EngineID engine_type)
       
   392 {
       
   393 	return ShipVehInfo(engine_type)->base_cost * (_price.ship_base>>3)>>5;
       
   394 }
       
   395 
       
   396 static void ShipArrivesAt(const Vehicle* v, Station* st)
       
   397 {
       
   398 	/* Check if station was ever visited before */
       
   399 	if (!(st->had_vehicle_of_type & HVOT_SHIP)) {
       
   400 		uint32 flags;
       
   401 
       
   402 		st->had_vehicle_of_type |= HVOT_SHIP;
       
   403 
       
   404 		SetDParam(0, st->index);
       
   405 		flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
       
   406 		AddNewsItem(
       
   407 			STR_9833_CITIZENS_CELEBRATE_FIRST,
       
   408 			flags,
       
   409 			v->index,
       
   410 			0);
       
   411 	}
       
   412 }
       
   413 
       
   414 typedef struct {
       
   415 	TileIndex skiptile;
       
   416 	TileIndex dest_coords;
       
   417 	uint best_bird_dist;
       
   418 	uint best_length;
       
   419 } PathFindShip;
       
   420 
       
   421 static bool ShipTrackFollower(TileIndex tile, PathFindShip *pfs, int track, uint length, byte *state)
       
   422 {
       
   423 	// Found dest?
       
   424 	if (tile == pfs->dest_coords) {
       
   425 		pfs->best_bird_dist = 0;
       
   426 
       
   427 		pfs->best_length = minu(pfs->best_length, length);
       
   428 		return true;
       
   429 	}
       
   430 
       
   431 	// Skip this tile in the calculation
       
   432 	if (tile != pfs->skiptile) {
       
   433 		pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile));
       
   434 	}
       
   435 
       
   436 	return false;
       
   437 }
       
   438 
       
   439 static const byte _ship_search_directions[6][4] = {
       
   440 	{ 0, 9, 2, 9 },
       
   441 	{ 9, 1, 9, 3 },
       
   442 	{ 9, 0, 3, 9 },
       
   443 	{ 1, 9, 9, 2 },
       
   444 	{ 3, 2, 9, 9 },
       
   445 	{ 9, 9, 1, 0 },
       
   446 };
       
   447 
       
   448 static const byte _pick_shiptrack_table[6] = {1, 3, 2, 2, 0, 0};
       
   449 
       
   450 static uint FindShipTrack(Vehicle *v, TileIndex tile, int dir, uint bits, TileIndex skiptile, int *track)
       
   451 {
       
   452 	PathFindShip pfs;
       
   453 	int i, best_track;
       
   454 	uint best_bird_dist = 0;
       
   455 	uint best_length    = 0;
       
   456 	uint r;
       
   457 	byte ship_dir = v->direction & 3;
       
   458 
       
   459 	pfs.dest_coords = v->dest_tile;
       
   460 	pfs.skiptile = skiptile;
       
   461 
       
   462 	best_track = -1;
       
   463 
       
   464 	do {
       
   465 		i = FIND_FIRST_BIT(bits);
       
   466 		bits = KILL_FIRST_BIT(bits);
       
   467 
       
   468 		pfs.best_bird_dist = (uint)-1;
       
   469 		pfs.best_length = (uint)-1;
       
   470 
       
   471 		FollowTrack(tile, 0x3800 | TRANSPORT_WATER, _ship_search_directions[i][dir], (TPFEnumProc*)ShipTrackFollower, NULL, &pfs);
       
   472 
       
   473 		if (best_track >= 0) {
       
   474 			if (pfs.best_bird_dist != 0) {
       
   475 				/* neither reached the destination, pick the one with the smallest bird dist */
       
   476 				if (pfs.best_bird_dist > best_bird_dist) goto bad;
       
   477 				if (pfs.best_bird_dist < best_bird_dist) goto good;
       
   478 			} else {
       
   479 				if (pfs.best_length > best_length) goto bad;
       
   480 				if (pfs.best_length < best_length) goto good;
       
   481 			}
       
   482 
       
   483 			/* if we reach this position, there's two paths of equal value so far.
       
   484 			 * pick one randomly. */
       
   485 			r = GB(Random(), 0, 8);
       
   486 			if (_pick_shiptrack_table[i] == ship_dir) r += 80;
       
   487 			if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80;
       
   488 			if (r <= 127) goto bad;
       
   489 		}
       
   490 good:;
       
   491 		best_track = i;
       
   492 		best_bird_dist = pfs.best_bird_dist;
       
   493 		best_length = pfs.best_length;
       
   494 bad:;
       
   495 
       
   496 	} while (bits != 0);
       
   497 
       
   498 	*track = best_track;
       
   499 	return best_bird_dist;
       
   500 }
       
   501 
       
   502 static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypeMask railtypes)
       
   503 {
       
   504 
       
   505 	void* perf = NpfBeginInterval();
       
   506 	NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, target, type, owner, railtypes);
       
   507 	int t = NpfEndInterval(perf);
       
   508 	DEBUG(yapf, 4, "[NPFW] %d us - %d rounds - %d open - %d closed -- ", t, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
       
   509 	return ret;
       
   510 }
       
   511 
       
   512 /* returns the track to choose on the next tile, or -1 when it's better to
       
   513  * reverse. The tile given is the tile we are about to enter, enterdir is the
       
   514  * direction in which we are entering the tile */
       
   515 static int ChooseShipTrack(Vehicle *v, TileIndex tile, int enterdir, uint tracks)
       
   516 {
       
   517 	assert(enterdir>=0 && enterdir<=3);
       
   518 
       
   519 	if (_patches.yapf.ship_use_yapf) {
       
   520 		Trackdir trackdir = YapfChooseShipTrack(v, tile, enterdir, tracks);
       
   521 		return (trackdir != INVALID_TRACKDIR) ? (int)TrackdirToTrack(trackdir) : -1;
       
   522 	} else if (_patches.new_pathfinding_all) {
       
   523 		NPFFindStationOrTileData fstd;
       
   524 		NPFFoundTargetData ftd;
       
   525 		TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir)));
       
   526 		byte trackdir = GetVehicleTrackdir(v);
       
   527 		assert (trackdir != 0xFF); /* Check that we are not in a depot */
       
   528 
       
   529 		NPFFillWithOrderData(&fstd, v);
       
   530 
       
   531 		ftd = PerfNPFRouteToStationOrTile(src_tile, trackdir, &fstd, TRANSPORT_WATER, v->owner, INVALID_RAILTYPE);
       
   532 
       
   533 		if (ftd.best_trackdir != 0xff) {
       
   534 			/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
       
   535 			the direction we need to take to get there, if ftd.best_bird_dist is not 0,
       
   536 			we did not find our target, but ftd.best_trackdir contains the direction leading
       
   537 			to the tile closest to our target. */
       
   538 			return ftd.best_trackdir & 7; /* TODO: Wrapper function? */
       
   539 		} else {
       
   540 			return -1; /* Already at target, reverse? */
       
   541 		}
       
   542 	} else {
       
   543 		uint b;
       
   544 		uint tot_dist, dist;
       
   545 		int track;
       
   546 		TileIndex tile2;
       
   547 
       
   548 		tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir));
       
   549 		tot_dist = (uint)-1;
       
   550 
       
   551 		/* Let's find out how far it would be if we would reverse first */
       
   552 		b = GetTileShipTrackStatus(tile2) & _ship_sometracks[ReverseDiagDir(enterdir)] & v->u.ship.state;
       
   553 		if (b != 0) {
       
   554 			dist = FindShipTrack(v, tile2, ReverseDiagDir(enterdir), b, tile, &track);
       
   555 			if (dist != (uint)-1)
       
   556 				tot_dist = dist + 1;
       
   557 		}
       
   558 		/* And if we would not reverse? */
       
   559 		dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track);
       
   560 		if (dist > tot_dist)
       
   561 			/* We could better reverse */
       
   562 			return -1;
       
   563 		return track;
       
   564 	}
       
   565 }
       
   566 
       
   567 static const Direction _new_vehicle_direction_table[] = {
       
   568 	DIR_N , DIR_NW, DIR_W , 0,
       
   569 	DIR_NE, DIR_N , DIR_SW, 0,
       
   570 	DIR_E , DIR_SE, DIR_S
       
   571 };
       
   572 
       
   573 static int ShipGetNewDirectionFromTiles(TileIndex new_tile, TileIndex old_tile)
       
   574 {
       
   575 	uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 +
       
   576 							TileX(new_tile) - TileX(old_tile) + 1;
       
   577 	assert(offs < 11 && offs != 3 && offs != 7);
       
   578 	return _new_vehicle_direction_table[offs];
       
   579 }
       
   580 
       
   581 static int ShipGetNewDirection(Vehicle *v, int x, int y)
       
   582 {
       
   583 	uint offs = (y - v->y_pos + 1) * 4 + (x - v->x_pos + 1);
       
   584 	assert(offs < 11 && offs != 3 && offs != 7);
       
   585 	return _new_vehicle_direction_table[offs];
       
   586 }
       
   587 
       
   588 static int GetAvailShipTracks(TileIndex tile, int dir)
       
   589 {
       
   590 	uint32 r = GetTileTrackStatus(tile, TRANSPORT_WATER);
       
   591 	return (byte) ((r | r >> 8)) & _ship_sometracks[dir];
       
   592 }
       
   593 
       
   594 static const byte _ship_subcoord[4][6][3] = {
       
   595 	{
       
   596 		{15, 8, 1},
       
   597 		{ 0, 0, 0},
       
   598 		{ 0, 0, 0},
       
   599 		{15, 8, 2},
       
   600 		{15, 7, 0},
       
   601 		{ 0, 0, 0},
       
   602 	},
       
   603 	{
       
   604 		{ 0, 0, 0},
       
   605 		{ 8, 0, 3},
       
   606 		{ 7, 0, 2},
       
   607 		{ 0, 0, 0},
       
   608 		{ 8, 0, 4},
       
   609 		{ 0, 0, 0},
       
   610 	},
       
   611 	{
       
   612 		{ 0, 8, 5},
       
   613 		{ 0, 0, 0},
       
   614 		{ 0, 7, 6},
       
   615 		{ 0, 0, 0},
       
   616 		{ 0, 0, 0},
       
   617 		{ 0, 8, 4},
       
   618 	},
       
   619 	{
       
   620 		{ 0, 0, 0},
       
   621 		{ 8,15, 7},
       
   622 		{ 0, 0, 0},
       
   623 		{ 8,15, 6},
       
   624 		{ 0, 0, 0},
       
   625 		{ 7,15, 0},
       
   626 	}
       
   627 };
       
   628 
       
   629 static void ShipController(Vehicle *v)
       
   630 {
       
   631 	GetNewVehiclePosResult gp;
       
   632 	uint32 r;
       
   633 	const byte *b;
       
   634 	Direction dir;
       
   635 	int track;
       
   636 	int tracks;
       
   637 
       
   638 	v->tick_counter++;
       
   639 
       
   640 	if (v->breakdown_ctr != 0) {
       
   641 		if (v->breakdown_ctr <= 2) {
       
   642 			HandleBrokenShip(v);
       
   643 			return;
       
   644 		}
       
   645 		v->breakdown_ctr--;
       
   646 	}
       
   647 
       
   648 	if (v->vehstatus & VS_STOPPED) return;
       
   649 
       
   650 	ProcessShipOrder(v);
       
   651 	HandleShipLoading(v);
       
   652 
       
   653 	if (v->current_order.type == OT_LOADING) return;
       
   654 
       
   655 	CheckShipLeaveDepot(v);
       
   656 
       
   657 	if (!ShipAccelerate(v)) return;
       
   658 
       
   659 	BeginVehicleMove(v);
       
   660 
       
   661 	if (GetNewVehiclePos(v, &gp)) {
       
   662 		// staying in tile
       
   663 		if (IsShipInDepot(v)) {
       
   664 			gp.x = v->x_pos;
       
   665 			gp.y = v->y_pos;
       
   666 		} else {
       
   667 			/* isnot inside depot */
       
   668 			r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
       
   669 			if (r & 0x8) goto reverse_direction;
       
   670 
       
   671 			/* A leave station order only needs one tick to get processed, so we can
       
   672 			 * always skip ahead. */
       
   673 			if (v->current_order.type == OT_LEAVESTATION) {
       
   674 				v->current_order.type = OT_NOTHING;
       
   675 				v->current_order.flags = 0;
       
   676 				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
   677 			} else if (v->dest_tile != 0) {
       
   678 				/* We have a target, let's see if we reached it... */
       
   679 				if (v->current_order.type == OT_GOTO_STATION &&
       
   680 						IsBuoyTile(v->dest_tile) &&
       
   681 						DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) {
       
   682 					/* We got within 3 tiles of our target buoy, so let's skip to our
       
   683 					 * next order */
       
   684 					v->cur_order_index++;
       
   685 					v->current_order.type = OT_DUMMY;
       
   686 					InvalidateVehicleOrder(v);
       
   687 				} else {
       
   688 					/* Non-buoy orders really need to reach the tile */
       
   689 					if (v->dest_tile == gp.new_tile) {
       
   690 						if (v->current_order.type == OT_GOTO_DEPOT) {
       
   691 							if ((gp.x&0xF)==8 && (gp.y&0xF)==8) {
       
   692 								VehicleEnterDepot(v);
       
   693 								return;
       
   694 							}
       
   695 						} else if (v->current_order.type == OT_GOTO_STATION) {
       
   696 							Station *st;
       
   697 
       
   698 							v->last_station_visited = v->current_order.dest;
       
   699 
       
   700 							/* Process station in the orderlist. */
       
   701 							st = GetStation(v->current_order.dest);
       
   702 							if (st->facilities & FACIL_DOCK) { /* ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations */
       
   703 								v->current_order.type = OT_LOADING;
       
   704 								v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER;
       
   705 								v->current_order.flags |= OF_NON_STOP;
       
   706 								ShipArrivesAt(v, st);
       
   707 
       
   708 								SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
       
   709 								if (LoadUnloadVehicle(v, true)) {
       
   710 									InvalidateWindow(WC_SHIPS_LIST, v->owner);
       
   711 									MarkShipDirty(v);
       
   712 								}
       
   713 								InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
   714 							} else { /* leave stations without docks right aways */
       
   715 								v->current_order.type = OT_LEAVESTATION;
       
   716 								v->current_order.flags = 0;
       
   717 								v->cur_order_index++;
       
   718 								InvalidateVehicleOrder(v);
       
   719 							}
       
   720 						}
       
   721 					}
       
   722 				}
       
   723 			}
       
   724 		}
       
   725 	} else {
       
   726 		DiagDirection diagdir;
       
   727 		// new tile
       
   728 		if (TileX(gp.new_tile) >= MapMaxX() || TileY(gp.new_tile) >= MapMaxY())
       
   729 			goto reverse_direction;
       
   730 
       
   731 		dir = ShipGetNewDirectionFromTiles(gp.new_tile, gp.old_tile);
       
   732 		assert(dir == DIR_NE || dir == DIR_SE || dir == DIR_SW || dir == DIR_NW);
       
   733 		diagdir = DirToDiagDir(dir);
       
   734 		tracks = GetAvailShipTracks(gp.new_tile, diagdir);
       
   735 		if (tracks == 0)
       
   736 			goto reverse_direction;
       
   737 
       
   738 		// Choose a direction, and continue if we find one
       
   739 		track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks);
       
   740 		if (track < 0)
       
   741 			goto reverse_direction;
       
   742 
       
   743 		b = _ship_subcoord[diagdir][track];
       
   744 
       
   745 		gp.x = (gp.x&~0xF) | b[0];
       
   746 		gp.y = (gp.y&~0xF) | b[1];
       
   747 
       
   748 		/* Call the landscape function and tell it that the vehicle entered the tile */
       
   749 		r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
       
   750 		if (r&0x8) goto reverse_direction;
       
   751 
       
   752 		if (!(r&0x4)) {
       
   753 			v->tile = gp.new_tile;
       
   754 			v->u.ship.state = 1 << track;
       
   755 		}
       
   756 
       
   757 		v->direction = b[2];
       
   758 	}
       
   759 
       
   760 	/* update image of ship, as well as delta XY */
       
   761 	dir = ShipGetNewDirection(v, gp.x, gp.y);
       
   762 	v->x_pos = gp.x;
       
   763 	v->y_pos = gp.y;
       
   764 	v->z_pos = GetSlopeZ(gp.x, gp.y);
       
   765 
       
   766 getout:
       
   767 	UpdateShipDeltaXY(v, dir);
       
   768 	v->cur_image = GetShipImage(v, dir);
       
   769 	VehiclePositionChanged(v);
       
   770 	EndVehicleMove(v);
       
   771 	return;
       
   772 
       
   773 reverse_direction:
       
   774 	dir = ReverseDir(v->direction);
       
   775 	v->direction = dir;
       
   776 	goto getout;
       
   777 }
       
   778 
       
   779 static void AgeShipCargo(Vehicle *v)
       
   780 {
       
   781 	if (_age_cargo_skip_counter != 0) return;
       
   782 	if (v->cargo_days != 255) v->cargo_days++;
       
   783 }
       
   784 
       
   785 void Ship_Tick(Vehicle *v)
       
   786 {
       
   787 	AgeShipCargo(v);
       
   788 	ShipController(v);
       
   789 }
       
   790 
       
   791 
       
   792 void ShipsYearlyLoop(void)
       
   793 {
       
   794 	Vehicle *v;
       
   795 
       
   796 	FOR_ALL_VEHICLES(v) {
       
   797 		if (v->type == VEH_Ship) {
       
   798 			v->profit_last_year = v->profit_this_year;
       
   799 			v->profit_this_year = 0;
       
   800 			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
   801 		}
       
   802 	}
       
   803 }
       
   804 
       
   805 /** Build a ship.
       
   806  * @param tile tile of depot where ship is built
       
   807  * @param p1 ship type being built (engine)
       
   808  * @param p2 bit 0 when set, the unitnumber will be 0, otherwise it will be a free number
       
   809  */
       
   810 int32 CmdBuildShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   811 {
       
   812 	int32 value;
       
   813 	Vehicle *v;
       
   814 	UnitID unit_num;
       
   815 	Engine *e;
       
   816 
       
   817 	if (!IsEngineBuildable(p1, VEH_Ship, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
       
   818 
       
   819 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
       
   820 
       
   821 	value = EstimateShipCost(p1);
       
   822 	if (flags & DC_QUERY_COST) return value;
       
   823 
       
   824 	/* The ai_new queries the vehicle cost before building the route,
       
   825 	 * so we must check against cheaters no sooner than now. --pasky */
       
   826 	if (!IsTileDepotType(tile, TRANSPORT_WATER)) return CMD_ERROR;
       
   827 	if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
       
   828 
       
   829 	v = AllocateVehicle();
       
   830 	unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Ship);
       
   831 
       
   832 	if (v == NULL || IsOrderPoolFull() || unit_num > _patches.max_ships)
       
   833 		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
       
   834 
       
   835 	if (flags & DC_EXEC) {
       
   836 		int x;
       
   837 		int y;
       
   838 
       
   839 		const ShipVehicleInfo *svi = ShipVehInfo(p1);
       
   840 
       
   841 		v->unitnumber = unit_num;
       
   842 
       
   843 		v->owner = _current_player;
       
   844 		v->tile = tile;
       
   845 		x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
       
   846 		y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
       
   847 		v->x_pos = x;
       
   848 		v->y_pos = y;
       
   849 		v->z_pos = GetSlopeZ(x,y);
       
   850 
       
   851 		v->z_height = 6;
       
   852 		v->sprite_width = 6;
       
   853 		v->sprite_height = 6;
       
   854 		v->x_offs = -3;
       
   855 		v->y_offs = -3;
       
   856 		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
       
   857 
       
   858 		v->spritenum = svi->image_index;
       
   859 		v->cargo_type = svi->cargo_type;
       
   860 		v->cargo_subtype = 0;
       
   861 		v->cargo_cap = svi->capacity;
       
   862 		v->value = value;
       
   863 
       
   864 		v->last_station_visited = INVALID_STATION;
       
   865 		v->max_speed = svi->max_speed;
       
   866 		v->engine_type = p1;
       
   867 
       
   868 		e = GetEngine(p1);
       
   869 		v->reliability = e->reliability;
       
   870 		v->reliability_spd_dec = e->reliability_spd_dec;
       
   871 		v->max_age = e->lifelength * 366;
       
   872 		_new_vehicle_id = v->index;
       
   873 
       
   874 		v->string_id = STR_SV_SHIP_NAME;
       
   875 		v->u.ship.state = 0x80;
       
   876 
       
   877 		v->service_interval = _patches.servint_ships;
       
   878 		v->date_of_last_service = _date;
       
   879 		v->build_year = _cur_year;
       
   880 		v->cur_image = 0x0E5E;
       
   881 		v->type = VEH_Ship;
       
   882 		v->random_bits = VehicleRandomBits();
       
   883 
       
   884 		VehiclePositionChanged(v);
       
   885 		GetPlayer(_current_player)->num_engines[p1]++;
       
   886 
       
   887 		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
       
   888 		RebuildVehicleLists();
       
   889 		InvalidateWindow(WC_COMPANY, v->owner);
       
   890 		if (IsLocalPlayer())
       
   891 			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Ship); // updates the replace Ship window
       
   892 	}
       
   893 
       
   894 	return value;
       
   895 }
       
   896 
       
   897 /** Sell a ship.
       
   898  * @param tile unused
       
   899  * @param p1 vehicle ID to be sold
       
   900  * @param p2 unused
       
   901  */
       
   902 int32 CmdSellShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   903 {
       
   904 	Vehicle *v;
       
   905 
       
   906 	if (!IsValidVehicleID(p1)) return CMD_ERROR;
       
   907 
       
   908 	v = GetVehicle(p1);
       
   909 
       
   910 	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
       
   911 
       
   912 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
       
   913 
       
   914 	if (!IsShipInDepotStopped(v)) {
       
   915 		return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
       
   916 	}
       
   917 
       
   918 	if (flags & DC_EXEC) {
       
   919 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
       
   920 		RebuildVehicleLists();
       
   921 		InvalidateWindow(WC_COMPANY, v->owner);
       
   922 		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
       
   923 		DeleteDepotHighlightOfVehicle(v);
       
   924 		DeleteVehicle(v);
       
   925 		if (IsLocalPlayer())
       
   926 			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Ship); // updates the replace Ship window
       
   927 	}
       
   928 
       
   929 	return -(int32)v->value;
       
   930 }
       
   931 
       
   932 /** Start/Stop a ship.
       
   933  * @param tile unused
       
   934  * @param p1 ship ID to start/stop
       
   935  * @param p2 unused
       
   936  */
       
   937 int32 CmdStartStopShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   938 {
       
   939 	Vehicle *v;
       
   940 	uint16 callback;
       
   941 
       
   942 	if (!IsValidVehicleID(p1)) return CMD_ERROR;
       
   943 
       
   944 	v = GetVehicle(p1);
       
   945 
       
   946 	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
       
   947 
       
   948 	/* Check if this ship can be started/stopped. The callback will fail or
       
   949 	 * return 0xFF if it can. */
       
   950 	callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
       
   951 	if (callback != CALLBACK_FAILED && callback != 0xFF) {
       
   952 		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
       
   953 		return_cmd_error(error);
       
   954 	}
       
   955 
       
   956 	if (flags & DC_EXEC) {
       
   957 		if (IsShipInDepotStopped(v)) {
       
   958 			DeleteVehicleNews(p1, STR_981C_SHIP_IS_WAITING_IN_DEPOT);
       
   959 		}
       
   960 
       
   961 		v->vehstatus ^= VS_STOPPED;
       
   962 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
   963 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
       
   964 		InvalidateWindowClasses(WC_SHIPS_LIST);
       
   965 	}
       
   966 
       
   967 	return 0;
       
   968 }
       
   969 
       
   970 /** Send a ship to the depot.
       
   971  * @param tile unused
       
   972  * @param p1 vehicle ID to send to the depot
       
   973  * @param p2 various bitmasked elements
       
   974  * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
       
   975  * - p2 bit 8-10 - VLW flag (for mass goto depot)
       
   976  */
       
   977 int32 CmdSendShipToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   978 {
       
   979 	Vehicle *v;
       
   980 	const Depot *dep;
       
   981 
       
   982 	if (p2 & DEPOT_MASS_SEND) {
       
   983 		/* Mass goto depot requested */
       
   984 		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
       
   985 		return SendAllVehiclesToDepot(VEH_Ship, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1);
       
   986 	}
       
   987 
       
   988 	if (!IsValidVehicleID(p1)) return CMD_ERROR;
       
   989 
       
   990 	v = GetVehicle(p1);
       
   991 
       
   992 	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
       
   993 
       
   994 	if (v->vehstatus & VS_CRASHED) return CMD_ERROR;
       
   995 
       
   996 	if (IsShipInDepot(v)) return CMD_ERROR;
       
   997 
       
   998 	/* If the current orders are already goto-depot */
       
   999 	if (v->current_order.type == OT_GOTO_DEPOT) {
       
  1000 		if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) {
       
  1001 			/* We called with a different DEPOT_SERVICE setting.
       
  1002 			 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
       
  1003 			 * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
       
  1004 			if (flags & DC_EXEC) {
       
  1005 				TOGGLEBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
       
  1006 				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
  1007 			}
       
  1008 			return 0;
       
  1009 		}
       
  1010 
       
  1011 		if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
       
  1012 		if (flags & DC_EXEC) {
       
  1013 			/* If the orders to 'goto depot' are in the orders list (forced servicing),
       
  1014 			 * then skip to the next order; effectively cancelling this forced service */
       
  1015 			if (HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS))
       
  1016 				v->cur_order_index++;
       
  1017 
       
  1018 			v->current_order.type = OT_DUMMY;
       
  1019 			v->current_order.flags = 0;
       
  1020 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
  1021 		}
       
  1022 		return 0;
       
  1023 	}
       
  1024 
       
  1025 	dep = FindClosestShipDepot(v);
       
  1026 	if (dep == NULL) return_cmd_error(STR_981A_UNABLE_TO_FIND_LOCAL_DEPOT);
       
  1027 
       
  1028 	if (flags & DC_EXEC) {
       
  1029 		v->dest_tile = dep->xy;
       
  1030 		v->current_order.type = OT_GOTO_DEPOT;
       
  1031 		v->current_order.flags = OF_NON_STOP;
       
  1032 		if (!(p2 & DEPOT_SERVICE)) SETBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
       
  1033 		v->current_order.refit_cargo = CT_INVALID;
       
  1034 		v->current_order.dest = dep->index;
       
  1035 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
       
  1036 	}
       
  1037 
       
  1038 	return 0;
       
  1039 }
       
  1040 
       
  1041 
       
  1042 /** Refits a ship to the specified cargo type.
       
  1043  * @param tile unused
       
  1044  * @param p1 vehicle ID of the ship to refit
       
  1045  * @param p2 various bitstuffed elements
       
  1046  * - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
       
  1047  * - p2 = (bit 8-15) - the new cargo subtype to refit to
       
  1048  */
       
  1049 int32 CmdRefitShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
  1050 {
       
  1051 	Vehicle *v;
       
  1052 	int32 cost;
       
  1053 	CargoID new_cid = GB(p2, 0, 8); //gets the cargo number
       
  1054 	byte new_subtype = GB(p2, 8, 8);
       
  1055 	uint16 capacity = CALLBACK_FAILED;
       
  1056 
       
  1057 	if (!IsValidVehicleID(p1)) return CMD_ERROR;
       
  1058 
       
  1059 	v = GetVehicle(p1);
       
  1060 
       
  1061 	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
       
  1062 
       
  1063 	if (!IsShipInDepotStopped(v)) {
       
  1064 		return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
       
  1065 	}
       
  1066 
       
  1067 	/* Check cargo */
       
  1068 	if (!ShipVehInfo(v->engine_type)->refittable) return CMD_ERROR;
       
  1069 	if (new_cid > NUM_CARGO || !CanRefitTo(v->engine_type, new_cid)) return CMD_ERROR;
       
  1070 
       
  1071 	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
       
  1072 
       
  1073 	/* Check the refit capacity callback */
       
  1074 	if (HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_REFIT_CAPACITY)) {
       
  1075 		/* Back up the existing cargo type */
       
  1076 		CargoID temp_cid = v->cargo_type;
       
  1077 		byte temp_subtype = v->cargo_subtype;
       
  1078 		v->cargo_type = new_cid;
       
  1079 		v->cargo_subtype = new_subtype;
       
  1080 
       
  1081 		capacity = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
       
  1082 
       
  1083 		/* Restore the cargo type */
       
  1084 		v->cargo_type = temp_cid;
       
  1085 		v->cargo_subtype = temp_subtype;
       
  1086 	}
       
  1087 
       
  1088 	if (capacity == CALLBACK_FAILED) {
       
  1089 		capacity = ShipVehInfo(v->engine_type)->capacity;
       
  1090 	}
       
  1091 	_returned_refit_capacity = capacity;
       
  1092 
       
  1093 	cost = 0;
       
  1094 	if (IsHumanPlayer(v->owner) && new_cid != v->cargo_type) {
       
  1095 		cost = GetRefitCost(v->engine_type);
       
  1096 	}
       
  1097 
       
  1098 	if (flags & DC_EXEC) {
       
  1099 		v->cargo_cap = capacity;
       
  1100 		v->cargo_count = (v->cargo_type == new_cid) ? min(v->cargo_cap, v->cargo_count) : 0;
       
  1101 		v->cargo_type = new_cid;
       
  1102 		v->cargo_subtype = new_subtype;
       
  1103 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
       
  1104 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
       
  1105 		RebuildVehicleLists();
       
  1106 	}
       
  1107 
       
  1108 	return cost;
       
  1109 
       
  1110 }