2006-04-20 21:51:57 +01:00
/* $Id$ */
2009-08-21 21:21:05 +01: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 16:11:33 +01:00
/** @file newgrf_spritegroup.cpp Handling of primarily NewGRF action 2. */
2007-03-21 03:06:21 +00:00
2006-04-20 21:51:57 +01:00
# include "stdafx.h"
2012-11-10 20:37:31 +00:00
# include "debug.h"
2006-04-27 20:53:58 +01:00
# include "newgrf_spritegroup.h"
2009-05-22 16:13:50 +01:00
# include "core/pool_func.hpp"
2006-04-20 21:51:57 +01:00
2009-05-22 16:13:50 +01:00
SpriteGroupPool _spritegroup_pool ( " SpriteGroup " ) ;
INSTANTIATE_POOL_METHODS ( SpriteGroup )
2006-04-20 21:51:57 +01:00
2013-12-23 18:08:16 +00:00
TemporaryStorageArray < int32 , 0x110 > _temp_store ;
/**
* ResolverObject ( re ) entry point .
* This cannot be made a call to a virtual function because virtual functions
* do not like NULL and checking for NULL * everywhere * is more cumbersome than
* 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 )
{
if ( group = = NULL ) return NULL ;
2013-12-23 18:08:36 +00:00
if ( top_level ) {
_temp_store . ClearChanges ( ) ;
}
2013-12-23 18:08:16 +00:00
return group - > Resolve ( object ) ;
}
2009-05-23 13:13:42 +01:00
RealSpriteGroup : : ~ RealSpriteGroup ( )
2006-08-26 20:47:13 +01:00
{
2011-11-12 13:00:29 +00:00
free ( this - > loaded ) ;
free ( this - > loading ) ;
2009-05-23 13:13:42 +01:00
}
DeterministicSpriteGroup : : ~ DeterministicSpriteGroup ( )
{
free ( this - > adjusts ) ;
free ( this - > ranges ) ;
}
RandomizedSpriteGroup : : ~ RandomizedSpriteGroup ( )
{
2011-11-12 13:00:29 +00:00
free ( this - > groups ) ;
2009-05-23 13:13:42 +01:00
}
2013-11-24 14:41:19 +00:00
static inline uint32 GetVariable ( const ResolverObject & object , ScopeResolver * scope , byte variable , uint32 parameter , bool * available )
2006-04-27 20:53:58 +01:00
{
2008-02-12 15:43:10 +00:00
/* First handle variables common with Action7/9/D */
uint32 value ;
2013-11-24 14:41:19 +00:00
if ( GetGlobalVariable ( variable , & value , object . grffile ) ) return value ;
2008-02-12 15:43:10 +00:00
/* Non-common variable */
2006-04-27 20:53:58 +01: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 ;
case 0x1C : return object . last_value ;
2006-04-27 20:53:58 +01:00
2012-11-10 20:37:31 +00:00
case 0x5F : return ( scope - > GetRandomBits ( ) < < 8 ) | scope - > GetTriggers ( ) ;
2008-06-17 08:05:17 +01:00
2011-06-12 21:40:21 +01:00
case 0x7D : return _temp_store . GetValue ( parameter ) ;
2007-04-21 08:27:16 +01:00
2008-07-30 19:23:12 +01:00
case 0x7F :
2013-11-24 14:41:19 +00:00
if ( object . grffile = = NULL ) return 0 ;
return object . grffile - > GetParam ( parameter ) ;
2008-07-30 19:23:12 +01:00
2013-01-08 22:46:42 +00:00
/* Not a common variable, so evaluate the feature specific variables */
2012-11-10 20:37:31 +00:00
default : return scope - > GetVariable ( variable , parameter , available ) ;
2006-04-27 20:53:58 +01:00
}
}
2013-11-24 14:41:19 +00:00
ScopeResolver : : ScopeResolver ( ResolverObject & ro )
: ro ( ro )
2012-11-10 20:37:31 +00:00
{
}
ScopeResolver : : ~ ScopeResolver ( ) { }
/**
* Get a few random bits . Default implementation has no random bits .
* @ return Random bits .
*/
/* virtual */ uint32 ScopeResolver : : GetRandomBits ( ) const
{
return 0 ;
}
/**
* Get the triggers . Base class returns \ c 0 to prevent trouble .
* @ return The triggers .
*/
/* virtual */ uint32 ScopeResolver : : GetTriggers ( ) const
{
return 0 ;
}
/**
* Set the triggers . Base class implementation does nothing .
* @ param triggers Triggers to set .
*/
/* virtual */ void ScopeResolver : : SetTriggers ( int triggers ) const { }
/**
* 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
*/
/* virtual */ uint32 ScopeResolver : : GetVariable ( byte variable , uint32 parameter , bool * available ) const
{
DEBUG ( grf , 1 , " Unhandled scope variable 0x%X " , variable ) ;
* available = false ;
return UINT_MAX ;
}
/**
* Store a value into the persistent storage area ( PSA ) . Default implementation does nothing ( for newgrf classes without storage ) .
* @ param pos Position to store into .
* @ param value Value to store .
*/
/* virtual */ void ScopeResolver : : StorePSA ( uint reg , int32 value ) { }
2012-11-10 20:46:39 +00:00
/**
* Resolver constructor .
2013-01-08 22:46:42 +00:00
* @ param grffile NewGRF file associated with the object ( or \ c NULL if none ) .
2012-11-10 20:46:39 +00:00
* @ param callback Callback code being resolved ( default value is # CBID_NO_CALLBACK ) .
* @ param callback_param1 First parameter ( var 10 ) of the callback ( only used when \ a callback is also set ) .
* @ param callback_param2 Second parameter ( var 18 ) of the callback ( only used when \ a callback is also set ) .
*/
2012-11-10 20:38:46 +00:00
ResolverObject : : ResolverObject ( const GRFFile * grffile , CallbackID callback , uint32 callback_param1 , uint32 callback_param2 )
2013-11-24 14:41:19 +00:00
: default_scope ( * this )
2012-11-10 20:37:31 +00:00
{
this - > callback = callback ;
this - > callback_param1 = callback_param1 ;
this - > callback_param2 = callback_param2 ;
this - > ResetState ( ) ;
this - > grffile = grffile ;
2014-03-03 20:02:31 +00:00
this - > root_spritegroup = NULL ;
2012-11-10 20:37:31 +00:00
}
ResolverObject : : ~ ResolverObject ( ) { }
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
{
2012-11-10 20:45:59 +00:00
return NULL ;
2012-11-10 20:37:31 +00:00
}
/**
2012-11-10 20:46:39 +00:00
* Get a resolver for the \ a scope .
2012-11-10 20:37:31 +00:00
* @ param scope Scope to return .
* @ param relative Additional parameter for # VSG_SCOPE_RELATIVE .
2012-11-10 20:46:39 +00:00
* @ return The resolver for the requested scope .
2012-11-10 20:37:31 +00:00
*/
/* virtual */ ScopeResolver * ResolverObject : : GetScope ( VarSpriteGroupScope scope , byte relative )
{
2012-11-10 20:45:59 +00:00
return & this - > default_scope ;
2012-11-10 20:37:31 +00:00
}
2006-04-27 20:53:58 +01:00
2007-09-22 21:29:17 +01:00
/**
* Rotate val rot times to the right
* @ param val the value to rotate
* @ param rot the amount of times to rotate
* @ return the rotated value
*/
static uint32 RotateRight ( uint32 val , uint32 rot )
{
/* Do not rotate more than necessary */
rot % = 32 ;
return ( val > > rot ) | ( val < < ( 32 - rot ) ) ;
}
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 >
2012-11-11 12:57:27 +00:00
static U EvalAdjustT ( const DeterministicSpriteGroupAdjust * adjust , ScopeResolver * scope , U last_value , uint32 value )
2007-01-11 10:58:53 +00:00
{
value > > = adjust - > shift_num ;
value & = adjust - > and_mask ;
if ( adjust - > type ! = DSGA_TYPE_NONE ) value + = ( S ) adjust - > add_val ;
2006-04-27 20:53:58 +01:00
2007-01-11 10:58:53 +00:00
switch ( adjust - > type ) {
case DSGA_TYPE_DIV : value / = ( S ) adjust - > divmod_val ; break ;
case DSGA_TYPE_MOD : value % = ( U ) adjust - > divmod_val ; break ;
case DSGA_TYPE_NONE : break ;
}
2006-04-27 20:53:58 +01:00
2007-01-11 10:58:53 +00:00
switch ( adjust - > operation ) {
case DSGA_OP_ADD : return last_value + value ;
case DSGA_OP_SUB : return last_value - value ;
2007-01-11 11:05:01 +00:00
case DSGA_OP_SMIN : return min ( ( S ) last_value , ( S ) value ) ;
case DSGA_OP_SMAX : return max ( ( S ) last_value , ( S ) value ) ;
2007-01-11 10:58:53 +00:00
case DSGA_OP_UMIN : return min ( ( U ) last_value , ( U ) value ) ;
case DSGA_OP_UMAX : return max ( ( U ) last_value , ( U ) value ) ;
2007-05-14 18:37:34 +01: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 21:40:21 +01:00
case DSGA_OP_STO : _temp_store . StoreValue ( ( U ) value , ( S ) last_value ) ; return last_value ;
2007-04-21 08:27:16 +01: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 ;
2007-09-22 21:29:17 +01:00
case DSGA_OP_ROR : return RotateRight ( last_value , value ) ;
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 ) ;
2014-04-20 16:47:50 +01:00
case DSGA_OP_SHL : return ( uint32 ) ( 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 ) ( U ) last_value > > ( ( U ) value & 0x1F ) ;
case DSGA_OP_SAR : return ( int32 ) ( S ) last_value > > ( ( U ) value & 0x1F ) ;
2007-01-11 10:58:53 +00:00
default : return value ;
}
}
2006-04-27 20:53:58 +01:00
2013-11-24 14:41:19 +00:00
const SpriteGroup * DeterministicSpriteGroup : : Resolve ( ResolverObject & object ) const
2006-04-27 20:53:58 +01:00
{
2007-01-11 14:40:12 +00:00
uint32 last_value = 0 ;
2007-01-11 14:25:17 +00:00
uint32 value = 0 ;
2006-04-27 20:53:58 +01:00
uint i ;
2013-11-24 14:41:19 +00:00
ScopeResolver * scope = object . GetScope ( this - > var_scope ) ;
2006-04-27 20:53:58 +01:00
2009-05-23 16:25:52 +01:00
for ( i = 0 ; i < this - > num_adjusts ; i + + ) {
DeterministicSpriteGroupAdjust * adjust = & this - > adjusts [ i ] ;
2006-05-23 20:36:50 +01:00
/* Try to get the variable. We shall assume it is available, unless told otherwise. */
bool available = true ;
2007-01-12 11:20:34 +00:00
if ( adjust - > variable = = 0x7E ) {
2013-12-23 18:08:16 +00:00
const SpriteGroup * subgroup = SpriteGroup : : Resolve ( adjust - > subroutine , object , false ) ;
2009-05-23 13:13:42 +01:00
if ( subgroup = = NULL ) {
2007-01-12 11:20:34 +00:00
value = CALLBACK_FAILED ;
} else {
2009-05-23 13:13:42 +01:00
value = subgroup - > GetCallbackResult ( ) ;
2007-01-12 11:20:34 +00:00
}
2009-09-30 21:25:59 +01:00
2012-11-11 12:57:27 +00:00
/* Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */
2010-12-22 22:03:57 +00:00
} else if ( adjust - > variable = = 0x7B ) {
2012-11-11 12:57:27 +00:00
value = GetVariable ( object , scope , adjust - > parameter , last_value , & available ) ;
2007-01-12 11:20:34 +00:00
} else {
2012-11-11 12:57:27 +00:00
value = GetVariable ( object , scope , adjust - > variable , adjust - > parameter , & available ) ;
2007-01-12 11:20:34 +00:00
}
2006-05-23 20:36:50 +01:00
if ( ! available ) {
2010-11-15 16:43:46 +00:00
/* Unsupported variable: skip further processing and return either
2006-05-23 20:36:50 +01:00
* the group from the first range or the default group . */
2013-12-23 18:08:16 +00:00
return SpriteGroup : : Resolve ( this - > num_ranges > 0 ? this - > ranges [ 0 ] . group : this - > default_group , object , false ) ;
2006-05-23 20:36:50 +01:00
}
2009-05-23 16:25:52 +01:00
switch ( this - > size ) {
2012-11-11 12:57:27 +00:00
case DSG_SIZE_BYTE : value = EvalAdjustT < uint8 , int8 > ( adjust , scope , last_value , value ) ; break ;
case DSG_SIZE_WORD : value = EvalAdjustT < uint16 , int16 > ( adjust , scope , last_value , value ) ; break ;
case DSG_SIZE_DWORD : value = EvalAdjustT < uint32 , int32 > ( adjust , scope , last_value , value ) ; break ;
2009-05-26 16:46:24 +01:00
default : NOT_REACHED ( ) ;
2006-04-27 20:53:58 +01: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
2009-05-23 16:25:52 +01:00
if ( this - > num_ranges = = 0 ) {
2006-05-23 20:36:50 +01:00
/* nvar == 0 is a special case -- we turn our value into a callback result */
2008-05-04 23:32:25 +01:00
if ( value ! = CALLBACK_FAILED ) value = GB ( value , 0 , 15 ) ;
2011-11-08 17:22:19 +00:00
static CallbackResultSpriteGroup nvarzero ( 0 , true ) ;
2009-05-23 13:13:42 +01:00
nvarzero . result = value ;
2006-05-23 20:36:50 +01:00
return & nvarzero ;
}
2006-04-27 20:53:58 +01:00
2009-05-23 16:25:52 +01:00
for ( i = 0 ; i < this - > num_ranges ; i + + ) {
if ( this - > ranges [ i ] . low < = value & & value < = this - > ranges [ i ] . high ) {
2013-12-23 18:08:16 +00:00
return SpriteGroup : : Resolve ( this - > ranges [ i ] . group , object , false ) ;
2006-04-27 20:53:58 +01:00
}
}
2013-12-23 18:08:16 +00:00
return SpriteGroup : : Resolve ( this - > default_group , object , false ) ;
2006-04-27 20:53:58 +01:00
}
2013-11-24 14:41:19 +00:00
const SpriteGroup * RandomizedSpriteGroup : : Resolve ( ResolverObject & object ) const
2006-04-27 20:53:58 +01:00
{
2013-11-24 14:41:19 +00:00
ScopeResolver * scope = object . GetScope ( this - > var_scope , this - > count ) ;
if ( object . trigger ! = 0 ) {
2006-04-27 20:53:58 +01:00
/* Handle triggers */
/* Magic code that may or may not do the right things... */
2012-11-10 20:37:31 +00:00
byte waiting_triggers = scope - > GetTriggers ( ) ;
2013-11-24 14:41:19 +00:00
byte match = this - > triggers & ( waiting_triggers | object . trigger ) ;
2009-05-23 16:25:52 +01:00
bool res = ( this - > cmp_mode = = RSG_CMP_ANY ) ? ( match ! = 0 ) : ( match = = this - > triggers ) ;
2006-04-27 20:53:58 +01:00
if ( res ) {
waiting_triggers & = ~ match ;
2013-11-24 14:41:19 +00:00
object . reseed [ this - > var_scope ] | = ( this - > num_groups - 1 ) < < this - > lowest_randbit ;
2006-04-27 20:53:58 +01:00
} else {
2013-11-24 14:41:19 +00:00
waiting_triggers | = object . trigger ;
2006-04-27 20:53:58 +01:00
}
2012-11-10 20:37:31 +00:00
scope - > SetTriggers ( waiting_triggers ) ;
2006-04-27 20:53:58 +01:00
}
2012-11-10 20:37:31 +00:00
uint32 mask = ( this - > num_groups - 1 ) < < this - > lowest_randbit ;
byte index = ( scope - > GetRandomBits ( ) & mask ) > > this - > lowest_randbit ;
2006-04-27 20:53:58 +01:00
2013-12-23 18:08:16 +00:00
return SpriteGroup : : Resolve ( this - > groups [ index ] , object , false ) ;
2006-04-27 20:53:58 +01:00
}
2013-11-24 14:41:19 +00:00
const SpriteGroup * RealSpriteGroup : : Resolve ( ResolverObject & object ) const
2006-04-27 20:53:58 +01:00
{
2013-11-24 14:41:19 +00:00
return object . ResolveReal ( this ) ;
2006-04-27 20:53:58 +01:00
}
2011-05-29 17:56:22 +01: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 .
* @ param [ in , out ] stage Construction stage ( 0 - 3 ) , or NULL if not applicable .
* @ return sprite layout to draw .
*/
const DrawTileSprites * TileLayoutSpriteGroup : : ProcessRegisters ( uint8 * stage ) const
{
2011-09-11 16:10:09 +01:00
if ( ! this - > dts . NeedsPreprocessing ( ) ) {
if ( stage ! = NULL & & this - > dts . consistent_max_offset > 0 ) * stage = GetConstructionStageOffset ( * stage , this - > dts . consistent_max_offset ) ;
return & this - > dts ;
}
2011-05-29 17:56:22 +01:00
static DrawTileSprites result ;
uint8 actual_stage = stage ! = NULL ? * stage : 0 ;
2011-09-11 16:10:09 +01:00
this - > dts . PrepareLayout ( 0 , 0 , 0 , actual_stage , false ) ;
2011-05-29 17:56:22 +01:00
this - > dts . ProcessRegisters ( 0 , 0 , false ) ;
result . seq = this - > dts . GetLayout ( & result . ground ) ;
/* Stage has been processed by PrepareLayout(), set it to zero. */
if ( stage ! = NULL ) * stage = 0 ;
return & result ;
}