openttd updated to 1.5.0-beta2

--HG--
branch : openttd
This commit is contained in:
Pavel Stupnikov
2015-03-01 00:30:53 +03:00
parent 0abb47ce90
commit d201932121
682 changed files with 26103 additions and 16553 deletions
+144 -71
View File
@@ -1,4 +1,4 @@
/* $Id: vehicle.cpp 26317 2014-02-07 23:48:56Z frosch $ */
/* $Id: vehicle.cpp 27148 2015-02-14 12:53:07Z frosch $ */
/*
* This file is part of OpenTTD.
@@ -55,6 +55,8 @@
#include "table/strings.h"
#include "safeguards.h"
#define GEN_HASH(x, y) ((GB((y), 6 + ZOOM_LVL_SHIFT, 6) << 6) + GB((x), 7 + ZOOM_LVL_SHIFT, 6))
VehicleID _new_vehicle_id;
@@ -204,7 +206,7 @@ uint Vehicle::Crash(bool flooded)
/* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.TotalCount();
v->vehstatus |= VS_CRASHED;
MarkSingleVehicleDirty(v);
v->MarkAllViewportsDirty();
}
/* Dirty some windows */
@@ -233,6 +235,9 @@ void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRF
const Engine *e = Engine::Get(engine);
GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
/* Missing GRF. Nothing useful can be done in this situation. */
if (grfconfig == NULL) return;
if (!HasBit(grfconfig->grf_bugs, bug_type)) {
SetBit(grfconfig->grf_bugs, bug_type);
SetDParamStr(0, grfconfig->GetName());
@@ -804,7 +809,7 @@ Vehicle::~Vehicle()
/* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
* it may happen that vehicle chain is deleted when visible */
if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty();
Vehicle *v = this->Next();
this->SetNext(NULL);
@@ -1201,9 +1206,10 @@ bool Vehicle::HandleBreakdown()
this->cur_speed = 0;
if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP;
SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
(this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
(this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
(train_or_ship ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
(train_or_ship ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
}
if (!(this->vehstatus & VS_HIDDEN) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_NO_BREAKDOWN_SMOKE)) {
@@ -1401,21 +1407,19 @@ void VehicleEnterDepot(Vehicle *v)
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
const Order *real_order = v->GetOrder(v->cur_real_order_index);
Order t = v->current_order;
v->current_order.MakeDummy();
/* Test whether we are heading for this depot. If not, do nothing.
* Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
if ((v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
(v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
(v->type == VEH_AIRCRAFT ? v->current_order.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
/* We are heading for another depot, keep driving. */
return;
}
if (t.IsRefit()) {
if (v->current_order.IsRefit()) {
Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | 0xFF << 8, DC_EXEC, GetCmdRefitVeh(v));
CommandCost cost = DoCommand(v->tile, v->index, v->current_order.GetRefitCargo() | 0xFF << 8, DC_EXEC, GetCmdRefitVeh(v));
cur_company.Restore();
if (cost.Failed()) {
@@ -1433,13 +1437,13 @@ void VehicleEnterDepot(Vehicle *v)
}
}
if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
if (v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
/* Part of orders */
v->DeleteUnreachedImplicitOrders();
UpdateVehicleTimetable(v, true);
v->IncrementImplicitOrderIndex();
}
if (t.GetDepotActionType() & ODATFB_HALT) {
if (v->current_order.GetDepotActionType() & ODATFB_HALT) {
/* Vehicles are always stopped on entering depots. Do not restart this one. */
_vehicles_to_autoreplace[v] = false;
/* Invalidate last_loading_station. As the link from the station
@@ -1452,6 +1456,7 @@ void VehicleEnterDepot(Vehicle *v)
}
AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
}
v->current_order.MakeDummy();
}
}
@@ -1459,67 +1464,62 @@ void VehicleEnterDepot(Vehicle *v)
/**
* Update the position of the vehicle. This will update the hash that tells
* which vehicles are on a tile.
* @param v The vehicle to update.
*/
void VehicleUpdatePosition(Vehicle *v)
void Vehicle::UpdatePosition()
{
UpdateVehicleTileHash(v, false);
UpdateVehicleTileHash(this, false);
}
/**
* Update the vehicle on the viewport, updating the right hash and setting the
* new coordinates.
* @param v The vehicle to update.
* @param dirty Mark the (new and old) coordinates of the vehicle as dirty.
*/
void VehicleUpdateViewport(Vehicle *v, bool dirty)
void Vehicle::UpdateViewport(bool dirty)
{
int img = v->cur_image;
Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
int img = this->cur_image;
Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
const Sprite *spr = GetSprite(img, ST_NORMAL);
pt.x += spr->x_offs;
pt.y += spr->y_offs;
UpdateVehicleViewportHash(v, pt.x, pt.y);
UpdateVehicleViewportHash(this, pt.x, pt.y);
Rect old_coord = v->coord;
v->coord.left = pt.x;
v->coord.top = pt.y;
v->coord.right = pt.x + spr->width + 2 * ZOOM_LVL_BASE;
v->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE;
Rect old_coord = this->coord;
this->coord.left = pt.x;
this->coord.top = pt.y;
this->coord.right = pt.x + spr->width + 2 * ZOOM_LVL_BASE;
this->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE;
if (dirty) {
if (old_coord.left == INVALID_COORD) {
MarkSingleVehicleDirty(v);
this->MarkAllViewportsDirty();
} else {
MarkAllViewportsDirty(
min(old_coord.left, v->coord.left),
min(old_coord.top, v->coord.top),
max(old_coord.right, v->coord.right) + 1 * ZOOM_LVL_BASE,
max(old_coord.bottom, v->coord.bottom) + 1 * ZOOM_LVL_BASE
);
::MarkAllViewportsDirty(
min(old_coord.left, this->coord.left),
min(old_coord.top, this->coord.top),
max(old_coord.right, this->coord.right),
max(old_coord.bottom, this->coord.bottom));
}
}
}
/**
* Update the position of the vehicle, and update the viewport.
* @param v The vehicle to update.
*/
void VehicleUpdatePositionAndViewport(Vehicle *v)
void Vehicle::UpdatePositionAndViewport()
{
VehicleUpdatePosition(v);
VehicleUpdateViewport(v, true);
this->UpdatePosition();
this->UpdateViewport(true);
}
/**
* Marks viewports dirty where the vehicle's image is.
* @param v vehicle to mark dirty
*/
void MarkSingleVehicleDirty(const Vehicle *v)
void Vehicle::MarkAllViewportsDirty() const
{
MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1 * ZOOM_LVL_BASE, v->coord.bottom + 1 * ZOOM_LVL_BASE);
::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
}
/**
@@ -2135,7 +2135,7 @@ void Vehicle::HandleLoading(bool mode)
{
switch (this->current_order.GetType()) {
case OT_LOADING: {
uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
/* Not the first call for this tick, or still loading */
if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
@@ -2339,6 +2339,61 @@ static const int8 _vehicle_smoke_pos[8] = {
1, 1, 1, 0, -1, -1, -1, 0
};
/**
* Call CBID_VEHICLE_SPAWN_VISUAL_EFFECT and spawn requested effects.
* @param v Vehicle to create effects for.
*/
static void SpawnAdvancedVisualEffect(const Vehicle *v)
{
uint16 callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v);
if (callback == CALLBACK_FAILED) return;
uint count = GB(callback, 0, 2);
bool auto_center = HasBit(callback, 13);
bool auto_rotate = !HasBit(callback, 14);
int8 l_center = 0;
if (auto_center) {
/* For road vehicles: Compute offset from vehicle position to vehicle center */
if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
} else {
/* For trains: Compute offset from vehicle position to sprite position */
if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
}
Direction l_dir = v->direction;
if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir);
Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
for (uint i = 0; i < count; i++) {
uint32 reg = GetRegister(0x100 + i);
uint type = GB(reg, 0, 8);
int8 x = GB(reg, 8, 8);
int8 y = GB(reg, 16, 8);
int8 z = GB(reg, 24, 8);
if (auto_rotate) {
int8 l = x;
int8 t = y;
x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
}
if (type >= 0xF0) {
switch (type) {
case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
default: break;
}
}
}
}
/**
* Draw visual effects (smoke and/or sparks) for a vehicle chain.
* @pre this->IsPrimaryVehicle()
@@ -2373,16 +2428,27 @@ void Vehicle::ShowVisualEffect() const
}
max_speed = min(max_speed, t->gcache.cached_max_track_speed);
max_speed = min(max_speed, this->current_order.max_speed);
max_speed = min(max_speed, this->current_order.GetMaxSpeed());
}
if (this->type == VEH_ROAD || this->type == VEH_SHIP) max_speed = min(max_speed, this->current_order.max_speed * 2);
if (this->type == VEH_ROAD || this->type == VEH_SHIP) max_speed = min(max_speed, this->current_order.GetMaxSpeed() * 2);
const Vehicle *v = this;
do {
bool advanced = HasBit(v->vcache.cached_vis_effect, VE_ADVANCED_EFFECT);
int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
VisualEffectSpawnModel effect_model = VESM_NONE;
if (advanced) {
effect_offset = VE_OFFSET_CENTRE;
effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, 0, VE_ADVANCED_EFFECT);
if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
} else {
effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
assert_compile((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
assert_compile((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL);
assert_compile((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
}
/* Show no smoke when:
* - Smoke has been disabled for this vehicle
@@ -2391,9 +2457,9 @@ void Vehicle::ShowVisualEffect() const
* - The vehicle is on a depot tile
* - The vehicle is on a tunnel tile
* - The vehicle is a train engine that is currently unpowered */
if (disable_effect ||
if (effect_model == VESM_NONE ||
v->vehstatus & VS_HIDDEN ||
(MayHaveBridgeAbove(v->tile) && IsBridgeAbove(v->tile)) ||
IsBridgeAbove(v->tile) ||
IsDepotTile(v->tile) ||
IsTunnelTile(v->tile) ||
(v->type == VEH_TRAIN &&
@@ -2401,33 +2467,20 @@ void Vehicle::ShowVisualEffect() const
continue;
}
/* The effect offset is relative to a point 4 units behind the vehicle's
* front (which is the center of an 8/8 vehicle). Shorter vehicles need a
* correction factor. */
if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
int x = _vehicle_smoke_pos[v->direction] * effect_offset;
int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
x = -x;
y = -y;
}
switch (effect_type) {
case VE_TYPE_STEAM:
EffectVehicleType evt = EV_END;
switch (effect_model) {
case VESM_STEAM:
/* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
* Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
* third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
* REGULATION:
* - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
sound = true;
evt = EV_STEAM_SMOKE;
}
break;
case VE_TYPE_DIESEL: {
case VESM_DIESEL: {
/* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
* when smoke emission stops.
* Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
@@ -2445,13 +2498,12 @@ void Vehicle::ShowVisualEffect() const
}
if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
sound = true;
evt = EV_DIESEL_SMOKE;
}
break;
}
case VE_TYPE_ELECTRIC:
case VESM_ELECTRIC:
/* Electric train's spark - more often occurs when train is departing (more load)
* Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
* emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
@@ -2460,13 +2512,34 @@ void Vehicle::ShowVisualEffect() const
* - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
if (GB(v->tick_counter, 0, 2) == 0 &&
Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
sound = true;
evt = EV_ELECTRIC_SPARK;
}
break;
default:
break;
NOT_REACHED();
}
if (evt != EV_END && advanced) {
sound = true;
SpawnAdvancedVisualEffect(v);
} else if (evt != EV_END) {
sound = true;
/* The effect offset is relative to a point 4 units behind the vehicle's
* front (which is the center of an 8/8 vehicle). Shorter vehicles need a
* correction factor. */
if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
int x = _vehicle_smoke_pos[v->direction] * effect_offset;
int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
x = -x;
y = -y;
}
CreateEffectVehicleRel(v, x, y, 10, evt);
}
} while ((v = v->Next()) != NULL);