VarAction2: Add support for more varaction2 types

Add CB failure and deterministic relative types
This commit is contained in:
Jonathan G Rennison
2023-03-14 17:57:30 +00:00
parent 48d602962f
commit 5718730d68
24 changed files with 282 additions and 50 deletions

View File

@@ -18,6 +18,7 @@
#include "newgrf_extension.h"
#include "scope.h"
#include "debug_settings.h"
#include "newgrf_engine.h"
#include "safeguards.h"
@@ -165,7 +166,7 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc
* @param relative Additional parameter for #VSG_SCOPE_RELATIVE.
* @return The resolver for the requested scope.
*/
/* virtual */ ScopeResolver *ResolverObject::GetScope(VarSpriteGroupScope scope, byte relative)
/* virtual */ ScopeResolver *ResolverObject::GetScope(VarSpriteGroupScope scope, VarSpriteGroupScopeOffset relative)
{
return &this->default_scope;
}
@@ -259,7 +260,7 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
uint32 last_value = 0;
uint32 value = 0;
ScopeResolver *scope = object.GetScope(this->var_scope);
ScopeResolver *scope = object.GetScope(this->var_scope, this->var_scope_count);
const DeterministicSpriteGroupAdjust *end = this->adjusts.data() + this->adjusts.size();
for (const DeterministicSpriteGroupAdjust *iter = this->adjusts.data(); iter != end; ++iter) {
@@ -271,6 +272,17 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
/* Try to get the variable. We shall assume it is available, unless told otherwise. */
GetVariableExtra extra(adjust.and_mask << adjust.shift_num);
if (adjust.variable == 0x7E) {
const Vehicle *relative_scope_vehicle = nullptr;
VarSpriteGroupScopeOffset relative_scope_cached_count = 0;
if (this->var_scope == VSG_SCOPE_RELATIVE) {
/* Save relative scope vehicle in case it will be changed during the procedure */
VehicleResolverObject *veh_object = dynamic_cast<VehicleResolverObject *>(&object);
if (veh_object != nullptr) {
relative_scope_vehicle = veh_object->relative_scope.v;
relative_scope_cached_count = veh_object->cached_relative_count;
}
}
const SpriteGroup *subgroup = SpriteGroup::Resolve(adjust.subroutine, object, false);
if (subgroup == nullptr) {
value = CALLBACK_FAILED;
@@ -278,6 +290,13 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
value = subgroup->GetCallbackResult();
}
if (relative_scope_vehicle != nullptr) {
/* Reset relative scope vehicle in case it was changed during the procedure */
VehicleResolverObject *veh_object = static_cast<VehicleResolverObject *>(&object);
veh_object->relative_scope.v = relative_scope_vehicle;
veh_object->cached_relative_count = relative_scope_cached_count;
}
/* Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */
} else if (adjust.variable == 0x7B) {
_sprite_group_resolve_check_veh_check = false;
@@ -338,7 +357,7 @@ bool DeterministicSpriteGroup::GroupMayBeBypassed() const
const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject &object) const
{
ScopeResolver *scope = object.GetScope(this->var_scope, this->count);
ScopeResolver *scope = object.GetScope(this->var_scope, this->var_scope_count);
if (object.callback == CBID_RANDOM_TRIGGER) {
/* Handle triggers */
byte match = this->triggers & object.waiting_triggers;
@@ -445,6 +464,14 @@ static const char *_sg_size_names[] {
"DWORD",
};
static const char *_sg_relative_scope_modes[] {
"BACKWARD_SELF",
"FORWARD_SELF",
"BACKWARD_ENGINE",
"BACKWARD_SAMEID",
};
static_assert(lengthof(_sg_relative_scope_modes) == VSGSRM_END);
static char *GetAdjustOperationName(char *str, const char *last, DeterministicSpriteGroupAdjustOperation operation)
{
if (operation < DSGA_OP_END) return strecat(str, _dsg_op_names[operation], last);
@@ -601,6 +628,23 @@ void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, const char *paddi
if (sg->sg_flags & SGF_INLINING) strecat(extra_info, " (inlining)", lastof(extra_info));
}
char scope_buffer[64] = "";
auto get_scope_name = [&](VarSpriteGroupScope var_scope, VarSpriteGroupScopeOffset var_scope_count) -> const char * {
if (var_scope == VSG_SCOPE_RELATIVE) {
char *b = scope_buffer;
b += seprintf(b, lastof(scope_buffer), "%s[%s, ", _sg_scope_names[var_scope], _sg_relative_scope_modes[GB(var_scope_count, 8, 2)]);
byte offset = GB(var_scope_count, 0, 8);
if (HasBit(var_scope_count, 15)) {
b += seprintf(b, lastof(scope_buffer), "var 0x100]");
} else {
b += seprintf(b, lastof(scope_buffer), "%u]", offset);
}
return scope_buffer;
} else {
return _sg_scope_names[var_scope];
}
};
switch (sg->type) {
case SGT_REAL: {
const RealSpriteGroup *rsg = (const RealSpriteGroup*)sg;
@@ -660,26 +704,26 @@ void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, const char *paddi
}
if (dsg == this->top_default_group && !((flags & SGDF_DEFAULT) && strlen(padding) == 2)) {
seprintf(this->buffer, lastof(this->buffer), "%sTOP LEVEL DEFAULT GROUP: Deterministic (%s, %s), [%u]",
padding, _sg_scope_names[dsg->var_scope], _sg_size_names[dsg->size], dsg->nfo_line);
padding, get_scope_name(dsg->var_scope, dsg->var_scope_count), _sg_size_names[dsg->size], dsg->nfo_line);
print();
return;
}
if (dsg == this->top_graphics_group && !((flags & SGDF_RANGE) && strlen(padding) == 2)) {
seprintf(this->buffer, lastof(this->buffer), "%sTOP LEVEL GRAPHICS GROUP: Deterministic (%s, %s), [%u]",
padding, _sg_scope_names[dsg->var_scope], _sg_size_names[dsg->size], dsg->nfo_line);
padding, get_scope_name(dsg->var_scope, dsg->var_scope_count), _sg_size_names[dsg->size], dsg->nfo_line);
print();
return;
}
auto res = this->seen_dsgs.insert(dsg);
if (!res.second) {
seprintf(this->buffer, lastof(this->buffer), "%sGROUP SEEN ABOVE: Deterministic (%s, %s), [%u]",
padding, _sg_scope_names[dsg->var_scope], _sg_size_names[dsg->size], dsg->nfo_line);
padding, get_scope_name(dsg->var_scope, dsg->var_scope_count), _sg_size_names[dsg->size], dsg->nfo_line);
print();
return;
}
char *p = this->buffer;
p += seprintf(p, lastof(this->buffer), "%sDeterministic (%s, %s)%s [%u]",
padding, _sg_scope_names[dsg->var_scope], _sg_size_names[dsg->size], extra_info, dsg->nfo_line);
padding, get_scope_name(dsg->var_scope, dsg->var_scope_count), _sg_size_names[dsg->size], extra_info, dsg->nfo_line);
if (HasBit(_misc_debug_flags, MDF_NEWGRF_SG_DUMP_MORE_DETAIL)) {
if (dsg->dsg_flags & DSGF_NO_DSE) p += seprintf(p, lastof(this->buffer), ", NO_DSE");
if (dsg->dsg_flags & DSGF_VAR_TRACKING_PENDING) p += seprintf(p, lastof(this->buffer), ", VAR_PENDING");
@@ -752,9 +796,9 @@ void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, const char *paddi
}
}
seprintf(this->buffer, lastof(this->buffer), "%sRandom (%s, %s, triggers: %X, count: %X, lowest_randbit: %X, groups: %u)%s [%u]",
padding, _sg_scope_names[rsg->var_scope], rsg->cmp_mode == RSG_CMP_ANY ? "ANY" : "ALL",
rsg->triggers, rsg->count, rsg->lowest_randbit, (uint)rsg->groups.size(), extra_info, rsg->nfo_line);
seprintf(this->buffer, lastof(this->buffer), "%sRandom (%s, %s, triggers: %X, lowest_randbit: %X, groups: %u)%s [%u]",
padding, get_scope_name(rsg->var_scope, rsg->var_scope_count), rsg->cmp_mode == RSG_CMP_ANY ? "ANY" : "ALL",
rsg->triggers, rsg->lowest_randbit, (uint)rsg->groups.size(), extra_info, rsg->nfo_line);
print();
emit_start();
std::string sub_padding(padding);