Merge branch 'master' into jgrpp

# Conflicts:
#	src/3rdparty/fmt/core.h
#	src/command_type.h
#	src/console_cmds.cpp
#	src/core/overflowsafe_type.hpp
#	src/landscape.cpp
#	src/network/network.cpp
#	src/newgrf_object.h
#	src/object_cmd.cpp
#	src/order_gui.cpp
#	src/saveload/vehicle_sl.cpp
#	src/script/api/script_industrytype.cpp
#	src/script/api/script_object.hpp
#	src/script/api/script_town.cpp
#	src/table/object_land.h
#	src/timetable_cmd.cpp
#	src/tree_cmd.cpp
#	src/vehicle_gui.cpp
#	src/window.cpp
This commit is contained in:
Jonathan G Rennison
2023-01-15 19:28:37 +00:00
64 changed files with 442 additions and 310 deletions

View File

@@ -10,17 +10,12 @@
#include "../../stdafx.h"
#include "script_base.hpp"
#include "script_error.hpp"
#include "../../network/network.h"
#include "../../core/random_func.hpp"
#include "../../safeguards.h"
/* static */ uint32 ScriptBase::Rand()
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client. */
if (_networking) return ::InteractiveRandom();
return ::Random();
return ScriptObject::GetRandomizer().Next();
}
/* static */ uint32 ScriptBase::RandItem(int unused_param)
@@ -30,10 +25,7 @@
/* static */ uint ScriptBase::RandRange(uint max)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client. */
if (_networking) return ::InteractiveRandomRange(max);
return ::RandomRange(max);
return ScriptObject::GetRandomizer().Next(max);
}
/* static */ uint32 ScriptBase::RandRangeItem(int unused_param, uint max)

View File

@@ -18,9 +18,6 @@
*
* @note The random functions are not called Random and RandomRange, because
* RANDOM_DEBUG does some tricky stuff, which messes with those names.
* @note In MP we cannot use Random because that will cause desyncs (scripts are
* ran on the server only, not on all clients). This means that
* we use InteractiveRandom in MP. Rand() takes care of this for you.
*/
class ScriptBase : public ScriptObject {
public:

View File

@@ -93,9 +93,10 @@
EnforcePrecondition(false, gender == GENDER_MALE || gender == GENDER_FEMALE);
EnforcePrecondition(false, GetPresidentGender(ScriptCompany::COMPANY_SELF) != gender);
Randomizer &randomizer = ScriptObject::GetRandomizer();
CompanyManagerFace cmf;
GenderEthnicity ge = (GenderEthnicity)((gender == GENDER_FEMALE ? (1 << ::GENDER_FEMALE) : 0) | (::InteractiveRandom() & (1 << ETHNICITY_BLACK)));
RandomCompanyManagerFaceBits(cmf, ge, false);
GenderEthnicity ge = (GenderEthnicity)((gender == GENDER_FEMALE ? (1 << ::GENDER_FEMALE) : 0) | (randomizer.Next() & (1 << ETHNICITY_BLACK)));
RandomCompanyManagerFaceBits(cmf, ge, false, randomizer);
return ScriptObject::DoCommand(0, 0, cmf, CMD_SET_COMPANY_MANAGER_FACE);
}

View File

@@ -26,6 +26,7 @@
if (!IsValid(setting)) return -1;
const SettingDesc *sd = GetSettingFromName(setting);
assert(sd != nullptr);
return sd->AsIntSetting()->Read(&_settings_game);
}
@@ -34,6 +35,7 @@
if (!IsValid(setting)) return false;
const SettingDesc *sd = GetSettingFromName(setting);
assert(sd != nullptr);
if ((sd->flags & SF_NO_NETWORK_SYNC) != 0) return false;

View File

@@ -9,6 +9,7 @@
#include "../../stdafx.h"
#include "script_industrytype.hpp"
#include "script_base.hpp"
#include "script_map.hpp"
#include "script_error.hpp"
#include "../../strings_func.h"
@@ -120,8 +121,8 @@
EnforcePrecondition(false, CanBuildIndustry(industry_type));
EnforcePrecondition(false, ScriptMap::IsValidTile(tile));
uint32 seed = ::InteractiveRandom();
uint32 layout_index = ::InteractiveRandomRange((uint32)::GetIndustrySpec(industry_type)->layouts.size());
uint32 seed = ScriptBase::Rand();
uint32 layout_index = ScriptBase::RandRange((uint32)::GetIndustrySpec(industry_type)->layouts.size());
return ScriptObject::DoCommand(tile, (1 << 16) | (layout_index << 8) | industry_type, seed, CMD_BUILD_INDUSTRY);
}
@@ -129,7 +130,7 @@
{
EnforcePrecondition(false, CanProspectIndustry(industry_type));
uint32 seed = ::InteractiveRandom();
uint32 seed = ScriptBase::Rand();
return ScriptObject::DoCommand(0, industry_type, seed, CMD_BUILD_INDUSTRY);
}

