2009-08-21 20:21:05 +00:00
/*
* 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/>.
*/
2008-05-06 15:11:33 +00:00
/** @file newgrf_spritegroup.cpp Handling of primarily NewGRF action 2. */
2007-03-21 03:06:21 +00:00
2006-04-20 20:51:57 +00:00
# include "stdafx.h"
2012-11-10 20:37:31 +00:00
# include "debug.h"
2006-04-27 19:53:58 +00:00
# include "newgrf_spritegroup.h"
2020-01-26 12:45:51 +00:00
# include "newgrf_profiling.h"
2009-05-22 15:13:50 +00:00
# include "core/pool_func.hpp"
2016-09-09 22:44:13 +00:00
# include "vehicle_type.h"
2020-08-25 00:26:44 +00:00
# include "newgrf_cache_check.h"
2021-05-21 18:35:22 +00:00
# include "string_func.h"
2022-05-26 20:31:20 +00:00
# include "newgrf_extension.h"
2022-06-04 20:08:35 +00:00
# include "scope.h"
2022-06-14 01:23:23 +00:00
# include "debug_settings.h"
2023-03-14 17:57:30 +00:00
# include "newgrf_engine.h"
2024-01-25 18:37:23 +00:00
# include <bit>
2006-04-20 20:51:57 +00:00
2014-04-23 20:13:33 +00:00
# include "safeguards.h"
2009-05-22 15:13:50 +00:00
SpriteGroupPool _spritegroup_pool ( " SpriteGroup " ) ;
INSTANTIATE_POOL_METHODS ( SpriteGroup )
2006-04-20 20:51:57 +00:00
2024-01-07 16:41:53 +00:00
TemporaryStorageArray < int32_t , 0x110 > _temp_store ;
2013-12-23 18:08:16 +00:00
2022-06-07 17:54:42 +00:00
std : : map < const DeterministicSpriteGroup * , DeterministicSpriteGroupShadowCopy > _deterministic_sg_shadows ;
std : : map < const RandomizedSpriteGroup * , RandomizedSpriteGroupShadowCopy > _randomized_sg_shadows ;
bool _grfs_loaded_with_sg_shadow_enable = false ;
2023-03-11 16:05:28 +00:00
GrfSpecFeature GetGrfSpecFeatureForParentScope ( GrfSpecFeature feature )
{
switch ( feature ) {
case GSF_STATIONS :
case GSF_BRIDGES :
case GSF_HOUSES :
case GSF_INDUSTRIES :
case GSF_OBJECTS :
case GSF_ROADSTOPS :
return GSF_FAKE_TOWNS ;
case GSF_INDUSTRYTILES :
return GSF_INDUSTRIES ;
default :
return feature ;
}
}
2013-12-23 18:08:16 +00:00
/**
* ResolverObject ( re ) entry point .
* This cannot be made a call to a virtual function because virtual functions
2019-04-10 21:07:06 +00:00
* do not like nullptr and checking for nullptr * everywhere * is more cumbersome than
2013-12-23 18:08:16 +00:00
* this little helper function .
* @ param group the group to resolve for
* @ param object information needed to resolve the group
* @ param top_level true if this is a top - level SpriteGroup , false if used nested in another SpriteGroup .
* @ return the resolved group
*/
/* static */ const SpriteGroup * SpriteGroup : : Resolve ( const SpriteGroup * group , ResolverObject & object , bool top_level )
{
2019-04-10 21:07:06 +00:00
if ( group = = nullptr ) return nullptr ;
2020-01-26 12:45:51 +00:00
const GRFFile * grf = object . grffile ;
auto profiler = std : : find_if ( _newgrf_profilers . begin ( ) , _newgrf_profilers . end ( ) , [ & ] ( const NewGRFProfiler & pr ) { return pr . grffile = = grf ; } ) ;
if ( profiler = = _newgrf_profilers . end ( ) | | ! profiler - > active ) {
if ( top_level ) _temp_store . ClearChanges ( ) ;
return group - > Resolve ( object ) ;
} else if ( top_level ) {
profiler - > BeginResolve ( object ) ;
2013-12-23 18:08:36 +00:00
_temp_store . ClearChanges ( ) ;
2020-01-26 12:45:51 +00:00
const SpriteGroup * result = group - > Resolve ( object ) ;
profiler - > EndResolve ( result ) ;
return result ;
} else {
profiler - > RecursiveResolve ( ) ;
return group - > Resolve ( object ) ;
2013-12-23 18:08:36 +00:00
}
2013-12-23 18:08:16 +00:00
}
2024-01-07 16:41:53 +00:00
static inline uint32_t GetVariable ( const ResolverObject & object , ScopeResolver * scope , uint16_t variable , uint32_t parameter , GetVariableExtra * extra )
2006-04-27 19:53:58 +00:00
{
2024-01-07 16:41:53 +00:00
uint32_t value ;
2006-04-27 19:53:58 +00:00
switch ( variable ) {
2013-11-24 14:41:19 +00:00
case 0x0C : return object . callback ;
case 0x10 : return object . callback_param1 ;
case 0x18 : return object . callback_param2 ;
2022-06-06 00:27:53 +00:00
case 0x1A : return UINT_MAX ;
2013-11-24 14:41:19 +00:00
case 0x1C : return object . last_value ;
2006-04-27 19:53:58 +00:00
2012-11-10 20:37:31 +00:00
case 0x5F : return ( scope - > GetRandomBits ( ) < < 8 ) | scope - > GetTriggers ( ) ;
2008-06-17 07:05:17 +00:00
2011-06-12 20:40:21 +00:00
case 0x7D : return _temp_store . GetValue ( parameter ) ;
2007-04-21 07:27:16 +00:00
2008-07-30 18:23:12 +00:00
case 0x7F :
2019-04-10 21:07:06 +00:00
if ( object . grffile = = nullptr ) return 0 ;
2013-11-24 14:41:19 +00:00
return object . grffile - > GetParam ( parameter ) ;
2008-07-30 18:23:12 +00:00
2018-03-11 13:17:44 +00:00
default :
/* First handle variables common with Action7/9/D */
if ( variable < 0x40 & & GetGlobalVariable ( variable , & value , object . grffile ) ) return value ;
/* Not a common variable, so evaluate the feature specific variables */
2020-08-25 00:26:44 +00:00
return scope - > GetVariable ( variable , parameter , extra ) ;
2006-04-27 19:53:58 +00:00
}
}
2012-11-10 20:37:31 +00:00
/**
* Get a few random bits . Default implementation has no random bits .
* @ return Random bits .
*/
2024-01-07 16:41:53 +00:00
/* virtual */ uint32_t ScopeResolver : : GetRandomBits ( ) const
2012-11-10 20:37:31 +00:00
{
return 0 ;
}
/**
* Get the triggers . Base class returns \ c 0 to prevent trouble .
* @ return The triggers .
*/
2024-01-07 16:41:53 +00:00
/* virtual */ uint32_t ScopeResolver : : GetTriggers ( ) const
2012-11-10 20:37:31 +00:00
{
return 0 ;
}
/**
* Get a variable value . Default implementation has no available variables .
* @ param variable Variable to read
* @ param parameter Parameter for 60 + x variables
* @ param [ out ] available Set to false , in case the variable does not exist .
* @ return Value
*/
2024-01-07 16:41:53 +00:00
/* virtual */ uint32_t ScopeResolver : : GetVariable ( uint16_t variable , uint32_t parameter , GetVariableExtra * extra ) const
2012-11-10 20:37:31 +00:00
{
DEBUG ( grf , 1 , " Unhandled scope variable 0x%X " , variable ) ;
2020-08-25 00:26:44 +00:00
extra - > available = false ;
2012-11-10 20:37:31 +00:00
return UINT_MAX ;
}
/**
* Store a value into the persistent storage area ( PSA ) . Default implementation does nothing ( for newgrf classes without storage ) .
*/
2024-01-07 16:41:53 +00:00
/* virtual */ void ScopeResolver : : StorePSA ( uint reg , int32_t value ) { }
2012-11-10 20:37:31 +00:00
2012-11-10 20:46:39 +00:00
/**
* Get the real sprites of the grf .
* @ param group Group to get .
* @ return The available sprite group .
*/
2012-11-10 20:37:31 +00:00
/* virtual */ const SpriteGroup * ResolverObject : : ResolveReal ( const RealSpriteGroup * group ) const
{
2021-06-04 11:52:00 +00:00
if ( ! group - > loaded . empty ( ) ) return group - > loaded [ 0 ] ;
if ( ! group - > loading . empty ( ) ) return group - > loading [ 0 ] ;
2019-04-10 21:07:06 +00:00
return nullptr ;
2012-11-10 20:37:31 +00:00
}
/**
2012-11-10 20:46:39 +00:00
* Get a resolver for the \ a scope .
* @ return The resolver for the requested scope .
2012-11-10 20:37:31 +00:00
*/
2023-03-14 17:57:30 +00:00
/* virtual */ ScopeResolver * ResolverObject : : GetScope ( VarSpriteGroupScope scope , VarSpriteGroupScopeOffset relative )
2012-11-10 20:37:31 +00:00
{
2012-11-10 20:45:59 +00:00
return & this - > default_scope ;
2012-11-10 20:37:31 +00:00
}
2006-04-27 19:53:58 +00:00
2007-01-11 10:58:53 +00:00
/* Evaluate an adjustment for a variable of the given size.
2009-03-14 18:16:29 +00:00
* U is the unsigned type and S is the signed type to use . */
2007-01-11 10:58:53 +00:00
template < typename U , typename S >
2024-01-07 16:41:53 +00:00
static U EvalAdjustT ( const DeterministicSpriteGroupAdjust & adjust , ScopeResolver * scope , U last_value , uint32_t value , const DeterministicSpriteGroupAdjust * * adjust_iter = nullptr )
2007-01-11 10:58:53 +00:00
{
2021-05-01 23:04:34 +00:00
value > > = adjust . shift_num ;
value & = adjust . and_mask ;
2007-01-11 10:58:53 +00:00
2021-05-01 23:04:34 +00:00
switch ( adjust . type ) {
case DSGA_TYPE_DIV : value = ( ( S ) value + ( S ) adjust . add_val ) / ( S ) adjust . divmod_val ; break ;
case DSGA_TYPE_MOD : value = ( ( S ) value + ( S ) adjust . add_val ) % ( S ) adjust . divmod_val ; break ;
2022-06-03 13:17:15 +00:00
case DSGA_TYPE_EQ : value = ( value = = adjust . add_val ) ? 1 : 0 ; break ;
case DSGA_TYPE_NEQ : value = ( value ! = adjust . add_val ) ? 1 : 0 ; break ;
2007-01-11 10:58:53 +00:00
case DSGA_TYPE_NONE : break ;
}
2006-04-27 19:53:58 +00:00
2022-07-30 22:32:23 +00:00
auto handle_jump = [ & ] ( bool jump , U jump_return_value ) - > U {
if ( jump & & adjust_iter ! = nullptr ) {
/* Jump */
( * adjust_iter ) + = adjust . jump ;
return jump_return_value ;
} else {
/* Don't jump */
return last_value ;
}
} ;
2021-05-01 23:04:34 +00:00
switch ( adjust . operation ) {
2007-01-11 10:58:53 +00:00
case DSGA_OP_ADD : return last_value + value ;
case DSGA_OP_SUB : return last_value - value ;
2021-01-08 10:16:18 +00:00
case DSGA_OP_SMIN : return std : : min < S > ( last_value , value ) ;
case DSGA_OP_SMAX : return std : : max < S > ( last_value , value ) ;
case DSGA_OP_UMIN : return std : : min < U > ( last_value , value ) ;
case DSGA_OP_UMAX : return std : : max < U > ( last_value , value ) ;
2007-05-14 17:37:34 +00:00
case DSGA_OP_SDIV : return value = = 0 ? ( S ) last_value : ( S ) last_value / ( S ) value ;
case DSGA_OP_SMOD : return value = = 0 ? ( S ) last_value : ( S ) last_value % ( S ) value ;
case DSGA_OP_UDIV : return value = = 0 ? ( U ) last_value : ( U ) last_value / ( U ) value ;
case DSGA_OP_UMOD : return value = = 0 ? ( U ) last_value : ( U ) last_value % ( U ) value ;
2007-01-11 10:58:53 +00:00
case DSGA_OP_MUL : return last_value * value ;
case DSGA_OP_AND : return last_value & value ;
case DSGA_OP_OR : return last_value | value ;
case DSGA_OP_XOR : return last_value ^ value ;
2011-06-12 20:40:21 +00:00
case DSGA_OP_STO : _temp_store . StoreValue ( ( U ) value , ( S ) last_value ) ; return last_value ;
2007-04-21 07:27:16 +00:00
case DSGA_OP_RST : return value ;
2012-11-11 12:57:27 +00:00
case DSGA_OP_STOP : scope - > StorePSA ( ( U ) value , ( S ) last_value ) ; return last_value ;
2024-01-17 19:58:06 +00:00
case DSGA_OP_ROR : return std : : rotr < uint32_t > ( ( U ) last_value , ( U ) value & 0x1F ) ; // mask 'value' to 5 bits, which should behave the same on all architectures.
2007-09-22 20:29:17 +00:00
case DSGA_OP_SCMP : return ( ( S ) last_value = = ( S ) value ) ? 1 : ( ( S ) last_value < ( S ) value ? 0 : 2 ) ;
case DSGA_OP_UCMP : return ( ( U ) last_value = = ( U ) value ) ? 1 : ( ( U ) last_value < ( U ) value ? 0 : 2 ) ;
2024-01-07 16:41:53 +00:00
case DSGA_OP_SHL : return ( uint32_t ) ( U ) last_value < < ( ( U ) value & 0x1F ) ; // Same behaviour as in ParamSet, mask 'value' to 5 bits, which should behave the same on all architectures.
case DSGA_OP_SHR : return ( uint32_t ) ( U ) last_value > > ( ( U ) value & 0x1F ) ;
case DSGA_OP_SAR : return ( int32_t ) ( S ) last_value > > ( ( U ) value & 0x1F ) ;
2022-05-25 00:50:10 +00:00
case DSGA_OP_TERNARY : return ( last_value ! = 0 ) ? value : adjust . add_val ;
2022-05-25 01:23:25 +00:00
case DSGA_OP_EQ : return ( last_value = = value ) ? 1 : 0 ;
2022-05-25 22:58:44 +00:00
case DSGA_OP_SLT : return ( ( S ) last_value < ( S ) value ) ? 1 : 0 ;
case DSGA_OP_SGE : return ( ( S ) last_value > = ( S ) value ) ? 1 : 0 ;
case DSGA_OP_SLE : return ( ( S ) last_value < = ( S ) value ) ? 1 : 0 ;
case DSGA_OP_SGT : return ( ( S ) last_value > ( S ) value ) ? 1 : 0 ;
2022-05-27 02:14:07 +00:00
case DSGA_OP_RSUB : return value - last_value ;
2022-06-07 21:21:51 +00:00
case DSGA_OP_STO_NC : _temp_store . StoreValue ( adjust . divmod_val , ( S ) value ) ; return last_value ;
2022-06-11 01:33:09 +00:00
case DSGA_OP_ABS : return ( ( S ) last_value < 0 ) ? - ( ( S ) last_value ) : ( S ) last_value ;
2022-07-30 22:32:23 +00:00
case DSGA_OP_JZ : return handle_jump ( value = = 0 , value ) ;
case DSGA_OP_JNZ : return handle_jump ( value ! = 0 , value ) ;
case DSGA_OP_JZ_LV : return handle_jump ( last_value = = 0 , last_value ) ;
case DSGA_OP_JNZ_LV : return handle_jump ( last_value ! = 0 , last_value ) ;
2022-08-09 20:36:03 +00:00
case DSGA_OP_NOOP : return last_value ;
2007-01-11 10:58:53 +00:00
default : return value ;
}
}
2006-04-27 19:53:58 +00:00
2024-01-07 16:41:53 +00:00
uint32_t EvaluateDeterministicSpriteGroupAdjust ( DeterministicSpriteGroupSize size , const DeterministicSpriteGroupAdjust & adjust , ScopeResolver * scope , uint32_t last_value , uint32_t value )
2022-05-25 00:50:10 +00:00
{
switch ( size ) {
2024-01-07 16:41:53 +00:00
case DSG_SIZE_BYTE : return EvalAdjustT < uint8_t , int8_t > ( adjust , scope , last_value , value ) ; break ;
case DSG_SIZE_WORD : return EvalAdjustT < uint16_t , int16_t > ( adjust , scope , last_value , value ) ; break ;
case DSG_SIZE_DWORD : return EvalAdjustT < uint32_t , int32_t > ( adjust , scope , last_value , value ) ; break ;
2022-05-25 00:50:10 +00:00
default : NOT_REACHED ( ) ;
}
}
2024-01-03 21:33:38 +00:00
static bool RangeHighComparator ( const DeterministicSpriteGroupRange & range , uint32_t value )
2018-03-11 13:21:27 +00:00
{
return range . high < value ;
}
2013-11-24 14:41:19 +00:00
const SpriteGroup * DeterministicSpriteGroup : : Resolve ( ResolverObject & object ) const
2006-04-27 19:53:58 +00:00
{
2023-12-07 17:53:13 +00:00
if ( ( this - > sg_flags & SGF_SKIP_CB ) ! = 0 & & object . callback > 1 ) {
static CallbackResultSpriteGroup cbfail ( CALLBACK_FAILED ) ;
return & cbfail ;
}
2024-01-07 16:41:53 +00:00
uint32_t last_value = 0 ;
uint32_t value = 0 ;
2006-04-27 19:53:58 +00:00
2023-03-14 17:57:30 +00:00
ScopeResolver * scope = object . GetScope ( this - > var_scope , this - > var_scope_count ) ;
2006-04-27 19:53:58 +00:00
2022-06-22 01:09:13 +00:00
const DeterministicSpriteGroupAdjust * end = this - > adjusts . data ( ) + this - > adjusts . size ( ) ;
for ( const DeterministicSpriteGroupAdjust * iter = this - > adjusts . data ( ) ; iter ! = end ; + + iter ) {
const DeterministicSpriteGroupAdjust & adjust = * iter ;
2022-06-14 01:23:23 +00:00
2022-06-06 22:04:45 +00:00
if ( ( adjust . adjust_flags & DSGAF_SKIP_ON_ZERO ) & & ( last_value = = 0 ) ) continue ;
if ( ( adjust . adjust_flags & DSGAF_SKIP_ON_LSB_SET ) & & ( last_value & 1 ) ! = 0 ) continue ;
2006-05-23 19:36:50 +00:00
/* Try to get the variable. We shall assume it is available, unless told otherwise. */
2021-05-01 23:04:34 +00:00
GetVariableExtra extra ( adjust . and_mask < < adjust . shift_num ) ;
if ( adjust . variable = = 0x7E ) {
2023-03-14 17:57:30 +00:00
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 ;
}
}
2021-05-01 23:04:34 +00:00
const SpriteGroup * subgroup = SpriteGroup : : Resolve ( adjust . subroutine , object , false ) ;
2019-04-10 21:07:06 +00:00
if ( subgroup = = nullptr ) {
2007-01-12 11:20:34 +00:00
value = CALLBACK_FAILED ;
} else {
2009-05-23 12:13:42 +00:00
value = subgroup - > GetCallbackResult ( ) ;
2007-01-12 11:20:34 +00:00
}
2009-09-30 20:25:59 +00:00
2023-03-14 17:57:30 +00:00
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 ;
}
2012-11-11 12:57:27 +00:00
/* Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */
2021-05-01 23:04:34 +00:00
} else if ( adjust . variable = = 0x7B ) {
2016-09-09 22:44:13 +00:00
_sprite_group_resolve_check_veh_check = false ;
2021-05-01 23:04:34 +00:00
value = GetVariable ( object , scope , adjust . parameter , last_value , & extra ) ;
2007-01-12 11:20:34 +00:00
} else {
2021-05-01 23:04:34 +00:00
value = GetVariable ( object , scope , adjust . variable , adjust . parameter , & extra ) ;
2007-01-12 11:20:34 +00:00
}
2006-05-23 19:36:50 +00:00
2020-08-25 00:26:44 +00:00
if ( ! extra . available ) {
2010-11-15 16:43:46 +00:00
/* Unsupported variable: skip further processing and return either
2006-05-23 19:36:50 +00:00
* the group from the first range or the default group . */
2018-03-11 13:21:27 +00:00
return SpriteGroup : : Resolve ( this - > error_group , object , false ) ;
2006-05-23 19:36:50 +00:00
}
2009-05-23 15:25:52 +00:00
switch ( this - > size ) {
2024-01-07 16:41:53 +00:00
case DSG_SIZE_BYTE : value = EvalAdjustT < uint8_t , int8_t > ( adjust , scope , last_value , value , & iter ) ; break ;
case DSG_SIZE_WORD : value = EvalAdjustT < uint16_t , int16_t > ( adjust , scope , last_value , value , & iter ) ; break ;
case DSG_SIZE_DWORD : value = EvalAdjustT < uint32_t , int32_t > ( adjust , scope , last_value , value , & iter ) ; break ;
2009-05-26 15:46:24 +00:00
default : NOT_REACHED ( ) ;
2006-04-27 19:53:58 +00:00
}
last_value = value ;
}
2013-11-24 14:41:19 +00:00
object . last_value = last_value ;
2007-01-11 14:40:12 +00:00
2018-03-11 15:08:51 +00:00
if ( this - > calculated_result ) {
2006-05-23 19:36:50 +00:00
/* nvar == 0 is a special case -- we turn our value into a callback result */
2008-05-04 22:32:25 +00:00
if ( value ! = CALLBACK_FAILED ) value = GB ( value , 0 , 15 ) ;
2022-06-04 19:29:32 +00:00
static CallbackResultSpriteGroup nvarzero ( 0 ) ;
2009-05-23 12:13:42 +00:00
nvarzero . result = value ;
2006-05-23 19:36:50 +00:00
return & nvarzero ;
}
2006-04-27 19:53:58 +00:00
2021-05-01 23:00:06 +00:00
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 ) {
2018-03-11 13:21:27 +00:00
assert ( lower - > low < = value & & value < = lower - > high ) ;
return SpriteGroup : : Resolve ( lower - > group , object , false ) ;
}
} else {
2021-05-01 23:00:06 +00:00
for ( const auto & range : this - > ranges ) {
if ( range . low < = value & & value < = range . high ) {
return SpriteGroup : : Resolve ( range . group , object , false ) ;
2018-03-11 13:21:27 +00:00
}
2006-04-27 19:53:58 +00:00
}
}
2013-12-23 18:08:16 +00:00
return SpriteGroup : : Resolve ( this - > default_group , object , false ) ;
2006-04-27 19:53:58 +00:00
}
2022-05-30 16:24:26 +00:00
bool DeterministicSpriteGroup : : GroupMayBeBypassed ( ) const
{
if ( this - > calculated_result ) return false ;
if ( this - > adjusts . size ( ) = = 0 ) return true ;
if ( ( this - > adjusts . size ( ) = = 1 & & this - > adjusts [ 0 ] . variable = = 0x1A & & ( this - > adjusts [ 0 ] . operation = = DSGA_OP_ADD | | this - > adjusts [ 0 ] . operation = = DSGA_OP_RST ) ) ) return true ;
return false ;
}
2013-11-24 14:41:19 +00:00
const SpriteGroup * RandomizedSpriteGroup : : Resolve ( ResolverObject & object ) const
2006-04-27 19:53:58 +00:00
{
2023-03-14 17:57:30 +00:00
ScopeResolver * scope = object . GetScope ( this - > var_scope , this - > var_scope_count ) ;
2017-10-25 15:38:14 +00:00
if ( object . callback = = CBID_RANDOM_TRIGGER ) {
2006-04-27 19:53:58 +00:00
/* Handle triggers */
2017-10-25 15:38:14 +00:00
byte match = this - > triggers & object . waiting_triggers ;
2009-05-23 15:25:52 +00:00
bool res = ( this - > cmp_mode = = RSG_CMP_ANY ) ? ( match ! = 0 ) : ( match = = this - > triggers ) ;
2006-04-27 19:53:58 +00:00
if ( res ) {
2017-10-25 15:38:14 +00:00
object . used_triggers | = match ;
2021-05-01 23:00:40 +00:00
object . reseed [ this - > var_scope ] | = ( this - > groups . size ( ) - 1 ) < < this - > lowest_randbit ;
2006-04-27 19:53:58 +00:00
}
}
2024-01-07 16:41:53 +00:00
uint32_t mask = ( ( uint ) this - > groups . size ( ) - 1 ) < < this - > lowest_randbit ;
2012-11-10 20:37:31 +00:00
byte index = ( scope - > GetRandomBits ( ) & mask ) > > this - > lowest_randbit ;
2006-04-27 19:53:58 +00:00
2013-12-23 18:08:16 +00:00
return SpriteGroup : : Resolve ( this - > groups [ index ] , object , false ) ;
2006-04-27 19:53:58 +00:00
}
2013-11-24 14:41:19 +00:00
const SpriteGroup * RealSpriteGroup : : Resolve ( ResolverObject & object ) const
2006-04-27 19:53:58 +00:00
{
2013-11-24 14:41:19 +00:00
return object . ResolveReal ( this ) ;
2006-04-27 19:53:58 +00:00
}
2011-05-29 16:56:22 +00:00
/**
* Process registers and the construction stage into the sprite layout .
* The passed construction stage might get reset to zero , if it gets incorporated into the layout
* during the preprocessing .
2019-04-10 21:07:06 +00:00
* @ param [ in , out ] stage Construction stage ( 0 - 3 ) , or nullptr if not applicable .
2011-05-29 16:56:22 +00:00
* @ return sprite layout to draw .
*/
2024-01-07 16:41:53 +00:00
const DrawTileSprites * TileLayoutSpriteGroup : : ProcessRegisters ( uint8_t * stage ) const
2011-05-29 16:56:22 +00:00
{
2011-09-11 15:10:09 +00:00
if ( ! this - > dts . NeedsPreprocessing ( ) ) {
2019-04-10 21:07:06 +00:00
if ( stage ! = nullptr & & this - > dts . consistent_max_offset > 0 ) * stage = GetConstructionStageOffset ( * stage , this - > dts . consistent_max_offset ) ;
2011-09-11 15:10:09 +00:00
return & this - > dts ;
}
2011-05-29 16:56:22 +00:00
static DrawTileSprites result ;
2024-01-07 16:41:53 +00:00
uint8_t actual_stage = stage ! = nullptr ? * stage : 0 ;
2011-09-11 15:10:09 +00:00
this - > dts . PrepareLayout ( 0 , 0 , 0 , actual_stage , false ) ;
2011-05-29 16:56:22 +00:00
this - > dts . ProcessRegisters ( 0 , 0 , false ) ;
result . seq = this - > dts . GetLayout ( & result . ground ) ;
/* Stage has been processed by PrepareLayout(), set it to zero. */
2019-04-10 21:07:06 +00:00
if ( stage ! = nullptr ) * stage = 0 ;
2011-05-29 16:56:22 +00:00
return & result ;
}
2021-05-21 18:35:22 +00:00
static const char * _dsg_op_names [ ] {
" ADD " ,
" SUB " ,
" SMIN " ,
" SMAX " ,
" UMIN " ,
" UMAX " ,
" SDIV " ,
" SMOD " ,
" UDIV " ,
" UMOD " ,
" MUL " ,
" AND " ,
" OR " ,
" XOR " ,
" STO " ,
" RST " ,
" STOP " ,
" ROR " ,
" SCMP " ,
" UCMP " ,
" SHL " ,
" SHR " ,
" SAR " ,
} ;
static_assert ( lengthof ( _dsg_op_names ) = = DSGA_OP_END ) ;
2022-05-25 22:58:44 +00:00
static const char * _dsg_op_special_names [ ] {
" TERNARY " ,
" EQ " ,
" SLT " ,
" SGE " ,
" SLE " ,
" SGT " ,
2022-05-27 02:14:07 +00:00
" RSUB " ,
2022-06-03 19:14:30 +00:00
" STO_NC " ,
2022-06-11 01:33:09 +00:00
" ABS " ,
2022-06-14 01:23:23 +00:00
" JZ " ,
2022-07-30 21:40:41 +00:00
" JNZ " ,
2022-07-30 22:32:23 +00:00
" JZ_LV " ,
" JNZ_LV " ,
2022-08-09 20:36:03 +00:00
" NOOP " ,
2022-05-25 22:58:44 +00:00
} ;
static_assert ( lengthof ( _dsg_op_special_names ) = = DSGA_OP_SPECIAL_END - DSGA_OP_TERNARY ) ;
2021-05-21 18:35:22 +00:00
static const char * _sg_scope_names [ ] {
" SELF " ,
" PARENT " ,
" RELATIVE " ,
} ;
static_assert ( lengthof ( _sg_scope_names ) = = VSG_END ) ;
static const char * _sg_size_names [ ] {
" BYTE " ,
" WORD " ,
" DWORD " ,
} ;
2023-03-14 17:57:30 +00:00
static const char * _sg_relative_scope_modes [ ] {
" BACKWARD_SELF " ,
" FORWARD_SELF " ,
" BACKWARD_ENGINE " ,
" BACKWARD_SAMEID " ,
} ;
static_assert ( lengthof ( _sg_relative_scope_modes ) = = VSGSRM_END ) ;
2022-06-06 21:06:52 +00:00
static char * GetAdjustOperationName ( char * str , const char * last , DeterministicSpriteGroupAdjustOperation operation )
2022-05-25 01:23:25 +00:00
{
2022-06-06 21:06:52 +00:00
if ( operation < DSGA_OP_END ) return strecat ( str , _dsg_op_names [ operation ] , last ) ;
if ( operation > = DSGA_OP_TERNARY & & operation < DSGA_OP_SPECIAL_END ) return strecat ( str , _dsg_op_special_names [ operation - DSGA_OP_TERNARY ] , last ) ;
return str + seprintf ( str , last , " \ ? \ ? \ ?(0x%X) " , operation ) ;
2022-05-25 01:23:25 +00:00
}
2024-01-07 16:41:53 +00:00
char * SpriteGroupDumper : : DumpSpriteGroupAdjust ( char * p , const char * last , const DeterministicSpriteGroupAdjust & adjust , const char * padding , uint32_t & highlight_tag , uint & conditional_indent )
2022-06-08 20:33:34 +00:00
{
if ( adjust . variable = = 0x7D ) {
/* Temp storage load */
highlight_tag = ( 1 < < 16 ) | ( adjust . parameter & 0xFFFF ) ;
}
2022-10-05 20:05:56 +00:00
if ( adjust . variable = = 0x7C ) {
/* Perm storage load */
highlight_tag = ( 2 < < 16 ) | ( adjust . parameter & 0xFFFF ) ;
}
2022-06-08 20:33:34 +00:00
2022-08-09 20:53:43 +00:00
p + = seprintf ( p , last , " %s " , padding ) ;
2022-06-14 01:23:23 +00:00
for ( uint i = 0 ; i < conditional_indent ; i + + ) {
p + = seprintf ( p , last , " > " ) ;
}
2022-06-08 20:33:34 +00:00
auto append_flags = [ & ] ( ) {
if ( adjust . adjust_flags & DSGAF_SKIP_ON_ZERO ) {
p + = seprintf ( p , last , " , skip on zero " ) ;
}
if ( adjust . adjust_flags & DSGAF_SKIP_ON_LSB_SET ) {
p + = seprintf ( p , last , " , skip on LSB set " ) ;
}
2023-12-27 23:52:36 +00:00
if ( adjust . adjust_flags & DSGAF_LAST_VAR_READ & & this - > more_details ) {
2022-06-14 01:23:23 +00:00
p + = seprintf ( p , last , " , last var read " ) ;
}
2023-12-27 23:52:36 +00:00
if ( adjust . adjust_flags & DSGAF_JUMP_INS_HINT & & this - > more_details ) {
2022-06-20 17:41:09 +00:00
p + = seprintf ( p , last , " , jump ins hint " ) ;
2022-06-14 01:23:23 +00:00
}
if ( adjust . adjust_flags & DSGAF_END_BLOCK ) {
2022-06-26 22:30:14 +00:00
p + = seprintf ( p , last , " , end block (%u) " , adjust . jump ) ;
2022-06-14 01:23:23 +00:00
}
2022-06-08 20:33:34 +00:00
} ;
2023-02-12 18:03:59 +00:00
auto append_extended_var = [ & ] ( int var_id ) {
2023-06-01 18:26:45 +00:00
const char * name = GetExtendedVariableNameById ( var_id ) ;
if ( name ! = nullptr ) {
p + = seprintf ( p , last , " (%s) " , name ) ;
2023-02-12 18:03:59 +00:00
}
} ;
2022-07-30 21:40:41 +00:00
if ( IsEvalAdjustJumpOperation ( adjust . operation ) ) {
2022-06-14 01:23:23 +00:00
conditional_indent + + ;
}
if ( adjust . adjust_flags & DSGAF_END_BLOCK ) {
2022-06-26 22:30:14 +00:00
conditional_indent - = adjust . jump ;
2022-06-14 01:23:23 +00:00
}
2022-06-08 20:33:34 +00:00
if ( adjust . operation = = DSGA_OP_TERNARY ) {
2022-06-14 01:23:23 +00:00
p + = seprintf ( p , last , " TERNARY: true: %X, false: %X " , adjust . and_mask , adjust . add_val ) ;
2022-06-08 20:33:34 +00:00
append_flags ( ) ;
return p ;
}
2022-06-11 01:33:09 +00:00
if ( adjust . operation = = DSGA_OP_ABS ) {
2022-06-14 01:23:23 +00:00
p + = seprintf ( p , last , " ABS " ) ;
2022-06-11 01:33:09 +00:00
append_flags ( ) ;
return p ;
2022-08-09 20:36:03 +00:00
}
if ( adjust . operation = = DSGA_OP_NOOP ) {
p + = seprintf ( p , last , " NOOP " ) ;
append_flags ( ) ;
return p ;
2022-06-11 01:33:09 +00:00
}
2022-07-30 22:32:23 +00:00
if ( adjust . operation = = DSGA_OP_JZ_LV | | adjust . operation = = DSGA_OP_JNZ_LV ) {
p = GetAdjustOperationName ( p , last , adjust . operation ) ;
p + = seprintf ( p , last , " +%u " , adjust . jump ) ;
append_flags ( ) ;
return p ;
}
2022-06-08 20:33:34 +00:00
if ( adjust . operation = = DSGA_OP_STO & & adjust . type = = DSGA_TYPE_NONE & & adjust . variable = = 0x1A & & adjust . shift_num = = 0 ) {
/* Temp storage store */
highlight_tag = ( 1 < < 16 ) | ( adjust . and_mask & 0xFFFF ) ;
}
2022-10-05 20:05:56 +00:00
if ( adjust . operation = = DSGA_OP_STOP & & adjust . type = = DSGA_TYPE_NONE & & adjust . variable = = 0x1A & & adjust . shift_num = = 0 ) {
/* Perm storage store */
highlight_tag = ( 2 < < 16 ) | ( adjust . and_mask & 0xFFFF ) ;
}
2022-06-14 01:23:23 +00:00
p + = seprintf ( p , last , " var: %X " , adjust . variable ) ;
2023-06-01 18:26:45 +00:00
if ( adjust . variable > = 0x100 ) {
2023-02-12 18:03:59 +00:00
append_extended_var ( adjust . variable ) ;
}
if ( adjust . variable = = 0x7B & & adjust . parameter > = 0x100 ) {
p + = seprintf ( p , last , " (parameter: %X " , adjust . parameter ) ;
append_extended_var ( adjust . parameter ) ;
p + = seprintf ( p , last , " ) " ) ;
} else if ( ( adjust . variable > = 0x60 & & adjust . variable < = 0x7F & & adjust . variable ! = 0x7E ) | | adjust . parameter ! = 0 ) {
p + = seprintf ( p , last , " (parameter: %X) " , adjust . parameter ) ;
2022-06-08 20:33:34 +00:00
}
p + = seprintf ( p , last , " , shift: %X, and: %X " , adjust . shift_num , adjust . and_mask ) ;
switch ( adjust . type ) {
case DSGA_TYPE_DIV : p + = seprintf ( p , last , " , add: %X, div: %X " , adjust . add_val , adjust . divmod_val ) ; break ;
case DSGA_TYPE_MOD : p + = seprintf ( p , last , " , add: %X, mod: %X " , adjust . add_val , adjust . divmod_val ) ; break ;
case DSGA_TYPE_EQ : p + = seprintf ( p , last , " , eq: %X " , adjust . add_val ) ; break ;
case DSGA_TYPE_NEQ : p + = seprintf ( p , last , " , neq: %X " , adjust . add_val ) ; break ;
case DSGA_TYPE_NONE : break ;
}
if ( adjust . operation = = DSGA_OP_STO_NC ) {
p + = seprintf ( p , last , " , store to: %X " , adjust . divmod_val ) ;
highlight_tag = ( 1 < < 16 ) | adjust . divmod_val ;
}
p + = seprintf ( p , last , " , op: " ) ;
p = GetAdjustOperationName ( p , last , adjust . operation ) ;
2022-07-30 21:40:41 +00:00
if ( IsEvalAdjustJumpOperation ( adjust . operation ) ) {
2022-06-22 01:09:13 +00:00
p + = seprintf ( p , last , " +%u " , adjust . jump ) ;
}
2022-06-08 20:33:34 +00:00
append_flags ( ) ;
return p ;
}
2022-08-09 20:53:43 +00:00
void SpriteGroupDumper : : DumpSpriteGroup ( const SpriteGroup * sg , const char * padding , uint flags )
2021-05-21 18:35:22 +00:00
{
2024-01-07 16:41:53 +00:00
uint32_t highlight_tag = 0 ;
2022-06-01 20:31:05 +00:00
auto print = [ & ] ( ) {
2022-06-04 20:08:35 +00:00
this - > print_fn ( sg , DSGPO_PRINT , highlight_tag , this - > buffer ) ;
2022-06-02 18:34:19 +00:00
highlight_tag = 0 ;
2022-06-01 20:31:05 +00:00
} ;
2021-05-21 18:35:22 +00:00
if ( sg = = nullptr ) {
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %sNULL GROUP " , padding ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2021-05-21 18:35:22 +00:00
return ;
}
2022-06-13 00:07:16 +00:00
if ( sg - > nfo_line ! = 0 ) this - > print_fn ( sg , DSGPO_NFO_LINE , sg - > nfo_line , nullptr ) ;
2022-06-04 20:08:35 +00:00
bool start_emitted = false ;
auto emit_start = [ & ] ( ) {
this - > print_fn ( sg , DSGPO_START , 0 , nullptr ) ;
start_emitted = true ;
} ;
auto guard = scope_guard ( [ & ] ( ) {
if ( start_emitted ) {
2022-08-09 20:53:43 +00:00
this - > print_fn ( sg , DSGPO_END , 0 , padding ) ;
2022-06-04 20:08:35 +00:00
}
} ) ;
2022-06-11 01:34:08 +00:00
char extra_info [ 64 ] = " " ;
if ( sg - > sg_flags & SGF_ACTION6 ) strecat ( extra_info , " (action 6 modified) " , lastof ( extra_info ) ) ;
2023-12-07 17:53:13 +00:00
if ( sg - > sg_flags & SGF_SKIP_CB ) strecat ( extra_info , " (skip CB) " , lastof ( extra_info ) ) ;
2023-12-27 23:52:36 +00:00
if ( this - > more_details ) {
2022-10-01 21:32:00 +00:00
if ( sg - > sg_flags & SGF_INLINING ) strecat ( extra_info , " (inlining) " , lastof ( extra_info ) ) ;
}
2022-06-11 01:34:08 +00:00
2023-03-14 17:57:30 +00:00
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 ] ;
}
} ;
2021-05-21 18:35:22 +00:00
switch ( sg - > type ) {
case SGT_REAL : {
const RealSpriteGroup * rsg = ( const RealSpriteGroup * ) sg ;
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %sReal (loaded: %u, loading: %u)%s [%u] " ,
padding , ( uint ) rsg - > loaded . size ( ) , ( uint ) rsg - > loading . size ( ) , extra_info , sg - > nfo_line ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-06-04 20:08:35 +00:00
emit_start ( ) ;
2022-08-09 20:53:43 +00:00
std : : string sub_padding ( padding ) ;
sub_padding + = " " ;
2021-05-21 18:35:22 +00:00
for ( size_t i = 0 ; i < rsg - > loaded . size ( ) ; i + + ) {
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s Loaded %u " , padding , ( uint ) i ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-08-09 20:53:43 +00:00
this - > DumpSpriteGroup ( rsg - > loaded [ i ] , sub_padding . c_str ( ) , 0 ) ;
2021-05-21 18:35:22 +00:00
}
for ( size_t i = 0 ; i < rsg - > loading . size ( ) ; i + + ) {
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s Loading %u " , padding , ( uint ) i ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-08-09 20:53:43 +00:00
this - > DumpSpriteGroup ( rsg - > loading [ i ] , sub_padding . c_str ( ) , 0 ) ;
2021-05-21 18:35:22 +00:00
}
break ;
}
case SGT_DETERMINISTIC : {
const DeterministicSpriteGroup * dsg = ( const DeterministicSpriteGroup * ) sg ;
2022-06-07 17:54:42 +00:00
const SpriteGroup * default_group = dsg - > default_group ;
const std : : vector < DeterministicSpriteGroupAdjust > * adjusts = & ( dsg - > adjusts ) ;
const std : : vector < DeterministicSpriteGroupRange > * ranges = & ( dsg - > ranges ) ;
2022-08-21 20:57:46 +00:00
bool calculated_result = dsg - > calculated_result ;
2022-06-07 17:54:42 +00:00
2023-12-27 23:46:45 +00:00
if ( this - > use_shadows ) {
2022-06-07 17:54:42 +00:00
auto iter = _deterministic_sg_shadows . find ( dsg ) ;
if ( iter ! = _deterministic_sg_shadows . end ( ) ) {
default_group = iter - > second . default_group ;
adjusts = & ( iter - > second . adjusts ) ;
ranges = & ( iter - > second . ranges ) ;
2022-08-21 20:57:46 +00:00
calculated_result = iter - > second . calculated_result ;
2022-06-07 17:54:42 +00:00
}
}
2022-07-31 18:28:35 +00:00
bool is_callback_group = false ;
2022-08-21 20:57:46 +00:00
if ( adjusts - > size ( ) = = 1 & & ! calculated_result ) {
2022-07-31 18:28:35 +00:00
const DeterministicSpriteGroupAdjust & adjust = ( * adjusts ) [ 0 ] ;
if ( adjust . variable = = 0xC & & ( adjust . operation = = DSGA_OP_ADD | | adjust . operation = = DSGA_OP_RST )
& & adjust . shift_num = = 0 & & ( adjust . and_mask & 0xFF ) = = 0xFF & & adjust . type = = DSGA_TYPE_NONE ) {
is_callback_group = true ;
2022-08-21 20:57:46 +00:00
if ( * padding = = 0 & & ! calculated_result & & ranges - > size ( ) > 0 ) {
2022-08-21 17:41:13 +00:00
const DeterministicSpriteGroupRange & first_range = ( * ranges ) [ 0 ] ;
if ( first_range . low = = 0 & & first_range . high = = 0 & & first_range . group ! = nullptr ) {
this - > top_graphics_group = first_range . group ;
}
}
2022-07-31 18:28:35 +00:00
}
}
2022-08-21 20:57:46 +00:00
if ( * padding = = 0 & & ! calculated_result & & default_group ! = nullptr ) {
2022-06-07 17:54:42 +00:00
this - > top_default_group = default_group ;
2021-05-21 18:35:22 +00:00
}
2022-08-21 14:24:16 +00:00
if ( dsg = = this - > top_default_group & & ! ( ( flags & SGDF_DEFAULT ) & & strlen ( padding ) = = 2 ) ) {
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %sTOP LEVEL DEFAULT GROUP: Deterministic (%s, %s), [%u] " ,
2023-03-14 17:57:30 +00:00
padding , get_scope_name ( dsg - > var_scope , dsg - > var_scope_count ) , _sg_size_names [ dsg - > size ] , dsg - > nfo_line ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2021-05-21 18:35:22 +00:00
return ;
}
2022-08-21 17:41:13 +00:00
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] " ,
2023-03-14 17:57:30 +00:00
padding , get_scope_name ( dsg - > var_scope , dsg - > var_scope_count ) , _sg_size_names [ dsg - > size ] , dsg - > nfo_line ) ;
2022-08-21 17:41:13 +00:00
print ( ) ;
return ;
}
2021-05-21 18:35:22 +00:00
auto res = this - > seen_dsgs . insert ( dsg ) ;
if ( ! res . second ) {
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %sGROUP SEEN ABOVE: Deterministic (%s, %s), [%u] " ,
2023-03-14 17:57:30 +00:00
padding , get_scope_name ( dsg - > var_scope , dsg - > var_scope_count ) , _sg_size_names [ dsg - > size ] , dsg - > nfo_line ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2021-05-21 18:35:22 +00:00
return ;
}
2022-06-14 00:23:05 +00:00
char * p = this - > buffer ;
2022-08-09 20:53:43 +00:00
p + = seprintf ( p , lastof ( this - > buffer ) , " %sDeterministic (%s, %s)%s [%u] " ,
2023-03-14 17:57:30 +00:00
padding , get_scope_name ( dsg - > var_scope , dsg - > var_scope_count ) , _sg_size_names [ dsg - > size ] , extra_info , dsg - > nfo_line ) ;
2023-12-27 23:52:36 +00:00
if ( this - > more_details ) {
2022-06-14 00:23:05 +00:00
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 " ) ;
if ( dsg - > dsg_flags & DSGF_REQUIRES_VAR1C ) p + = seprintf ( p , lastof ( this - > buffer ) , " , REQ_1C " ) ;
2022-06-14 01:23:23 +00:00
if ( dsg - > dsg_flags & DSGF_CHECK_EXPENSIVE_VARS ) p + = seprintf ( p , lastof ( this - > buffer ) , " , CHECK_EXP_VAR " ) ;
2022-06-20 17:46:31 +00:00
if ( dsg - > dsg_flags & DSGF_CHECK_INSERT_JUMP ) p + = seprintf ( p , lastof ( this - > buffer ) , " , CHECK_INS_JMP " ) ;
2022-11-26 19:42:37 +00:00
if ( dsg - > dsg_flags & DSGF_CB_RESULT ) p + = seprintf ( p , lastof ( this - > buffer ) , " , CB_RESULT " ) ;
2022-08-21 17:41:13 +00:00
if ( dsg - > dsg_flags & DSGF_CB_HANDLER ) p + = seprintf ( p , lastof ( this - > buffer ) , " , CB_HANDLER " ) ;
2022-10-01 21:32:00 +00:00
if ( dsg - > dsg_flags & DSGF_INLINE_CANDIDATE ) p + = seprintf ( p , lastof ( this - > buffer ) , " , INLINE_CANDIDATE " ) ;
2022-06-14 00:23:05 +00:00
}
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-06-04 20:08:35 +00:00
emit_start ( ) ;
2022-08-09 20:53:43 +00:00
std : : string sub_padding ( padding ) ;
sub_padding + = " " ;
2022-06-14 01:23:23 +00:00
uint conditional_indent = 0 ;
2022-06-07 17:54:42 +00:00
for ( const auto & adjust : ( * adjusts ) ) {
2023-12-27 23:52:36 +00:00
this - > DumpSpriteGroupAdjust ( this - > buffer , lastof ( this - > buffer ) , adjust , sub_padding . c_str ( ) , highlight_tag , conditional_indent ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-05-29 02:25:14 +00:00
if ( adjust . variable = = 0x7E & & adjust . subroutine ! = nullptr ) {
2022-08-09 20:53:43 +00:00
std : : string subroutine_padding ( sub_padding ) ;
for ( uint i = 0 ; i < conditional_indent ; i + + ) {
subroutine_padding + = " > " ;
}
2022-08-21 14:44:19 +00:00
subroutine_padding + = " | " ;
2022-08-09 20:53:43 +00:00
this - > DumpSpriteGroup ( adjust . subroutine , subroutine_padding . c_str ( ) , 0 ) ;
2022-05-29 02:25:14 +00:00
}
2021-05-21 18:35:22 +00:00
}
2022-08-21 20:57:46 +00:00
if ( calculated_result ) {
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %scalculated_result " , padding ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2021-05-21 18:35:22 +00:00
} else {
2022-08-09 20:53:43 +00:00
std : : string subgroup_padding ( padding ) ;
subgroup_padding + = " " ;
2022-06-07 17:54:42 +00:00
for ( const auto & range : ( * ranges ) ) {
2022-07-31 18:28:35 +00:00
char * p = this - > buffer ;
2022-08-09 20:53:43 +00:00
p + = seprintf ( p , lastof ( this - > buffer ) , " %srange: %X -> %X " , padding , range . low , range . high ) ;
2022-07-31 18:28:35 +00:00
if ( range . low = = range . high & & is_callback_group ) {
const char * cb_name = GetNewGRFCallbackName ( ( CallbackID ) range . low ) ;
if ( cb_name ! = nullptr ) {
p + = seprintf ( p , lastof ( this - > buffer ) , " (%s) " , cb_name ) ;
}
}
2023-12-27 23:52:36 +00:00
if ( this - > more_details & & range . group = = dsg - > error_group ) {
2023-01-29 12:37:57 +00:00
p + = seprintf ( p , lastof ( this - > buffer ) , " (error_group) " ) ;
}
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-08-21 17:41:13 +00:00
this - > DumpSpriteGroup ( range . group , subgroup_padding . c_str ( ) , SGDF_RANGE ) ;
2021-05-21 18:35:22 +00:00
}
2022-06-07 17:54:42 +00:00
if ( default_group ! = nullptr ) {
2023-01-29 12:37:57 +00:00
char * p = this - > buffer ;
p + = seprintf ( p , lastof ( this - > buffer ) , " %sdefault " , padding ) ;
2023-12-27 23:52:36 +00:00
if ( this - > more_details & & default_group = = dsg - > error_group ) {
2023-01-29 12:37:57 +00:00
p + = seprintf ( p , lastof ( this - > buffer ) , " (error_group) " ) ;
}
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-08-09 20:53:43 +00:00
this - > DumpSpriteGroup ( default_group , subgroup_padding . c_str ( ) , SGDF_DEFAULT ) ;
2021-05-21 18:35:22 +00:00
}
}
break ;
}
case SGT_RANDOMIZED : {
const RandomizedSpriteGroup * rsg = ( const RandomizedSpriteGroup * ) sg ;
2022-06-07 17:54:42 +00:00
const std : : vector < const SpriteGroup * > * groups = & ( rsg - > groups ) ;
2023-12-27 23:46:45 +00:00
if ( this - > use_shadows ) {
2022-06-07 17:54:42 +00:00
auto iter = _randomized_sg_shadows . find ( rsg ) ;
if ( iter ! = _randomized_sg_shadows . end ( ) ) {
groups = & ( iter - > second . groups ) ;
}
}
2023-03-14 17:57:30 +00:00
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 ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-06-04 20:08:35 +00:00
emit_start ( ) ;
2022-08-09 20:53:43 +00:00
std : : string sub_padding ( padding ) ;
sub_padding + = " " ;
2023-01-04 19:47:34 +00:00
std : : string sub_padding_indent ( sub_padding ) ;
sub_padding_indent + = " " ;
auto end = groups - > end ( ) ;
for ( auto iter = groups - > begin ( ) ; iter ! = end ; ) {
uint count = 1 ;
const SpriteGroup * group = * iter ;
while ( true ) {
+ + iter ;
if ( iter = = end ) break ;
if ( * iter ! = group ) break ;
count + + ;
}
if ( count > 1 ) {
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s%u x: " , sub_padding . c_str ( ) , count ) ;
print ( ) ;
this - > DumpSpriteGroup ( group , sub_padding_indent . c_str ( ) , 0 ) ;
} else {
this - > DumpSpriteGroup ( group , sub_padding . c_str ( ) , 0 ) ;
}
2021-05-21 18:35:22 +00:00
}
break ;
}
case SGT_CALLBACK :
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %sCallback Result: %X " , padding , ( ( const CallbackResultSpriteGroup * ) sg ) - > result ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2021-05-21 18:35:22 +00:00
break ;
case SGT_RESULT :
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %sSprite Result: SpriteID: %u, num: %u " ,
padding , ( ( const ResultSpriteGroup * ) sg ) - > sprite , ( ( const ResultSpriteGroup * ) sg ) - > num_sprites ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2021-05-21 18:35:22 +00:00
break ;
2022-05-29 19:50:53 +00:00
case SGT_TILELAYOUT : {
const TileLayoutSpriteGroup * tlsg = ( const TileLayoutSpriteGroup * ) sg ;
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %sTile Layout%s [%u] " , padding , extra_info , sg - > nfo_line ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-06-04 20:08:35 +00:00
emit_start ( ) ;
2022-10-26 22:08:28 +00:00
const TileLayoutRegisters * registers = tlsg - > dts . registers ;
auto print_reg_info = [ & ] ( char * b , uint i , bool is_parent ) {
if ( registers = = nullptr ) {
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-10-26 22:08:28 +00:00
return ;
}
const TileLayoutRegisters * reg = registers + i ;
if ( reg - > flags = = 0 ) {
print ( ) ;
return ;
}
seprintf ( b , lastof ( this - > buffer ) , " , register flags: %X " , reg - > flags ) ;
print ( ) ;
2024-01-07 16:41:53 +00:00
auto log_reg = [ & ] ( TileLayoutFlags flag , const char * name , uint8_t flag_reg ) {
2022-10-26 22:08:28 +00:00
if ( reg - > flags & flag ) {
highlight_tag = ( 1 < < 16 ) | flag_reg ;
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s %s reg: %X " , padding , name , flag_reg ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-05-29 19:50:53 +00:00
}
2022-10-26 22:08:28 +00:00
} ;
log_reg ( TLF_DODRAW , " TLF_DODRAW " , reg - > dodraw ) ;
log_reg ( TLF_SPRITE , " TLF_SPRITE " , reg - > sprite ) ;
log_reg ( TLF_PALETTE , " TLF_PALETTE " , reg - > palette ) ;
if ( is_parent ) {
log_reg ( TLF_BB_XY_OFFSET , " TLF_BB_XY_OFFSET x " , reg - > delta . parent [ 0 ] ) ;
log_reg ( TLF_BB_XY_OFFSET , " TLF_BB_XY_OFFSET y " , reg - > delta . parent [ 1 ] ) ;
log_reg ( TLF_BB_Z_OFFSET , " TLF_BB_Z_OFFSET " , reg - > delta . parent [ 2 ] ) ;
} else {
log_reg ( TLF_CHILD_X_OFFSET , " TLF_CHILD_X_OFFSET " , reg - > delta . child [ 0 ] ) ;
log_reg ( TLF_CHILD_Y_OFFSET , " TLF_CHILD_Y_OFFSET " , reg - > delta . child [ 1 ] ) ;
}
if ( reg - > flags & TLF_SPRITE_VAR10 ) {
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s TLF_SPRITE_VAR10 value: %X " , padding , reg - > sprite_var10 ) ;
print ( ) ;
}
if ( reg - > flags & TLF_PALETTE_VAR10 ) {
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s TLF_PALETTE_VAR10 value: %X " , padding , reg - > palette_var10 ) ;
print ( ) ;
}
} ;
char * b = this - > buffer + seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s ground: (%X, %X) " ,
padding , tlsg - > dts . ground . sprite , tlsg - > dts . ground . pal ) ;
print_reg_info ( b , 0 , false ) ;
uint offset = 0 ; // offset 0 is the ground sprite
const DrawTileSeqStruct * element ;
foreach_draw_tile_seq ( element , tlsg - > dts . seq ) {
offset + + ;
char * b = this - > buffer ;
if ( element - > IsParentSprite ( ) ) {
b + = seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s section: %X, image: (%X, %X), d: (%d, %d, %d), s: (%d, %d, %d) " ,
padding , offset , element - > image . sprite , element - > image . pal ,
element - > delta_x , element - > delta_y , element - > delta_z ,
element - > size_x , element - > size_y , element - > size_z ) ;
} else {
b + = seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s section: %X, image: (%X, %X), d: (%d, %d) " ,
padding , offset , element - > image . sprite , element - > image . pal ,
element - > delta_x , element - > delta_y ) ;
2022-05-29 19:50:53 +00:00
}
2022-10-26 22:08:28 +00:00
print_reg_info ( b , offset , element - > IsParentSprite ( ) ) ;
2022-05-29 19:50:53 +00:00
}
2021-05-21 18:35:22 +00:00
break ;
2022-05-29 19:50:53 +00:00
}
2022-05-29 22:36:04 +00:00
case SGT_INDUSTRY_PRODUCTION : {
const IndustryProductionSpriteGroup * ipsg = ( const IndustryProductionSpriteGroup * ) sg ;
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %sIndustry Production (version %X) [%u] " , padding , ipsg - > version , ipsg - > nfo_line ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-06-04 20:08:35 +00:00
emit_start ( ) ;
2022-05-29 22:36:04 +00:00
auto log_io = [ & ] ( const char * prefix , int i , int quantity , CargoID cargo ) {
2022-06-02 18:34:19 +00:00
if ( ipsg - > version > = 1 ) highlight_tag = ( 1 < < 16 ) | quantity ;
2022-05-29 22:36:04 +00:00
if ( ipsg - > version > = 2 ) {
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s %s %X: reg %X, cargo ID: %X " , padding , prefix , i , quantity , cargo ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-05-29 22:36:04 +00:00
} else {
const char * type = ( ipsg - > version > = 1 ) ? " reg " : " value " ;
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s %s %X: %s %X " , padding , prefix , i , type , quantity ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2022-05-29 22:36:04 +00:00
}
} ;
for ( int i = 0 ; i < ipsg - > num_input ; i + + ) {
log_io ( " Subtract input " , i , ipsg - > subtract_input [ i ] , ipsg - > cargo_input [ i ] ) ;
}
for ( int i = 0 ; i < ipsg - > num_output ; i + + ) {
log_io ( " Add input " , i , ipsg - > add_output [ i ] , ipsg - > cargo_output [ i ] ) ;
}
2022-06-02 18:34:19 +00:00
if ( ipsg - > version > = 1 ) highlight_tag = ( 1 < < 16 ) | ipsg - > again ;
2022-08-09 20:53:43 +00:00
seprintf ( this - > buffer , lastof ( this - > buffer ) , " %s Again: %s %X " , padding , ( ipsg - > version > = 1 ) ? " reg " : " value " , ipsg - > again ) ;
2022-06-01 20:31:05 +00:00
print ( ) ;
2021-05-21 18:35:22 +00:00
break ;
2022-05-29 22:36:04 +00:00
}
2021-05-21 18:35:22 +00:00
}
}