mirror of https://github.com/OpenTTD/OpenTTD
Add: [NewGRF] Special value 0x7FFE for VarAction2 results specifying 'return calculated result'.
parent
9b2ee5bf5d
commit
4208f248d0
|
@ -23,6 +23,7 @@
|
|||
#include "../safeguards.h"
|
||||
|
||||
constexpr uint16_t GROUPID_CALLBACK_FAILED = 0x7FFF; ///< Explicit "failure" result.
|
||||
constexpr uint16_t GROUPID_CALCULATED_RESULT = 0x7FFE; ///< Return calculated result from VarAction2.
|
||||
|
||||
/**
|
||||
* Map the colour modifiers of TTDPatch to those that Open is using.
|
||||
|
@ -420,15 +421,31 @@ static void NewSpriteGroup(ByteReader &buf)
|
|||
std::vector<DeterministicSpriteGroupRange> ranges;
|
||||
ranges.resize(buf.ReadByte());
|
||||
for (auto &range : ranges) {
|
||||
range.group = GetGroupFromGroupID(setid, type, buf.ReadWord());
|
||||
auto groupid = buf.ReadWord();
|
||||
if (groupid == GROUPID_CALCULATED_RESULT) {
|
||||
range.result.calculated_result = true;
|
||||
} else {
|
||||
range.result.group = GetGroupFromGroupID(setid, type, groupid);
|
||||
}
|
||||
range.low = buf.ReadVarSize(varsize);
|
||||
range.high = buf.ReadVarSize(varsize);
|
||||
}
|
||||
|
||||
group->default_group = GetGroupFromGroupID(setid, type, buf.ReadWord());
|
||||
group->error_group = ranges.empty() ? group->default_group : ranges[0].group;
|
||||
/* nvar == 0 is a special case -- we turn our value into a callback result */
|
||||
group->calculated_result = ranges.empty();
|
||||
auto defgroupid = buf.ReadWord();
|
||||
if (defgroupid == GROUPID_CALCULATED_RESULT) {
|
||||
group->default_result.calculated_result = true;
|
||||
} else {
|
||||
group->default_result.group = GetGroupFromGroupID(setid, type, defgroupid);
|
||||
}
|
||||
/* 'calculated_result' makes no sense for the 'error' case. Use callback failure (nullptr) instead */
|
||||
group->error_group = ranges.empty() ? group->default_result.group : ranges[0].result.group;
|
||||
/* nvar == 0 is a special case:
|
||||
* - set "default_result" to "calculated_result".
|
||||
* - the old value specifies the "error_group". */
|
||||
if (ranges.empty()) {
|
||||
group->default_result.calculated_result = true;
|
||||
group->default_result.group = nullptr;
|
||||
}
|
||||
|
||||
/* Sort ranges ascending. When ranges overlap, this may required clamping or splitting them */
|
||||
std::vector<uint32_t> bounds;
|
||||
|
@ -440,13 +457,13 @@ static void NewSpriteGroup(ByteReader &buf)
|
|||
std::sort(bounds.begin(), bounds.end());
|
||||
bounds.erase(std::unique(bounds.begin(), bounds.end()), bounds.end());
|
||||
|
||||
std::vector<const SpriteGroup *> target;
|
||||
std::vector<DeterministicSpriteGroupResult> target;
|
||||
target.reserve(bounds.size());
|
||||
for (const auto &bound : bounds) {
|
||||
const SpriteGroup *t = group->default_group;
|
||||
auto t = group->default_result;
|
||||
for (const auto &range : ranges) {
|
||||
if (range.low <= bound && bound <= range.high) {
|
||||
t = range.group;
|
||||
t = range.result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -455,11 +472,11 @@ static void NewSpriteGroup(ByteReader &buf)
|
|||
assert(target.size() == bounds.size());
|
||||
|
||||
for (uint j = 0; j < bounds.size(); ) {
|
||||
if (target[j] != group->default_group) {
|
||||
if (target[j] != group->default_result) {
|
||||
DeterministicSpriteGroupRange &r = group->ranges.emplace_back();
|
||||
r.group = target[j];
|
||||
r.result = target[j];
|
||||
r.low = bounds[j];
|
||||
while (j < bounds.size() && target[j] == r.group) {
|
||||
while (j < bounds.size() && target[j] == r.result) {
|
||||
j++;
|
||||
}
|
||||
r.high = j < bounds.size() ? bounds[j] - 1 : UINT32_MAX;
|
||||
|
|
|
@ -224,26 +224,27 @@ static bool RangeHighComparator(const DeterministicSpriteGroupRange &range, uint
|
|||
|
||||
object.last_value = last_value;
|
||||
|
||||
if (this->calculated_result) {
|
||||
/* nvar == 0 is a special case -- we turn our value into a callback result */
|
||||
return static_cast<CallbackResult>(GB(value, 0, 15));
|
||||
}
|
||||
auto result = this->default_result;
|
||||
|
||||
if (this->ranges.size() > 4) {
|
||||
const auto &lower = std::lower_bound(this->ranges.begin(), this->ranges.end(), value, RangeHighComparator);
|
||||
if (lower != this->ranges.end() && lower->low <= value) {
|
||||
assert(lower->low <= value && value <= lower->high);
|
||||
return SpriteGroup::Resolve(lower->group, object, false);
|
||||
result = lower->result;
|
||||
}
|
||||
} else {
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.low <= value && value <= range.high) {
|
||||
return SpriteGroup::Resolve(range.group, object, false);
|
||||
result = range.result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SpriteGroup::Resolve(this->default_group, object, false);
|
||||
if (result.calculated_result) {
|
||||
return static_cast<CallbackResult>(GB(value, 0, 15));
|
||||
}
|
||||
return SpriteGroup::Resolve(result.group, object, false);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -163,8 +163,15 @@ struct DeterministicSpriteGroupAdjust {
|
|||
};
|
||||
|
||||
|
||||
struct DeterministicSpriteGroupRange {
|
||||
struct DeterministicSpriteGroupResult {
|
||||
bool calculated_result = false;
|
||||
const SpriteGroup *group = nullptr;
|
||||
|
||||
bool operator==(const DeterministicSpriteGroupResult &) const = default;
|
||||
};
|
||||
|
||||
struct DeterministicSpriteGroupRange {
|
||||
DeterministicSpriteGroupResult result;
|
||||
uint32_t low = 0;
|
||||
uint32_t high = 0;
|
||||
};
|
||||
|
@ -175,12 +182,11 @@ struct DeterministicSpriteGroup : SpriteGroup {
|
|||
|
||||
VarSpriteGroupScope var_scope{};
|
||||
DeterministicSpriteGroupSize size{};
|
||||
bool calculated_result = false;
|
||||
std::vector<DeterministicSpriteGroupAdjust> adjusts{};
|
||||
std::vector<DeterministicSpriteGroupRange> ranges{}; // Dynamically allocated
|
||||
|
||||
/* Dynamically allocated, this is the sole owner */
|
||||
const SpriteGroup *default_group = nullptr;
|
||||
DeterministicSpriteGroupResult default_result;
|
||||
|
||||
const SpriteGroup *error_group = nullptr; // was first range, before sorting ranges
|
||||
|
||||
|
|
Loading…
Reference in New Issue