Update to OpenTTD 1.9.0-beta2
--HG-- branch : openttd
This commit is contained in:
188
src/ship_cmd.cpp
188
src/ship_cmd.cpp
@@ -1,4 +1,4 @@
|
||||
/* $Id: ship_cmd.cpp 27858 2017-04-23 09:19:32Z peter1138 $ */
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "company_base.h"
|
||||
#include "tunnelbridge_map.h"
|
||||
#include "zoom_func.h"
|
||||
#include "framerate_type.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -128,6 +129,8 @@ void Ship::GetImage(Direction direction, EngineImageType image_type, VehicleSpri
|
||||
{
|
||||
uint8 spritenum = this->spritenum;
|
||||
|
||||
if (image_type == EIT_ON_MAP) direction = this->rotation;
|
||||
|
||||
if (is_custom_sprite(spritenum)) {
|
||||
GetCustomVehicleSprite(this, direction, image_type, result);
|
||||
if (result->IsValid()) return;
|
||||
@@ -192,7 +195,7 @@ static void CheckIfShipNeedsService(Vehicle *v)
|
||||
}
|
||||
|
||||
v->current_order.MakeGoToDepot(depot->index, ODTFB_SERVICE);
|
||||
v->dest_tile = depot->xy;
|
||||
v->SetDestTile(depot->xy);
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
}
|
||||
|
||||
@@ -296,7 +299,7 @@ TileIndex Ship::GetOrderStationLocation(StationID station)
|
||||
}
|
||||
}
|
||||
|
||||
void Ship::UpdateDeltaXY(Direction direction)
|
||||
void Ship::UpdateDeltaXY()
|
||||
{
|
||||
static const int8 _delta_xy_table[8][4] = {
|
||||
/* y_extent, x_extent, y_offs, x_offs */
|
||||
@@ -310,12 +313,29 @@ void Ship::UpdateDeltaXY(Direction direction)
|
||||
{32, 6, -16, -3}, // NW
|
||||
};
|
||||
|
||||
const int8 *bb = _delta_xy_table[direction];
|
||||
const int8 *bb = _delta_xy_table[this->rotation];
|
||||
this->x_offs = bb[3];
|
||||
this->y_offs = bb[2];
|
||||
this->x_extent = bb[1];
|
||||
this->y_extent = bb[0];
|
||||
this->z_extent = 6;
|
||||
|
||||
if (this->direction != this->rotation) {
|
||||
/* If we are rotating, then it is possible the ship was moved to its next position. In that
|
||||
* case, because we are still showing the old direction, the ship will appear to glitch sideways
|
||||
* slightly. We can work around this by applying an additional offset to make the ship appear
|
||||
* where it was before it moved. */
|
||||
this->x_offs -= this->x_pos - this->rotation_x_pos;
|
||||
this->y_offs -= this->y_pos - this->rotation_y_pos;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test-procedure for HasVehicleOnPos to check for a ship.
|
||||
*/
|
||||
static Vehicle *EnsureNoVisibleShipProc(Vehicle *v, void *data)
|
||||
{
|
||||
return v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0 ? v : NULL;
|
||||
}
|
||||
|
||||
static bool CheckShipLeaveDepot(Ship *v)
|
||||
@@ -329,6 +349,13 @@ static bool CheckShipLeaveDepot(Ship *v)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Don't leave depot if no destination set */
|
||||
if (v->dest_tile == 0) return true;
|
||||
|
||||
/* Don't leave depot if another vehicle is already entering/leaving */
|
||||
/* This helps avoid CPU load if many ships are set to start at the same time */
|
||||
if (HasVehicleOnPos(v->tile, NULL, &EnsureNoVisibleShipProc)) return true;
|
||||
|
||||
TileIndex tile = v->tile;
|
||||
Axis axis = GetShipDepotAxis(tile);
|
||||
|
||||
@@ -354,10 +381,10 @@ static bool CheckShipLeaveDepot(Ship *v)
|
||||
|
||||
if (north_tracks) {
|
||||
/* Leave towards north */
|
||||
v->direction = DiagDirToDir(north_dir);
|
||||
v->rotation = v->direction = DiagDirToDir(north_dir);
|
||||
} else if (south_tracks) {
|
||||
/* Leave towards south */
|
||||
v->direction = DiagDirToDir(south_dir);
|
||||
v->rotation = v->direction = DiagDirToDir(south_dir);
|
||||
} else {
|
||||
/* Both ways blocked */
|
||||
return false;
|
||||
@@ -442,11 +469,41 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr
|
||||
|
||||
bool path_found = true;
|
||||
Track track;
|
||||
switch (_settings_game.pf.pathfinder_for_ships) {
|
||||
case VPF_OPF: track = OPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break;
|
||||
case VPF_NPF: track = NPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break;
|
||||
case VPF_YAPF: track = YapfShipChooseTrack(v, tile, enterdir, tracks, path_found); break;
|
||||
default: NOT_REACHED();
|
||||
|
||||
if (v->dest_tile == 0 || DistanceManhattan(tile, v->dest_tile) > SHIP_MAX_ORDER_DISTANCE + 5) {
|
||||
/* No destination or destination too far, don't invoke pathfinder. */
|
||||
track = TrackBitsToTrack(v->state);
|
||||
if (!IsDiagonalTrack(track)) track = TrackToOppositeTrack(track);
|
||||
if (!HasBit(tracks, track)) {
|
||||
/* Can't continue in same direction so pick first available track. */
|
||||
if (_settings_game.pf.forbid_90_deg) {
|
||||
tracks &= ~TrackCrossesTracks(TrackdirToTrack(v->GetVehicleTrackdir()));
|
||||
if (tracks == TRACK_BIT_NONE) return INVALID_TRACK;
|
||||
}
|
||||
track = FindFirstTrack(tracks);
|
||||
}
|
||||
path_found = false;
|
||||
} else {
|
||||
/* Attempt to follow cached path. */
|
||||
if (!v->path.empty()) {
|
||||
track = TrackdirToTrack(v->path.front());
|
||||
|
||||
if (HasBit(tracks, track)) {
|
||||
v->path.pop_front();
|
||||
/* HandlePathfindResult() is not called here because this is not a new pathfinder result. */
|
||||
return track;
|
||||
}
|
||||
|
||||
/* Cached path is invalid so continue with pathfinder. */
|
||||
v->path.clear();
|
||||
}
|
||||
|
||||
switch (_settings_game.pf.pathfinder_for_ships) {
|
||||
case VPF_OPF: track = OPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break;
|
||||
case VPF_NPF: track = NPFShipChooseTrack(v, path_found); break;
|
||||
case VPF_YAPF: track = YapfShipChooseTrack(v, tile, enterdir, tracks, path_found, v->path); break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
v->HandlePathfindingResult(path_found);
|
||||
@@ -493,11 +550,60 @@ static const byte _ship_subcoord[4][6][3] = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test if a ship is in the centre of a lock and should move up or down.
|
||||
* @param v Ship being tested.
|
||||
* @return 0 if ship is not moving in lock, or -1 to move down, 1 to move up.
|
||||
*/
|
||||
static int ShipTestUpDownOnLock(const Ship *v)
|
||||
{
|
||||
/* Suitable tile? */
|
||||
if (!IsTileType(v->tile, MP_WATER) || !IsLock(v->tile) || GetLockPart(v->tile) != LOCK_PART_MIDDLE) return 0;
|
||||
|
||||
/* Must be at the centre of the lock */
|
||||
if ((v->x_pos & 0xF) != 8 || (v->y_pos & 0xF) != 8) return 0;
|
||||
|
||||
DiagDirection diagdir = GetInclinedSlopeDirection(GetTileSlope(v->tile));
|
||||
assert(IsValidDiagDirection(diagdir));
|
||||
|
||||
if (DirToDiagDir(v->direction) == diagdir) {
|
||||
/* Move up */
|
||||
return (v->z_pos < GetTileMaxZ(v->tile) * (int)TILE_HEIGHT) ? 1 : 0;
|
||||
} else {
|
||||
/* Move down */
|
||||
return (v->z_pos > GetTileZ(v->tile) * (int)TILE_HEIGHT) ? -1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test and move a ship up or down in a lock.
|
||||
* @param v Ship to move.
|
||||
* @return true iff ship is moving up or down in a lock.
|
||||
*/
|
||||
static bool ShipMoveUpDownOnLock(Ship *v)
|
||||
{
|
||||
/* Moving up/down through lock */
|
||||
int dz = ShipTestUpDownOnLock(v);
|
||||
if (dz == 0) return false;
|
||||
|
||||
if (v->cur_speed != 0) {
|
||||
v->cur_speed = 0;
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
}
|
||||
|
||||
if ((v->tick_counter & 7) == 0) {
|
||||
v->z_pos += dz;
|
||||
v->UpdatePosition();
|
||||
v->UpdateViewport(true, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ShipController(Ship *v)
|
||||
{
|
||||
uint32 r;
|
||||
const byte *b;
|
||||
Direction dir;
|
||||
Track track;
|
||||
TrackBits tracks;
|
||||
|
||||
@@ -517,6 +623,18 @@ static void ShipController(Ship *v)
|
||||
|
||||
v->ShowVisualEffect();
|
||||
|
||||
/* Rotating on spot */
|
||||
if (v->direction != v->rotation) {
|
||||
if ((v->tick_counter & 7) == 0) {
|
||||
DirDiff diff = DirDifference(v->direction, v->rotation);
|
||||
v->rotation = ChangeDir(v->rotation, diff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
|
||||
v->UpdateViewport(true, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShipMoveUpDownOnLock(v)) return;
|
||||
|
||||
if (!ShipAccelerate(v)) return;
|
||||
|
||||
GetNewVehiclePosResult gp = GetNewVehiclePos(v);
|
||||
@@ -537,6 +655,10 @@ static void ShipController(Ship *v)
|
||||
if (v->current_order.IsType(OT_LEAVESTATION)) {
|
||||
v->current_order.Free();
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
/* Test if continuing forward would lead to a dead-end, moving into the dock. */
|
||||
DiagDirection exitdir = VehicleExitDir(v->direction, v->state);
|
||||
TileIndex tile = TileAddByDiagDir(v->tile, exitdir);
|
||||
if (TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0, exitdir)) == TRACK_BIT_NONE) goto reverse_direction;
|
||||
} else if (v->dest_tile != 0) {
|
||||
/* We have a target, let's see if we reached it... */
|
||||
if (v->current_order.IsType(OT_GOTO_WAYPOINT) &&
|
||||
@@ -603,7 +725,25 @@ static void ShipController(Ship *v)
|
||||
if (old_wc != new_wc) v->UpdateCache();
|
||||
}
|
||||
|
||||
v->direction = (Direction)b[2];
|
||||
Direction new_direction = (Direction)b[2];
|
||||
DirDiff diff = DirDifference(new_direction, v->direction);
|
||||
switch (diff) {
|
||||
case DIRDIFF_SAME:
|
||||
case DIRDIFF_45RIGHT:
|
||||
case DIRDIFF_45LEFT:
|
||||
/* Continue at speed */
|
||||
v->rotation = v->direction = new_direction;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Stop for rotation */
|
||||
v->cur_speed = 0;
|
||||
v->direction = new_direction;
|
||||
/* Remember our current location to avoid movement glitch */
|
||||
v->rotation_x_pos = v->x_pos;
|
||||
v->rotation_y_pos = v->y_pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* On a bridge */
|
||||
@@ -619,7 +759,6 @@ static void ShipController(Ship *v)
|
||||
/* update image of ship, as well as delta XY */
|
||||
v->x_pos = gp.x;
|
||||
v->y_pos = gp.y;
|
||||
v->z_pos = GetSlopePixelZ(gp.x, gp.y);
|
||||
|
||||
getout:
|
||||
v->UpdatePosition();
|
||||
@@ -627,13 +766,19 @@ getout:
|
||||
return;
|
||||
|
||||
reverse_direction:
|
||||
dir = ReverseDir(v->direction);
|
||||
v->direction = dir;
|
||||
v->direction = ReverseDir(v->direction);
|
||||
/* Remember our current location to avoid movement glitch */
|
||||
v->rotation_x_pos = v->x_pos;
|
||||
v->rotation_y_pos = v->y_pos;
|
||||
v->cur_speed = 0;
|
||||
v->path.clear();
|
||||
goto getout;
|
||||
}
|
||||
|
||||
bool Ship::Tick()
|
||||
{
|
||||
PerformanceAccumulator framerate(PFE_GL_SHIPS);
|
||||
|
||||
if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
|
||||
|
||||
ShipController(this);
|
||||
@@ -641,13 +786,20 @@ bool Ship::Tick()
|
||||
return true;
|
||||
}
|
||||
|
||||
void Ship::SetDestTile(TileIndex tile)
|
||||
{
|
||||
if (tile == this->dest_tile) return;
|
||||
this->path.clear();
|
||||
this->dest_tile = tile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a ship.
|
||||
* @param tile tile of the depot where ship is built.
|
||||
* @param flags type of operation.
|
||||
* @param e the engine to build.
|
||||
* @param data unused.
|
||||
* @param ret[out] the vehicle that has been built.
|
||||
* @param[out] ret the vehicle that has been built.
|
||||
* @return the cost of this operation or an error.
|
||||
*/
|
||||
CommandCost CmdBuildShip(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret)
|
||||
@@ -670,7 +822,7 @@ CommandCost CmdBuildShip(TileIndex tile, DoCommandFlag flags, const Engine *e, u
|
||||
v->y_pos = y;
|
||||
v->z_pos = GetSlopePixelZ(x, y);
|
||||
|
||||
v->UpdateDeltaXY(v->direction);
|
||||
v->UpdateDeltaXY();
|
||||
v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
|
||||
|
||||
v->spritenum = svi->image_index;
|
||||
|
||||
Reference in New Issue
Block a user