|
|
|
/*
|
|
|
|
* This file is part of OpenTTD.
|
|
|
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
|
|
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** @file script_engine.cpp Implementation of ScriptEngine. */
|
|
|
|
|
|
|
|
#include "../../stdafx.h"
|
|
|
|
#include "script_engine.hpp"
|
|
|
|
#include "script_cargo.hpp"
|
|
|
|
#include "../../company_base.h"
|
|
|
|
#include "../../strings_func.h"
|
|
|
|
#include "../../rail.h"
|
|
|
|
#include "../../road.h"
|
|
|
|
#include "../../engine_base.h"
|
|
|
|
#include "../../engine_func.h"
|
|
|
|
#include "../../articulated_vehicles.h"
|
|
|
|
#include "table/strings.h"
|
|
|
|
|
|
|
|
#include "../../safeguards.h"
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::IsValidEngine(EngineID engine_id)
|
|
|
|
{
|
|
|
|
const Engine *e = ::Engine::GetIfValid(engine_id);
|
|
|
|
if (e == nullptr || !e->IsEnabled()) return false;
|
|
|
|
|
|
|
|
/* AIs have only access to engines they can purchase or still have in use.
|
|
|
|
* Deity has access to all engined that will be or were available ever. */
|
|
|
|
CompanyID company = ScriptObject::GetCompany();
|
|
|
|
return company == OWNER_DEITY || ::IsEngineBuildable(engine_id, e->type, company) || ::Company::Get(company)->group_all[e->type].num_engines[engine_id] > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::IsBuildable(EngineID engine_id)
|
|
|
|
{
|
|
|
|
const Engine *e = ::Engine::GetIfValid(engine_id);
|
|
|
|
return e != nullptr && ::IsEngineBuildable(engine_id, e->type, ScriptObject::GetCompany());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ char *ScriptEngine::GetName(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return nullptr;
|
|
|
|
|
|
|
|
::SetDParam(0, engine_id);
|
|
|
|
return GetString(STR_ENGINE_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ CargoID ScriptEngine::GetCargoType(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return CT_INVALID;
|
|
|
|
|
|
|
|
CargoArray cap = ::GetCapacityOfArticulatedParts(engine_id);
|
|
|
|
|
|
|
|
CargoID most_cargo = CT_INVALID;
|
|
|
|
uint amount = 0;
|
|
|
|
for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
|
|
|
|
if (cap[cid] > amount) {
|
|
|
|
amount = cap[cid];
|
|
|
|
most_cargo = cid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return most_cargo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::CanRefitCargo(EngineID engine_id, CargoID cargo_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return false;
|
|
|
|
if (!ScriptCargo::IsValidCargo(cargo_id)) return false;
|
|
|
|
|
|
|
|
return HasBit(::GetUnionOfArticulatedRefitMasks(engine_id, true), cargo_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::CanPullCargo(EngineID engine_id, CargoID cargo_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return false;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false;
|
|
|
|
if (!ScriptCargo::IsValidCargo(cargo_id)) return false;
|
|
|
|
|
|
|
|
return (::RailVehInfo(engine_id)->ai_passenger_only != 1) || ScriptCargo::HasCargoClass(cargo_id, ScriptCargo::CC_PASSENGERS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* static */ int32 ScriptEngine::GetCapacity(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return -1;
|
|
|
|
|
|
|
|
const Engine *e = ::Engine::Get(engine_id);
|
|
|
|
switch (e->type) {
|
|
|
|
case VEH_ROAD:
|
|
|
|
case VEH_TRAIN: {
|
|
|
|
CargoArray capacities = GetCapacityOfArticulatedParts(engine_id);
|
|
|
|
for (CargoID c = 0; c < NUM_CARGO; c++) {
|
|
|
|
if (capacities[c] == 0) continue;
|
|
|
|
return capacities[c];
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
case VEH_SHIP:
|
|
|
|
case VEH_AIRCRAFT:
|
|
|
|
return e->GetDisplayDefaultCapacity();
|
|
|
|
|
|
|
|
default: NOT_REACHED();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ int32 ScriptEngine::GetReliability(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return -1;
|
|
|
|
if (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL && IsWagon(engine_id)) return -1;
|
|
|
|
|
|
|
|
return ::ToPercent16(::Engine::Get(engine_id)->reliability);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ int32 ScriptEngine::GetMaxSpeed(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return -1;
|
|
|
|
|
|
|
|
const Engine *e = ::Engine::Get(engine_id);
|
|
|
|
int32 max_speed = e->GetDisplayMaxSpeed(); // km-ish/h
|
|
|
|
if (e->type == VEH_AIRCRAFT) max_speed /= _settings_game.vehicle.plane_speed;
|
|
|
|
return max_speed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ Money ScriptEngine::GetPrice(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return -1;
|
|
|
|
|
|
|
|
return ::Engine::Get(engine_id)->GetCost();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ int32 ScriptEngine::GetMaxAge(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return -1;
|
|
|
|
if (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL && IsWagon(engine_id)) return -1;
|
|
|
|
|
|
|
|
return ::Engine::Get(engine_id)->GetLifeLengthInDays();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ Money ScriptEngine::GetRunningCost(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return -1;
|
|
|
|
|
|
|
|
return ::Engine::Get(engine_id)->GetRunningCost();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ int32 ScriptEngine::GetPower(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return -1;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL && GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return -1;
|
|
|
|
if (IsWagon(engine_id)) return -1;
|
|
|
|
|
|
|
|
return ::Engine::Get(engine_id)->GetPower();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ int32 ScriptEngine::GetWeight(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return -1;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL && GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return -1;
|
|
|
|
|
|
|
|
return ::Engine::Get(engine_id)->GetDisplayWeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ int32 ScriptEngine::GetMaxTractiveEffort(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return -1;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL && GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return -1;
|
|
|
|
if (IsWagon(engine_id)) return -1;
|
|
|
|
|
|
|
|
return ::Engine::Get(engine_id)->GetDisplayMaxTractiveEffort();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ ScriptDate::Date ScriptEngine::GetDesignDate(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return ScriptDate::DATE_INVALID;
|
|
|
|
|
|
|
|
return (ScriptDate::Date)::Engine::Get(engine_id)->intro_date;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ ScriptVehicle::VehicleType ScriptEngine::GetVehicleType(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return ScriptVehicle::VT_INVALID;
|
|
|
|
|
|
|
|
switch (::Engine::Get(engine_id)->type) {
|
|
|
|
case VEH_ROAD: return ScriptVehicle::VT_ROAD;
|
|
|
|
case VEH_TRAIN: return ScriptVehicle::VT_RAIL;
|
|
|
|
case VEH_SHIP: return ScriptVehicle::VT_WATER;
|
|
|
|
case VEH_AIRCRAFT: return ScriptVehicle::VT_AIR;
|
|
|
|
default: NOT_REACHED();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::IsWagon(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return false;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false;
|
|
|
|
|
|
|
|
return ::RailVehInfo(engine_id)->power == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::CanRunOnRail(EngineID engine_id, ScriptRail::RailType track_rail_type)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return false;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false;
|
|
|
|
if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
|
|
|
|
|
|
|
|
return ::IsCompatibleRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::HasPowerOnRail(EngineID engine_id, ScriptRail::RailType track_rail_type)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return false;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false;
|
|
|
|
if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
|
|
|
|
|
|
|
|
return ::HasPowerOnRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::CanRunOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type)
|
|
|
|
{
|
|
|
|
return HasPowerOnRoad(engine_id, road_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::HasPowerOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return false;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return false;
|
|
|
|
if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return false;
|
|
|
|
|
|
|
|
return ::HasPowerOnRoad((::RoadType)::RoadVehInfo(engine_id)->roadtype, (::RoadType)road_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ ScriptRoad::RoadType ScriptEngine::GetRoadType(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return ScriptRoad::ROADTYPE_INVALID;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return ScriptRoad::ROADTYPE_INVALID;
|
|
|
|
|
|
|
|
return (ScriptRoad::RoadType)(uint)::RoadVehInfo(engine_id)->roadtype;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ ScriptRail::RailType ScriptEngine::GetRailType(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return ScriptRail::RAILTYPE_INVALID;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return ScriptRail::RAILTYPE_INVALID;
|
|
|
|
|
|
|
|
return (ScriptRail::RailType)(uint)::RailVehInfo(engine_id)->railtype;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::IsArticulated(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return false;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD && GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false;
|
|
|
|
|
|
|
|
return IsArticulatedEngine(engine_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ ScriptAirport::PlaneType ScriptEngine::GetPlaneType(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return ScriptAirport::PT_INVALID;
|
|
|
|
if (GetVehicleType(engine_id) != ScriptVehicle::VT_AIR) return ScriptAirport::PT_INVALID;
|
|
|
|
|
|
|
|
return (ScriptAirport::PlaneType)::AircraftVehInfo(engine_id)->subtype;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ uint ScriptEngine::GetMaximumOrderDistance(EngineID engine_id)
|
|
|
|
{
|
|
|
|
if (!IsValidEngine(engine_id)) return 0;
|
|
|
|
|
|
|
|
switch (GetVehicleType(engine_id)) {
|
|
|
|
case ScriptVehicle::VT_AIR:
|
|
|
|
return ::Engine::Get(engine_id)->GetRange() * ::Engine::Get(engine_id)->GetRange();
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::EnableForCompany(EngineID engine_id, ScriptCompany::CompanyID company)
|
|
|
|
{
|
|
|
|
company = ScriptCompany::ResolveCompanyID(company);
|
|
|
|
|
|
|
|
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
|
|
|
|
EnforcePrecondition(false, IsValidEngine(engine_id));
|
|
|
|
EnforcePrecondition(false, company != ScriptCompany::COMPANY_INVALID);
|
|
|
|
|
|
|
|
return ScriptObject::DoCommand(0, engine_id, (uint32)company | (1 << 31), CMD_ENGINE_CTRL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool ScriptEngine::DisableForCompany(EngineID engine_id, ScriptCompany::CompanyID company)
|
|
|
|
{
|
|
|
|
company = ScriptCompany::ResolveCompanyID(company);
|
|
|
|
|
|
|
|
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
|
|
|
|
EnforcePrecondition(false, IsValidEngine(engine_id));
|
|
|
|
EnforcePrecondition(false, company != ScriptCompany::COMPANY_INVALID);
|
|
|
|
|
|
|
|
return ScriptObject::DoCommand(0, engine_id, company, CMD_ENGINE_CTRL);
|
|
|
|
}
|