View File

@@ -395,3 +395,19 @@ ScriptObject::ActiveInstance::~ActiveInstance()
NOT_REACHED();
}
/* static */ Randomizer ScriptObject::random_states[OWNER_END];
Randomizer &ScriptObject::GetRandomizer(Owner owner)
{
return ScriptObject::random_states[owner];
}
void ScriptObject::InitializeRandomizers()
{
Randomizer random = _random;
for (Owner owner = OWNER_BEGIN; owner < OWNER_END; owner++) {
ScriptObject::GetRandomizer(owner).SetSeed(random.Next());
}
}

View File

@@ -13,6 +13,7 @@
#include "../../misc/countedptr.hpp"
#include "../../road_type.h"
#include "../../rail_type.h"
#include "../../core/random_func.hpp"
#include "script_types.hpp"
#include "../script_suspend.hpp"
@@ -67,6 +68,18 @@ public:
*/
static class ScriptInstance *GetActiveInstance();
/**
* Get a reference of the randomizer that brings this script random values.
* @param owner The owner/script to get the randomizer for. This defaults to ScriptObject::GetRootCompany()
*/
static Randomizer &GetRandomizer(Owner owner = ScriptObject::GetRootCompany());
/**
* Initialize/reset the script random states. The state of the scripts are
* based on the current _random seed, but _random does not get changed.
*/
static void InitializeRandomizers();
protected:
/**
* Executes a raw DoCommand for the script.
@@ -315,6 +328,8 @@ private:
* @param story_page_id The new StoryPageID.
*/
static void SetNewStoryPageElementID(StoryPageElementID story_page_element_id);
static Randomizer random_states[OWNER_END]; ///< Random states for each of the scripts (game script uses OWNER_DEITY)
};
#endif /* SCRIPT_OBJECT_HPP */

View File

@@ -67,6 +67,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, ScriptOrder::OrderPositio
if (order_position == ScriptOrder::ORDER_INVALID) return nullptr;
}
const Order *order = v->GetFirstOrder();
assert(order != nullptr);
while (order->GetType() == OT_IMPLICIT) order = order->next;
while (order_position > 0) {
order_position = (ScriptOrder::OrderPosition)(order_position - 1);
@@ -91,6 +92,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
int res = (int)order_position;
const Order *order = v->orders->GetFirstOrder();
assert(order != nullptr);
for (; order->GetType() == OT_IMPLICIT; order = order->next) res++;
while (order_position > 0) {
order_position = (ScriptOrder::OrderPosition)(order_position - 1);
@@ -136,6 +138,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
const Order *order = ::Vehicle::Get(vehicle_id)->GetOrder(ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position));
assert(order != nullptr);
return order->GetType() == OT_CONDITIONAL;
}
@@ -145,6 +148,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
const Order *order = ::ResolveOrder(vehicle_id, order_position);
assert(order != nullptr);
return order->GetType() == OT_DUMMY;
}
@@ -176,6 +180,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
if (order_position == ORDER_CURRENT) {
int cur_order_pos = ::Vehicle::Get(vehicle_id)->cur_real_order_index;
const Order *order = ::Vehicle::Get(vehicle_id)->GetFirstOrder();
assert(order != nullptr);
int num_implicit_orders = 0;
for (int i = 0; i < cur_order_pos; i++) {
if (order->GetType() == OT_IMPLICIT) num_implicit_orders++;

View File

@@ -303,7 +303,7 @@
EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_TOWN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
}
uint32 townnameparts;
if (!GenerateTownName(&townnameparts)) {
if (!GenerateTownName(ScriptObject::GetRandomizer(), &townnameparts)) {
ScriptController::DecreaseOps(50000);
ScriptObject::SetLastError(ScriptError::ERR_NAME_IS_NOT_UNIQUE);
return false;

View File

@@ -46,6 +46,7 @@
if (colour != TC_INVALID && (::TextColour)colour >= ::TC_END) return;
Window *w = FindWindowById((::WindowClass)window, number);
assert(w != nullptr);
if (widget == WIDGET_ALL) {
if (colour != TC_INVALID) return;