2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 1998 - 2000 , Matthes Bender
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
/* That which fills the world with life */
2016-04-03 18:07:56 +00:00
# include "C4Include.h"
# include "object/C4Object.h"
2009-05-08 13:28:41 +00:00
2016-04-03 18:07:56 +00:00
# include "script/C4AulExec.h"
2016-04-02 17:44:44 +00:00
# include "object/C4Def.h"
2016-04-03 18:07:56 +00:00
# include "object/C4DefList.h"
# include "script/C4Effect.h"
# include "object/C4ObjectInfo.h"
# include "game/C4Physics.h"
# include "landscape/C4PXS.h"
# include "object/C4ObjectCom.h"
# include "object/C4Command.h"
# include "game/C4Viewport.h"
# include "landscape/C4MaterialList.h"
# include "control/C4Record.h"
# include "landscape/C4SolidMask.h"
# include "platform/C4SoundSystem.h"
# include "lib/C4Random.h"
# include "lib/C4Log.h"
# include "player/C4Player.h"
# include "object/C4ObjectMenu.h"
# include "player/C4RankSystem.h"
# include "gui/C4GameMessage.h"
# include "graphics/C4GraphicsResource.h"
# include "game/C4GraphicsSystem.h"
# include "game/C4Game.h"
2016-08-02 04:13:53 +00:00
# include "game/C4Application.h"
2016-04-03 18:07:56 +00:00
# include "player/C4PlayerList.h"
# include "object/C4GameObjects.h"
# include "control/C4Record.h"
# include "object/C4MeshAnimation.h"
# include "landscape/fow/C4FoW.h"
2016-04-25 19:22:18 +00:00
# include "landscape/C4Particles.h"
2009-05-08 13:28:41 +00:00
2010-04-01 21:00:05 +00:00
namespace
{
const StdMeshInstance : : AttachedMesh : : DenumeratorFactoryFunc C4MeshDenumeratorFactory = StdMeshInstance : : AttachedMesh : : DenumeratorFactory < C4MeshDenumerator > ;
}
void C4MeshDenumerator : : CompileFunc ( StdCompiler * pComp , StdMeshInstance : : AttachedMesh * attach )
{
if ( pComp - > isCompiler ( ) )
{
int32_t def ;
pComp - > Value ( mkNamingCountAdapt ( def , " ChildInstance " ) ) ;
if ( def )
{
C4DefGraphics * pGfx = NULL ;
pComp - > Value ( mkNamingAdapt ( C4DefGraphicsAdapt ( pGfx ) , " ChildMesh " ) ) ;
2011-06-05 12:10:37 +00:00
Def = pGfx - > pDef ;
2010-04-01 21:00:05 +00:00
if ( pGfx - > Type ! = C4DefGraphics : : TYPE_Mesh )
pComp - > excCorrupt ( " ChildMesh points to non-mesh graphics " ) ;
assert ( ! attach - > Child ) ;
pComp - > Value ( mkParAdapt ( mkNamingContextPtrAdapt ( attach - > Child , * pGfx - > Mesh , " ChildInstance " ) , C4MeshDenumeratorFactory ) ) ;
2011-06-05 12:10:37 +00:00
assert ( attach - > Child ! = NULL ) ;
2010-04-01 21:00:05 +00:00
attach - > OwnChild = true ; // Delete the newly allocated child instance when the parent instance is gone
2011-06-05 12:10:37 +00:00
// TODO: Do we leak pGfx?
2010-04-01 21:00:05 +00:00
}
else
{
pComp - > Value ( mkNamingAdapt ( Object , " ChildObject " ) ) ;
attach - > OwnChild = false ; // Keep child instance when parent instance is gone since it belongs to a different object
}
}
else
{
int32_t def = 0 ;
if ( Def ) + + def ;
pComp - > Value ( mkNamingCountAdapt ( def , " ChildInstance " ) ) ;
if ( Def )
{
assert ( attach - > OwnChild ) ;
C4DefGraphics * pGfx = & Def - > Graphics ;
2011-06-05 12:10:37 +00:00
assert ( pGfx - > Type = = C4DefGraphics : : TYPE_Mesh ) ;
2010-04-01 21:00:05 +00:00
pComp - > Value ( mkNamingAdapt ( C4DefGraphicsAdapt ( pGfx ) , " ChildMesh " ) ) ;
pComp - > Value ( mkParAdapt ( mkNamingContextPtrAdapt ( attach - > Child , * pGfx - > Mesh , " ChildInstance " ) , C4MeshDenumeratorFactory ) ) ;
}
else
{
assert ( ! attach - > OwnChild ) ;
pComp - > Value ( mkNamingAdapt ( Object , " ChildObject " ) ) ;
}
}
}
void C4MeshDenumerator : : DenumeratePointers ( StdMeshInstance : : AttachedMesh * attach )
{
Object . DenumeratePointers ( ) ;
// Set child instance of attach after denumeration
if ( Object )
{
assert ( ! attach - > OwnChild ) ;
assert ( ! attach - > Child | | attach - > Child = = Object - > pMeshInstance ) ;
if ( ! attach - > Child )
attach - > Child = Object - > pMeshInstance ;
}
}
2013-05-27 13:52:50 +00:00
bool C4MeshDenumerator : : ClearPointers ( C4Object * pObj )
{
if ( Object = = pObj )
{
Object = NULL ;
// Return false causes the attached mesh to be deleted by StdMeshInstance
return false ;
}
return true ;
}
2012-06-08 14:19:36 +00:00
static void DrawVertex ( C4Facet & cgo , float tx , float ty , int32_t col , int32_t contact )
2010-03-28 18:58:01 +00:00
{
2010-09-24 00:35:26 +00:00
if ( Inside < int32_t > ( tx , cgo . X , cgo . X + cgo . Wdt ) & & Inside < int32_t > ( ty , cgo . Y , cgo . Y + cgo . Hgt ) )
2010-03-28 18:58:01 +00:00
{
2012-06-08 14:19:36 +00:00
pDraw - > DrawLineDw ( cgo . Surface , tx - 1 , ty , tx + 1 , ty , col , 0.5f ) ;
pDraw - > DrawLineDw ( cgo . Surface , tx , ty - 1 , tx , ty + 1 , col , 0.5f ) ;
if ( contact ) pDraw - > DrawFrameDw ( cgo . Surface , tx - 1.5 , ty - 1.5 , tx + 1.5 , ty + 1.5 , C4RGB ( 0xff , 0xff , 0xff ) ) ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Action : : SetBridgeData ( int32_t iBridgeTime , bool fMoveClonk , bool fWall , int32_t iBridgeMaterial )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// validity
2015-11-15 12:53:01 +00:00
iBridgeMaterial = std : : min ( iBridgeMaterial , : : MaterialMap . Num - 1 ) ;
2009-05-08 13:28:41 +00:00
if ( iBridgeMaterial < 0 ) iBridgeMaterial = 0xff ;
2015-02-12 22:05:55 +00:00
iBridgeTime = Clamp < int32_t > ( iBridgeTime , 0 , 0xffff ) ;
2009-05-08 13:28:41 +00:00
// mask in this->Data
Data = ( uint32_t ( iBridgeTime ) < < 16 ) + ( uint32_t ( fMoveClonk ) < < 8 ) + ( uint32_t ( fWall ) < < 9 ) + iBridgeMaterial ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Action : : GetBridgeData ( int32_t & riBridgeTime , bool & rfMoveClonk , bool & rfWall , int32_t & riBridgeMaterial )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// mask from this->Data
uint32_t uiData = Data ;
riBridgeTime = ( uint32_t ( uiData ) > > 16 ) ;
rfMoveClonk = ! ! ( uiData & 0x100 ) ;
rfWall = ! ! ( uiData & 0x200 ) ;
riBridgeMaterial = ( uiData & 0xff ) ;
if ( riBridgeMaterial = = 0xff ) riBridgeMaterial = - 1 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Object : : C4Object ( )
2010-03-28 18:58:01 +00:00
{
2013-12-17 20:40:40 +00:00
FrontParticles = BackParticles = 0 ;
2009-05-08 13:28:41 +00:00
Default ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : Default ( )
2010-03-28 18:58:01 +00:00
{
2010-01-25 03:14:52 +00:00
id = C4ID : : None ;
2009-05-08 13:28:41 +00:00
nInfo . Clear ( ) ;
RemovalDelay = 0 ;
Owner = NO_OWNER ;
Controller = NO_OWNER ;
LastEnergyLossCausePlayer = NO_OWNER ;
Category = 0 ;
Con = 0 ;
Mass = OwnMass = 0 ;
Damage = 0 ;
Energy = 0 ;
Alive = 0 ;
Breath = 0 ;
InMat = MNone ;
Color = 0 ;
2015-01-02 00:06:00 +00:00
lightRange = 0 ;
lightFadeoutRange = 0 ;
2015-07-19 07:01:38 +00:00
lightColor = 0xffffffff ;
2009-05-08 13:28:41 +00:00
fix_x = fix_y = fix_r = 0 ;
2010-03-27 16:05:02 +00:00
xdir = ydir = rdir = 0 ;
Mobile = 0 ;
2009-08-15 18:50:32 +00:00
Unsorted = false ;
Initializing = false ;
2010-03-27 16:05:02 +00:00
OnFire = 0 ;
InLiquid = 0 ;
EntranceStatus = 0 ;
2015-08-28 01:44:23 +00:00
Audible = AudiblePan = 0 ;
AudiblePlayer = NO_OWNER ;
2010-03-27 16:05:02 +00:00
t_contact = 0 ;
OCF = 0 ;
Action . Default ( ) ;
Shape . Default ( ) ;
2009-05-08 13:28:41 +00:00
fOwnVertices = 0 ;
2010-03-27 16:05:02 +00:00
Contents . Default ( ) ;
2009-05-08 13:28:41 +00:00
SolidMask . Default ( ) ;
PictureRect . Default ( ) ;
Def = NULL ;
2010-03-27 16:05:02 +00:00
Info = NULL ;
Command = NULL ;
Contained = NULL ;
2009-05-08 13:28:41 +00:00
TopFace . Default ( ) ;
Menu = NULL ;
MaterialContents = NULL ;
Marker = 0 ;
2009-08-23 21:46:56 +00:00
ColorMod = 0xffffffff ;
BlitMode = 0 ;
2009-08-15 18:50:32 +00:00
CrewDisabled = false ;
2010-03-30 21:08:15 +00:00
Layer = NULL ;
2009-05-08 13:28:41 +00:00
pSolidMaskData = NULL ;
pGraphics = NULL ;
2009-07-10 23:10:18 +00:00
pMeshInstance = NULL ;
2009-05-08 13:28:41 +00:00
pDrawTransform = NULL ;
pEffects = NULL ;
pGfxOverlay = NULL ;
iLastAttachMovementFrame = - 1 ;
2013-09-21 15:22:46 +00:00
2013-12-22 17:51:05 +00:00
ClearParticleLists ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : Init ( C4PropList * pDef , C4Object * pCreator ,
2010-03-28 18:58:01 +00:00
int32_t iOwner , C4ObjectInfo * pInfo ,
int32_t nx , int32_t ny , int32_t nr ,
2010-05-04 15:35:18 +00:00
C4Real nxdir , C4Real nydir , C4Real nrdir , int32_t iController )
2010-03-28 18:58:01 +00:00
{
2010-03-21 23:40:03 +00:00
C4PropListNumbered : : AcquireNumber ( ) ;
2009-05-08 13:28:41 +00:00
// currently initializing
2009-08-15 18:50:32 +00:00
Initializing = true ;
2009-05-08 13:28:41 +00:00
// Def & basics
2010-03-27 16:05:02 +00:00
Owner = iOwner ;
2009-05-08 13:28:41 +00:00
if ( iController > NO_OWNER ) Controller = iController ; else Controller = iOwner ;
LastEnergyLossCausePlayer = NO_OWNER ;
2010-03-27 16:05:02 +00:00
Info = pInfo ;
2010-03-28 18:58:01 +00:00
Def = pDef - > GetDef ( ) ; assert ( Def ) ;
2010-12-06 15:19:15 +00:00
SetProperty ( P_Prototype , C4VPropList ( pDef ) ) ;
2009-04-12 12:04:28 +00:00
id = Def - > id ;
2009-04-03 19:06:29 +00:00
if ( Info ) SetName ( pInfo - > Name ) ;
2010-03-27 16:05:02 +00:00
Category = Def - > Category ;
2010-12-27 19:15:55 +00:00
Plane = Def - > GetPlane ( ) ; assert ( Plane ) ;
2009-05-08 13:28:41 +00:00
Def - > Count + + ;
2010-03-30 21:08:15 +00:00
if ( pCreator ) Layer = pCreator - > Layer ;
2009-05-08 13:28:41 +00:00
// graphics
pGraphics = & Def - > Graphics ;
2010-03-28 18:58:01 +00:00
if ( pGraphics - > Type = = C4DefGraphics : : TYPE_Mesh )
{
2012-02-26 00:09:42 +00:00
pMeshInstance = new StdMeshInstance ( * pGraphics - > Mesh , Def - > GrowthType ? 1.0f : static_cast < float > ( Con ) / static_cast < float > ( FullCon ) ) ;
2010-06-08 22:55:34 +00:00
pMeshInstance - > SetFaceOrderingForClrModulation ( ColorMod ) ;
2010-03-28 18:58:01 +00:00
}
2009-07-10 23:10:18 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-07-10 23:10:18 +00:00
pMeshInstance = NULL ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
BlitMode = Def - > BlitMode ;
// Position
if ( ! Def - > Rotateable ) { nr = 0 ; nrdir = 0 ; }
fix_x = itofix ( nx ) ;
fix_y = itofix ( ny ) ;
2013-05-25 12:59:58 +00:00
fix_r = itofix ( nr ) ;
2009-05-08 13:28:41 +00:00
xdir = nxdir ; ydir = nydir ; rdir = nrdir ;
// Initial mobility
2010-10-11 17:59:54 +00:00
if ( ! ! xdir | | ! ! ydir | | ! ! rdir )
Mobile = 1 ;
2009-05-08 13:28:41 +00:00
// Mass
2015-11-15 12:53:01 +00:00
Mass = std : : max < int32_t > ( Def - > Mass * Con / FullCon , 1 ) ;
2009-05-08 13:28:41 +00:00
// Life, energy, breath
if ( Category & C4D_Living ) Alive = 1 ;
2010-12-12 21:38:15 +00:00
if ( Alive ) Energy = GetPropertyInt ( P_MaxEnergy ) ;
2010-12-12 22:01:08 +00:00
Breath = GetPropertyInt ( P_MaxBreath ) ;
2009-05-08 13:28:41 +00:00
// Color
2010-03-27 16:05:02 +00:00
if ( Def - > ColorByOwner )
2011-03-28 18:58:42 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ValidPlr ( Owner ) )
2009-06-12 23:09:32 +00:00
Color = : : Players . Get ( Owner ) - > ColorDw ;
2010-11-15 11:22:08 +00:00
else
Color = 0xff ; // no-owner color: blue
2011-03-28 18:58:42 +00:00
}
2009-05-08 13:28:41 +00:00
// Shape & face
Shape = Def - > Shape ;
SolidMask = Def - > SolidMask ;
CheckSolidMaskRect ( ) ;
UpdateGraphics ( false ) ;
2010-03-27 16:05:02 +00:00
UpdateFace ( true ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Initial audibility
2015-08-28 01:44:23 +00:00
Audible = : : Viewports . GetAudibility ( GetX ( ) , GetY ( ) , & AudiblePan , 0 , & AudiblePlayer ) ;
2009-05-08 13:28:41 +00:00
// Initial OCF
SetOCF ( ) ;
// finished initializing
2009-08-15 18:50:32 +00:00
Initializing = false ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Object : : ~ C4Object ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Clear ( ) ;
# if defined(_DEBUG)
// debug: mustn't be listed in any list now
2009-06-15 21:47:26 +00:00
: : Objects . Sectors . AssertObjectNotInList ( this ) ;
2009-05-08 13:28:41 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-12-22 17:51:05 +00:00
void C4Object : : ClearParticleLists ( )
{
if ( FrontParticles ! = 0 )
Particles . ReleaseParticleList ( FrontParticles ) ;
if ( BackParticles ! = 0 )
Particles . ReleaseParticleList ( BackParticles ) ;
FrontParticles = BackParticles = 0 ;
}
2009-08-15 18:50:32 +00:00
void C4Object : : AssignRemoval ( bool fExitContents )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check status
if ( ! Status ) return ;
2013-05-25 20:38:08 +00:00
if ( Config . General . DebugRec )
{
C4RCCreateObj rc ;
memset ( & rc , ' \0 ' , sizeof ( rc ) ) ;
rc . oei = Number ;
if ( Def & & Def - > GetName ( ) ) strncpy ( rc . id , Def - > GetName ( ) , 32 + 1 ) ;
rc . x = GetX ( ) ; rc . y = GetY ( ) ; rc . ownr = Owner ;
AddDbgRec ( RCT_DsObj , & rc , sizeof ( rc ) ) ;
}
2009-05-08 13:28:41 +00:00
// Destruction call in container
if ( Contained )
2010-03-28 18:58:01 +00:00
{
2014-05-30 23:03:23 +00:00
C4AulParSet pars ( this ) ;
2009-05-08 13:28:41 +00:00
Contained - > Call ( PSF_ContentsDestruction , & pars ) ;
if ( ! Status ) return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Destruction call
Call ( PSF_Destruction ) ;
// Destruction-callback might have deleted the object already
if ( ! Status ) return ;
2010-03-27 16:05:02 +00:00
// remove all effects (extinguishes as well)
if ( pEffects )
2010-03-28 18:58:01 +00:00
{
2016-05-04 01:46:28 +00:00
pEffects - > ClearAll ( C4FxCall_RemoveClear ) ;
2009-05-08 13:28:41 +00:00
// Effect-callback might actually have deleted the object already
if ( ! Status ) return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// remove particles
2013-12-22 17:51:05 +00:00
ClearParticleLists ( ) ;
2009-05-08 13:28:41 +00:00
// Action idle
2009-04-12 12:03:14 +00:00
SetAction ( 0 ) ;
// Object system operation
2009-05-08 13:28:41 +00:00
if ( Status = = C4OS_INACTIVE )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// object was inactive: activate first, then delete
2009-06-15 21:47:26 +00:00
: : Objects . InactiveObjects . Remove ( this ) ;
2009-05-08 13:28:41 +00:00
Status = C4OS_NORMAL ;
2009-06-15 21:47:26 +00:00
: : Objects . Add ( this ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
Status = 0 ;
2009-05-08 13:28:41 +00:00
// count decrease
Def - > Count - - ;
2015-01-14 21:51:44 +00:00
// get container for next actions
C4Object * pCont = Contained ;
// remove or exit contents
2014-10-24 20:50:14 +00:00
for ( C4Object * cobj : Contents )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( fExitContents )
2015-01-14 21:51:44 +00:00
{
// move objects to parent container or exit them completely
if ( ! pCont | | ! cobj - > Enter ( pCont , false ) )
cobj - > Exit ( GetX ( ) , GetY ( ) ) ;
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Contents . Remove ( cobj ) ;
2015-09-04 03:39:06 +00:00
cobj - > Contained = NULL ;
2009-05-08 13:28:41 +00:00
cobj - > AssignRemoval ( ) ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2015-01-14 21:51:44 +00:00
// remove this object from container *after* its contents have been removed!
if ( pCont )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pCont - > Contents . Remove ( this ) ;
pCont - > UpdateMass ( ) ;
pCont - > SetOCF ( ) ;
Contained = NULL ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Object info
if ( Info ) Info - > Retire ( ) ;
2009-05-08 13:28:41 +00:00
Info = NULL ;
2009-05-19 22:12:11 +00:00
// Object system operation
2013-02-04 21:27:04 +00:00
ClearRefs ( ) ;
2010-10-29 22:05:36 +00:00
Game . ClearPointers ( this ) ;
2010-03-27 16:05:02 +00:00
ClearCommands ( ) ;
2009-05-08 13:28:41 +00:00
if ( pSolidMaskData )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
delete pSolidMaskData ;
pSolidMaskData = NULL ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
SolidMask . Wdt = 0 ;
2010-03-27 16:05:02 +00:00
RemovalDelay = 2 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateShape ( bool bUpdateVertices )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Line shape independent
if ( Def - > Line ) return ;
// Copy shape from def
Shape . CopyFrom ( Def - > Shape , bUpdateVertices , ! ! fOwnVertices ) ;
2010-03-27 16:05:02 +00:00
// Construction zoom
if ( Con ! = FullCon )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( Def - > GrowthType )
Shape . Stretch ( Con , bUpdateVertices ) ;
else
Shape . Jolt ( Con , bUpdateVertices ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Rotation
if ( Def - > Rotateable )
2013-05-25 12:59:58 +00:00
if ( fix_r ! = Fix0 )
2013-05-25 11:10:54 +00:00
Shape . Rotate ( fix_r , bUpdateVertices ) ;
2009-05-08 13:28:41 +00:00
// covered area changed? to be on the save side, update pos
UpdatePos ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdatePos ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get new area covered
// do *NOT* do this while initializing, because object cannot be sorted by main list
if ( ! Initializing & & Status = = C4OS_NORMAL )
2009-06-15 21:47:26 +00:00
: : Objects . UpdatePos ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateFace ( bool bUpdateShape , bool fTemp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Update shape - NOT for temp call, because temnp calls are done in drawing routine
2009-05-08 13:28:41 +00:00
// must not change sync relevant data here (although the shape and pos *should* be updated at that time anyway,
// because a runtime join would desync otherwise)
2010-03-27 16:05:02 +00:00
if ( ! fTemp ) { if ( bUpdateShape ) UpdateShape ( ) ; else UpdatePos ( ) ; }
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// SolidMask
if ( ! fTemp ) UpdateSolidMask ( false ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Null defaults
2009-05-08 13:28:41 +00:00
TopFace . Default ( ) ;
// newgfx: TopFace only
2010-03-27 16:05:02 +00:00
if ( Con > = FullCon | | Def - > GrowthType )
2013-05-25 12:59:58 +00:00
if ( ! Def - > Rotateable | | ( fix_r = = Fix0 ) )
2009-05-08 13:28:41 +00:00
if ( Def - > TopFace . Wdt > 0 ) // Fullcon & no rotation
TopFace . Set ( GetGraphics ( ) - > GetBitmap ( Color ) ,
2010-03-28 18:58:01 +00:00
Def - > TopFace . x , Def - > TopFace . y ,
Def - > TopFace . Wdt , Def - > TopFace . Hgt ) ;
2009-05-08 13:28:41 +00:00
// Active face
UpdateActionFace ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateGraphics ( bool fGraphicsChanged , bool fTemp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check color
if ( ! fTemp ) if ( ! pGraphics - > IsColorByOwner ( ) ) Color = 0 ;
2014-01-08 00:55:33 +00:00
// new grafics: update face
2009-05-08 13:28:41 +00:00
if ( fGraphicsChanged )
2010-03-28 18:58:01 +00:00
{
2011-08-19 22:01:08 +00:00
// Keep mesh instance if it uses the same underlying mesh
2013-05-27 13:52:50 +00:00
if ( ! pMeshInstance | | pGraphics - > Type ! = C4DefGraphics : : TYPE_Mesh | |
2011-08-19 22:01:08 +00:00
& pMeshInstance - > GetMesh ( ) ! = pGraphics - > Mesh )
2010-03-28 18:58:01 +00:00
{
2013-05-27 13:52:50 +00:00
// If this mesh is attached somewhere, detach it before deletion
if ( pMeshInstance & & pMeshInstance - > GetAttachParent ( ) ! = NULL )
{
// TODO: If the new mesh has a bone with the same name, we could try updating...
StdMeshInstance : : AttachedMesh * attach_parent = pMeshInstance - > GetAttachParent ( ) ;
attach_parent - > Parent - > DetachMesh ( attach_parent - > Number ) ;
}
2011-08-19 22:01:08 +00:00
delete pMeshInstance ;
2013-05-27 13:52:50 +00:00
2011-08-19 22:01:08 +00:00
if ( pGraphics - > Type = = C4DefGraphics : : TYPE_Mesh )
{
2012-02-26 00:09:42 +00:00
pMeshInstance = new StdMeshInstance ( * pGraphics - > Mesh , Def - > GrowthType ? 1.0f : static_cast < float > ( Con ) / static_cast < float > ( FullCon ) ) ;
2011-08-19 22:01:08 +00:00
pMeshInstance - > SetFaceOrderingForClrModulation ( ColorMod ) ;
}
else
{
pMeshInstance = NULL ;
}
2010-03-28 18:58:01 +00:00
}
2009-07-10 23:10:18 +00:00
2009-05-08 13:28:41 +00:00
// update face - this also puts any SolidMask
UpdateFace ( false ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateFlipDir ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iFlipDir ;
// We're active
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
if ( pActionDef )
2009-05-08 13:28:41 +00:00
// Get flipdir value from action
2010-03-18 23:04:29 +00:00
if ( ( iFlipDir = pActionDef - > GetPropertyInt ( P_FlipDir ) ) )
2009-05-08 13:28:41 +00:00
// Action dir is in flipdir range
if ( Action . Dir > = iFlipDir )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Calculate flipped drawing dir (from the flipdir direction going backwards)
Action . DrawDir = ( iFlipDir - 1 - ( Action . Dir - iFlipDir ) ) ;
// Set draw transform, creating one if necessary
if ( pDrawTransform )
pDrawTransform - > SetFlipDir ( - 1 ) ;
else
pDrawTransform = new C4DrawTransform ( - 1 ) ;
// Done setting flipdir
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// No flipdir necessary
Action . DrawDir = Action . Dir ;
// Draw transform present?
if ( pDrawTransform )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// reset flip dir
pDrawTransform - > SetFlipDir ( 1 ) ;
// if it's identity now, remove the matrix
if ( pDrawTransform - > IsIdentity ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
delete pDrawTransform ;
pDrawTransform = NULL ;
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
void C4Object : : DrawFaceImpl ( C4TargetFacet & cgo , bool action , float fx , float fy , float fwdt , float fhgt , float tx , float ty , float twdt , float thgt , C4DrawTransform * transform ) const
2010-03-28 18:58:01 +00:00
{
2011-10-03 14:06:41 +00:00
C4Surface * sfc ;
2010-03-28 18:58:01 +00:00
switch ( GetGraphics ( ) - > Type )
{
2015-01-25 15:43:51 +00:00
case C4DefGraphics : : TYPE_None :
// no graphics.
break ;
2010-03-28 18:58:01 +00:00
case C4DefGraphics : : TYPE_Bitmap :
sfc = action ? Action . Facet . Surface : GetGraphics ( ) - > GetBitmap ( Color ) ;
2011-10-03 14:30:18 +00:00
pDraw - > Blit ( sfc ,
2010-03-28 18:58:01 +00:00
fx , fy , fwdt , fhgt ,
cgo . Surface , tx , ty , twdt , thgt ,
true , transform ) ;
break ;
case C4DefGraphics : : TYPE_Mesh :
C4Value value ;
2010-12-06 15:19:15 +00:00
GetProperty ( P_MeshTransformation , & value ) ;
2010-03-28 18:58:01 +00:00
StdMeshMatrix matrix ;
2010-07-21 20:23:34 +00:00
if ( ! C4ValueToMatrix ( value , & matrix ) )
matrix = StdMeshMatrix : : Identity ( ) ;
2010-03-28 18:58:01 +00:00
2016-03-30 23:19:58 +00:00
if ( fix_r ! = Fix0 )
{
2016-04-03 10:22:11 +00:00
const auto mesh_center = pMeshInstance - > GetMesh ( ) . GetBoundingBox ( ) . GetCenter ( ) ;
matrix = StdMeshMatrix : : Translate ( - mesh_center . x , - mesh_center . y , - mesh_center . z ) * matrix ;
2016-03-30 23:19:58 +00:00
matrix = StdMeshMatrix : : Rotate ( fixtof ( fix_r ) * ( M_PI / 180.0f ) , 0.0f , 0.0f , 1.0f ) * matrix ;
2016-04-03 10:22:11 +00:00
matrix = StdMeshMatrix : : Translate ( mesh_center . x , mesh_center . y , mesh_center . z ) * matrix ;
2016-03-30 23:19:58 +00:00
}
2010-07-21 20:23:34 +00:00
if ( twdt ! = fwdt | | thgt ! = fhgt )
{
// Also scale Z so that the mesh is not totally distorted and
// so that normals halfway keep pointing into sensible directions.
// We don't have a better guess so use the geometric mean for Z scale.
matrix = StdMeshMatrix : : Scale ( twdt / fwdt , thgt / fhgt , std : : sqrt ( twdt * thgt / ( fwdt * fhgt ) ) ) * matrix ;
}
2011-10-03 14:30:18 +00:00
pDraw - > SetMeshTransform ( & matrix ) ;
2010-07-21 20:23:34 +00:00
2011-10-03 14:30:18 +00:00
pDraw - > RenderMesh ( * pMeshInstance , cgo . Surface , tx , ty , twdt , thgt , Color , transform ) ;
pDraw - > SetMeshTransform ( NULL ) ;
2010-03-28 18:58:01 +00:00
break ;
2009-07-10 23:10:18 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-07-10 23:10:18 +00:00
2013-08-31 21:23:35 +00:00
void C4Object : : DrawFace ( C4TargetFacet & cgo , float offX , float offY , int32_t iPhaseX , int32_t iPhaseY ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
const float swdt = float ( Def - > Shape . Wdt ) ;
const float shgt = float ( Def - > Shape . Hgt ) ;
2010-03-28 18:58:01 +00:00
// Grow Type Display
float fx = float ( swdt * iPhaseX ) ;
float fy = float ( shgt * iPhaseY ) ;
2009-05-08 13:28:41 +00:00
float fwdt = float ( swdt ) ;
float fhgt = float ( shgt ) ;
float stretch_factor = static_cast < float > ( Con ) / FullCon ;
float tx = offX + Def - > Shape . GetX ( ) * stretch_factor ;
float ty = offY + Def - > Shape . GetY ( ) * stretch_factor ;
float twdt = swdt * stretch_factor ;
float thgt = shgt * stretch_factor ;
// Construction Type Display
if ( ! Def - > GrowthType )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
tx = offX + Def - > Shape . GetX ( ) ;
twdt = swdt ;
fy + = fhgt - thgt ;
fhgt = thgt ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-16 16:30:17 +00:00
C4DrawTransform transform ;
bool transform_active = false ;
if ( pDrawTransform )
2010-03-28 18:58:01 +00:00
{
2016-04-16 16:30:17 +00:00
transform . SetTransformAt ( * pDrawTransform , offX , offY ) ;
transform_active = true ;
2010-03-28 18:58:01 +00:00
}
2016-04-16 16:30:17 +00:00
// Meshes aren't rotated via DrawTransform to ensure lighting is applied correctly.
if ( GetGraphics ( ) - > Type ! = C4DefGraphics : : TYPE_Mesh & & Def - > Rotateable & & fix_r ! = Fix0 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pDrawTransform )
2016-04-16 16:30:17 +00:00
transform . Rotate ( fixtof ( fix_r ) , offX , offY ) ;
2009-05-08 13:28:41 +00:00
else
2016-04-16 16:30:17 +00:00
transform . SetRotate ( fixtof ( fix_r ) , offX , offY ) ;
transform_active = true ;
2009-05-08 13:28:41 +00:00
}
2016-04-16 16:30:17 +00:00
DrawFaceImpl ( cgo , false , fx , fy , fwdt , fhgt , tx , ty , twdt , thgt , transform_active ? & transform : NULL ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
void C4Object : : DrawActionFace ( C4TargetFacet & cgo , float offX , float offY ) const
2010-03-28 18:58:01 +00:00
{
2010-03-09 19:14:47 +00:00
// This should not be called for meshes since Facet has no meaning
// for them. Only use DrawFace() with meshes!
assert ( GetGraphics ( ) - > Type = = C4DefGraphics : : TYPE_Bitmap ) ;
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
2010-03-09 19:14:47 +00:00
2009-05-08 13:28:41 +00:00
// Regular action facet
const float swdt = float ( Action . Facet . Wdt ) ;
const float shgt = float ( Action . Facet . Hgt ) ;
int32_t iPhase = Action . Phase ;
2010-03-18 23:04:29 +00:00
if ( pActionDef - > GetPropertyInt ( P_Reverse ) ) iPhase = pActionDef - > GetPropertyInt ( P_Length ) - 1 - Action . Phase ;
2009-05-08 13:28:41 +00:00
// Grow Type Display
float fx = float ( Action . Facet . X + swdt * iPhase ) ;
float fy = float ( Action . Facet . Y + shgt * Action . DrawDir ) ;
float fwdt = float ( swdt ) ;
float fhgt = float ( shgt ) ;
// draw stretched towards shape center with transform
float stretch_factor = static_cast < float > ( Con ) / FullCon ;
float tx = ( Def - > Shape . GetX ( ) + Action . FacetX ) * stretch_factor + offX ;
float ty = ( Def - > Shape . GetY ( ) + Action . FacetY ) * stretch_factor + offY ;
float twdt = swdt * stretch_factor ;
float thgt = shgt * stretch_factor ;
// Construction Type Display
if ( ! Def - > GrowthType )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// FIXME
if ( Con ! = FullCon )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// incomplete constructions do not show actions
DrawFace ( cgo , offX , offY ) ;
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
tx = Def - > Shape . GetX ( ) + Action . FacetX + offX ;
twdt = swdt ;
2015-11-15 12:53:01 +00:00
float offset_from_top = shgt * std : : max ( FullCon - Con , 0 ) / FullCon ;
2009-05-08 13:28:41 +00:00
fy + = offset_from_top ;
fhgt - = offset_from_top ;
2010-03-28 18:58:01 +00:00
}
2016-04-16 16:30:17 +00:00
C4DrawTransform transform ;
bool transform_active = false ;
if ( pDrawTransform )
2010-03-28 18:58:01 +00:00
{
2016-04-16 16:30:17 +00:00
transform . SetTransformAt ( * pDrawTransform , offX , offY ) ;
transform_active = true ;
2010-03-28 18:58:01 +00:00
}
2016-04-16 16:30:17 +00:00
// Meshes aren't rotated via DrawTransform to ensure lighting is applied correctly.
if ( GetGraphics ( ) - > Type ! = C4DefGraphics : : TYPE_Mesh & & Def - > Rotateable & & fix_r ! = Fix0 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pDrawTransform )
2016-04-16 16:30:17 +00:00
transform . Rotate ( fixtof ( fix_r ) , offX , offY ) ;
2009-05-08 13:28:41 +00:00
else
2016-04-16 16:30:17 +00:00
transform . SetRotate ( fixtof ( fix_r ) , offX , offY ) ;
transform_active = true ;
2009-05-08 13:28:41 +00:00
}
2016-04-16 16:30:17 +00:00
DrawFaceImpl ( cgo , true , fx , fy , fwdt , fhgt , tx , ty , twdt , thgt , transform_active ? & transform : NULL ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateMass ( )
2010-03-28 18:58:01 +00:00
{
2015-11-15 12:53:01 +00:00
Mass = std : : max < int32_t > ( ( Def - > Mass + OwnMass ) * Con / FullCon , 1 ) ;
2016-04-30 15:49:52 +00:00
if ( ! Def - > NoMassFromContents ) Mass + = Contents . Mass ;
2010-03-27 16:05:02 +00:00
if ( Contained )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
Contained - > Contents . MassCount ( ) ;
Contained - > UpdateMass ( ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-09-12 13:04:16 +00:00
void C4Object : : UpdateInMat ( )
{
// get new mat
int32_t newmat ;
if ( Contained )
newmat = Contained - > Def - > ClosedContainer ? MNone : Contained - > InMat ;
else
newmat = GBackMat ( GetX ( ) , GetY ( ) ) ;
// mat changed?
if ( newmat ! = InMat )
{
2014-05-30 23:03:23 +00:00
Call ( PSF_OnMaterialChanged , & C4AulParSet ( newmat , InMat ) ) ;
2010-09-12 13:04:16 +00:00
InMat = newmat ;
}
}
2009-05-08 13:28:41 +00:00
void C4Object : : SetOCF ( )
2010-03-28 18:58:01 +00:00
{
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC_OCF
uint32_t dwOCFOld = OCF ;
# endif
// Update the object character flag according to the object's current situation
2010-05-04 15:35:18 +00:00
C4Real cspeed = GetSpeed ( ) ;
2009-05-08 13:28:41 +00:00
# ifdef _DEBUG
2011-02-06 00:59:49 +00:00
if ( Contained & & ! C4PropListNumbered : : CheckPropList ( Contained ) )
2010-01-25 04:00:59 +00:00
{ LogF ( " Warning: contained in wild object %p! " , static_cast < void * > ( Contained ) ) ; }
2010-03-28 18:58:01 +00:00
else if ( Contained & & ! Contained - > Status )
2011-05-25 18:09:12 +00:00
{ LogF ( " Warning: contained in deleted object (#%d) (%s)! " , Contained - > Number , Contained - > GetName ( ) ) ; }
2009-05-08 13:28:41 +00:00
# endif
// OCF_Normal: The OCF is never zero
2010-03-27 16:05:02 +00:00
OCF = OCF_Normal ;
// OCF_Construct: Can be built outside
if ( Def - > Constructable & & ( Con < FullCon )
2013-05-25 12:59:58 +00:00
& & ( fix_r = = Fix0 ) & & ! OnFire )
2010-03-28 18:58:01 +00:00
OCF | = OCF_Construct ;
2010-03-27 16:05:02 +00:00
// OCF_Grab: Can be pushed
2011-01-02 22:55:48 +00:00
if ( GetPropertyInt ( P_Touchable ) )
2010-03-28 18:58:01 +00:00
OCF | = OCF_Grab ;
2010-03-27 16:05:02 +00:00
// OCF_Carryable: Can be picked up
if ( GetPropertyInt ( P_Collectible ) )
OCF | = OCF_Carryable ;
// OCF_OnFire: Is burning
if ( OnFire )
OCF | = OCF_OnFire ;
// OCF_Inflammable: Is not burning and is inflammable
2012-04-29 08:21:16 +00:00
if ( ! OnFire & & GetPropertyInt ( P_ContactIncinerate ) > 0 )
2011-01-02 18:51:17 +00:00
OCF | = OCF_Inflammable ;
2010-03-27 16:05:02 +00:00
// OCF_FullCon: Is fully completed/grown
if ( Con > = FullCon )
OCF | = OCF_FullCon ;
// OCF_Rotate: Can be rotated
if ( Def - > Rotateable )
2009-05-08 13:28:41 +00:00
// Don't rotate minimum (invisible) construction sites
2010-03-27 16:05:02 +00:00
if ( Con > 100 )
OCF | = OCF_Rotate ;
// OCF_Exclusive: No action through this, no construction in front of this
if ( Def - > Exclusive )
OCF | = OCF_Exclusive ;
// OCF_Entrance: Can currently be entered/activated
if ( ( Def - > Entrance . Wdt > 0 ) & & ( Def - > Entrance . Hgt > 0 ) )
2013-05-25 12:59:58 +00:00
if ( ( OCF & OCF_FullCon ) & & ( ( Def - > RotatedEntrance = = 1 ) | | ( GetR ( ) < = Def - > RotatedEntrance ) ) )
2010-03-27 16:05:02 +00:00
OCF | = OCF_Entrance ;
// HitSpeeds
if ( cspeed > = HitSpeed1 ) OCF | = OCF_HitSpeed1 ;
if ( cspeed > = HitSpeed2 ) OCF | = OCF_HitSpeed2 ;
if ( cspeed > = HitSpeed3 ) OCF | = OCF_HitSpeed3 ;
if ( cspeed > = HitSpeed4 ) OCF | = OCF_HitSpeed4 ;
// OCF_Collection
if ( ( OCF & OCF_FullCon ) | | Def - > IncompleteActivity )
if ( ( Def - > Collection . Wdt > 0 ) & & ( Def - > Collection . Hgt > 0 ) )
if ( ! pActionDef | | ( ! pActionDef - > GetPropertyInt ( P_ObjectDisabled ) ) )
OCF | = OCF_Collection ;
2011-01-02 18:40:48 +00:00
// OCF_Alive
if ( Alive ) OCF | = OCF_Alive ;
2009-05-08 13:28:41 +00:00
// OCF_CrewMember
if ( Def - > CrewMember )
if ( Alive )
OCF | = OCF_CrewMember ;
// OCF_AttractLightning
if ( Def - > AttractLightning )
2010-03-28 18:58:01 +00:00
if ( OCF & OCF_FullCon )
2009-05-08 13:28:41 +00:00
OCF | = OCF_AttractLightning ;
// OCF_NotContained
if ( ! Contained )
OCF | = OCF_NotContained ;
// OCF_InLiquid
if ( InLiquid )
if ( ! Contained )
OCF | = OCF_InLiquid ;
// OCF_InSolid
if ( ! Contained )
if ( GBackSolid ( GetX ( ) , GetY ( ) ) )
OCF | = OCF_InSolid ;
// OCF_InFree
if ( ! Contained )
if ( ! GBackSemiSolid ( GetX ( ) , GetY ( ) - 1 ) )
OCF | = OCF_InFree ;
// OCF_Available
if ( ! Contained | | ( Contained - > Def - > GrabPutGet & C4D_Grab_Get ) | | ( Contained - > OCF & OCF_Entrance ) )
if ( ! GBackSemiSolid ( GetX ( ) , GetY ( ) - 1 ) | | ( ! GBackSolid ( GetX ( ) , GetY ( ) - 1 ) & & ! GBackSemiSolid ( GetX ( ) , GetY ( ) - 8 ) ) )
OCF | = OCF_Available ;
// OCF_Container
if ( ( Def - > GrabPutGet & C4D_Grab_Put ) | | ( Def - > GrabPutGet & C4D_Grab_Get ) | | ( OCF & OCF_Entrance ) )
OCF | = OCF_Container ;
# ifdef DEBUGREC_OCF
2013-05-25 21:01:41 +00:00
if ( Config . General . DebugRec )
{
C4RCOCF rc = { dwOCFOld , OCF , false } ;
AddDbgRec ( RCT_OCF , & rc , sizeof ( rc ) ) ;
}
2009-05-08 13:28:41 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateOCF ( )
2010-03-28 18:58:01 +00:00
{
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC_OCF
uint32_t dwOCFOld = OCF ;
# endif
// Update the object character flag according to the object's current situation
2010-05-04 15:35:18 +00:00
C4Real cspeed = GetSpeed ( ) ;
2009-05-08 13:28:41 +00:00
# ifdef _DEBUG
2011-02-06 00:59:49 +00:00
if ( Contained & & ! C4PropListNumbered : : CheckPropList ( Contained ) )
2010-01-25 04:00:59 +00:00
{ LogF ( " Warning: contained in wild object %p! " , static_cast < void * > ( Contained ) ) ; }
2010-03-28 18:58:01 +00:00
else if ( Contained & & ! Contained - > Status )
2010-01-25 04:00:59 +00:00
{ LogF ( " Warning: contained in deleted object %p (%s)! " , static_cast < void * > ( Contained ) , Contained - > GetName ( ) ) ; }
2009-05-08 13:28:41 +00:00
# endif
// Keep the bits that only have to be updated with SetOCF (def, category, con, alive, onfire)
2015-12-16 21:27:30 +00:00
OCF = OCF & ( OCF_Normal | OCF_Exclusive | OCF_FullCon | OCF_Rotate | OCF_OnFire
2015-11-10 18:13:52 +00:00
| OCF_Alive | OCF_CrewMember | OCF_AttractLightning ) ;
// OCF_inflammable: can catch fire and is not currently burning.
if ( ! OnFire & & GetPropertyInt ( P_ContactIncinerate ) > 0 )
OCF | = OCF_Inflammable ;
2010-03-27 16:05:02 +00:00
// OCF_Carryable: Can be picked up
if ( GetPropertyInt ( P_Collectible ) )
OCF | = OCF_Carryable ;
2015-12-16 21:27:30 +00:00
// OCF_Grab: Can be grabbed.
if ( GetPropertyInt ( P_Touchable ) )
OCF | = OCF_Grab ;
2010-03-27 16:05:02 +00:00
// OCF_Construct: Can be built outside
if ( Def - > Constructable & & ( Con < FullCon )
2013-05-25 12:59:58 +00:00
& & ( fix_r = = Fix0 ) & & ! OnFire )
2010-03-28 18:58:01 +00:00
OCF | = OCF_Construct ;
2010-03-27 16:05:02 +00:00
// OCF_Entrance: Can currently be entered/activated
if ( ( Def - > Entrance . Wdt > 0 ) & & ( Def - > Entrance . Hgt > 0 ) )
2013-05-25 12:59:58 +00:00
if ( ( OCF & OCF_FullCon ) & & ( ( Def - > RotatedEntrance = = 1 ) | | ( GetR ( ) < = Def - > RotatedEntrance ) ) )
2010-03-27 16:05:02 +00:00
OCF | = OCF_Entrance ;
// HitSpeeds
if ( cspeed > = HitSpeed1 ) OCF | = OCF_HitSpeed1 ;
if ( cspeed > = HitSpeed2 ) OCF | = OCF_HitSpeed2 ;
if ( cspeed > = HitSpeed3 ) OCF | = OCF_HitSpeed3 ;
if ( cspeed > = HitSpeed4 ) OCF | = OCF_HitSpeed4 ;
// OCF_Collection
if ( ( OCF & OCF_FullCon ) | | Def - > IncompleteActivity )
if ( ( Def - > Collection . Wdt > 0 ) & & ( Def - > Collection . Hgt > 0 ) )
if ( ! pActionDef | | ( ! pActionDef - > GetPropertyInt ( P_ObjectDisabled ) ) )
OCF | = OCF_Collection ;
2009-05-08 13:28:41 +00:00
// OCF_NotContained
if ( ! Contained )
OCF | = OCF_NotContained ;
// OCF_InLiquid
if ( InLiquid )
if ( ! Contained )
OCF | = OCF_InLiquid ;
// OCF_InSolid
if ( ! Contained )
if ( GBackSolid ( GetX ( ) , GetY ( ) ) )
OCF | = OCF_InSolid ;
// OCF_InFree
if ( ! Contained )
if ( ! GBackSemiSolid ( GetX ( ) , GetY ( ) - 1 ) )
OCF | = OCF_InFree ;
// OCF_Available
if ( ! Contained | | ( Contained - > Def - > GrabPutGet & C4D_Grab_Get ) | | ( Contained - > OCF & OCF_Entrance ) )
if ( ! GBackSemiSolid ( GetX ( ) , GetY ( ) - 1 ) | | ( ! GBackSolid ( GetX ( ) , GetY ( ) - 1 ) & & ! GBackSemiSolid ( GetX ( ) , GetY ( ) - 8 ) ) )
OCF | = OCF_Available ;
// OCF_Container
if ( ( Def - > GrabPutGet & C4D_Grab_Put ) | | ( Def - > GrabPutGet & C4D_Grab_Get ) | | ( OCF & OCF_Entrance ) )
OCF | = OCF_Container ;
# ifdef DEBUGREC_OCF
2013-05-25 21:01:41 +00:00
if ( Config . General . DebugRec )
{
C4RCOCF rc = { dwOCFOld , OCF , true } ;
AddDbgRec ( RCT_OCF , & rc , sizeof ( rc ) ) ;
}
2009-05-08 13:28:41 +00:00
# endif
# ifdef _DEBUG
DEBUGREC_OFF
uint32_t updateOCF = OCF ;
SetOCF ( ) ;
assert ( updateOCF = = OCF ) ;
DEBUGREC_ON
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : ExecLife ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Breathing
if ( ! : : Game . iTick5 )
if ( Alive & & ! Def - > NoBreath )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Supply check
2009-08-15 18:50:32 +00:00
bool Breathe = false ;
2009-05-08 13:28:41 +00:00
// Forcefields are breathable.
if ( GBackMat ( GetX ( ) , GetY ( ) + Shape . GetY ( ) / 2 ) = = MVehic )
2009-08-15 18:50:32 +00:00
{ Breathe = true ; }
2010-12-12 20:49:47 +00:00
else if ( GetPropertyInt ( P_BreatheWater ) )
2009-08-15 18:50:32 +00:00
{ if ( GBackMat ( GetX ( ) , GetY ( ) ) = = MWater ) Breathe = true ; }
2009-05-08 13:28:41 +00:00
else
2009-08-15 18:50:32 +00:00
{ if ( ! GBackSemiSolid ( GetX ( ) , GetY ( ) + Shape . GetY ( ) / 2 ) ) Breathe = true ; }
if ( Contained ) Breathe = true ;
2010-03-27 16:05:02 +00:00
// No supply
if ( ! Breathe )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Reduce breath, then energy, bubble
2010-12-13 21:46:42 +00:00
if ( Breath > 0 ) DoBreath ( - 5 ) ;
2010-03-27 16:05:02 +00:00
else DoEnergy ( - 1 , false , C4FxCall_EngAsphyxiation , NO_OWNER ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Supply
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Take breath
2010-12-12 22:01:08 +00:00
int32_t takebreath = GetPropertyInt ( P_MaxBreath ) - Breath ;
2010-03-28 18:58:01 +00:00
if ( takebreath > 0 ) DoBreath ( takebreath ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Corrosion energy loss
2010-03-27 16:05:02 +00:00
if ( ! : : Game . iTick10 )
if ( Alive )
2009-05-08 13:28:41 +00:00
if ( InMat ! = MNone )
2009-06-05 18:46:03 +00:00
if ( : : MaterialMap . Map [ InMat ] . Corrosive )
2010-12-12 20:49:47 +00:00
if ( ! GetPropertyInt ( P_CorrosionResist ) )
2009-06-05 18:46:03 +00:00
DoEnergy ( - : : MaterialMap . Map [ InMat ] . Corrosive / 15 , false , C4FxCall_EngCorrosion , NO_OWNER ) ;
2009-05-08 13:28:41 +00:00
// InMat incineration
2010-03-27 16:05:02 +00:00
if ( ! : : Game . iTick10 )
2009-05-08 13:28:41 +00:00
if ( InMat ! = MNone )
2016-02-09 22:45:02 +00:00
if ( : : MaterialMap . Map [ InMat ] . Incendiary )
2012-04-29 08:21:16 +00:00
if ( GetPropertyInt ( P_ContactIncinerate ) > 0 )
2011-03-12 17:38:47 +00:00
{
2014-05-21 01:07:10 +00:00
Call ( PSF_OnInIncendiaryMaterial , & C4AulParSet ( ) ) ;
2011-03-12 17:38:47 +00:00
}
2009-05-08 13:28:41 +00:00
// birthday
2009-06-12 18:52:21 +00:00
if ( ! : : Game . iTick255 )
2009-05-08 13:28:41 +00:00
if ( Alive )
2010-03-28 18:58:01 +00:00
if ( Info )
2009-05-08 13:28:41 +00:00
{
int32_t iPlayingTime = Info - > TotalPlayingTime + ( Game . Time - Info - > InActionTime ) ;
int32_t iNewAge = iPlayingTime / 3600 / 5 ;
2010-03-28 18:58:01 +00:00
if ( Info - > Age ! = iNewAge & & Info - > Age )
2009-05-08 13:28:41 +00:00
{
// message
2009-05-11 13:09:53 +00:00
GameMsgObject ( FormatString ( LoadResStr ( " IDS_OBJ_BIRTHDAY " ) , GetName ( ) , Info - > TotalPlayingTime / 3600 / 5 ) . getData ( ) , this ) ;
2015-12-13 21:14:55 +00:00
StartSoundEffect ( " UI::Trumpet " , false , 100 , this ) ;
2009-05-08 13:28:41 +00:00
}
Info - > Age = iNewAge ;
}
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : Execute ( )
2010-03-28 18:58:01 +00:00
{
2013-05-25 20:38:08 +00:00
if ( Config . General . DebugRec )
{
// record debug
C4RCExecObj rc ;
rc . Number = Number ;
rc . fx = fix_x ;
rc . fy = fix_y ;
rc . fr = fix_r ;
AddDbgRec ( RCT_ExecObj , & rc , sizeof ( rc ) ) ;
}
2009-05-08 13:28:41 +00:00
// OCF
UpdateOCF ( ) ;
// Command
ExecuteCommand ( ) ;
// Action
// need not check status, because dead objects have lost their action
ExecAction ( ) ;
// commands and actions are likely to have removed the object, and movement
// *must not* be executed for dead objects (SolidMask-errors)
if ( ! Status ) return ;
// Movement
ExecMovement ( ) ;
2010-03-28 18:58:01 +00:00
if ( ! Status ) return ;
2009-05-08 13:28:41 +00:00
// effects
if ( pEffects )
2010-03-28 18:58:01 +00:00
{
2016-05-04 01:46:28 +00:00
C4Effect : : Execute ( & pEffects ) ;
2009-05-08 13:28:41 +00:00
if ( ! Status ) return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Life
ExecLife ( ) ;
2010-01-29 21:18:18 +00:00
// Animation. If the mesh is attached, then don't execute animation here but let the parent object do it to make sure it is only executed once a frame.
2010-03-28 18:58:01 +00:00
if ( pMeshInstance & & ! pMeshInstance - > GetAttachParent ( ) )
2010-03-16 22:31:53 +00:00
pMeshInstance - > ExecuteAnimation ( 1.0f / 37.0f /* play smoothly at 37 FPS */ ) ;
2009-05-08 13:28:41 +00:00
// Menu
if ( Menu ) Menu - > Execute ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
bool C4Object : : At ( int32_t ctx , int32_t cty ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Status ) if ( ! Contained ) if ( Def )
2010-03-28 18:58:01 +00:00
if ( Inside < int32_t > ( cty - ( GetY ( ) + Shape . GetY ( ) - addtop ( ) ) , 0 , Shape . Hgt - 1 + addtop ( ) ) )
if ( Inside < int32_t > ( ctx - ( GetX ( ) + Shape . GetX ( ) ) , 0 , Shape . Wdt - 1 ) )
return true ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
bool C4Object : : At ( int32_t ctx , int32_t cty , DWORD & ocf ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Status ) if ( ! Contained ) if ( Def )
2010-03-28 18:58:01 +00:00
if ( OCF & ocf )
if ( Inside < int32_t > ( cty - ( GetY ( ) + Shape . GetY ( ) - addtop ( ) ) , 0 , Shape . Hgt - 1 + addtop ( ) ) )
if ( Inside < int32_t > ( ctx - ( GetX ( ) + Shape . GetX ( ) ) , 0 , Shape . Wdt - 1 ) )
{
// Set ocf return value
GetOCFForPos ( ctx , cty , ocf ) ;
return true ;
}
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
void C4Object : : GetOCFForPos ( int32_t ctx , int32_t cty , DWORD & ocf ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
DWORD rocf = OCF ;
// Verify entrance area OCF return
if ( rocf & OCF_Entrance )
if ( ! Inside < int32_t > ( cty - ( GetY ( ) + Def - > Entrance . y ) , 0 , Def - > Entrance . Hgt - 1 )
2010-03-28 18:58:01 +00:00
| | ! Inside < int32_t > ( ctx - ( GetX ( ) + Def - > Entrance . x ) , 0 , Def - > Entrance . Wdt - 1 ) )
rocf & = ( ~ OCF_Entrance ) ;
2009-05-08 13:28:41 +00:00
// Verify collection area OCF return
if ( rocf & OCF_Collection )
if ( ! Inside < int32_t > ( cty - ( GetY ( ) + Def - > Collection . y ) , 0 , Def - > Collection . Hgt - 1 )
2010-03-28 18:58:01 +00:00
| | ! Inside < int32_t > ( ctx - ( GetX ( ) + Def - > Collection . x ) , 0 , Def - > Collection . Wdt - 1 ) )
rocf & = ( ~ OCF_Collection ) ;
2009-05-08 13:28:41 +00:00
ocf = rocf ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : AssignDeath ( bool fForced )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Object * thing ;
2009-05-08 13:28:41 +00:00
// Alive objects only
2010-03-27 16:05:02 +00:00
if ( ! Alive ) return ;
2009-05-08 13:28:41 +00:00
// clear all effects
// do not delete effects afterwards, because they might have denied removal
// set alive-flag before, so objects know what's up
// and prevent recursive death-calls this way
// get death causing player before doing effect calls, because those might meddle around with the flags
int32_t iDeathCausingPlayer = LastEnergyLossCausePlayer ;
Alive = 0 ;
2016-05-04 01:46:28 +00:00
if ( pEffects ) pEffects - > ClearAll ( C4FxCall_RemoveDeath ) ;
2009-05-08 13:28:41 +00:00
// if the object is alive again, abort here if the kill is not forced
if ( Alive & & ! fForced ) return ;
// Action
2010-03-27 16:05:02 +00:00
SetActionByName ( " Dead " ) ;
2009-05-08 13:28:41 +00:00
// Values
Alive = 0 ;
2010-03-27 16:05:02 +00:00
ClearCommands ( ) ;
2011-10-02 16:47:21 +00:00
C4ObjectInfo * pInfo = Info ;
2009-05-08 13:28:41 +00:00
if ( Info )
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
Info - > HasDied = true ;
2009-05-08 13:28:41 +00:00
+ + Info - > DeathCount ;
Info - > Retire ( ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Remove from crew/cursor/view
2009-06-12 23:09:32 +00:00
C4Player * pPlr = : : Players . Get ( Owner ) ;
2010-03-27 16:05:02 +00:00
if ( pPlr ) pPlr - > ClearPointers ( this , true ) ;
2014-12-29 22:09:04 +00:00
// Remove from light sources
2015-01-02 00:06:00 +00:00
SetLightRange ( 0 , 0 ) ;
2009-05-08 13:28:41 +00:00
// Engine script call
2014-05-30 23:03:23 +00:00
C4AulParSet pars ( iDeathCausingPlayer ) ;
2010-03-27 16:05:02 +00:00
Call ( PSF_Death , & pars ) ;
2014-04-22 18:15:26 +00:00
// Lose contents
while ( ( thing = Contents . GetObject ( ) ) ) thing - > Exit ( thing - > GetX ( ) , thing - > GetY ( ) ) ;
2009-05-08 13:28:41 +00:00
// Update OCF. Done here because previously it would have been done in the next frame
// Whats worse: Having the OCF change because of some unrelated script-call like
// SetCategory, or slightly breaking compatibility?
SetOCF ( ) ;
2011-08-02 13:46:24 +00:00
// Engine broadcast: relaunch player (in CR, this was called from clonk script.
// Now, it is done for every crew member)
if ( pPlr )
if ( ! pPlr - > Crew . ObjectCount ( ) )
2014-05-11 21:32:22 +00:00
: : Game . GRBroadcast ( PSF_RelaunchPlayer ,
2014-05-30 23:03:23 +00:00
& C4AulParSet ( Owner , iDeathCausingPlayer , Status ? this : NULL ) ) ;
2011-10-02 16:47:21 +00:00
if ( pInfo )
pInfo - > HasDied = false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : ChangeDef ( C4ID idNew )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Get new definition
C4Def * pDef = C4Id2Def ( idNew ) ;
if ( ! pDef ) return false ;
2009-05-08 13:28:41 +00:00
// Containment storage
C4Object * pContainer = Contained ;
// Exit container (no Ejection/Departure)
2009-08-15 18:50:32 +00:00
if ( Contained ) Exit ( 0 , 0 , 0 , Fix0 , Fix0 , Fix0 , false ) ;
2009-04-12 12:03:14 +00:00
// Pre change resets
SetAction ( 0 ) ;
2010-12-06 15:24:41 +00:00
ResetProperty ( & Strings . P [ P_Action ] ) ; // Enforce ActIdle because SetAction may have failed due to NoOtherAction
2009-05-08 13:28:41 +00:00
SetDir ( 0 ) ; // will drop any outdated flipdir
2010-04-20 20:38:18 +00:00
if ( pSolidMaskData ) { delete pSolidMaskData ; pSolidMaskData = NULL ; }
2009-05-08 13:28:41 +00:00
Def - > Count - - ;
2010-03-27 16:05:02 +00:00
// Def change
Def = pDef ;
2010-12-06 15:19:15 +00:00
SetProperty ( P_Prototype , C4VPropList ( pDef ) ) ;
2009-05-08 13:28:41 +00:00
id = pDef - > id ;
Def - > Count + + ;
// new def: Needs to be resorted
Unsorted = true ;
// graphics change
pGraphics = & pDef - > Graphics ;
// blit mode adjustment
if ( ! ( BlitMode & C4GFXBLIT_CUSTOM ) ) BlitMode = Def - > BlitMode ;
// an object may have newly become an ColorByOwner-object
// if it had been ColorByOwner, but is not now, this will be caught in UpdateGraphics()
if ( ! Color & & ValidPlr ( Owner ) )
2009-06-12 23:09:32 +00:00
Color = : : Players . Get ( Owner ) - > ColorDw ;
2013-05-25 12:59:58 +00:00
if ( ! Def - > Rotateable ) { fix_r = rdir = Fix0 ; }
2009-05-08 13:28:41 +00:00
// Reset solid mask
SolidMask = Def - > SolidMask ;
// Post change updates
UpdateGraphics ( true ) ;
UpdateMass ( ) ;
UpdateFace ( true ) ;
SetOCF ( ) ;
// Any effect callbacks to this object might need to reinitialize their target functions
// This is ugly, because every effect there is must be updated...
2015-12-19 18:53:08 +00:00
if ( : : ScriptEngine . pGlobalEffects )
: : ScriptEngine . pGlobalEffects - > OnObjectChangedDef ( this ) ;
2015-12-23 22:10:48 +00:00
if ( : : GameScript . pScenarioEffects )
: : GameScript . pScenarioEffects - > OnObjectChangedDef ( this ) ;
2014-10-24 20:50:14 +00:00
for ( C4Object * obj : Objects )
if ( obj - > pEffects ) obj - > pEffects - > OnObjectChangedDef ( this ) ;
2009-05-08 13:28:41 +00:00
// Containment (no Entrance)
2009-08-15 18:50:32 +00:00
if ( pContainer ) Enter ( pContainer , false ) ;
2009-05-08 13:28:41 +00:00
// Done
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : DoDamage ( int32_t iChange , int32_t iCausedBy , int32_t iCause )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// non-living: ask effects first
if ( pEffects & & ! Alive )
2010-03-28 18:58:01 +00:00
{
2016-05-04 01:46:28 +00:00
pEffects - > DoDamage ( iChange , iCause , iCausedBy ) ;
2009-05-08 13:28:41 +00:00
if ( ! iChange ) return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Change value
2015-11-15 12:53:01 +00:00
Damage = std : : max < int32_t > ( Damage + iChange , 0 ) ;
2009-05-08 13:28:41 +00:00
// Engine script call
2014-05-30 23:03:23 +00:00
Call ( PSF_Damage , & C4AulParSet ( iChange , iCause , iCausedBy ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : DoEnergy ( int32_t iChange , bool fExact , int32_t iCause , int32_t iCausedByPlr )
2010-03-28 18:58:01 +00:00
{
2016-01-23 03:51:51 +00:00
if ( ! fExact )
{
// Clamp range of change to prevent integer overflow errors
// Do not clamp directly to (0...MaxEnergy)-current_energy, because
// the change value calculated here may be reduced by effect callbacks
int32_t scale = C4MaxPhysical / 100 ; // iChange 100% = Physical 100000
iChange = Clamp < int32_t > ( iChange , std : : numeric_limits < int32_t > : : min ( ) / scale , std : : numeric_limits < int32_t > : : max ( ) / scale ) * scale ;
}
2009-05-08 13:28:41 +00:00
// Was zero?
2010-03-27 16:05:02 +00:00
bool fWasZero = ( Energy = = 0 ) ;
2009-05-08 13:28:41 +00:00
// Mark last damage causing player to trace kills
if ( iChange < 0 ) UpdatLastEnergyLossCause ( iCausedByPlr ) ;
// Living things: ask effects for change first
if ( pEffects & & Alive )
2016-05-04 01:46:28 +00:00
pEffects - > DoDamage ( iChange , iCause , iCausedByPlr ) ;
2009-05-08 13:28:41 +00:00
// Do change
2015-02-12 22:05:55 +00:00
iChange = Clamp < int32_t > ( iChange , - Energy , GetPropertyInt ( P_MaxEnergy ) - Energy ) ;
2010-03-27 16:05:02 +00:00
Energy + = iChange ;
2009-10-13 00:36:11 +00:00
// call to object
2014-05-30 23:03:23 +00:00
Call ( PSF_EnergyChange , & C4AulParSet ( iChange , iCause , iCausedByPlr ) ) ;
2009-05-08 13:28:41 +00:00
// Alive and energy reduced to zero: death
2010-03-27 16:05:02 +00:00
if ( Alive ) if ( Energy = = 0 ) if ( ! fWasZero ) AssignDeath ( false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdatLastEnergyLossCause ( int32_t iNewCausePlr )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Mark last damage causing player to trace kills
// do not regard self-administered damage if there was a previous damage causing player, because that would steal kills
// if people tumble themselves via stop-stop-(left/right)-throw while falling into teh abyss
if ( iNewCausePlr ! = Controller | | LastEnergyLossCausePlayer < 0 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
LastEnergyLossCausePlayer = iNewCausePlr ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : DoBreath ( int32_t iChange )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Do change
2015-02-12 22:05:55 +00:00
iChange = Clamp < int32_t > ( iChange , - Breath , GetPropertyInt ( P_MaxBreath ) - Breath ) ;
2010-03-27 16:05:02 +00:00
Breath + = iChange ;
2009-10-13 00:36:11 +00:00
// call to object
2014-05-30 23:03:23 +00:00
Call ( PSF_BreathChange , & C4AulParSet ( iChange ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-01-11 21:04:35 +00:00
void C4Object : : DoCon ( int32_t iChange , bool grow_from_center )
2010-03-28 18:58:01 +00:00
{
2012-07-27 15:44:59 +00:00
C4Real strgt_con_b = fix_y + Shape . GetBottom ( ) ;
2009-08-15 18:50:32 +00:00
bool fWasFull = ( Con > = FullCon ) ;
2016-05-01 09:41:19 +00:00
int32_t old_con = Con ;
2009-05-08 13:28:41 +00:00
// Change con
if ( Def - > Oversize )
2015-11-15 12:53:01 +00:00
Con = std : : max < int32_t > ( Con + iChange , 0 ) ;
2009-05-08 13:28:41 +00:00
else
2015-02-12 22:05:55 +00:00
Con = Clamp < int32_t > ( Con + iChange , 0 , FullCon ) ;
2009-05-08 13:28:41 +00:00
// Update OCF
SetOCF ( ) ;
2012-07-27 14:09:25 +00:00
// Mass
UpdateMass ( ) ;
// shape and position
UpdateShape ( ) ;
// make the bottom-most vertex stay in place
2015-01-11 21:04:35 +00:00
if ( ! grow_from_center )
{
fix_y = strgt_con_b - Shape . GetBottom ( ) ;
}
2012-07-27 14:09:25 +00:00
// Face (except for the shape)
UpdateFace ( false ) ;
2016-05-01 09:41:19 +00:00
// Do a callback on completion change.
if ( iChange ! = 0 )
Call ( PSF_OnCompletionChange , & C4AulParSet ( old_con , Con ) ) ;
2012-07-27 14:09:25 +00:00
// Unfullcon
if ( fWasFull & & ( Con < FullCon ) )
2010-03-28 18:58:01 +00:00
{
2012-07-27 14:09:25 +00:00
// Lose contents
if ( ! Def - > IncompleteActivity )
2010-03-28 18:58:01 +00:00
{
2012-07-27 14:09:25 +00:00
C4Object * cobj ;
while ( ( cobj = Contents . GetObject ( ) ) )
if ( Contained ) cobj - > Enter ( Contained ) ;
else cobj - > Exit ( cobj - > GetX ( ) , cobj - > GetY ( ) ) ;
SetAction ( 0 ) ;
2010-03-28 18:58:01 +00:00
}
}
2011-01-02 01:03:44 +00:00
2012-07-27 14:09:25 +00:00
// Completion
2009-05-08 13:28:41 +00:00
if ( ! fWasFull & & ( Con > = FullCon ) )
Call ( PSF_Initialize ) ;
// Con Zero Removal
if ( Con < = 0 )
AssignRemoval ( ) ;
2012-02-26 00:09:42 +00:00
// Mesh Graphics Update
else if ( pMeshInstance )
pMeshInstance - > SetCompletion ( Def - > GrowthType ? 1.0f : static_cast < float > ( Con ) / static_cast < float > ( FullCon ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : DoExperience ( int32_t change )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
const int32_t MaxExperience = 100000000 ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
if ( ! Info ) return ;
2009-05-08 13:28:41 +00:00
2015-02-12 22:05:55 +00:00
Info - > Experience = Clamp < int32_t > ( Info - > Experience + change , 0 , MaxExperience ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Promotion check
2009-05-08 13:28:41 +00:00
if ( Info - > Experience < MaxExperience )
2009-06-05 15:13:33 +00:00
if ( Info - > Experience > = : : DefaultRanks . Experience ( Info - > Rank + 1 ) )
2009-08-15 18:50:32 +00:00
Promote ( Info - > Rank + 1 , false , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool C4Object : : Exit ( int32_t iX , int32_t iY , int32_t iR , C4Real iXDir , C4Real iYDir , C4Real iRDir , bool fCalls )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// 1. Exit the current container.
// 2. Update Contents of container object and set Contained to NULL.
// 3. Set offset position/motion if desired.
// 4. Call Ejection for container and Departure for object.
// Not contained
C4Object * pContainer = Contained ;
2010-03-27 16:05:02 +00:00
if ( ! pContainer ) return false ;
// Remove object from container
pContainer - > Contents . Remove ( this ) ;
pContainer - > UpdateMass ( ) ;
pContainer - > SetOCF ( ) ;
// No container
Contained = NULL ;
2009-05-08 13:28:41 +00:00
// Position/motion
2013-05-25 12:59:58 +00:00
fix_x = itofix ( iX ) ; fix_y = itofix ( iY ) ;
fix_r = itofix ( iR ) ;
2010-03-18 17:05:02 +00:00
BoundsCheck ( fix_x , fix_y ) ;
2009-05-08 13:28:41 +00:00
xdir = iXDir ; ydir = iYDir ; rdir = iRDir ;
// Misc updates
2010-03-27 16:05:02 +00:00
Mobile = 1 ;
InLiquid = 0 ;
CloseMenu ( true ) ;
UpdateFace ( true ) ;
SetOCF ( ) ;
2016-02-21 20:56:07 +00:00
// Object list callback (before script callbacks, because script callbacks may enter again)
ObjectListChangeListener . OnObjectContainerChanged ( this , pContainer , NULL ) ;
2009-05-08 13:28:41 +00:00
// Engine calls
2014-05-30 23:03:23 +00:00
if ( fCalls ) pContainer - > Call ( PSF_Ejection , & C4AulParSet ( this ) ) ;
if ( fCalls ) Call ( PSF_Departure , & C4AulParSet ( pContainer ) ) ;
2009-05-08 13:28:41 +00:00
// Success (if the obj wasn't "re-entered" by script)
2010-03-27 16:05:02 +00:00
return ! Contained ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : Enter ( C4Object * pTarget , bool fCalls , bool fCopyMotion , bool * pfRejectCollect )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// 0. Query entrance and collection
// 1. Exit if contained.
// 2. Set new container.
// 3. Update Contents and mass of the new container.
// 4. Call collection for container
// 5. Call entrance for object.
2015-09-03 02:57:24 +00:00
// No valid target or target is self
2009-08-15 18:50:32 +00:00
if ( ! pTarget | | ( pTarget = = this ) ) return false ;
2009-05-08 13:28:41 +00:00
// check if entrance is allowed
2014-05-30 23:03:23 +00:00
if ( ! ! Call ( PSF_RejectEntrance , & C4AulParSet ( pTarget ) ) ) return false ;
2009-05-08 13:28:41 +00:00
// check if we end up in an endless container-recursion
for ( C4Object * pCnt = pTarget - > Contained ; pCnt ; pCnt = pCnt - > Contained )
2009-08-15 18:50:32 +00:00
if ( pCnt = = this ) return false ;
2009-05-08 13:28:41 +00:00
// Check RejectCollect, if desired
if ( pfRejectCollect )
2010-03-28 18:58:01 +00:00
{
2014-05-30 23:03:23 +00:00
if ( ! ! pTarget - > Call ( PSF_RejectCollection , & C4AulParSet ( Def , this ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
* pfRejectCollect = true ;
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
* pfRejectCollect = false ;
}
2009-05-08 13:28:41 +00:00
// Exit if contained
2009-08-15 18:50:32 +00:00
if ( Contained ) if ( ! Exit ( GetX ( ) , GetY ( ) ) ) return false ;
if ( Contained | | ! Status | | ! pTarget - > Status ) return false ;
2009-05-08 13:28:41 +00:00
// Failsafe updates
2015-09-03 02:57:24 +00:00
if ( Menu )
{
CloseMenu ( true ) ;
// CloseMenu might do bad stuff
if ( Contained | | ! Status | | ! pTarget - > Status ) return false ;
}
2009-05-08 13:28:41 +00:00
SetOCF ( ) ;
// Set container
Contained = pTarget ;
// Enter
if ( ! Contained - > Contents . Add ( this , C4ObjectList : : stContents ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Contained = NULL ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Assume that the new container controls this object, if it cannot control itself (i.e.: Alive)
// So it can be traced back who caused the damage, if a projectile hits its target
2011-01-02 18:52:29 +00:00
if ( ! Alive )
2009-05-08 13:28:41 +00:00
Controller = pTarget - > Controller ;
// Misc updates
// motion must be copied immediately, so the position will be correct when OCF is set, and
// OCF_Available will be set for newly bought items, even if 50/50 is solid in the landscape
// however, the motion must be preserved sometimes to keep flags like OCF_HitSpeed upon collection
if ( fCopyMotion )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// remove any solidmask before copying the motion...
UpdateSolidMask ( false ) ;
CopyMotion ( Contained ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
SetOCF ( ) ;
2010-03-27 16:05:02 +00:00
UpdateFace ( true ) ;
// Update container
Contained - > UpdateMass ( ) ;
Contained - > SetOCF ( ) ;
2016-02-21 20:56:07 +00:00
// Object list callback (before script callbacks, because script callbacks may exit again)
ObjectListChangeListener . OnObjectContainerChanged ( this , NULL , Contained ) ;
2009-05-08 13:28:41 +00:00
// Collection call
2014-05-30 23:03:23 +00:00
if ( fCalls ) pTarget - > Call ( PSF_Collection2 , & C4AulParSet ( this ) ) ;
2009-08-15 18:50:32 +00:00
if ( ! Contained | | ! Contained - > Status | | ! pTarget - > Status ) return true ;
2009-05-08 13:28:41 +00:00
// Entrance call
2014-05-30 23:03:23 +00:00
if ( fCalls ) Call ( PSF_Entrance , & C4AulParSet ( Contained ) ) ;
2009-08-15 18:50:32 +00:00
if ( ! Contained | | ! Contained - > Status | | ! pTarget - > Status ) return true ;
2009-05-08 13:28:41 +00:00
// Success
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
void C4Object : : Fling ( C4Real txdir , C4Real tydir , bool fAddSpeed )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( fAddSpeed ) { txdir + = xdir / 2 ; tydir + = ydir / 2 ; }
2010-03-27 16:05:02 +00:00
if ( ! ObjectActionTumble ( this , ( txdir < 0 ) , txdir , tydir ) )
if ( ! ObjectActionJump ( this , txdir , tydir , false ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
xdir = txdir ; ydir = tydir ;
Mobile = 1 ;
Action . t_attach & = ~ CNAT_Bottom ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : ActivateEntrance ( int32_t by_plr , C4Object * by_obj )
2010-03-28 18:58:01 +00:00
{
2009-10-11 19:57:31 +00:00
2010-03-27 16:05:02 +00:00
// Try entrance activation
if ( OCF & OCF_Entrance )
2014-05-30 23:03:23 +00:00
if ( ! ! Call ( PSF_ActivateEntrance , & C4AulParSet ( by_obj ) ) )
2010-03-27 16:05:02 +00:00
return true ;
2009-05-08 13:28:41 +00:00
// Failure
2010-03-27 16:05:02 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool C4Object : : Push ( C4Real txdir , C4Real dforce , bool fStraighten )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Valid check
if ( ! Status | | ! Def | | Contained | | ! ( OCF & OCF_Grab ) ) return false ;
// Grabbing okay, no pushing
2011-01-02 22:55:48 +00:00
if ( GetPropertyInt ( P_Touchable ) = = 2 ) return true ;
2010-03-27 16:05:02 +00:00
// Mobilization check (pre-mobilization zero)
if ( ! Mobile )
{ xdir = ydir = Fix0 ; }
// General pushing force vs. object mass
dforce = dforce * 100 / Mass ;
// Set dir
if ( xdir < 0 ) SetDir ( DIR_Left ) ;
if ( xdir > 0 ) SetDir ( DIR_Right ) ;
// Work towards txdir
if ( Abs ( xdir - txdir ) < = dforce ) // Close-enough-set
{ xdir = txdir ; }
else // Work towards
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( xdir < txdir ) xdir + = dforce ;
if ( xdir > txdir ) xdir - = dforce ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Straighten
if ( fStraighten )
2010-03-28 18:58:01 +00:00
{
2013-05-25 12:59:58 +00:00
if ( Inside < int32_t > ( GetR ( ) , - StableRange , + StableRange ) )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
rdir = 0 ; // cheap way out
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
else
2010-03-28 18:58:01 +00:00
{
2013-05-25 12:59:58 +00:00
if ( fix_r > Fix0 ) { if ( rdir > - RotateAccel ) rdir - = dforce ; }
2010-03-27 16:05:02 +00:00
else { if ( rdir < + RotateAccel ) rdir + = dforce ; }
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Mobilization check
if ( ! ! xdir | | ! ! ydir | | ! ! rdir ) Mobile = 1 ;
// Stuck check
if ( ! : : Game . iTick35 ) if ( txdir ) if ( ! Def - > NoHorizontalMove )
2010-03-28 18:58:01 +00:00
if ( ContactCheck ( GetX ( ) , GetY ( ) ) ) // Resets t_contact
{
2010-06-28 23:02:16 +00:00
GameMsgObjectError ( FormatString ( LoadResStr ( " IDS_OBJ_STUCK " ) , GetName ( ) ) . getData ( ) , this ) ;
2010-03-28 18:58:01 +00:00
Call ( PSF_Stuck ) ;
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool C4Object : : Lift ( C4Real tydir , C4Real dforce )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Valid check
if ( ! Status | | ! Def | | Contained ) return false ;
// Mobilization check
if ( ! Mobile )
{ xdir = ydir = Fix0 ; Mobile = 1 ; }
// General pushing force vs. object mass
dforce = dforce * 100 / Mass ;
// If close enough, set tydir
if ( Abs ( tydir - ydir ) < = Abs ( dforce ) )
ydir = tydir ;
else // Work towards tydir
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ydir < tydir ) ydir + = dforce ;
if ( ydir > tydir ) ydir - = dforce ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Stuck check
if ( tydir ! = - GravAccel )
if ( ContactCheck ( GetX ( ) , GetY ( ) ) ) // Resets t_contact
2010-03-28 18:58:01 +00:00
{
2010-06-28 23:02:16 +00:00
GameMsgObjectError ( FormatString ( LoadResStr ( " IDS_OBJ_STUCK " ) , GetName ( ) ) . getData ( ) , this ) ;
2010-03-27 16:05:02 +00:00
Call ( PSF_Stuck ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-04-12 12:04:28 +00:00
C4Object * C4Object : : CreateContents ( C4PropList * PropList )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Object * nobj ;
if ( ! ( nobj = Game . CreateObject ( PropList , this , Owner ) ) ) return NULL ;
if ( ! nobj - > Enter ( this ) ) { nobj - > AssignRemoval ( ) ; return NULL ; }
return nobj ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : CreateContentsByList ( C4IDList & idlist )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t cnt , cnt2 ;
for ( cnt = 0 ; idlist . GetID ( cnt ) ; cnt + + )
for ( cnt2 = 0 ; cnt2 < idlist . GetCount ( cnt ) ; cnt2 + + )
if ( ! CreateContents ( C4Id2Def ( idlist . GetID ( cnt ) ) ) )
return false ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-10-17 19:38:56 +00:00
static void DrawMenuSymbol ( int32_t iMenu , C4Facet & cgo , int32_t iOwner )
{
C4Facet ccgo ;
DWORD dwColor = 0 ;
if ( ValidPlr ( iOwner ) ) dwColor = : : Players . Get ( iOwner ) - > ColorDw ;
switch ( iMenu )
{
case C4MN_Buy :
: : GraphicsResource . fctFlagClr . DrawClr ( ccgo = cgo . GetFraction ( 75 , 75 ) , true , dwColor ) ;
: : GraphicsResource . fctWealth . Draw ( ccgo = cgo . GetFraction ( 100 , 50 , C4FCT_Left , C4FCT_Bottom ) ) ;
: : GraphicsResource . fctArrow . Draw ( ccgo = cgo . GetFraction ( 70 , 70 , C4FCT_Right , C4FCT_Center ) , false , 0 ) ;
break ;
case C4MN_Sell :
: : GraphicsResource . fctFlagClr . DrawClr ( ccgo = cgo . GetFraction ( 75 , 75 ) , true , dwColor ) ;
: : GraphicsResource . fctWealth . Draw ( ccgo = cgo . GetFraction ( 100 , 50 , C4FCT_Left , C4FCT_Bottom ) ) ;
: : GraphicsResource . fctArrow . Draw ( ccgo = cgo . GetFraction ( 70 , 70 , C4FCT_Right , C4FCT_Center ) , false , 1 ) ;
break ;
}
}
2009-08-15 18:50:32 +00:00
bool C4Object : : ActivateMenu ( int32_t iMenu , int32_t iMenuSelect ,
2010-03-28 18:58:01 +00:00
int32_t iMenuData , int32_t iMenuPosition ,
C4Object * pTarget )
{
2009-05-08 13:28:41 +00:00
// Variables
C4FacetSurface fctSymbol ;
C4IDList ListItems ;
// Close any other menu
2009-08-15 18:50:32 +00:00
if ( Menu & & Menu - > IsActive ( ) ) if ( ! Menu - > TryClose ( true , false ) ) return false ;
2009-05-08 13:28:41 +00:00
// Create menu
2011-01-02 20:10:53 +00:00
if ( ! Menu ) Menu = new C4ObjectMenu ; else Menu - > ClearItems ( ) ;
2009-05-08 13:28:41 +00:00
// Open menu
switch ( iMenu )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case C4MN_Activate :
// No target specified: use own container as target
if ( ! pTarget ) if ( ! ( pTarget = Contained ) ) break ;
// Opening contents menu blocked by RejectContents
if ( ! ! pTarget - > Call ( PSF_RejectContents ) ) return false ;
// Create symbol
fctSymbol . Create ( C4SymbolSize , C4SymbolSize ) ;
pTarget - > Def - > Draw ( fctSymbol , false , pTarget - > Color , pTarget ) ;
// Init
2010-12-04 22:44:57 +00:00
Menu - > Init ( fctSymbol , FormatString ( LoadResStr ( " IDS_OBJ_EMPTY " ) , pTarget - > GetName ( ) ) . getData ( ) , this , C4MN_Extra_None , 0 , iMenu ) ;
2010-03-28 18:58:01 +00:00
Menu - > SetPermanent ( true ) ;
Menu - > SetRefillObject ( pTarget ) ;
// Success
return true ;
2009-05-08 13:28:41 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case C4MN_Buy :
// No target specified: container is base
if ( ! pTarget ) if ( ! ( pTarget = Contained ) ) break ;
// Create symbol
fctSymbol . Create ( C4SymbolSize , C4SymbolSize ) ;
2010-10-17 19:38:56 +00:00
DrawMenuSymbol ( C4MN_Buy , fctSymbol , pTarget - > Owner ) ;
2010-03-28 18:58:01 +00:00
// Init menu
Menu - > Init ( fctSymbol , LoadResStr ( " IDS_PLR_NOBUY " ) , this , C4MN_Extra_Value , 0 , iMenu ) ;
Menu - > SetPermanent ( true ) ;
Menu - > SetRefillObject ( pTarget ) ;
// Success
return true ;
2009-05-08 13:28:41 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case C4MN_Sell :
// No target specified: container is base
if ( ! pTarget ) if ( ! ( pTarget = Contained ) ) break ;
// Create symbol & init
fctSymbol . Create ( C4SymbolSize , C4SymbolSize ) ;
2010-10-17 19:38:56 +00:00
DrawMenuSymbol ( C4MN_Sell , fctSymbol , pTarget - > Owner ) ;
2010-12-04 22:44:57 +00:00
Menu - > Init ( fctSymbol , FormatString ( LoadResStr ( " IDS_OBJ_EMPTY " ) , pTarget - > GetName ( ) ) . getData ( ) , this , C4MN_Extra_Value , 0 , iMenu ) ;
2010-03-28 18:58:01 +00:00
Menu - > SetPermanent ( true ) ;
Menu - > SetRefillObject ( pTarget ) ;
// Success
return true ;
2009-05-08 13:28:41 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case C4MN_Get :
case C4MN_Contents :
// No target specified
if ( ! pTarget ) break ;
// Opening contents menu blocked by RejectContents
if ( ! ! pTarget - > Call ( PSF_RejectContents ) ) return false ;
// Create symbol & init
fctSymbol . Create ( C4SymbolSize , C4SymbolSize ) ;
pTarget - > Def - > Draw ( fctSymbol , false , pTarget - > Color , pTarget ) ;
2010-12-04 22:44:57 +00:00
Menu - > Init ( fctSymbol , FormatString ( LoadResStr ( " IDS_OBJ_EMPTY " ) , pTarget - > GetName ( ) ) . getData ( ) , this , C4MN_Extra_None , 0 , iMenu ) ;
2010-03-28 18:58:01 +00:00
Menu - > SetPermanent ( true ) ;
Menu - > SetRefillObject ( pTarget ) ;
// Success
return true ;
2009-05-08 13:28:41 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case C4MN_Info :
// Target by parameter
if ( ! pTarget ) break ;
// Create symbol & init menu
fctSymbol . Create ( C4SymbolSize , C4SymbolSize ) ; GfxR - > fctOKCancel . Draw ( fctSymbol , true , 0 , 1 ) ;
Menu - > Init ( fctSymbol , pTarget - > GetName ( ) , this , C4MN_Extra_None , 0 , iMenu , C4MN_Style_Info ) ;
Menu - > SetPermanent ( true ) ;
Menu - > SetAlignment ( C4MN_Align_Free ) ;
2010-09-29 01:44:05 +00:00
C4Viewport * pViewport = : : Viewports . GetViewport ( Controller ) ; // Hackhackhack!!!
2015-01-03 21:51:02 +00:00
if ( pViewport ) Menu - > SetLocation ( ( pTarget - > GetX ( ) + pTarget - > Shape . GetX ( ) + pTarget - > Shape . Wdt + 10 - pViewport - > GetViewX ( ) ) * pViewport - > GetZoom ( ) ,
( pTarget - > GetY ( ) + pTarget - > Shape . GetY ( ) - pViewport - > GetViewY ( ) ) * pViewport - > GetZoom ( ) ) ;
2010-03-28 18:58:01 +00:00
// Add info item
fctSymbol . Create ( C4PictureSize , C4PictureSize ) ; pTarget - > Def - > Draw ( fctSymbol , false , pTarget - > Color , pTarget ) ;
Menu - > Add ( pTarget - > GetName ( ) , fctSymbol , " " , C4MN_Item_NoCount , NULL , pTarget - > GetInfoString ( ) . getData ( ) ) ;
fctSymbol . Default ( ) ;
// Success
return true ;
2009-05-08 13:28:41 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Invalid menu identification
CloseMenu ( true ) ;
2010-03-27 16:05:02 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : CloseMenu ( bool fForce )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Menu )
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
if ( Menu - > IsActive ( ) ) if ( ! Menu - > TryClose ( fForce , false ) ) return false ;
2009-05-08 13:28:41 +00:00
if ( ! Menu - > IsCloseQuerying ( ) ) { delete Menu ; Menu = NULL ; } // protect menu deletion from recursive menu operation calls
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
BYTE C4Object : : GetArea ( int32_t & aX , int32_t & aY , int32_t & aWdt , int32_t & aHgt ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! Status | | ! Def ) return 0 ;
aX = GetX ( ) + Shape . GetX ( ) ; aY = GetY ( ) + Shape . GetY ( ) ;
aWdt = Shape . Wdt ; aHgt = Shape . Hgt ;
return 1 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
BYTE C4Object : : GetEntranceArea ( int32_t & aX , int32_t & aY , int32_t & aWdt , int32_t & aHgt ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! Status | | ! Def ) return 0 ;
// Return actual entrance
if ( OCF & OCF_Entrance )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
aX = GetX ( ) + Def - > Entrance . x ;
aY = GetY ( ) + Def - > Entrance . y ;
aWdt = Def - > Entrance . Wdt ;
aHgt = Def - > Entrance . Hgt ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Return object center
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
aX = GetX ( ) ; aY = GetY ( ) ;
aWdt = 0 ; aHgt = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Done
return 1 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
BYTE C4Object : : GetMomentum ( C4Real & rxdir , C4Real & rydir ) const
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
rxdir = rydir = 0 ;
if ( ! Status | | ! Def ) return 0 ;
rxdir = xdir ; rydir = ydir ;
return 1 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
C4Real C4Object : : GetSpeed ( ) const
2010-03-28 18:58:01 +00:00
{
2010-05-04 15:35:18 +00:00
C4Real cobjspd = Fix0 ;
2010-03-27 16:05:02 +00:00
if ( xdir < 0 ) cobjspd - = xdir ; else cobjspd + = xdir ;
if ( ydir < 0 ) cobjspd - = ydir ; else cobjspd + = ydir ;
return cobjspd ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-01-12 22:43:05 +00:00
StdStrBuf C4Object : : GetDataString ( )
{
StdStrBuf Output ;
// Type
Output . AppendFormat ( LoadResStr ( " IDS_CNS_TYPE " ) , GetName ( ) , Def - > id . ToString ( ) ) ;
// Owner
if ( ValidPlr ( Owner ) )
{
Output . Append ( LineFeed ) ;
Output . AppendFormat ( LoadResStr ( " IDS_CNS_OWNER " ) , : : Players . Get ( Owner ) - > GetName ( ) ) ;
}
// Contents
if ( Contents . ObjectCount ( ) )
{
Output . Append ( LineFeed ) ;
Output . Append ( LoadResStr ( " IDS_CNS_CONTENTS " ) ) ;
Output . Append ( Contents . GetNameList ( : : Definitions ) ) ;
}
// Action
if ( GetAction ( ) )
{
Output . Append ( LineFeed ) ;
Output . Append ( LoadResStr ( " IDS_CNS_ACTION " ) ) ;
Output . Append ( GetAction ( ) - > GetName ( ) ) ;
}
2011-01-13 16:55:58 +00:00
// Properties
Output . Append ( LineFeed ) ;
Output . Append ( LoadResStr ( " IDS_CNS_PROPERTIES " ) ) ;
Output . Append ( LineFeed " " ) ;
AppendDataString ( & Output , LineFeed " " ) ;
2011-01-12 22:43:05 +00:00
// Effects
if ( pEffects )
{
Output . Append ( LineFeed ) ;
Output . Append ( LoadResStr ( " IDS_CNS_EFFECTS " ) ) ;
}
for ( C4Effect * pEffect = pEffects ; pEffect ; pEffect = pEffect - > pNext )
{
Output . Append ( LineFeed ) ;
// Effect name
2011-03-16 18:07:18 +00:00
Output . AppendFormat ( " %s: Priority %d, Interval %d " , pEffect - > GetName ( ) , pEffect - > iPriority , pEffect - > iInterval ) ;
2011-01-12 22:43:05 +00:00
}
StdStrBuf Output2 ;
2011-03-26 22:59:35 +00:00
C4ValueNumbers numbers ;
2011-03-27 22:15:06 +00:00
DecompileToBuf_Log < StdCompilerINIWrite > ( mkNamingAdapt ( mkInsertAdapt ( mkParAdapt ( * this , & numbers ) ,
mkNamingAdapt ( numbers , " Values " ) , false ) ,
" Object " ) , & Output2 , " C4Object::GetDataString " ) ;
2011-01-12 22:43:05 +00:00
Output . Append ( LineFeed ) ;
Output . Append ( Output2 ) ;
return Output ;
}
2009-04-03 19:06:29 +00:00
void C4Object : : SetName ( const char * NewName )
2010-03-28 18:58:01 +00:00
{
if ( ! NewName & & Info )
2009-04-03 19:06:29 +00:00
C4PropList : : SetName ( Info - > Name ) ;
2009-05-08 13:28:41 +00:00
else
2009-04-03 19:06:29 +00:00
C4PropList : : SetName ( NewName ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int32_t C4Object : : GetValue ( C4Object * pInBase , int32_t iForPlayer )
2010-03-28 18:58:01 +00:00
{
2014-05-30 23:03:23 +00:00
C4Value r = Call ( PSF_CalcValue , & C4AulParSet ( pInBase , iForPlayer ) ) ;
2009-05-08 13:28:41 +00:00
int32_t iValue ;
2011-10-14 23:59:15 +00:00
if ( r ! = C4VNull )
iValue = r . getInt ( ) ;
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get value of def
// Caution: Do not pass pInBase here, because the def base value is to be queried
// - and not the value if you had to buy the object in this particular base
2011-10-14 23:59:15 +00:00
iValue = Def - > GetValue ( NULL , iForPlayer ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Con percentage
2011-10-14 23:59:15 +00:00
iValue = iValue * Con / FullCon ;
// do any adjustments based on where the item is bought
2009-05-08 13:28:41 +00:00
if ( pInBase )
2010-03-28 18:58:01 +00:00
{
2014-05-30 23:03:23 +00:00
r = pInBase - > Call ( PSF_CalcSellValue , & C4AulParSet ( this , iValue ) ) ;
2011-10-14 23:59:15 +00:00
if ( r ! = C4VNull )
iValue = r . getInt ( ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
return iValue ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : Promote ( int32_t torank , bool exception , bool fForceRankName )
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
if ( ! Info ) return false ;
2009-05-08 13:28:41 +00:00
// get rank system
C4Def * pUseDef = C4Id2Def ( Info - > id ) ;
C4RankSystem * pRankSys ;
if ( pUseDef & & pUseDef - > pRankNames )
pRankSys = pUseDef - > pRankNames ;
else
2009-06-05 15:13:33 +00:00
pRankSys = & : : DefaultRanks ;
2009-05-08 13:28:41 +00:00
// always promote info
Info - > Promote ( torank , * pRankSys , fForceRankName ) ;
// silent update?
2009-08-15 18:50:32 +00:00
if ( ! pRankSys - > GetRankName ( torank , false ) ) return false ;
2009-05-08 13:28:41 +00:00
GameMsgObject ( FormatString ( LoadResStr ( " IDS_OBJ_PROMOTION " ) , GetName ( ) , Info - > sRankName . getData ( ) ) . getData ( ) , this ) ;
2009-10-13 00:36:11 +00:00
// call to object
Call ( PSF_Promotion ) ;
2015-12-13 21:14:55 +00:00
StartSoundEffect ( " UI::Trumpet " , 0 , 100 , this ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : ClearPointers ( C4Object * pObj )
2010-03-28 18:58:01 +00:00
{
2013-05-27 13:52:50 +00:00
// mesh attachments and animation nodes
if ( pMeshInstance ) pMeshInstance - > ClearPointers ( pObj ) ;
2009-05-08 13:28:41 +00:00
// effects
if ( pEffects ) pEffects - > ClearPointers ( pObj ) ;
2015-09-03 02:57:24 +00:00
// contents/contained: although normally not necessery because it's done in AssignRemoval and StatusDeactivate,
// it is also required during game destruction (because ClearPointers might do script callbacks)
// Perform silent exit to avoid additional callbacks
2015-09-03 18:04:56 +00:00
if ( Contained = = pObj )
2015-09-03 02:57:24 +00:00
{
Contained - > Contents . Remove ( this ) ;
Contained = NULL ;
}
2015-09-03 18:04:56 +00:00
Contents . Remove ( pObj ) ;
2009-05-08 13:28:41 +00:00
// Action targets
2010-03-27 16:05:02 +00:00
if ( Action . Target = = pObj ) Action . Target = NULL ;
if ( Action . Target2 = = pObj ) Action . Target2 = NULL ;
2009-05-08 13:28:41 +00:00
// Commands
C4Command * cCom ;
2010-03-27 16:05:02 +00:00
for ( cCom = Command ; cCom ; cCom = cCom - > Next )
2009-05-08 13:28:41 +00:00
cCom - > ClearPointers ( pObj ) ;
// Menu
if ( Menu ) Menu - > ClearPointers ( pObj ) ;
// Layer
2010-03-30 21:08:15 +00:00
if ( Layer = = pObj ) Layer = NULL ;
2009-05-08 13:28:41 +00:00
// gfx overlays
if ( pGfxOverlay )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4GraphicsOverlay * pNextGfxOvrl = pGfxOverlay , * pGfxOvrl ;
2010-01-25 04:00:59 +00:00
while ( ( pGfxOvrl = pNextGfxOvrl ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pNextGfxOvrl = pGfxOvrl - > GetNext ( ) ;
if ( pGfxOvrl - > GetOverlayObject ( ) = = pObj )
// overlay relying on deleted object: Delete!
RemoveGraphicsOverlay ( pGfxOvrl - > GetID ( ) ) ;
}
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : SetPhase ( int32_t iPhase )
2009-12-30 20:41:56 +00:00
{
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
if ( ! pActionDef ) return false ;
const int32_t length = pActionDef - > GetPropertyInt ( P_Length ) ;
2015-02-12 22:05:55 +00:00
Action . Phase = Clamp < int32_t > ( iPhase , 0 , length ) ;
2009-07-12 14:27:04 +00:00
Action . PhaseDelay = 0 ;
2009-08-15 18:50:32 +00:00
return true ;
2009-12-30 20:41:56 +00:00
}
2009-05-08 13:28:41 +00:00
2010-09-23 01:51:08 +00:00
void C4Object : : Draw ( C4TargetFacet & cgo , int32_t iByPlayer , DrawMode eDrawMode , float offX , float offY )
2010-03-28 18:58:01 +00:00
{
2013-10-18 16:46:46 +00:00
# ifndef USE_CONSOLE
2009-05-08 13:28:41 +00:00
C4Facet ccgo ;
2011-09-05 15:13:44 +00:00
2009-05-08 13:28:41 +00:00
// Status
if ( ! Status | | ! Def ) return ;
// visible?
2010-03-28 18:58:01 +00:00
if ( ! IsVisible ( iByPlayer , ! ! eDrawMode ) ) return ;
2009-05-08 13:28:41 +00:00
// Line
2015-08-28 01:44:23 +00:00
if ( Def - > Line ) { DrawLine ( cgo , iByPlayer ) ; return ; }
2009-05-08 13:28:41 +00:00
// background particles (bounds not checked)
2013-12-17 20:40:40 +00:00
if ( BackParticles ) BackParticles - > Draw ( cgo , this ) ;
2009-05-08 13:28:41 +00:00
// Object output position
2015-01-05 23:50:40 +00:00
float newzoom = cgo . Zoom ;
2010-09-23 01:51:08 +00:00
if ( eDrawMode ! = ODM_Overlay )
{
2010-09-24 17:51:34 +00:00
if ( ! GetDrawPosition ( cgo , offX , offY , newzoom ) ) return ;
2010-09-23 01:51:08 +00:00
}
2010-09-24 17:51:34 +00:00
ZoomDataStackItem zdsi ( newzoom ) ;
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool fYStretchObject = false ;
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
if ( pActionDef )
if ( pActionDef - > GetPropertyInt ( P_FacetTargetStretch ) )
2009-08-15 18:50:32 +00:00
fYStretchObject = true ;
2009-05-08 13:28:41 +00:00
// Set audibility
2015-08-28 01:44:23 +00:00
if ( ! eDrawMode ) SetAudibilityAt ( cgo , GetX ( ) , GetY ( ) , iByPlayer ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Output boundary
2012-10-30 21:18:27 +00:00
if ( ! fYStretchObject & & ! eDrawMode & & ! ( Category & C4D_Parallax ) )
2010-03-28 18:58:01 +00:00
{
2015-09-25 04:51:36 +00:00
// For actions with a custom facet set, check against that action facet. Otherwise (or with oversize objects), just check against shape.
if ( pActionDef & & fix_r = = Fix0 & & ! pActionDef - > GetPropertyInt ( P_FacetBase ) & & Con < = FullCon & & Action . Facet . Wdt )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// active
2010-09-24 00:35:26 +00:00
if ( ! Inside < float > ( offX + Shape . GetX ( ) + Action . FacetX , cgo . X - Action . Facet . Wdt , cgo . X + cgo . Wdt )
| | ( ! Inside < float > ( offY + Shape . GetY ( ) + Action . FacetY , cgo . Y - Action . Facet . Hgt , cgo . Y + cgo . Hgt ) ) )
2013-09-25 11:30:06 +00:00
{
2013-12-17 20:40:40 +00:00
if ( FrontParticles & & ! Contained ) FrontParticles - > Draw ( cgo , this ) ;
2013-09-25 11:30:06 +00:00
return ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
// idle
2010-09-24 00:35:26 +00:00
if ( ! Inside < float > ( offX + Shape . GetX ( ) , cgo . X - Shape . Wdt , cgo . X + cgo . Wdt )
| | ( ! Inside < float > ( offY + Shape . GetY ( ) , cgo . Y - Shape . Hgt , cgo . Y + cgo . Hgt ) ) )
2013-09-25 11:30:06 +00:00
{
2013-12-17 20:40:40 +00:00
if ( FrontParticles & & ! Contained ) FrontParticles - > Draw ( cgo , this ) ;
2013-09-25 11:30:06 +00:00
return ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ensure correct color is set
2009-07-10 23:10:18 +00:00
if ( GetGraphics ( ) - > Type = = C4DefGraphics : : TYPE_Bitmap )
2010-01-25 04:00:59 +00:00
if ( GetGraphics ( ) - > Bmp . BitmapClr ) GetGraphics ( ) - > Bmp . BitmapClr - > SetClr ( Color ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Debug Display //////////////////////////////////////////////////////////////////////
if ( : : GraphicsSystem . ShowCommand & & ! eDrawMode )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Command * pCom ;
int32_t ccx = GetX ( ) , ccy = GetY ( ) ;
2010-09-23 01:51:08 +00:00
float offX1 , offY1 , offX2 , offY2 , newzoom ;
2010-03-27 16:05:02 +00:00
char szCommand [ 200 ] ;
StdStrBuf Cmds ;
2009-05-08 13:28:41 +00:00
int32_t iMoveTos = 0 ;
2010-03-27 16:05:02 +00:00
for ( pCom = Command ; pCom ; pCom = pCom - > Next )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
switch ( pCom - > Command )
2010-03-28 18:58:01 +00:00
{
case C4CMD_MoveTo :
// Angle
int32_t iAngle ; iAngle = Angle ( ccx , ccy , pCom - > Tx . _getInt ( ) , pCom - > Ty ) ; while ( iAngle > 180 ) iAngle - = 360 ;
// Path
2010-09-24 17:51:34 +00:00
if ( GetDrawPosition ( cgo , ccx , ccy , cgo . Zoom , offX1 , offY1 , newzoom ) & &
GetDrawPosition ( cgo , pCom - > Tx . _getInt ( ) , pCom - > Ty , cgo . Zoom , offX2 , offY2 , newzoom ) )
2010-09-23 01:51:08 +00:00
{
2010-09-24 17:51:34 +00:00
ZoomDataStackItem zdsi ( newzoom ) ;
2011-10-03 14:30:18 +00:00
pDraw - > DrawLineDw ( cgo . Surface , offX1 , offY1 , offX2 , offY2 , C4RGB ( 0xca , 0 , 0 ) ) ;
pDraw - > DrawFrameDw ( cgo . Surface , offX2 - 1 , offY2 - 1 , offX2 + 1 , offY2 + 1 , C4RGB ( 0xca , 0 , 0 ) ) ;
2010-09-23 01:51:08 +00:00
}
2010-03-28 18:58:01 +00:00
ccx = pCom - > Tx . _getInt ( ) ; ccy = pCom - > Ty ;
// Message
iMoveTos + + ; szCommand [ 0 ] = 0 ;
break ;
case C4CMD_Put :
2013-03-03 18:25:18 +00:00
sprintf ( szCommand , " %s %s to %s " , CommandName ( pCom - > Command ) , pCom - > Target2 ? pCom - > Target2 - > GetName ( ) : pCom - > Data ? pCom - > Data . GetDataString ( ) . getData ( ) : " Content " , pCom - > Target ? pCom - > Target - > GetName ( ) : " " ) ;
2010-03-28 18:58:01 +00:00
break ;
case C4CMD_Buy : case C4CMD_Sell :
2013-03-03 18:25:18 +00:00
sprintf ( szCommand , " %s %s at %s " , CommandName ( pCom - > Command ) , pCom - > Data . GetDataString ( ) . getData ( ) , pCom - > Target ? pCom - > Target - > GetName ( ) : " closest base " ) ;
2010-03-28 18:58:01 +00:00
break ;
case C4CMD_Acquire :
2013-03-03 18:25:18 +00:00
sprintf ( szCommand , " %s %s " , CommandName ( pCom - > Command ) , pCom - > Data . GetDataString ( ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
break ;
case C4CMD_Call :
sprintf ( szCommand , " %s %s in %s " , CommandName ( pCom - > Command ) , pCom - > Text - > GetCStr ( ) , pCom - > Target ? pCom - > Target - > GetName ( ) : " (null) " ) ;
break ;
case C4CMD_None :
szCommand [ 0 ] = 0 ;
break ;
case C4CMD_Transfer :
// Path
2010-09-24 17:51:34 +00:00
if ( GetDrawPosition ( cgo , ccx , ccy , cgo . Zoom , offX1 , offY1 , newzoom ) & &
GetDrawPosition ( cgo , pCom - > Tx . _getInt ( ) , pCom - > Ty , cgo . Zoom , offX2 , offY2 , newzoom ) )
2010-09-23 01:51:08 +00:00
{
2010-09-24 17:51:34 +00:00
ZoomDataStackItem zdsi ( newzoom ) ;
2011-10-03 14:30:18 +00:00
pDraw - > DrawLineDw ( cgo . Surface , offX1 , offY1 , offX2 , offY2 , C4RGB ( 0 , 0xca , 0 ) ) ;
pDraw - > DrawFrameDw ( cgo . Surface , offX2 - 1 , offY2 - 1 , offX2 + 1 , offY2 + 1 , C4RGB ( 0 , 0xca , 0 ) ) ;
2010-09-23 01:51:08 +00:00
}
2010-03-28 18:58:01 +00:00
ccx = pCom - > Tx . _getInt ( ) ; ccy = pCom - > Ty ;
// Message
sprintf ( szCommand , " %s %s " , CommandName ( pCom - > Command ) , pCom - > Target ? pCom - > Target - > GetName ( ) : " " ) ;
break ;
default :
sprintf ( szCommand , " %s %s " , CommandName ( pCom - > Command ) , pCom - > Target ? pCom - > Target - > GetName ( ) : " " ) ;
break ;
}
2009-05-08 13:28:41 +00:00
// Compose command stack message
if ( szCommand [ 0 ] )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// End MoveTo stack first
if ( iMoveTos ) { Cmds . AppendChar ( ' | ' ) ; Cmds . AppendFormat ( " %dx MoveTo " , iMoveTos ) ; iMoveTos = 0 ; }
// Current message
Cmds . AppendChar ( ' | ' ) ;
if ( pCom - > Finished ) Cmds . Append ( " <i> " ) ;
2010-03-27 16:05:02 +00:00
Cmds . Append ( szCommand ) ;
2009-05-08 13:28:41 +00:00
if ( pCom - > Finished ) Cmds . Append ( " </i> " ) ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Open MoveTo stack
if ( iMoveTos ) { Cmds . AppendChar ( ' | ' ) ; Cmds . AppendFormat ( " %dx MoveTo " , iMoveTos ) ; iMoveTos = 0 ; }
// Draw message
2009-06-05 15:19:15 +00:00
int32_t cmwdt , cmhgt ; : : GraphicsResource . FontRegular . GetTextExtent ( Cmds . getData ( ) , cmwdt , cmhgt , true ) ;
2011-10-03 14:34:08 +00:00
pDraw - > TextOut ( Cmds . getData ( ) , : : GraphicsResource . FontRegular , 1.0 , cgo . Surface , offX , offY + Shape . GetY ( ) - 10 - cmhgt , C4Draw : : DEFAULT_MESSAGE_COLOR , ACenter ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Debug Display ///////////////////////////////////////////////////////////////////////////////
2009-05-08 13:28:41 +00:00
// Don't draw (show solidmask)
2015-07-15 00:44:11 +00:00
if ( : : GraphicsSystem . Show8BitSurface ! = 0 )
2009-05-08 13:28:41 +00:00
if ( SolidMask . Wdt )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// DrawSolidMask(cgo); - no need to draw it, because the 8bit-surface will be shown
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Contained check
if ( Contained & & ! eDrawMode ) return ;
// Visibility inside FoW
2014-11-07 16:53:10 +00:00
const C4FoWRegion * pOldFoW = pDraw - > GetFoW ( ) ;
if ( pOldFoW & & ( Category & C4D_IgnoreFoW ) )
pDraw - > SetFoW ( NULL ) ;
2009-05-08 13:28:41 +00:00
// color modulation (including construction sign...)
2009-08-23 21:46:56 +00:00
if ( ColorMod ! = 0xffffffff | | BlitMode ) if ( ! eDrawMode ) PrepareDrawing ( ) ;
2009-05-08 13:28:41 +00:00
// Not active or rotated: BaseFace only
2010-03-18 23:04:29 +00:00
if ( ! pActionDef )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
DrawFace ( cgo , offX , offY ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Active
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// FacetBase
2010-03-18 23:04:29 +00:00
if ( pActionDef - > GetPropertyInt ( P_FacetBase ) | | GetGraphics ( ) - > Type ! = C4DefGraphics : : TYPE_Bitmap )
2009-05-08 13:28:41 +00:00
DrawFace ( cgo , offX , offY , 0 , Action . DrawDir ) ;
// Special: stretched action facet
2010-03-18 23:04:29 +00:00
if ( Action . Facet . Surface & & pActionDef - > GetPropertyInt ( P_FacetTargetStretch ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Action . Target )
2011-10-03 14:30:18 +00:00
pDraw - > Blit ( Action . Facet . Surface ,
2010-03-28 18:58:01 +00:00
float ( Action . Facet . X ) , float ( Action . Facet . Y ) , float ( Action . Facet . Wdt ) , float ( Action . Facet . Hgt ) ,
cgo . Surface ,
offX + Shape . GetX ( ) + Action . FacetX , offY + Shape . GetY ( ) + Action . FacetY , Action . Facet . Wdt ,
( fixtof ( Action . Target - > fix_y ) + Action . Target - > Shape . GetY ( ) ) - ( fixtof ( fix_y ) + Shape . GetY ( ) + Action . FacetY ) ,
true ) ;
}
2010-03-09 19:14:47 +00:00
else if ( Action . Facet . Surface )
2009-05-08 13:28:41 +00:00
DrawActionFace ( cgo , offX , offY ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// end of color modulation
2009-08-23 21:46:56 +00:00
if ( ColorMod ! = 0xffffffff | | BlitMode ) if ( ! eDrawMode ) FinishedDrawing ( ) ;
2009-05-08 13:28:41 +00:00
// draw overlays - after blit mode changes, because overlay gfx set their own
if ( pGfxOverlay ) if ( eDrawMode ! = ODM_BaseOnly )
2010-03-28 18:58:01 +00:00
for ( C4GraphicsOverlay * pGfxOvrl = pGfxOverlay ; pGfxOvrl ; pGfxOvrl = pGfxOvrl - > GetNext ( ) )
if ( ! pGfxOvrl - > IsPicture ( ) )
pGfxOvrl - > Draw ( cgo , this , iByPlayer ) ;
2009-05-08 13:28:41 +00:00
// local particles in front of the object
2013-09-25 11:30:06 +00:00
if ( eDrawMode ! = ODM_BaseOnly )
{
2013-12-17 20:40:40 +00:00
if ( FrontParticles )
FrontParticles - > Draw ( cgo , this ) ;
2013-09-25 11:30:06 +00:00
}
2009-05-08 13:28:41 +00:00
// Debug Display ////////////////////////////////////////////////////////////////////////
2009-06-05 15:14:20 +00:00
if ( : : GraphicsSystem . ShowVertices ) if ( eDrawMode ! = ODM_BaseOnly )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
int32_t cnt ;
if ( Shape . VtxNum > 1 )
for ( cnt = 0 ; cnt < Shape . VtxNum ; cnt + + )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
DrawVertex ( cgo ,
2010-09-24 00:35:26 +00:00
offX + Shape . VtxX [ cnt ] ,
offY + Shape . VtxY [ cnt ] ,
2010-06-28 23:02:16 +00:00
( Shape . VtxCNAT [ cnt ] & CNAT_NoCollision ) ? C4RGB ( 0 , 0 , 0xff ) : ( Mobile ? C4RGB ( 0xff , 0 , 0 ) : C4RGB ( 0xef , 0xef , 0 ) ) ,
2010-03-28 18:58:01 +00:00
Shape . VtxContactCNAT [ cnt ] ) ;
2009-05-08 13:28:41 +00:00
}
}
2009-06-05 15:14:20 +00:00
if ( : : GraphicsSystem . ShowEntrance ) if ( eDrawMode ! = ODM_BaseOnly )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
if ( OCF & OCF_Entrance )
2011-10-03 14:30:18 +00:00
pDraw - > DrawFrameDw ( cgo . Surface , offX + Def - > Entrance . x ,
2010-09-24 00:35:26 +00:00
offY + Def - > Entrance . y ,
offX + Def - > Entrance . x + Def - > Entrance . Wdt - 1 ,
offY + Def - > Entrance . y + Def - > Entrance . Hgt - 1 ,
2010-06-28 23:02:16 +00:00
C4RGB ( 0 , 0 , 0xff ) ) ;
2010-03-28 18:58:01 +00:00
if ( OCF & OCF_Collection )
2011-10-03 14:30:18 +00:00
pDraw - > DrawFrameDw ( cgo . Surface , offX + Def - > Collection . x ,
2010-09-24 00:35:26 +00:00
offY + Def - > Collection . y ,
offX + Def - > Collection . x + Def - > Collection . Wdt - 1 ,
offY + Def - > Collection . y + Def - > Collection . Hgt - 1 ,
2010-06-28 23:02:16 +00:00
C4RGB ( 0xca , 0 , 0 ) ) ;
2009-05-08 13:28:41 +00:00
}
2009-06-05 15:14:20 +00:00
if ( : : GraphicsSystem . ShowAction ) if ( eDrawMode ! = ODM_BaseOnly )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
if ( pActionDef )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
StdStrBuf str ;
str . Format ( " %s (%d) " , pActionDef - > GetName ( ) , Action . Phase ) ;
int32_t cmwdt , cmhgt ; : : GraphicsResource . FontRegular . GetTextExtent ( str . getData ( ) , cmwdt , cmhgt , true ) ;
2011-10-03 14:30:18 +00:00
pDraw - > TextOut ( str . getData ( ) , : : GraphicsResource . FontRegular ,
2010-09-24 00:35:26 +00:00
1.0 , cgo . Surface , offX , offY + Shape . GetY ( ) - cmhgt ,
2011-10-03 14:34:08 +00:00
InLiquid ? 0xfa0000FF : C4Draw : : DEFAULT_MESSAGE_COLOR , ACenter ) ;
2009-05-08 13:28:41 +00:00
}
}
2010-03-27 16:05:02 +00:00
// Debug Display ///////////////////////////////////////////////////////////////////////
2009-05-08 13:28:41 +00:00
// Restore visibility inside FoW
2014-11-07 16:53:10 +00:00
if ( pOldFoW ) pDraw - > SetFoW ( pOldFoW ) ;
2013-10-18 16:46:46 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-09-23 01:51:08 +00:00
void C4Object : : DrawTopFace ( C4TargetFacet & cgo , int32_t iByPlayer , DrawMode eDrawMode , float offX , float offY )
2010-03-28 18:58:01 +00:00
{
2013-10-18 16:46:46 +00:00
# ifndef USE_CONSOLE
2009-05-08 13:28:41 +00:00
// Status
2010-03-27 16:05:02 +00:00
if ( ! Status | | ! Def ) return ;
2009-05-08 13:28:41 +00:00
// visible?
2010-03-28 18:58:01 +00:00
if ( ! IsVisible ( iByPlayer , eDrawMode = = ODM_Overlay ) ) return ;
2009-05-08 13:28:41 +00:00
// target pos (parallax)
2015-01-05 23:50:40 +00:00
float newzoom = cgo . Zoom ;
2010-09-24 17:51:34 +00:00
if ( eDrawMode ! = ODM_Overlay ) GetDrawPosition ( cgo , offX , offY , newzoom ) ;
ZoomDataStackItem zdsi ( newzoom ) ;
2009-05-08 13:28:41 +00:00
// TopFace
if ( ! ( TopFace . Surface | | ( OCF & OCF_Construct ) ) ) return ;
// Output bounds check
2010-09-23 01:51:08 +00:00
if ( ! Inside < float > ( offX , cgo . X - Shape . Wdt , cgo . X + cgo . Wdt )
| | ! Inside < float > ( offY , cgo . Y - Shape . Hgt , cgo . Y + cgo . Hgt ) )
2010-03-28 18:58:01 +00:00
return ;
2009-05-08 13:28:41 +00:00
// Don't draw (show solidmask)
2015-07-15 00:44:11 +00:00
if ( : : GraphicsSystem . Show8BitSurface ! = 0 & & SolidMask . Wdt ) return ;
2009-05-08 13:28:41 +00:00
// Contained
if ( Contained ) if ( eDrawMode ! = ODM_Overlay ) return ;
// Construction sign
2013-05-25 12:59:58 +00:00
if ( OCF & OCF_Construct & & fix_r = = Fix0 )
2010-09-23 01:51:08 +00:00
if ( eDrawMode ! = ODM_BaseOnly )
{
C4Facet & fctConSign = : : GraphicsResource . fctConstruction ;
2011-10-03 14:30:18 +00:00
pDraw - > Blit ( fctConSign . Surface ,
2010-09-23 01:51:08 +00:00
fctConSign . X , fctConSign . Y ,
fctConSign . Wdt , fctConSign . Hgt ,
cgo . Surface ,
offX + Shape . GetX ( ) , offY + Shape . GetY ( ) + Shape . Hgt - fctConSign . Hgt ,
fctConSign . Wdt , fctConSign . Hgt , true ) ;
}
2012-02-26 00:01:55 +00:00
if ( TopFace . Surface )
2010-03-28 18:58:01 +00:00
{
2012-02-26 00:01:55 +00:00
// FacetTopFace: Override TopFace.GetX()/GetY()
C4PropList * pActionDef = GetAction ( ) ;
if ( pActionDef & & pActionDef - > GetPropertyInt ( P_FacetTopFace ) )
{
int32_t iPhase = Action . Phase ;
if ( pActionDef - > GetPropertyInt ( P_Reverse ) ) iPhase = pActionDef - > GetPropertyInt ( P_Length ) - 1 - Action . Phase ;
TopFace . X = pActionDef - > GetPropertyInt ( P_X ) + Def - > TopFace . x + pActionDef - > GetPropertyInt ( P_Wdt ) * iPhase ;
TopFace . Y = pActionDef - > GetPropertyInt ( P_Y ) + Def - > TopFace . y + pActionDef - > GetPropertyInt ( P_Hgt ) * Action . DrawDir ;
}
// ensure correct color is set
if ( GetGraphics ( ) - > Bmp . BitmapClr ) GetGraphics ( ) - > Bmp . BitmapClr - > SetClr ( Color ) ;
// color modulation
if ( ! eDrawMode ) PrepareDrawing ( ) ;
// Draw top face bitmap
if ( Con ! = FullCon & & Def - > GrowthType )
// stretched
pDraw - > Blit ( TopFace . Surface ,
TopFace . X , TopFace . Y , TopFace . Wdt , TopFace . Hgt ,
cgo . Surface ,
offX + Shape . GetX ( ) + float ( Def - > TopFace . tx * Con ) / FullCon , offY + Shape . GetY ( ) + float ( Def - > TopFace . ty * Con ) / FullCon ,
float ( TopFace . Wdt * Con ) / FullCon , float ( TopFace . Hgt * Con ) / FullCon ,
true , pDrawTransform ? & C4DrawTransform ( * pDrawTransform , offX , offY ) : NULL ) ;
else
// normal
pDraw - > Blit ( TopFace . Surface ,
TopFace . X , TopFace . Y ,
TopFace . Wdt , TopFace . Hgt ,
cgo . Surface ,
offX + Shape . GetX ( ) + Def - > TopFace . tx , offY + Shape . GetY ( ) + Def - > TopFace . ty ,
TopFace . Wdt , TopFace . Hgt ,
true , pDrawTransform ? & C4DrawTransform ( * pDrawTransform , offX , offY ) : NULL ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// end of color modulation
if ( ! eDrawMode ) FinishedDrawing ( ) ;
2013-10-18 16:46:46 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-08-28 01:44:23 +00:00
void C4Object : : DrawLine ( C4TargetFacet & cgo , int32_t at_player )
2010-03-28 18:58:01 +00:00
{
2015-02-15 13:23:18 +00:00
// Nothing to draw if the object has less than two vertices
if ( Shape . VtxNum < 2 )
return ;
2013-10-18 16:46:46 +00:00
# ifndef USE_CONSOLE
2009-05-08 13:28:41 +00:00
// Audibility
2015-08-28 01:44:23 +00:00
SetAudibilityAt ( cgo , Shape . VtxX [ 0 ] , Shape . VtxY [ 0 ] , at_player ) ;
SetAudibilityAt ( cgo , Shape . VtxX [ Shape . VtxNum - 1 ] , Shape . VtxY [ Shape . VtxNum - 1 ] , at_player ) ;
2009-05-08 13:28:41 +00:00
// additive mode?
PrepareDrawing ( ) ;
// Draw line segments
2010-12-06 15:19:15 +00:00
C4Value colorsV ; GetProperty ( P_LineColors , & colorsV ) ;
2009-07-22 16:24:07 +00:00
C4ValueArray * colors = colorsV . getArray ( ) ;
2015-01-25 15:43:51 +00:00
// TODO: Edge color (color1) is currently ignored.
2015-02-08 11:37:00 +00:00
int32_t color0 = 0xFFFF00FF ; // , color1 = 0xFFFF00FF; // use bright colors so author notices
2009-07-22 16:24:07 +00:00
if ( colors )
2010-03-28 18:58:01 +00:00
{
2010-12-21 18:22:06 +00:00
color0 = colors - > GetItem ( 0 ) . getInt ( ) ;
2010-03-28 18:58:01 +00:00
}
2014-10-18 17:35:20 +00:00
std : : vector < C4BltVertex > vertices ;
vertices . resize ( ( Shape . VtxNum - 1 ) * 2 ) ;
2010-03-27 16:05:02 +00:00
for ( int32_t vtx = 0 ; vtx + 1 < Shape . VtxNum ; vtx + + )
2014-10-18 17:35:20 +00:00
{
DwTo4UB ( color0 , vertices [ 2 * vtx ] . color ) ;
DwTo4UB ( color0 , vertices [ 2 * vtx + 1 ] . color ) ;
vertices [ 2 * vtx ] . ftx = Shape . VtxX [ vtx ] + cgo . X - cgo . TargetX ;
vertices [ 2 * vtx ] . fty = Shape . VtxY [ vtx ] + cgo . Y - cgo . TargetY ;
vertices [ 2 * vtx + 1 ] . ftx = Shape . VtxX [ vtx + 1 ] + cgo . X - cgo . TargetX ;
vertices [ 2 * vtx + 1 ] . fty = Shape . VtxY [ vtx + 1 ] + cgo . Y - cgo . TargetY ;
}
2015-09-12 22:14:18 +00:00
pDraw - > PerformMultiLines ( cgo . Surface , & vertices [ 0 ] , vertices . size ( ) , 1.0f , NULL ) ;
2014-10-18 17:35:20 +00:00
2009-05-08 13:28:41 +00:00
// reset blit mode
FinishedDrawing ( ) ;
2013-10-18 16:46:46 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-03-26 22:59:35 +00:00
void C4Object : : CompileFunc ( StdCompiler * pComp , C4ValueNumbers * numbers )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
bool fCompiler = pComp - > isCompiler ( ) ;
2010-03-28 18:58:01 +00:00
if ( fCompiler )
2010-03-27 16:05:02 +00:00
Clear ( ) ;
2009-05-08 13:28:41 +00:00
// Compile ID, search definition
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( id , " id " , C4ID : : None ) ) ;
if ( fCompiler )
{
2009-06-05 16:46:37 +00:00
Def = : : Definitions . ID2Def ( id ) ;
2010-03-28 18:58:01 +00:00
if ( ! Def )
2010-01-25 15:57:57 +00:00
{ pComp - > excNotFound ( LoadResStr ( " IDS_PRC_UNDEFINEDOBJECT " ) , id . ToString ( ) ) ; return ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( static_cast < C4PropListNumbered & > ( * this ) , numbers ) , " Properties " ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( Status , " Status " , 1 ) ) ;
2011-03-27 22:15:06 +00:00
if ( Info ) nInfo = Info - > Name ; else nInfo . Clear ( ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( toC4CStrBuf ( nInfo ) , " Info " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( Owner , " Owner " , NO_OWNER ) ) ;
pComp - > Value ( mkNamingAdapt ( Controller , " Controller " , NO_OWNER ) ) ;
pComp - > Value ( mkNamingAdapt ( LastEnergyLossCausePlayer , " LastEngLossPlr " , NO_OWNER ) ) ;
pComp - > Value ( mkNamingAdapt ( Category , " Category " , 0 ) ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkNamingAdapt ( Plane , " Plane " , 0 ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( iLastAttachMovementFrame , " LastSolidAtchFrame " , - 1 ) ) ;
pComp - > Value ( mkNamingAdapt ( Con , " Size " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( OwnMass , " OwnMass " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Mass , " Mass " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Damage , " Damage " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Energy , " Energy " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Alive , " Alive " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( Breath , " Breath " , 0 ) ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkNamingAdapt ( Color , " Color " , 0u ) ) ;
pComp - > Value ( mkNamingAdapt ( fix_x , " X " , Fix0 ) ) ;
pComp - > Value ( mkNamingAdapt ( fix_y , " Y " , Fix0 ) ) ;
pComp - > Value ( mkNamingAdapt ( fix_r , " R " , Fix0 ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( xdir , " XDir " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ydir , " YDir " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( rdir , " RDir " , 0 ) ) ;
2013-03-30 14:59:15 +00:00
pComp - > Value ( mkParAdapt ( Shape , & Def - > Shape ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( fOwnVertices , " OwnVertices " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( SolidMask , " SolidMask " , Def - > SolidMask ) ) ;
pComp - > Value ( mkNamingAdapt ( PictureRect , " Picture " ) ) ;
pComp - > Value ( mkNamingAdapt ( Mobile , " Mobile " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( OnFire , " OnFire " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( InLiquid , " InLiquid " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( EntranceStatus , " EntranceStatus " , false ) ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkNamingAdapt ( OCF , " OCF " , 0u ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( Action ) ;
2010-03-30 21:08:15 +00:00
pComp - > Value ( mkNamingAdapt ( Contained , " Contained " , C4ObjectPtr : : Null ) ) ;
pComp - > Value ( mkNamingAdapt ( Action . Target , " ActionTarget1 " , C4ObjectPtr : : Null ) ) ;
pComp - > Value ( mkNamingAdapt ( Action . Target2 , " ActionTarget2 " , C4ObjectPtr : : Null ) ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( Contents , numbers ) , " Contents " ) ) ;
2015-01-02 00:06:00 +00:00
pComp - > Value ( mkNamingAdapt ( lightRange , " LightRange " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( lightFadeoutRange , " LightFadeoutRange " , 0 ) ) ;
2015-07-19 07:01:38 +00:00
pComp - > Value ( mkNamingAdapt ( lightColor , " lightColor " , 0xffffffffu ) ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkNamingAdapt ( ColorMod , " ColorMod " , 0xffffffffu ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( BlitMode , " BlitMode " , 0u ) ) ;
pComp - > Value ( mkNamingAdapt ( CrewDisabled , " CrewDisabled " , false ) ) ;
2010-03-30 21:08:15 +00:00
pComp - > Value ( mkNamingAdapt ( Layer , " Layer " , C4ObjectPtr : : Null ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( C4DefGraphicsAdapt ( pGraphics ) , " Graphics " , & Def - > Graphics ) ) ;
pComp - > Value ( mkNamingPtrAdapt ( pDrawTransform , " DrawTransform " ) ) ;
2016-05-04 01:44:59 +00:00
pComp - > Value ( mkParAdapt ( mkNamingPtrAdapt ( pEffects , " Effects " ) , this , numbers ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( C4GraphicsOverlayListAdapt ( pGfxOverlay ) , " GfxOverlay " , ( C4GraphicsOverlay * ) NULL ) ) ;
2010-04-01 21:00:05 +00:00
// Serialize mesh instance if we have a mesh graphics
if ( pGraphics - > Type = = C4DefGraphics : : TYPE_Mesh )
{
if ( pComp - > isCompiler ( ) )
{
assert ( ! pMeshInstance ) ;
2012-02-26 00:09:42 +00:00
pMeshInstance = new StdMeshInstance ( * pGraphics - > Mesh , Def - > GrowthType ? 1.0f : static_cast < float > ( Con ) / static_cast < float > ( FullCon ) ) ;
2010-04-01 21:00:05 +00:00
}
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( * pMeshInstance , C4MeshDenumeratorFactory ) , " Mesh " ) ) ;
// Does not work because unanimated meshes without attached meshes
// do not even write a [Mesh] header so this does not create a mesh instance in that case
/* pComp->Value(mkNamingContextPtrAdapt( pMeshInstance, *pGraphics->Mesh, "Mesh"));
if ( ! pMeshInstance )
pComp - > excCorrupt ( " Mesh graphics without mesh instance " ) ; */
}
2010-01-22 18:27:02 +00:00
// TODO: Animations / attached meshes
2009-05-08 13:28:41 +00:00
2010-01-22 18:27:02 +00:00
// Commands
2010-03-28 18:58:01 +00:00
if ( pComp - > FollowName ( " Commands " ) )
{
if ( fCompiler )
2010-01-25 04:00:59 +00:00
{
2009-05-08 13:28:41 +00:00
C4Command * pCmd = NULL ;
2010-03-28 18:58:01 +00:00
for ( int i = 1 ; ; i + + )
{
2009-05-08 13:28:41 +00:00
// Every command has its own naming environment
StdStrBuf Naming = FormatString ( " Command%d " , i ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkParAdapt ( mkNamingPtrAdapt ( pCmd ? pCmd - > Next : Command , Naming . getData ( ) ) , numbers ) ) ;
2009-05-08 13:28:41 +00:00
// Last command?
pCmd = ( pCmd ? pCmd - > Next : Command ) ;
2010-03-28 18:58:01 +00:00
if ( ! pCmd )
2009-05-08 13:28:41 +00:00
break ;
pCmd - > cObj = this ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Command * pCmd = Command ;
2010-03-28 18:58:01 +00:00
for ( int i = 1 ; pCmd ; i + + , pCmd = pCmd - > Next )
{
2009-05-08 13:28:41 +00:00
StdStrBuf Naming = FormatString ( " Command%d " , i ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( * pCmd , numbers ) , Naming . getData ( ) ) ) ;
2009-05-08 13:28:41 +00:00
}
2010-01-25 04:00:59 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-01-22 18:27:02 +00:00
// Compiling? Do initialization.
2010-03-28 18:58:01 +00:00
if ( fCompiler )
{
2010-01-22 18:27:02 +00:00
// add to def count
Def - > Count + + ;
// Set action (override running data)
2010-03-28 18:58:01 +00:00
/* FIXME
2010-01-22 18:27:02 +00:00
int32_t iTime = Action . Time ;
int32_t iPhase = Action . Phase ;
int32_t iPhaseDelay = Action . PhaseDelay ;
2010-03-28 18:58:01 +00:00
if ( SetActionByName ( Action . pActionDef - > GetName ( ) , 0 , 0 , false ) )
{
Action . Time = iTime ;
Action . Phase = iPhase ; // No checking for valid phase
Action . PhaseDelay = iPhaseDelay ;
} */
2010-01-22 18:27:02 +00:00
2010-03-28 18:58:01 +00:00
if ( pMeshInstance )
2010-04-01 21:00:05 +00:00
{
2011-03-12 17:38:47 +00:00
// Set Action animation by slot 0
2010-01-22 18:27:02 +00:00
Action . Animation = pMeshInstance - > GetRootAnimationForSlot ( 0 ) ;
2010-06-08 22:55:34 +00:00
pMeshInstance - > SetFaceOrderingForClrModulation ( ColorMod ) ;
2010-04-01 21:00:05 +00:00
}
2010-01-22 18:27:02 +00:00
// blit mode not assigned? use definition default then
if ( ! BlitMode ) BlitMode = Def - > BlitMode ;
// object needs to be resorted? May happen if there's unsorted objects in savegame
if ( Unsorted ) Game . fResortAnyObject = true ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2011-03-26 22:59:35 +00:00
void C4Object : : Denumerate ( C4ValueNumbers * numbers )
2010-03-28 18:58:01 +00:00
{
2011-03-26 22:59:35 +00:00
C4PropList : : Denumerate ( numbers ) ;
2009-05-08 13:28:41 +00:00
// Standard enumerated pointers
2010-03-30 21:08:15 +00:00
Contained . DenumeratePointers ( ) ;
Action . Target . DenumeratePointers ( ) ;
Action . Target2 . DenumeratePointers ( ) ;
Layer . DenumeratePointers ( ) ;
2009-05-08 13:28:41 +00:00
// Post-compile object list
2011-09-19 19:02:28 +00:00
Contents . DenumeratePointers ( ) ;
2009-05-08 13:28:41 +00:00
// Commands
for ( C4Command * pCom = Command ; pCom ; pCom = pCom - > Next )
2011-03-26 22:59:35 +00:00
pCom - > Denumerate ( numbers ) ;
2009-05-08 13:28:41 +00:00
// effects
2011-03-26 22:59:35 +00:00
if ( pEffects ) pEffects - > Denumerate ( numbers ) ;
2009-05-08 13:28:41 +00:00
// gfx overlays
if ( pGfxOverlay )
for ( C4GraphicsOverlay * pGfxOvrl = pGfxOverlay ; pGfxOvrl ; pGfxOvrl = pGfxOvrl - > GetNext ( ) )
pGfxOvrl - > DenumeratePointers ( ) ;
2010-04-01 21:00:05 +00:00
// mesh instance
if ( pMeshInstance ) pMeshInstance - > DenumeratePointers ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-11-16 16:29:42 +00:00
void C4Object : : DrawPicture ( C4Facet & cgo , bool fSelected , C4DrawTransform * transform )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Draw def picture with object color
2010-06-28 20:34:34 +00:00
Def - > Draw ( cgo , fSelected , Color , this , 0 , 0 , transform ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : Picture2Facet ( C4FacetSurface & cgo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// set picture rect to facet
C4Rect fctPicRect = PictureRect ;
if ( ! fctPicRect . Wdt ) fctPicRect = Def - > PictureRect ;
C4Facet fctPicture ;
fctPicture . Set ( GetGraphics ( ) - > GetBitmap ( Color ) , fctPicRect . x , fctPicRect . y , fctPicRect . Wdt , fctPicRect . Hgt ) ;
// use direct facet w/o own data if possible
2009-08-23 21:46:56 +00:00
if ( ColorMod = = 0xffffffff & & BlitMode = = C4GFXBLIT_NORMAL & & ! pGfxOverlay )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
cgo . Set ( fctPicture ) ;
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// otherwise, draw to picture facet
if ( ! cgo . Create ( cgo . Wdt , cgo . Hgt ) ) return ;
// specific object color?
PrepareDrawing ( ) ;
// draw picture itself
2009-08-15 18:50:32 +00:00
fctPicture . Draw ( cgo , true ) ;
2009-05-08 13:28:41 +00:00
// draw overlays
if ( pGfxOverlay )
for ( C4GraphicsOverlay * pGfxOvrl = pGfxOverlay ; pGfxOvrl ; pGfxOvrl = pGfxOvrl - > GetNext ( ) )
if ( pGfxOvrl - > IsPicture ( ) )
2010-06-28 22:12:52 +00:00
pGfxOvrl - > DrawPicture ( cgo , this , NULL ) ;
2009-05-08 13:28:41 +00:00
// done; reset drawing states
FinishedDrawing ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : ValidateOwner ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check owner and controller
if ( ! ValidPlr ( Owner ) ) Owner = NO_OWNER ;
if ( ! ValidPlr ( Controller ) ) Controller = NO_OWNER ;
// Color is not reset any more, because many scripts change colors to non-owner-colors these days
// Additionally, player colors are now guarantueed to remain the same in savegame resumes
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : AssignInfo ( )
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
if ( Info | | ! ValidPlr ( Owner ) ) return false ;
2009-05-08 13:28:41 +00:00
// In crew list?
2009-06-12 23:09:32 +00:00
C4Player * pPlr = : : Players . Get ( Owner ) ;
2009-05-08 13:28:41 +00:00
if ( pPlr - > Crew . GetLink ( this ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Register with player
2010-03-28 18:58:01 +00:00
if ( ! : : Players . Get ( Owner ) - > MakeCrewMember ( this , true , false ) )
2009-05-08 13:28:41 +00:00
pPlr - > Crew . Remove ( this ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Info set, but not in crew list, so
// a) The savegame is old-style (without crew list)
// or b) The clonk is dead
// or c) The clonk belongs to a script player that's restored without Game.txt
else if ( nInfo . getLength ( ) )
2010-03-28 18:58:01 +00:00
{
if ( ! : : Players . Get ( Owner ) - > MakeCrewMember ( this , true , false ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Dead and gone (info flags, remove from crew/cursor)
if ( ! Alive )
2010-03-28 18:58:01 +00:00
{
2009-06-12 23:09:32 +00:00
if ( ValidPlr ( Owner ) ) : : Players . Get ( Owner ) - > ClearPointers ( this , true ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return false ;
}
2009-05-08 13:28:41 +00:00
2015-01-02 00:06:00 +00:00
bool C4Object : : AssignLightRange ( )
2010-03-28 18:58:01 +00:00
{
2015-01-02 00:06:00 +00:00
if ( ! lightRange & & ! lightFadeoutRange ) return true ;
UpdateLight ( ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : ClearInfo ( C4ObjectInfo * pInfo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Info = = pInfo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Info = NULL ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2013-12-22 17:51:05 +00:00
ClearParticleLists ( ) ;
2013-09-21 15:22:46 +00:00
2009-05-08 13:28:41 +00:00
if ( pEffects ) { delete pEffects ; pEffects = NULL ; }
2009-07-10 23:10:18 +00:00
if ( pSolidMaskData ) { delete pSolidMaskData ; pSolidMaskData = NULL ; }
2009-05-08 13:28:41 +00:00
if ( Menu ) delete Menu ; Menu = NULL ;
if ( MaterialContents ) delete MaterialContents ; MaterialContents = NULL ;
// clear commands!
C4Command * pCom , * pNext ;
for ( pCom = Command ; pCom ; pCom = pNext )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pNext = pCom - > Next ; delete pCom ; pCom = pNext ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( pDrawTransform ) { delete pDrawTransform ; pDrawTransform = NULL ; }
if ( pGfxOverlay ) { delete pGfxOverlay ; pGfxOverlay = NULL ; }
2009-07-10 23:10:18 +00:00
if ( pMeshInstance ) { delete pMeshInstance ; pMeshInstance = NULL ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : MenuCommand ( const char * szCommand )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Native script execution
2009-08-15 18:50:32 +00:00
if ( ! Def | | ! Status ) return false ;
2015-02-01 21:20:52 +00:00
return ! ! : : AulExec . DirectExec ( this , szCommand , " MenuCommand " ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : SetSolidMask ( int32_t iX , int32_t iY , int32_t iWdt , int32_t iHgt , int32_t iTX , int32_t iTY )
2010-03-28 18:58:01 +00:00
{
2014-01-08 00:55:33 +00:00
// remove old
2010-04-20 20:38:18 +00:00
if ( pSolidMaskData ) { delete pSolidMaskData ; pSolidMaskData = NULL ; }
2009-05-08 13:28:41 +00:00
// set new data
SolidMask . Set ( iX , iY , iWdt , iHgt , iTX , iTY ) ;
// re-put if valid
if ( CheckSolidMaskRect ( ) ) UpdateSolidMask ( false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-08-30 13:19:36 +00:00
void C4Object : : SetHalfVehicleSolidMask ( bool set )
{
if ( ! pSolidMaskData ) return ;
pSolidMaskData - > SetHalfVehicle ( set ) ;
}
2009-05-08 13:28:41 +00:00
bool C4Object : : CheckSolidMaskRect ( )
2010-03-28 18:58:01 +00:00
{
2014-01-08 00:55:33 +00:00
// Ensure SolidMask rect lies within bounds of SolidMask bitmap in definition
CSurface8 * sfcGraphics = Def - > pSolidMask ;
if ( ! sfcGraphics )
{
// no graphics to set solid in
SolidMask . Set ( 0 , 0 , 0 , 0 , 0 , 0 ) ;
return false ;
}
2015-11-15 12:53:01 +00:00
SolidMask . Set ( std : : max < int32_t > ( SolidMask . x , 0 ) , std : : max < int32_t > ( SolidMask . y , 0 ) ,
std : : min < int32_t > ( SolidMask . Wdt , sfcGraphics - > Wdt - SolidMask . x ) , std : : min < int32_t > ( SolidMask . Hgt , sfcGraphics - > Hgt - SolidMask . y ) ,
2009-05-08 13:28:41 +00:00
SolidMask . tx , SolidMask . ty ) ;
if ( SolidMask . Hgt < = 0 ) SolidMask . Wdt = 0 ;
return SolidMask . Wdt > 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : SyncClearance ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Misc. no-save safeties
Action . t_attach = CNAT_None ;
InMat = MNone ;
t_contact = 0 ;
// Update OCF
SetOCF ( ) ;
// Menu
CloseMenu ( true ) ;
// Material contents
if ( MaterialContents ) delete MaterialContents ; MaterialContents = NULL ;
// reset speed of staticback-objects
if ( Category & C4D_StaticBack )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
xdir = ydir = 0 ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
void C4Object : : DrawSelectMark ( C4TargetFacet & cgo ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Status
if ( ! Status ) return ;
// No select marks in film playback
if ( Game . C4S . Head . Film & & Game . C4S . Head . Replay ) return ;
// target pos (parallax)
2010-09-23 01:51:08 +00:00
float offX , offY , newzoom ;
2010-09-24 17:51:34 +00:00
GetDrawPosition ( cgo , offX , offY , newzoom ) ;
2009-05-08 13:28:41 +00:00
// Output boundary
2010-09-23 01:51:08 +00:00
if ( ! Inside < float > ( offX , cgo . X , cgo . X + cgo . Wdt )
| | ! Inside < float > ( offY , cgo . Y , cgo . Y + cgo . Hgt ) ) return ;
2009-05-08 13:28:41 +00:00
// Draw select marks
2011-08-18 17:46:51 +00:00
float cox = offX + Shape . GetX ( ) - cgo . X + cgo . X - 2 ;
float coy = offY + Shape . GetY ( ) - cgo . Y + cgo . Y - 2 ;
2009-05-08 13:28:41 +00:00
GfxR - > fctSelectMark . Draw ( cgo . Surface , cox , coy , 0 ) ;
2011-08-18 17:46:51 +00:00
GfxR - > fctSelectMark . Draw ( cgo . Surface , cox + Shape . Wdt , coy , 1 ) ;
GfxR - > fctSelectMark . Draw ( cgo . Surface , cox , coy + Shape . Hgt , 2 ) ;
GfxR - > fctSelectMark . Draw ( cgo . Surface , cox + Shape . Wdt , coy + Shape . Hgt , 3 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : ClearCommands ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Command * pNext ;
while ( Command )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pNext = Command - > Next ;
2010-03-28 18:58:01 +00:00
if ( ! Command - > iExec )
2009-05-08 13:28:41 +00:00
delete Command ;
else
Command - > iExec = 2 ;
2010-03-27 16:05:02 +00:00
Command = pNext ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : ClearCommand ( C4Command * pUntil )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Command * pCom , * pNext ;
for ( pCom = Command ; pCom ; pCom = pNext )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Last one to clear
2010-03-27 16:05:02 +00:00
if ( pCom = = pUntil ) pNext = NULL ;
2009-05-08 13:28:41 +00:00
// Next one to clear after this
2010-03-27 16:05:02 +00:00
else pNext = pCom - > Next ;
Command = pCom - > Next ;
2010-03-28 18:58:01 +00:00
if ( ! pCom - > iExec )
2009-05-08 13:28:41 +00:00
delete pCom ;
else
pCom - > iExec = 2 ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : AddCommand ( int32_t iCommand , C4Object * pTarget , C4Value iTx , int32_t iTy ,
2010-03-28 18:58:01 +00:00
int32_t iUpdateInterval , C4Object * pTarget2 ,
bool fInitEvaluation , C4Value iData , bool fAppend ,
int32_t iRetries , C4String * szText , int32_t iBaseMode )
{
2009-05-08 13:28:41 +00:00
// Command stack size safety
const int32_t MaxCommandStack = 35 ;
C4Command * pCom , * pLast ; int32_t iCommands ;
for ( pCom = Command , iCommands = 0 ; pCom ; pCom = pCom - > Next , iCommands + + ) { }
if ( iCommands > = MaxCommandStack ) return false ;
// Valid command safety
if ( ! Inside ( iCommand , C4CMD_First , C4CMD_Last ) ) return false ;
// Allocate and set new command
2010-03-27 16:05:02 +00:00
if ( ! ( pCom = new C4Command ) ) return false ;
2009-05-08 13:28:41 +00:00
pCom - > Set ( iCommand , this , pTarget , iTx , iTy , pTarget2 , iData ,
2010-03-28 18:58:01 +00:00
iUpdateInterval , ! fInitEvaluation , iRetries , szText , iBaseMode ) ;
2009-05-08 13:28:41 +00:00
// Append to bottom of stack
if ( fAppend )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
for ( pLast = Command ; pLast & & pLast - > Next ; pLast = pLast - > Next ) { }
if ( pLast ) pLast - > Next = pCom ;
else Command = pCom ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Add to top of command stack
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pCom - > Next = Command ;
Command = pCom ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Success
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : SetCommand ( int32_t iCommand , C4Object * pTarget , C4Value iTx , int32_t iTy ,
2010-03-28 18:58:01 +00:00
C4Object * pTarget2 , bool fControl , C4Value iData ,
int32_t iRetries , C4String * szText )
{
2009-05-08 13:28:41 +00:00
// Clear stack
2010-03-27 16:05:02 +00:00
ClearCommands ( ) ;
2009-05-08 13:28:41 +00:00
// Close menu
if ( fControl )
if ( ! CloseMenu ( false ) ) return ;
// Script overload
if ( fControl )
2014-05-30 23:03:23 +00:00
if ( ! ! Call ( PSF_ControlCommand , & C4AulParSet ( CommandName ( iCommand ) ,
pTarget ,
2010-03-28 18:58:01 +00:00
iTx ,
2014-05-30 23:03:23 +00:00
iTy ,
pTarget2 ,
2010-03-28 18:58:01 +00:00
iData ) ) )
2009-05-08 13:28:41 +00:00
return ;
// Inside vehicle control overload
2010-03-27 16:05:02 +00:00
if ( Contained )
2009-05-08 13:28:41 +00:00
if ( Contained - > Def - > VehicleControl & C4D_VehicleControl_Inside )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Contained - > Controller = Controller ;
2014-05-30 23:03:23 +00:00
if ( ! ! Contained - > Call ( PSF_ControlCommand , & C4AulParSet ( CommandName ( iCommand ) ,
pTarget ,
2010-03-28 18:58:01 +00:00
iTx ,
2014-05-30 23:03:23 +00:00
iTy ,
pTarget2 ,
2010-03-28 18:58:01 +00:00
iData ,
2014-05-30 23:03:23 +00:00
this ) ) )
2009-05-08 13:28:41 +00:00
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Outside vehicle control overload
if ( GetProcedure ( ) = = DFA_PUSH )
if ( Action . Target ) if ( Action . Target - > Def - > VehicleControl & C4D_VehicleControl_Outside )
{
2010-03-28 18:58:01 +00:00
Action . Target - > Controller = Controller ;
2014-05-30 23:03:23 +00:00
if ( ! ! Action . Target - > Call ( PSF_ControlCommand , & C4AulParSet ( CommandName ( iCommand ) ,
pTarget ,
2010-03-28 18:58:01 +00:00
iTx ,
2014-05-30 23:03:23 +00:00
iTy ,
pTarget2 ,
2010-03-28 18:58:01 +00:00
iData ) ) )
return ;
2009-05-08 13:28:41 +00:00
}
// Add new command
2009-08-15 18:50:32 +00:00
AddCommand ( iCommand , pTarget , iTx , iTy , 0 , pTarget2 , true , iData , false , iRetries , szText , C4CMD_Mode_Base ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
C4Command * C4Object : : FindCommand ( int32_t iCommandType ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// seek all commands
for ( C4Command * pCom = Command ; pCom ; pCom = pCom - > Next )
if ( pCom - > Command = = iCommandType ) return pCom ;
// nothing found
return NULL ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : ExecuteCommand ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Execute first command
if ( Command ) Command - > Execute ( ) ;
// Command finished: engine call
if ( Command & & Command - > Finished )
2014-05-30 23:03:23 +00:00
Call ( PSF_ControlCommandFinished , & C4AulParSet ( CommandName ( Command - > Command ) , Command - > Target , Command - > Tx , Command - > Ty , Command - > Target2 , Command - > Data ) ) ;
2009-05-08 13:28:41 +00:00
// Clear finished commands
while ( Command & & Command - > Finished ) ClearCommand ( Command ) ;
// Done
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : Resort ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Flag resort
2009-08-15 18:50:32 +00:00
Unsorted = true ;
Game . fResortAnyObject = true ;
2009-05-08 13:28:41 +00:00
// Must not immediately resort - link change/removal would crash Game::ExecObjects
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-01-12 22:43:05 +00:00
C4PropList * C4Object : : GetAction ( ) const
2010-03-18 23:04:29 +00:00
{
C4Value value ;
2010-12-06 15:19:15 +00:00
GetProperty ( P_Action , & value ) ;
2010-03-18 23:04:29 +00:00
return value . getPropList ( ) ;
}
2009-08-15 18:50:32 +00:00
bool C4Object : : SetAction ( C4PropList * Act , C4Object * pTarget , C4Object * pTarget2 , int32_t iCalls , bool fForce )
2010-03-28 18:58:01 +00:00
{
2010-12-12 20:12:04 +00:00
C4Value vLastAction ;
GetProperty ( P_Action , & vLastAction ) ;
C4PropList * LastAction = vLastAction . getPropList ( ) ;
2009-05-08 13:28:41 +00:00
int32_t iLastPhase = Action . Phase ;
2010-07-30 17:42:54 +00:00
C4Object * pLastTarget = Action . Target ;
C4Object * pLastTarget2 = Action . Target2 ;
2009-04-12 12:03:14 +00:00
// No other action
if ( LastAction )
if ( LastAction - > GetPropertyInt ( P_NoOtherAction ) & & ! fForce )
if ( Act ! = LastAction )
2009-08-15 18:50:32 +00:00
return false ;
2009-07-28 01:49:33 +00:00
// Set animation on instance. Abort if the mesh does not have
2009-07-12 14:27:04 +00:00
// such an animation.
2010-03-28 18:58:01 +00:00
if ( pMeshInstance )
{
if ( Action . Animation ) pMeshInstance - > StopAnimation ( Action . Animation ) ;
2010-01-22 18:27:02 +00:00
Action . Animation = NULL ;
2009-12-30 20:41:56 +00:00
2010-01-22 18:27:02 +00:00
C4String * Animation = Act ? Act - > GetPropertyStr ( P_Animation ) : NULL ;
2010-03-28 18:58:01 +00:00
if ( Animation )
{
2010-01-22 18:27:02 +00:00
// note that weight is ignored
2016-01-29 03:02:27 +00:00
Action . Animation = pMeshInstance - > PlayAnimation ( Animation - > GetData ( ) , 0 , NULL , new C4ValueProviderAction ( this ) , new C4ValueProviderConst ( itofix ( 1 ) ) , true ) ;
2009-07-28 01:49:33 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-04-12 12:03:14 +00:00
// Stop previous act sound
if ( LastAction )
if ( Act ! = LastAction )
if ( LastAction - > GetPropertyStr ( P_Sound ) )
StopSoundEffect ( LastAction - > GetPropertyStr ( P_Sound ) - > GetCStr ( ) , this ) ;
// Unfullcon objects no action
if ( Con < FullCon )
2009-05-08 13:28:41 +00:00
if ( ! Def - > IncompleteActivity )
2009-04-12 12:03:14 +00:00
Act = 0 ;
// Reset action time on change
if ( Act ! = LastAction )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Action . Time = 0 ;
2016-01-15 02:40:42 +00:00
// reset action data and targets if procedure is changed
2010-12-08 22:17:00 +00:00
if ( ( Act ? Act - > GetPropertyP ( P_Procedure ) : - 1 )
2016-01-15 13:14:46 +00:00
! = ( LastAction ? LastAction - > GetPropertyP ( P_Procedure ) : - 1 ) )
{
2010-03-28 18:58:01 +00:00
Action . Data = 0 ;
2016-01-15 13:14:46 +00:00
Action . Target = NULL ;
Action . Target2 = NULL ;
}
2010-03-28 18:58:01 +00:00
}
2009-04-12 12:03:14 +00:00
// Set new action
2010-12-06 15:19:15 +00:00
SetProperty ( P_Action , C4VPropList ( Act ) ) ;
2009-04-12 12:03:14 +00:00
Action . Phase = Action . PhaseDelay = 0 ;
2009-05-08 13:28:41 +00:00
// Set target if specified
2009-04-12 12:03:14 +00:00
if ( pTarget ) Action . Target = pTarget ;
if ( pTarget2 ) Action . Target2 = pTarget2 ;
2009-05-08 13:28:41 +00:00
// Set Action Facet
UpdateActionFace ( ) ;
// update flipdir
2009-04-12 12:03:14 +00:00
if ( ( LastAction ? LastAction - > GetPropertyInt ( P_FlipDir ) : 0 )
2010-03-28 18:58:01 +00:00
! = ( Act ? Act - > GetPropertyInt ( P_FlipDir ) : 0 ) ) UpdateFlipDir ( ) ;
2009-04-12 12:03:14 +00:00
// Start act sound
2010-03-18 23:04:29 +00:00
if ( Act )
if ( Act ! = LastAction )
if ( Act - > GetPropertyStr ( P_Sound ) )
StartSoundEffect ( Act - > GetPropertyStr ( P_Sound ) - > GetCStr ( ) , + 1 , 100 , this ) ;
2009-04-12 12:03:14 +00:00
// Reset OCF
SetOCF ( ) ;
2009-05-08 13:28:41 +00:00
// issue calls
2010-01-22 14:52:01 +00:00
// Execute EndCall for last action
2009-04-12 12:03:14 +00:00
if ( iCalls & SAC_EndCall & & ! fForce )
if ( LastAction )
2010-03-28 18:58:01 +00:00
{
2009-04-12 12:03:14 +00:00
if ( LastAction - > GetPropertyStr ( P_EndCall ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Def * pOldDef = Def ;
2009-04-12 12:03:14 +00:00
Call ( LastAction - > GetPropertyStr ( P_EndCall ) - > GetCStr ( ) ) ;
2009-05-08 13:28:41 +00:00
// abort exeution if def changed
2009-08-15 18:50:32 +00:00
if ( Def ! = pOldDef | | ! Status ) return true ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2010-01-22 14:52:01 +00:00
// Execute AbortCall for last action
2009-04-12 12:03:14 +00:00
if ( iCalls & SAC_AbortCall & & ! fForce )
if ( LastAction )
2010-03-28 18:58:01 +00:00
{
2009-04-12 12:03:14 +00:00
if ( LastAction - > GetPropertyStr ( P_AbortCall ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Def * pOldDef = Def ;
2010-07-30 17:42:54 +00:00
if ( pLastTarget & & ! pLastTarget - > Status ) pLastTarget = NULL ;
if ( pLastTarget2 & & ! pLastTarget2 - > Status ) pLastTarget2 = NULL ;
2014-05-30 23:03:23 +00:00
Call ( LastAction - > GetPropertyStr ( P_AbortCall ) - > GetCStr ( ) , & C4AulParSet ( iLastPhase , pLastTarget , pLastTarget2 ) ) ;
2009-05-08 13:28:41 +00:00
// abort exeution if def changed
2009-08-15 18:50:32 +00:00
if ( Def ! = pOldDef | | ! Status ) return true ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2010-01-22 14:52:01 +00:00
// Execute StartCall for new action
if ( iCalls & SAC_StartCall )
2010-03-18 23:04:29 +00:00
if ( Act )
2010-03-28 18:58:01 +00:00
{
2010-03-18 23:04:29 +00:00
if ( Act - > GetPropertyStr ( P_StartCall ) )
2010-03-28 18:58:01 +00:00
{
2010-01-22 14:52:01 +00:00
C4Def * pOldDef = Def ;
2010-03-18 23:04:29 +00:00
Call ( Act - > GetPropertyStr ( P_StartCall ) - > GetCStr ( ) ) ;
2010-01-22 14:52:01 +00:00
// abort exeution if def changed
if ( Def ! = pOldDef | | ! Status ) return true ;
}
2010-03-28 18:58:01 +00:00
}
2010-08-17 21:56:15 +00:00
C4Def * pOldDef = Def ;
2014-05-30 23:03:23 +00:00
Call ( PSF_OnActionChanged , & C4AulParSet ( LastAction ? LastAction - > GetName ( ) : " Idle " ) ) ;
2010-08-17 21:56:15 +00:00
if ( Def ! = pOldDef | | ! Status ) return true ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateActionFace ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Default: no action face
Action . Facet . Default ( ) ;
// Active: get action facet from action definition
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
if ( pActionDef )
2010-03-28 18:58:01 +00:00
{
2010-03-18 23:04:29 +00:00
if ( pActionDef - > GetPropertyInt ( P_Wdt ) > 0 )
2010-03-28 18:58:01 +00:00
{
2009-04-12 12:03:14 +00:00
Action . Facet . Set ( GetGraphics ( ) - > GetBitmap ( Color ) ,
2010-03-28 18:58:01 +00:00
pActionDef - > GetPropertyInt ( P_X ) , pActionDef - > GetPropertyInt ( P_Y ) ,
pActionDef - > GetPropertyInt ( P_Wdt ) , pActionDef - > GetPropertyInt ( P_Hgt ) ) ;
2010-03-18 23:04:29 +00:00
Action . FacetX = pActionDef - > GetPropertyInt ( P_OffX ) ;
Action . FacetY = pActionDef - > GetPropertyInt ( P_OffY ) ;
2009-04-12 12:03:14 +00:00
}
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-12-21 12:50:42 +00:00
bool C4Object : : SetActionByName ( C4String * ActName ,
2010-03-28 18:58:01 +00:00
C4Object * pTarget , C4Object * pTarget2 ,
int32_t iCalls , bool fForce )
2009-12-21 12:50:42 +00:00
{
assert ( ActName ) ;
// If we get the null string or ActIdle by name, set ActIdle
2010-12-06 15:24:41 +00:00
if ( ! ActName | | ActName = = & Strings . P [ P_Idle ] )
2009-04-12 12:03:14 +00:00
return SetAction ( 0 , 0 , 0 , iCalls , fForce ) ;
2010-12-06 15:19:15 +00:00
C4Value ActMap ; GetProperty ( P_ActMap , & ActMap ) ;
2009-04-12 12:03:14 +00:00
if ( ! ActMap . getPropList ( ) ) return false ;
2010-12-06 15:19:15 +00:00
C4Value Action ; ActMap . getPropList ( ) - > GetPropertyByS ( ActName , & Action ) ;
2009-04-12 12:03:14 +00:00
if ( ! Action . getPropList ( ) ) return false ;
2010-03-28 18:58:01 +00:00
return SetAction ( Action . getPropList ( ) , pTarget , pTarget2 , iCalls , fForce ) ;
2009-12-21 12:50:42 +00:00
}
2009-04-12 12:03:14 +00:00
2010-03-28 18:58:01 +00:00
bool C4Object : : SetActionByName ( const char * szActName ,
C4Object * pTarget , C4Object * pTarget2 ,
int32_t iCalls , bool fForce )
{
2009-04-12 12:03:14 +00:00
C4String * ActName = Strings . RegString ( szActName ) ;
ActName - > IncRef ( ) ;
2009-10-13 21:43:12 +00:00
bool r = SetActionByName ( ActName , pTarget , pTarget2 , iCalls , fForce ) ;
2009-04-12 12:03:14 +00:00
ActName - > DecRef ( ) ;
return r ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : SetDir ( int32_t iDir )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Not active
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
if ( ! pActionDef ) return ;
2009-05-08 13:28:41 +00:00
// Invalid direction
2010-03-18 23:04:29 +00:00
if ( ! Inside < int32_t > ( iDir , 0 , pActionDef - > GetPropertyInt ( P_Directions ) - 1 ) ) return ;
2009-05-08 13:28:41 +00:00
// Execute turn action
if ( iDir ! = Action . Dir )
2010-03-18 23:04:29 +00:00
if ( pActionDef - > GetPropertyStr ( P_TurnAction ) )
{ SetActionByName ( pActionDef - > GetPropertyStr ( P_TurnAction ) ) ; }
2009-05-08 13:28:41 +00:00
// Set dir
2009-04-12 12:03:14 +00:00
Action . Dir = iDir ;
2009-05-08 13:28:41 +00:00
// update by flipdir?
2010-03-18 23:04:29 +00:00
if ( pActionDef - > GetPropertyInt ( P_FlipDir ) )
2009-05-08 13:28:41 +00:00
UpdateFlipDir ( ) ;
else
Action . DrawDir = iDir ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
int32_t C4Object : : GetProcedure ( ) const
2010-03-28 18:58:01 +00:00
{
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
2010-12-08 22:17:00 +00:00
if ( ! pActionDef ) return - 1 ;
return pActionDef - > GetPropertyP ( P_Procedure ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-01-15 13:54:03 +00:00
void GrabLost ( C4Object * cObj , C4Object * prev_target )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Grab lost script call on target (quite hacky stuff...)
2016-01-15 13:54:03 +00:00
if ( prev_target & & prev_target - > Status ) prev_target - > Call ( PSF_GrabLost ) ;
2009-05-08 13:28:41 +00:00
// Clear commands down to first PushTo (if any) in command stack
for ( C4Command * pCom = cObj - > Command ; pCom ; pCom = pCom - > Next )
if ( pCom - > Next & & pCom - > Next - > Command = = C4CMD_PushTo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
cObj - > ClearCommand ( pCom ) ;
break ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
2010-12-11 23:05:42 +00:00
static void DoGravity ( C4Object * cobj ) ;
2009-05-08 13:28:41 +00:00
void C4Object : : NoAttachAction ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Active objects
2010-03-18 23:04:29 +00:00
if ( GetAction ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iProcedure = GetProcedure ( ) ;
2016-01-15 13:54:03 +00:00
C4Object * prev_target = Action . Target ;
2009-05-08 13:28:41 +00:00
// Scaling upwards: corner scale
if ( iProcedure = = DFA_SCALE & & Action . ComDir ! = COMD_Stop & & ComDirLike ( Action . ComDir , COMD_Up ) )
if ( ObjectActionCornerScale ( this ) ) return ;
if ( iProcedure = = DFA_SCALE & & Action . ComDir = = COMD_Left & & Action . Dir = = DIR_Left )
if ( ObjectActionCornerScale ( this ) ) return ;
if ( iProcedure = = DFA_SCALE & & Action . ComDir = = COMD_Right & & Action . Dir = = DIR_Right )
if ( ObjectActionCornerScale ( this ) ) return ;
// Scaling and stopped: fall off to side (avoid zuppel)
if ( ( iProcedure = = DFA_SCALE ) & & ( Action . ComDir = = COMD_Stop ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Action . Dir = = DIR_Left )
{ if ( ObjectActionJump ( this , itofix ( 1 ) , Fix0 , false ) ) return ; }
else
{ if ( ObjectActionJump ( this , itofix ( - 1 ) , Fix0 , false ) ) return ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Pushing: grab loss
2016-01-15 13:54:03 +00:00
if ( iProcedure = = DFA_PUSH ) GrabLost ( this , prev_target ) ;
2009-05-08 13:28:41 +00:00
// Else jump
ObjectActionJump ( this , xdir , ydir , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Inactive objects, simple mobile natural gravity
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
DoGravity ( this ) ;
Mobile = 1 ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : ContactAction ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Take certain action on contact. Evaluate t_contact-CNAT and Procedure.
// Determine Procedure
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
if ( ! pActionDef ) return ;
2010-12-08 22:17:00 +00:00
int32_t iProcedure = pActionDef - > GetPropertyP ( P_Procedure ) ;
2010-03-18 23:04:29 +00:00
int32_t fDisabled = pActionDef - > GetPropertyInt ( P_ObjectDisabled ) ;
2009-05-08 13:28:41 +00:00
//------------------------------- Hit Bottom ---------------------------------------------
if ( t_contact & CNAT_Bottom )
switch ( iProcedure )
2010-03-28 18:58:01 +00:00
{
case DFA_FLIGHT :
2012-10-13 15:14:13 +00:00
if ( ydir < 0 ) return ;
2010-03-28 18:58:01 +00:00
// Jump: FlatHit / HardHit / Walk
if ( ( OCF & OCF_HitSpeed4 ) | | fDisabled )
if ( ObjectActionFlat ( this , Action . Dir ) ) return ;
if ( OCF & OCF_HitSpeed3 )
if ( ObjectActionKneel ( this ) ) return ;
ObjectActionWalk ( this ) ;
2012-06-08 14:17:42 +00:00
ydir = 0 ;
2010-03-28 18:58:01 +00:00
return ;
case DFA_SCALE :
2012-06-08 14:17:42 +00:00
// Scale down: stand
if ( ComDirLike ( Action . ComDir , COMD_Down ) )
2009-05-08 13:28:41 +00:00
{
2012-06-08 14:17:42 +00:00
ObjectActionStand ( this ) ;
2009-05-08 13:28:41 +00:00
return ;
}
2012-06-08 14:17:42 +00:00
break ;
2010-03-28 18:58:01 +00:00
case DFA_DIG :
2011-09-18 16:23:22 +00:00
// no special action
break ;
2010-03-28 18:58:01 +00:00
case DFA_SWIM :
// Try corner scale out
2015-03-26 18:52:11 +00:00
if ( ! GBackSemiSolid ( GetX ( ) , GetY ( ) - 1 + Def - > Float * Con / FullCon - 1 ) )
2010-03-28 18:58:01 +00:00
if ( ObjectActionCornerScale ( this ) ) return ;
2012-06-08 14:17:42 +00:00
break ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
//------------------------------- Hit Ceiling -----------------------------------------
if ( t_contact & CNAT_Top )
switch ( iProcedure )
{
2010-03-28 18:58:01 +00:00
case DFA_WALK :
// Walk: Stop
ObjectActionStand ( this ) ; return ;
case DFA_SCALE :
// Scale: Try hangle, else stop if going upward
if ( ComDirLike ( Action . ComDir , COMD_Up ) )
{
2012-06-08 14:17:42 +00:00
if ( ObjectActionHangle ( this ) )
{
SetDir ( Action . Dir = = DIR_Left ? DIR_Right : DIR_Left ) ;
return ;
}
2010-12-12 00:09:29 +00:00
Action . ComDir = COMD_Stop ;
2010-03-28 18:58:01 +00:00
}
break ;
case DFA_FLIGHT :
// Jump: Try hangle, else bounce off
// High Speed Flight: Tumble
if ( ( OCF & OCF_HitSpeed3 ) | | fDisabled )
2012-07-15 17:05:20 +00:00
{ ObjectActionTumble ( this , Action . Dir , xdir , ydir ) ; break ; }
2012-06-08 14:17:42 +00:00
if ( ObjectActionHangle ( this ) ) return ;
2010-03-28 18:58:01 +00:00
break ;
case DFA_DIG :
2011-09-18 16:23:22 +00:00
// No action
break ;
2010-03-28 18:58:01 +00:00
case DFA_HANGLE :
Action . ComDir = COMD_Stop ;
break ;
2009-05-08 13:28:41 +00:00
}
//---------------------------- Hit Left Wall ----------------------------------------
if ( t_contact & CNAT_Left )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
switch ( iProcedure )
2010-03-28 18:58:01 +00:00
{
case DFA_FLIGHT :
// High Speed Flight: Tumble
if ( ( OCF & OCF_HitSpeed3 ) | | fDisabled )
2012-07-15 17:05:20 +00:00
{ ObjectActionTumble ( this , DIR_Left , xdir , ydir ) ; break ; }
2010-03-28 18:58:01 +00:00
// Else
2012-06-18 23:40:37 +00:00
else if ( ! ComDirLike ( Action . ComDir , COMD_Right ) & & ObjectActionScale ( this , DIR_Left ) ) return ;
2010-03-28 18:58:01 +00:00
break ;
case DFA_WALK :
2012-06-08 14:17:42 +00:00
// Walk: Try scale
2010-03-28 18:58:01 +00:00
if ( ComDirLike ( Action . ComDir , COMD_Left ) )
2009-05-08 13:28:41 +00:00
{
2012-06-08 14:17:42 +00:00
if ( ObjectActionScale ( this , DIR_Left ) )
{
ydir = C4REAL100 ( - 1 ) ;
return ;
}
2010-03-28 18:58:01 +00:00
}
// Heading away from solid
if ( ComDirLike ( Action . ComDir , COMD_Right ) )
{
// Slide off
ObjectActionJump ( this , xdir / 2 , ydir , false ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return ;
case DFA_SWIM :
2013-10-06 12:55:48 +00:00
// Only scale if swimming at the surface
2015-03-26 18:52:11 +00:00
if ( ! GBackSemiSolid ( GetX ( ) , GetY ( ) - 1 + Def - > Float * Con / FullCon - 1 ) )
2013-10-06 12:55:48 +00:00
{
// Try scale, only if swimming at the surface.
if ( ComDirLike ( Action . ComDir , COMD_Left ) )
if ( ObjectActionScale ( this , DIR_Left ) ) return ;
// Try corner scale out
if ( ObjectActionCornerScale ( this ) ) return ;
}
2010-03-28 18:58:01 +00:00
return ;
case DFA_HANGLE :
2012-06-08 14:17:42 +00:00
// Hangle: Try scale
2010-12-12 00:09:29 +00:00
if ( ObjectActionScale ( this , DIR_Left ) )
2012-06-08 14:17:42 +00:00
{
ydir = C4REAL100 ( 1 ) ;
2010-12-12 00:09:29 +00:00
return ;
2012-06-08 14:17:42 +00:00
}
2010-03-28 18:58:01 +00:00
return ;
case DFA_DIG :
2011-09-18 16:23:22 +00:00
// Dig: no action
break ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
//------------------------------ Hit Right Wall --------------------------------------
if ( t_contact & CNAT_Right )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
switch ( iProcedure )
2010-03-28 18:58:01 +00:00
{
case DFA_FLIGHT :
// High Speed Flight: Tumble
if ( ( OCF & OCF_HitSpeed3 ) | | fDisabled )
2012-07-15 17:05:20 +00:00
{ ObjectActionTumble ( this , DIR_Right , xdir , ydir ) ; break ; }
2010-03-28 18:58:01 +00:00
// Else Scale
2012-06-18 23:40:37 +00:00
else if ( ! ComDirLike ( Action . ComDir , COMD_Left ) & & ObjectActionScale ( this , DIR_Right ) ) return ;
2010-03-28 18:58:01 +00:00
break ;
case DFA_WALK :
2012-06-08 14:17:42 +00:00
// Walk: Try scale
2010-03-28 18:58:01 +00:00
if ( ComDirLike ( Action . ComDir , COMD_Right ) )
2009-05-08 13:28:41 +00:00
{
2012-06-08 14:17:42 +00:00
if ( ObjectActionScale ( this , DIR_Right ) )
{
ydir = C4REAL100 ( - 1 ) ;
return ;
}
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
// Heading away from solid
if ( ComDirLike ( Action . ComDir , COMD_Left ) )
{
// Slide off
ObjectActionJump ( this , xdir / 2 , ydir , false ) ;
}
return ;
case DFA_SWIM :
2013-10-06 12:55:48 +00:00
// Only scale if swimming at the surface
2015-03-26 18:52:11 +00:00
if ( ! GBackSemiSolid ( GetX ( ) , GetY ( ) - 1 + Def - > Float * Con / FullCon - 1 ) )
2013-10-06 12:55:48 +00:00
{
// Try scale
if ( ComDirLike ( Action . ComDir , COMD_Right ) )
if ( ObjectActionScale ( this , DIR_Right ) ) return ;
// Try corner scale out
if ( ObjectActionCornerScale ( this ) ) return ;
}
2010-03-28 18:58:01 +00:00
return ;
case DFA_HANGLE :
2012-06-08 14:17:42 +00:00
// Hangle: Try scale
2010-12-12 00:09:29 +00:00
if ( ObjectActionScale ( this , DIR_Right ) )
2012-06-08 14:17:42 +00:00
{
ydir = C4REAL100 ( 1 ) ;
2010-12-12 00:09:29 +00:00
return ;
2012-06-08 14:17:42 +00:00
}
2010-03-28 18:58:01 +00:00
return ;
case DFA_DIG :
2011-09-18 16:23:22 +00:00
// Dig: no action
break ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
//---------------------------- Unresolved Cases ---------------------------------------
// Flight stuck
if ( iProcedure = = DFA_FLIGHT )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Enforce slide free (might slide through tiny holes this way)
if ( ! ydir )
2010-03-28 18:58:01 +00:00
{
2010-10-11 00:33:13 +00:00
int fAllowDown = ! ( t_contact & CNAT_Bottom ) ;
2009-05-08 13:28:41 +00:00
if ( t_contact & CNAT_Right )
2010-03-28 18:58:01 +00:00
{
2010-10-10 16:46:23 +00:00
ForcePosition ( fix_x - 1 , fix_y + fAllowDown ) ;
2009-05-08 13:28:41 +00:00
xdir = ydir = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( t_contact & CNAT_Left )
2010-03-28 18:58:01 +00:00
{
2010-10-10 16:46:23 +00:00
ForcePosition ( fix_x + 1 , fix_y + fAllowDown ) ;
2009-05-08 13:28:41 +00:00
xdir = ydir = 0 ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( ! xdir )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( t_contact & CNAT_Top )
2010-03-28 18:58:01 +00:00
{
2010-10-10 16:46:23 +00:00
ForcePosition ( fix_x , fix_y + 1 ) ;
2009-05-08 13:28:41 +00:00
xdir = ydir = 0 ;
}
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
void Towards ( C4Real & val , C4Real target , C4Real step )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( val = = target ) return ;
if ( Abs ( val - target ) < = step ) { val = target ; return ; }
if ( val < target ) val + = step ; else val - = step ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool DoBridge ( C4Object * clk )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iBridgeTime ; bool fMoveClonk , fWall ; int32_t iBridgeMaterial ;
clk - > Action . GetBridgeData ( iBridgeTime , fMoveClonk , fWall , iBridgeMaterial ) ;
if ( ! iBridgeTime ) iBridgeTime = 100 ; // default bridge time
if ( clk - > Action . Time > = iBridgeTime ) { ObjectActionStand ( clk ) ; return false ; }
// get bridge advancement
int32_t dtp ;
if ( fWall ) switch ( clk - > Action . ComDir )
{
case COMD_Left : case COMD_Right : dtp = 4 ; fMoveClonk = false ; break ; // vertical wall: default 25 pixels
case COMD_UpLeft : case COMD_UpRight : dtp = 5 ; fMoveClonk = false ; break ; // diagonal roof over Clonk: default 20 pixels up and 20 pixels side (28 pixels - optimized to close tunnels completely)
case COMD_Up : dtp = 5 ; break ; // horizontal roof over Clonk
default : return true ; // bridge procedure just for show
}
else switch ( clk - > Action . ComDir )
{
case COMD_Left : case COMD_Right : dtp = 5 ; break ; // horizontal bridges: default 20 pixels
case COMD_Up : dtp = 4 ; break ; // vertical bridges: default 25 pixels (same as
case COMD_UpLeft : case COMD_UpRight : dtp = 6 ; break ; // diagonal bridges: default 16 pixels up and 16 pixels side (23 pixels)
default : return true ; // bridge procedure just for show
}
if ( clk - > Action . Time % dtp ) return true ; // no advancement in this frame
// get target pos for Clonk and bridge
int32_t cx = clk - > GetX ( ) , cy = clk - > GetY ( ) , cw = clk - > Shape . Wdt , ch = clk - > Shape . Hgt ;
2010-03-27 16:05:02 +00:00
int32_t tx = cx , ty = cy + ch / 2 ;
2009-05-08 13:28:41 +00:00
int32_t dt ;
if ( fMoveClonk ) dt = 0 ; else dt = clk - > Action . Time / dtp ;
if ( fWall ) switch ( clk - > Action . ComDir )
{
case COMD_Left : tx - = cw / 2 ; ty + = - dt ; break ;
case COMD_Right : tx + = cw / 2 ; ty + = - dt ; break ;
case COMD_Up :
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t x0 ;
if ( fMoveClonk ) x0 = - 3 ; else x0 = ( iBridgeTime / dtp ) / - 2 ;
tx + = ( x0 + dt ) * ( ( clk - > Action . Dir = = DIR_Right ) * 2 - 1 ) ; cx + = ( ( clk - > Action . Dir = = DIR_Right ) * 2 - 1 ) ; ty - = ch + 3 ; break ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
case COMD_UpLeft : tx - = - 4 + dt ; ty + = - ch - 7 + dt ; break ;
case COMD_UpRight : tx + = - 4 + dt ; ty + = - ch - 7 + dt ; break ;
}
else switch ( clk - > Action . ComDir )
{
case COMD_Left : tx + = - 3 - dt ; - - cx ; break ;
case COMD_Right : tx + = + 2 + dt ; + + cx ; break ;
case COMD_Up : tx + = ( - cw / 2 + ( cw - 1 ) * ( clk - > Action . Dir = = DIR_Right ) ) * ( ! fMoveClonk ) ; ty + = - dt - fMoveClonk ; - - cy ; break ;
case COMD_UpLeft : tx + = - 5 - dt + fMoveClonk * 3 ; ty + = 2 - dt - fMoveClonk * 3 ; - - cx ; - - cy ; break ;
case COMD_UpRight : tx + = + 5 + dt - fMoveClonk * 2 ; ty + = 2 - dt - fMoveClonk * 3 ; + + cx ; - - cy ; break ;
}
// check if Clonk movement is posible
if ( fMoveClonk )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t cx2 = cx , cy2 = cy ;
if ( /*!clk->Shape.Attach(cx2, cy2, (clk->Action.t_attach & CNAT_Flags) | CNAT_Bottom) ||*/ clk - > Shape . CheckContact ( cx2 , cy2 - 1 ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Clonk would collide here: Change to nonmoving Clonk mode and redo bridging
iBridgeTime - = clk - > Action . Time ;
clk - > Action . Time = 0 ;
if ( fWall & & clk - > Action . ComDir = = COMD_Up )
2010-03-28 18:58:01 +00:00
{
2015-12-30 11:54:04 +00:00
// special for roof above Clonk: The nonmoving roof is started at bridgelength before the Clonk
2009-05-08 13:28:41 +00:00
// so, when interrupted, an action time halfway through the action must be set
clk - > Action . Time = iBridgeTime ;
iBridgeTime + = iBridgeTime ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
clk - > Action . SetBridgeData ( iBridgeTime , false , fWall , iBridgeMaterial ) ;
return DoBridge ( clk ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// draw bridge into landscape
2010-03-27 16:05:02 +00:00
: : Landscape . DrawMaterialRect ( iBridgeMaterial , tx - 2 , ty , 4 , 3 ) ;
2009-05-08 13:28:41 +00:00
// Move Clonk
if ( fMoveClonk ) clk - > MovePosition ( cx - clk - > GetX ( ) , cy - clk - > GetY ( ) ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-12-11 23:05:42 +00:00
static void DoGravity ( C4Object * cobj )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Floatation in liquids
2010-03-27 16:05:02 +00:00
if ( cobj - > InLiquid & & cobj - > Def - > Float )
2010-03-28 18:58:01 +00:00
{
2010-12-11 23:05:42 +00:00
cobj - > ydir - = GravAccel * C4REAL100 ( 80 ) ;
if ( cobj - > ydir < C4REAL100 ( - 160 ) ) cobj - > ydir = C4REAL100 ( - 160 ) ;
if ( cobj - > xdir < - FloatFriction ) cobj - > xdir + = FloatFriction ;
if ( cobj - > xdir > + FloatFriction ) cobj - > xdir - = FloatFriction ;
if ( cobj - > rdir < - FloatFriction ) cobj - > rdir + = FloatFriction ;
if ( cobj - > rdir > + FloatFriction ) cobj - > rdir - = FloatFriction ;
2015-12-30 11:54:04 +00:00
// Reduce upwards speed when about to leave liquid to prevent eternal moving up and down.
// Check both for no liquid one and two pixels above the surface, because the object could
// skip one pixel as its speed can be more than 100.
int32_t y_float = cobj - > GetY ( ) - 1 + cobj - > Def - > Float * cobj - > GetCon ( ) / FullCon ;
if ( ! GBackLiquid ( cobj - > GetX ( ) , y_float - 1 ) | | ! GBackLiquid ( cobj - > GetX ( ) , y_float - 2 ) )
if ( cobj - > ydir < 0 )
{
// Reduce the upwards speed and set to zero for small values to prevent fluctuations.
cobj - > ydir / = 2 ;
if ( Abs ( cobj - > ydir ) < C4REAL100 ( 10 ) )
cobj - > ydir = 0 ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Free fall gravity
2010-03-27 16:05:02 +00:00
else if ( ~ cobj - > Category & C4D_StaticBack )
cobj - > ydir + = GravAccel ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void StopActionDelayCommand ( C4Object * cobj )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
ObjectComStop ( cobj ) ;
cobj - > AddCommand ( C4CMD_Wait , NULL , 0 , 0 , 50 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool ReduceLineSegments ( C4Shape & rShape , bool fAlternate )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// try if line could go by a path directly when skipping on evertex. If fAlternate is true, try by skipping two vertices
for ( int32_t cnt = 0 ; cnt + 2 + fAlternate < rShape . VtxNum ; cnt + + )
if ( PathFree ( rShape . VtxX [ cnt ] , rShape . VtxY [ cnt ] ,
2010-03-28 18:58:01 +00:00
rShape . VtxX [ cnt + 2 + fAlternate ] , rShape . VtxY [ cnt + 2 + fAlternate ] ) )
{
2009-05-08 13:28:41 +00:00
if ( fAlternate ) rShape . RemoveVertex ( cnt + 2 ) ;
rShape . RemoveVertex ( cnt + 1 ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : ExecAction ( )
2010-03-28 18:58:01 +00:00
{
2010-05-04 15:35:18 +00:00
C4Real iTXDir ;
C4Real lftspeed , tydir ;
2009-05-08 13:28:41 +00:00
int32_t iTargetX ;
int32_t iPushRange , iPushDistance ;
// Standard phase advance
2010-03-27 16:05:02 +00:00
int32_t iPhaseAdvance = 1 ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Upright attachment check
if ( ! Mobile )
if ( Def - > UprightAttach )
2013-05-25 12:59:58 +00:00
if ( Inside < int32_t > ( GetR ( ) , - StableRange , + StableRange ) )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
Action . t_attach | = Def - > UprightAttach ;
Mobile = 1 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
2012-10-10 19:28:25 +00:00
// No IncompleteActivity? Reset action if there was one
if ( ! ( OCF & OCF_FullCon ) & & ! Def - > IncompleteActivity & & pActionDef )
{
SetAction ( 0 ) ;
pActionDef = 0 ;
}
// InLiquidAction check
if ( InLiquid )
if ( pActionDef & & pActionDef - > GetPropertyStr ( P_InLiquidAction ) )
{
SetActionByName ( pActionDef - > GetPropertyStr ( P_InLiquidAction ) ) ;
pActionDef = GetAction ( ) ;
}
// Idle objects do natural gravity only
2010-03-18 23:04:29 +00:00
if ( ! pActionDef )
2010-03-28 18:58:01 +00:00
{
2012-10-10 19:28:25 +00:00
Action . t_attach = CNAT_None ;
2009-04-12 12:03:14 +00:00
if ( Mobile ) DoGravity ( this ) ;
return ;
2010-03-28 18:58:01 +00:00
}
2010-05-04 15:35:18 +00:00
C4Real fWalk , fMove ;
2009-05-08 13:28:41 +00:00
// Action time advance
2009-04-12 12:03:14 +00:00
Action . Time + + ;
2010-03-28 18:58:01 +00:00
2012-06-16 01:01:47 +00:00
C4Value Attach ;
2012-07-15 19:47:50 +00:00
pActionDef - > GetProperty ( P_Attach , & Attach ) ;
if ( Attach . GetType ( ) ! = C4V_Nil )
2012-06-16 01:01:47 +00:00
{
Action . t_attach = Attach . getInt ( ) ;
}
else switch ( pActionDef - > GetPropertyP ( P_Procedure ) )
{
case DFA_SCALE :
if ( Action . Dir = = DIR_Left ) Action . t_attach = CNAT_Left ;
if ( Action . Dir = = DIR_Right ) Action . t_attach = CNAT_Right ;
break ;
case DFA_HANGLE :
Action . t_attach = CNAT_Top ;
break ;
case DFA_WALK :
case DFA_KNEEL :
case DFA_THROW :
case DFA_BRIDGE :
case DFA_PUSH :
case DFA_PULL :
case DFA_DIG :
Action . t_attach = CNAT_Bottom ;
break ;
default :
Action . t_attach = CNAT_None ;
}
2009-05-08 13:28:41 +00:00
// if an object is in controllable state, so it can be assumed that if it dies later because of NO_OWNER's cause,
// it has been its own fault and not the fault of the last one who threw a flint on it
// do not reset for burning objects to make sure the killer is set correctly if they fall out of the map while burning
2010-12-08 22:17:00 +00:00
if ( ! pActionDef - > GetPropertyInt ( P_ObjectDisabled ) & & pActionDef - > GetPropertyP ( P_Procedure ) ! = DFA_FLIGHT & & ! OnFire )
2009-05-08 13:28:41 +00:00
LastEnergyLossCausePlayer = NO_OWNER ;
2009-04-12 12:03:14 +00:00
// Handle Default Action Procedure: evaluates Procedure and Action.ComDir
// Update xdir,ydir,Action.Dir,attachment,iPhaseAdvance
2009-11-30 15:57:37 +00:00
int32_t dir = Action . Dir ;
2010-12-11 20:10:05 +00:00
C4Real accel = C4REAL100 ( pActionDef - > GetPropertyInt ( P_Accel ) ) ;
2012-07-15 19:47:50 +00:00
C4Real decel = accel ;
{
C4Value decel_val ;
pActionDef - > GetProperty ( P_Decel , & decel_val ) ;
if ( decel_val . GetType ( ) ! = C4V_Nil )
decel = C4REAL100 ( decel_val . getInt ( ) ) ;
}
2011-07-05 10:47:07 +00:00
C4Real limit = C4REAL100 ( pActionDef - > GetPropertyInt ( P_Speed ) ) ;
2010-05-04 15:35:18 +00:00
2010-12-08 22:17:00 +00:00
switch ( pActionDef - > GetPropertyP ( P_Procedure ) )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_WALK :
switch ( Action . ComDir )
{
case COMD_Left : case COMD_UpLeft : case COMD_DownLeft :
// breaaak!!!
2010-12-11 20:10:05 +00:00
if ( dir = = DIR_Right )
xdir - = decel ;
else
xdir - = accel ;
2011-07-05 10:47:07 +00:00
if ( xdir < - limit ) xdir = - limit ;
2010-03-27 16:05:02 +00:00
break ;
2010-03-28 18:58:01 +00:00
case COMD_Right : case COMD_UpRight : case COMD_DownRight :
2010-12-11 20:10:05 +00:00
if ( dir = = DIR_Left )
xdir + = decel ;
else
xdir + = accel ;
2011-07-05 10:47:07 +00:00
if ( xdir > + limit ) xdir = + limit ;
2010-03-27 16:05:02 +00:00
break ;
2010-03-28 18:58:01 +00:00
case COMD_Stop : case COMD_Up : case COMD_Down :
2010-12-11 20:10:05 +00:00
if ( xdir < 0 ) xdir + = decel ;
if ( xdir > 0 ) xdir - = decel ;
if ( ( xdir > - decel ) & & ( xdir < + decel ) ) xdir = 0 ;
2009-05-08 13:28:41 +00:00
break ;
2010-03-28 18:58:01 +00:00
}
iPhaseAdvance = 0 ;
if ( xdir < 0 )
{
if ( dir ! = DIR_Left ) { SetDir ( DIR_Left ) ; xdir = - 1 ; }
iPhaseAdvance = - fixtoi ( xdir * 10 ) ;
}
if ( xdir > 0 )
{
if ( dir ! = DIR_Right ) { SetDir ( DIR_Right ) ; xdir = 1 ; }
iPhaseAdvance = + fixtoi ( xdir * 10 ) ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
Mobile = 1 ;
// object is rotateable? adjust to ground, if in horizontal movement or not attached to the center vertex
if ( Def - > Rotateable & & Shape . AttachMat ! = MNone & & ( ! ! xdir | | Def - > Shape . VtxX [ Shape . iAttachVtx ] ) )
AdjustWalkRotation ( 20 , 20 , 100 ) ;
else
rdir = 0 ;
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_KNEEL :
ydir = 0 ;
Mobile = 1 ;
break ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_SCALE :
{
int ComDir = Action . ComDir ;
2012-06-18 23:40:37 +00:00
if ( Shape . CheckScaleToWalk ( GetX ( ) , GetY ( ) ) )
{
ObjectActionWalk ( this ) ;
return ;
}
2012-06-08 14:17:42 +00:00
if ( ( Action . Dir = = DIR_Left & & ComDir = = COMD_Left ) | | ( Action . Dir = = DIR_Right & & ComDir = = COMD_Right ) )
{
2012-10-13 16:03:20 +00:00
ComDir = COMD_Up ;
2012-06-08 14:17:42 +00:00
}
2010-03-28 18:58:01 +00:00
switch ( ComDir )
{
case COMD_Up : case COMD_UpRight : case COMD_UpLeft :
2012-07-15 19:47:50 +00:00
if ( ydir > 0 ) ydir - = decel ;
else ydir - = accel ;
if ( ydir < - limit ) ydir = - limit ; break ;
2010-03-28 18:58:01 +00:00
case COMD_Down : case COMD_DownRight : case COMD_DownLeft :
2012-07-15 19:47:50 +00:00
if ( ydir < 0 ) ydir + = decel ;
else ydir + = accel ;
if ( ydir > + limit ) ydir = + limit ; break ;
2010-03-28 18:58:01 +00:00
case COMD_Left : case COMD_Right : case COMD_Stop :
2012-07-15 19:47:50 +00:00
if ( ydir < 0 ) ydir + = decel ;
if ( ydir > 0 ) ydir - = decel ;
if ( ( ydir > - decel ) & & ( ydir < + decel ) ) ydir = 0 ;
2010-03-28 18:58:01 +00:00
break ;
}
iPhaseAdvance = 0 ;
if ( ydir < 0 ) iPhaseAdvance = - fixtoi ( ydir * 14 ) ;
if ( ydir > 0 ) iPhaseAdvance = + fixtoi ( ydir * 14 ) ;
xdir = 0 ;
Mobile = 1 ;
break ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_HANGLE :
switch ( Action . ComDir )
{
case COMD_Left : case COMD_UpLeft : case COMD_DownLeft :
2012-07-15 19:47:50 +00:00
if ( xdir > 0 ) xdir - = decel ;
else xdir - = accel ;
if ( xdir < - limit ) xdir = - limit ;
2010-03-28 18:58:01 +00:00
break ;
case COMD_Right : case COMD_UpRight : case COMD_DownRight :
2012-07-15 19:47:50 +00:00
if ( xdir < 0 ) xdir + = decel ;
else xdir + = accel ;
if ( xdir > + limit ) xdir = + limit ;
2010-03-28 18:58:01 +00:00
break ;
case COMD_Up :
2012-07-15 19:47:50 +00:00
if ( Action . Dir = = DIR_Left )
if ( xdir > 0 ) xdir - = decel ;
else xdir - = accel ;
else
if ( xdir < 0 ) xdir + = decel ;
else xdir + = accel ;
if ( xdir < - limit ) xdir = - limit ;
if ( xdir > + limit ) xdir = + limit ;
2010-08-19 16:20:27 +00:00
break ;
2010-03-28 18:58:01 +00:00
case COMD_Stop : case COMD_Down :
2012-07-15 19:47:50 +00:00
if ( xdir < 0 ) xdir + = decel ;
if ( xdir > 0 ) xdir - = decel ;
if ( ( xdir > - decel ) & & ( xdir < + decel ) ) xdir = 0 ;
2010-03-28 18:58:01 +00:00
break ;
}
iPhaseAdvance = 0 ;
if ( xdir < 0 ) { iPhaseAdvance = - fixtoi ( xdir * 10 ) ; SetDir ( DIR_Left ) ; }
if ( xdir > 0 ) { iPhaseAdvance = + fixtoi ( xdir * 10 ) ; SetDir ( DIR_Right ) ; }
ydir = 0 ;
Mobile = 1 ;
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_FLIGHT :
// Contained: fall out (one try only)
if ( ! : : Game . iTick10 )
if ( Contained )
2010-02-09 21:29:48 +00:00
{
2010-03-28 18:58:01 +00:00
StopActionDelayCommand ( this ) ;
SetCommand ( C4CMD_Exit ) ;
2010-02-09 21:29:48 +00:00
}
2010-03-28 18:58:01 +00:00
switch ( Action . ComDir )
{
case COMD_Left : case COMD_UpLeft : case COMD_DownLeft :
2015-11-15 12:53:01 +00:00
xdir - = std : : max ( std : : min ( limit + xdir , xdir > 0 ? decel : accel ) , itofix ( 0 ) ) ;
2009-05-08 13:28:41 +00:00
break ;
2010-03-28 18:58:01 +00:00
case COMD_Right : case COMD_UpRight : case COMD_DownRight :
2015-11-15 12:53:01 +00:00
xdir + = std : : max ( std : : min ( limit - xdir , xdir < 0 ? decel : accel ) , itofix ( 0 ) ) ;
2010-03-28 18:58:01 +00:00
break ;
}
// Gravity/mobile
DoGravity ( this ) ;
Mobile = 1 ;
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_DIG :
{
2012-06-18 23:40:37 +00:00
int32_t smpx = GetX ( ) , smpy = GetY ( ) ;
2010-03-28 18:58:01 +00:00
bool fAttachOK = false ;
if ( Action . t_attach & CNAT_Bottom & & Shape . Attach ( smpx , smpy , CNAT_Bottom ) ) fAttachOK = true ;
else if ( Action . t_attach & CNAT_Left & & Shape . Attach ( smpx , smpy , CNAT_Left ) ) { fAttachOK = true ; }
else if ( Action . t_attach & CNAT_Right & & Shape . Attach ( smpx , smpy , CNAT_Right ) ) { fAttachOK = true ; }
else if ( Action . t_attach & CNAT_Top & & Shape . Attach ( smpx , smpy , CNAT_Top ) ) fAttachOK = true ;
if ( ! fAttachOK )
{ ObjectComStopDig ( this ) ; return ; }
2011-07-05 10:47:07 +00:00
iPhaseAdvance = 40 * limit ;
2010-03-28 18:58:01 +00:00
if ( xdir < 0 ) SetDir ( DIR_Left ) ; else if ( xdir > 0 ) SetDir ( DIR_Right ) ;
Action . t_attach = CNAT_None ;
Mobile = 1 ;
break ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_SWIM :
// ComDir changes xdir/ydir
switch ( Action . ComDir )
{
2010-12-11 22:14:30 +00:00
case COMD_Up : ydir - = accel ; break ;
case COMD_UpRight : ydir - = accel ; xdir + = accel ; break ;
case COMD_Right : xdir + = accel ; break ;
case COMD_DownRight : ydir + = accel ; xdir + = accel ; break ;
case COMD_Down : ydir + = accel ; break ;
case COMD_DownLeft : ydir + = accel ; xdir - = accel ; break ;
case COMD_Left : xdir - = accel ; break ;
case COMD_UpLeft : ydir - = accel ; xdir - = accel ; break ;
2010-03-28 18:58:01 +00:00
case COMD_Stop :
2011-07-06 17:11:12 +00:00
if ( xdir < 0 ) xdir + = decel ;
if ( xdir > 0 ) xdir - = decel ;
if ( ( xdir > - decel ) & & ( xdir < + decel ) ) xdir = 0 ;
if ( ydir < 0 ) ydir + = decel ;
if ( ydir > 0 ) ydir - = decel ;
if ( ( ydir > - decel ) & & ( ydir < + decel ) ) ydir = 0 ;
2010-03-28 18:58:01 +00:00
break ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Out of liquid check
if ( ! InLiquid )
{
// Just above liquid: move down
2010-12-11 22:14:30 +00:00
if ( GBackLiquid ( GetX ( ) , GetY ( ) + 1 + Def - > Float * Con / FullCon - 1 ) ) ydir = + accel ;
2010-03-28 18:58:01 +00:00
// Free fall: walk
else { ObjectActionWalk ( this ) ; return ; }
}
2009-05-08 13:28:41 +00:00
2011-07-06 17:11:12 +00:00
// xdir/ydir bounds, don't apply if COMD_None
if ( Action . ComDir ! = COMD_None )
{
if ( ydir < - limit ) ydir = - limit ; if ( ydir > + limit ) ydir = + limit ;
if ( xdir > + limit ) xdir = + limit ; if ( xdir < - limit ) xdir = - limit ;
}
2010-03-28 18:58:01 +00:00
// Surface dir bound
if ( ! GBackLiquid ( GetX ( ) , GetY ( ) - 1 + Def - > Float * Con / FullCon - 1 ) ) if ( ydir < 0 ) ydir = 0 ;
// Dir, Phase, Attach
if ( xdir < 0 ) SetDir ( DIR_Left ) ;
if ( xdir > 0 ) SetDir ( DIR_Right ) ;
2011-07-05 10:47:07 +00:00
iPhaseAdvance = fixtoi ( limit * 10 ) ;
2010-03-28 18:58:01 +00:00
Mobile = 1 ;
2010-03-27 16:05:02 +00:00
2010-03-28 18:58:01 +00:00
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_THROW :
Mobile = 1 ;
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_BRIDGE :
{
if ( ! DoBridge ( this ) ) return ;
switch ( Action . ComDir )
{
case COMD_Left : case COMD_UpLeft : SetDir ( DIR_Left ) ; break ;
case COMD_Right : case COMD_UpRight : SetDir ( DIR_Right ) ; break ;
}
ydir = 0 ; xdir = 0 ;
Mobile = 1 ;
}
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_PUSH :
// No target
if ( ! Action . Target ) { StopActionDelayCommand ( this ) ; return ; }
// Inside target
if ( Contained = = Action . Target ) { StopActionDelayCommand ( this ) ; return ; }
// Target pushing force
bool fStraighten ;
iTXDir = 0 ; fStraighten = false ;
switch ( Action . ComDir )
{
2011-07-05 10:47:07 +00:00
case COMD_Left : case COMD_DownLeft : iTXDir = - limit ; break ;
case COMD_UpLeft : fStraighten = 1 ; iTXDir = - limit ; break ;
case COMD_Right : case COMD_DownRight : iTXDir = + limit ; break ;
case COMD_UpRight : fStraighten = 1 ; iTXDir = + limit ; break ;
2010-03-28 18:58:01 +00:00
case COMD_Up : fStraighten = 1 ; break ;
case COMD_Stop : case COMD_Down : iTXDir = 0 ; break ;
}
// Push object
2010-12-11 22:28:01 +00:00
if ( ! Action . Target - > Push ( iTXDir , accel , fStraighten ) )
2010-03-28 18:58:01 +00:00
{ StopActionDelayCommand ( this ) ; return ; }
// Set target controller
Action . Target - > Controller = Controller ;
// ObjectAction got hold check
2015-11-15 12:53:01 +00:00
iPushDistance = std : : max ( Shape . Wdt / 2 - 8 , 0 ) ;
2010-03-28 18:58:01 +00:00
iPushRange = iPushDistance + 10 ;
int32_t sax , say , sawdt , sahgt ;
Action . Target - > GetArea ( sax , say , sawdt , sahgt ) ;
// Object lost
if ( ! Inside ( GetX ( ) - sax , - iPushRange , sawdt - 1 + iPushRange )
| | ! Inside ( GetY ( ) - say , - iPushRange , sahgt - 1 + iPushRange ) )
{
2016-01-15 13:54:03 +00:00
C4Object * prev_target = Action . Target ;
2010-03-28 18:58:01 +00:00
// Wait command (why, anyway?)
StopActionDelayCommand ( this ) ;
// Grab lost action
2016-01-15 13:54:03 +00:00
GrabLost ( this , prev_target ) ;
2010-03-28 18:58:01 +00:00
// Done
return ;
}
// Follow object (full xdir reset)
// Vertical follow: If object moves out at top, assume it's being pushed upwards and the Clonk must run after it
if ( GetY ( ) - iPushDistance > say + sahgt & & iTXDir ) { if ( iTXDir > 0 ) sax + = sawdt / 2 ; sawdt / = 2 ; }
// Horizontal follow
2015-02-12 22:05:55 +00:00
iTargetX = Clamp ( GetX ( ) , sax - iPushDistance , sax + sawdt - 1 + iPushDistance ) ;
2010-03-28 18:58:01 +00:00
if ( GetX ( ) = = iTargetX ) xdir = 0 ;
2011-07-05 10:47:07 +00:00
else { if ( GetX ( ) < iTargetX ) xdir = + limit ; if ( GetX ( ) > iTargetX ) xdir = - limit ; }
2010-03-28 18:58:01 +00:00
// Phase by XDir
if ( xdir < 0 ) { iPhaseAdvance = - fixtoi ( xdir * 10 ) ; SetDir ( DIR_Left ) ; }
if ( xdir > 0 ) { iPhaseAdvance = + fixtoi ( xdir * 10 ) ; SetDir ( DIR_Right ) ; }
// No YDir
ydir = 0 ;
Mobile = 1 ;
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_PULL :
// No target
if ( ! Action . Target ) { StopActionDelayCommand ( this ) ; return ; }
// Inside target
if ( Contained = = Action . Target ) { StopActionDelayCommand ( this ) ; return ; }
// Target contained
if ( Action . Target - > Contained ) { StopActionDelayCommand ( this ) ; return ; }
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
int32_t iPullDistance ;
int32_t iPullX ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
iPullDistance = Action . Target - > Shape . Wdt / 2 + Shape . Wdt / 2 ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
iTargetX = GetX ( ) ;
if ( Action . ComDir = = COMD_Right ) iTargetX = Action . Target - > GetX ( ) + iPullDistance ;
if ( Action . ComDir = = COMD_Left ) iTargetX = Action . Target - > GetX ( ) - iPullDistance ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
iPullX = Action . Target - > GetX ( ) ;
if ( Action . ComDir = = COMD_Right ) iPullX = GetX ( ) - iPullDistance ;
if ( Action . ComDir = = COMD_Left ) iPullX = GetX ( ) + iPullDistance ;
2009-05-08 13:28:41 +00:00
2011-07-05 10:47:07 +00:00
fWalk = limit ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
fMove = 0 ;
if ( Action . ComDir = = COMD_Right ) fMove = + fWalk ;
if ( Action . ComDir = = COMD_Left ) fMove = - fWalk ;
2009-05-08 13:28:41 +00:00
2015-02-12 22:05:55 +00:00
iTXDir = fMove + fWalk * Clamp < int32_t > ( iPullX - Action . Target - > GetX ( ) , - 10 , + 10 ) / 10 ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Push object
2010-12-11 22:28:01 +00:00
if ( ! Action . Target - > Push ( iTXDir , accel , false ) )
2010-03-28 18:58:01 +00:00
{ StopActionDelayCommand ( this ) ; return ; }
// Set target controller
Action . Target - > Controller = Controller ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Train pulling: com dir transfer
if ( ( Action . Target - > GetProcedure ( ) = = DFA_WALK )
| | ( Action . Target - > GetProcedure ( ) = = DFA_PULL ) )
{
Action . Target - > Action . ComDir = COMD_Stop ;
if ( iTXDir < 0 ) Action . Target - > Action . ComDir = COMD_Left ;
if ( iTXDir > 0 ) Action . Target - > Action . ComDir = COMD_Right ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Pulling range
2015-11-15 12:53:01 +00:00
iPushDistance = std : : max ( Shape . Wdt / 2 - 8 , 0 ) ;
2010-03-28 18:58:01 +00:00
iPushRange = iPushDistance + 20 ;
Action . Target - > GetArea ( sax , say , sawdt , sahgt ) ;
// Object lost
if ( ! Inside ( GetX ( ) - sax , - iPushRange , sawdt - 1 + iPushRange )
| | ! Inside ( GetY ( ) - say , - iPushRange , sahgt - 1 + iPushRange ) )
{
2016-01-15 13:54:03 +00:00
// Remember target. Will be lost on changing action.
C4Object * prev_target = Action . Target ;
2010-03-28 18:58:01 +00:00
// Wait command (why, anyway?)
StopActionDelayCommand ( this ) ;
// Grab lost action
2016-01-15 13:54:03 +00:00
GrabLost ( this , prev_target ) ;
2010-03-28 18:58:01 +00:00
// Lose target
Action . Target = NULL ;
// Done
return ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Move to pulling position
2015-02-12 22:05:55 +00:00
xdir = fMove + fWalk * Clamp < int32_t > ( iTargetX - GetX ( ) , - 10 , + 10 ) / 10 ;
2010-03-28 18:58:01 +00:00
// Phase by XDir
iPhaseAdvance = 0 ;
if ( xdir < 0 ) { iPhaseAdvance = - fixtoi ( xdir * 10 ) ; SetDir ( DIR_Left ) ; }
if ( xdir > 0 ) { iPhaseAdvance = + fixtoi ( xdir * 10 ) ; SetDir ( DIR_Right ) ; }
// No YDir
ydir = 0 ;
Mobile = 1 ;
2010-03-27 16:05:02 +00:00
2010-03-28 18:58:01 +00:00
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_LIFT :
// Valid check
if ( ! Action . Target ) { SetAction ( 0 ) ; return ; }
// Target lifting force
lftspeed = itofix ( 2 ) ; tydir = 0 ;
switch ( Action . ComDir )
{
case COMD_Up : tydir = - lftspeed ; break ;
case COMD_Stop : tydir = - GravAccel ; break ;
case COMD_Down : tydir = + lftspeed ; break ;
}
// Lift object
2010-05-19 03:19:49 +00:00
if ( ! Action . Target - > Lift ( tydir , C4REAL100 ( 50 ) ) )
2010-03-28 18:58:01 +00:00
{ SetAction ( 0 ) ; return ; }
// Check LiftTop
if ( Def - > LiftTop )
if ( Action . Target - > GetY ( ) < = ( GetY ( ) + Def - > LiftTop ) )
if ( Action . ComDir = = COMD_Up )
Call ( PSF_LiftTop ) ;
// General
DoGravity ( this ) ;
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_FLOAT :
// ComDir changes xdir/ydir
switch ( Action . ComDir )
{
2013-10-07 17:15:46 +00:00
case COMD_Up :
ydir - = accel ;
if ( xdir < 0 ) xdir + = decel ;
if ( xdir > 0 ) xdir - = decel ;
if ( ( xdir > - decel ) & & ( xdir < + decel ) ) xdir = 0 ;
break ;
case COMD_UpRight :
ydir - = accel ; xdir + = accel ; break ;
case COMD_Right :
xdir + = accel ;
if ( ydir < 0 ) ydir + = decel ;
if ( ydir > 0 ) ydir - = decel ;
if ( ( ydir > - decel ) & & ( ydir < + decel ) ) ydir = 0 ;
break ;
case COMD_DownRight :
ydir + = accel ; xdir + = accel ; break ;
case COMD_Down :
ydir + = accel ;
if ( xdir < 0 ) xdir + = decel ;
if ( xdir > 0 ) xdir - = decel ;
if ( ( xdir > - decel ) & & ( xdir < + decel ) ) xdir = 0 ;
break ;
case COMD_DownLeft :
ydir + = accel ; xdir - = accel ; break ;
case COMD_Left :
xdir - = accel ;
if ( ydir < 0 ) ydir + = decel ;
if ( ydir > 0 ) ydir - = decel ;
if ( ( ydir > - decel ) & & ( ydir < + decel ) ) ydir = 0 ;
break ;
case COMD_UpLeft :
ydir - = accel ; xdir - = accel ; break ;
2011-07-05 10:47:07 +00:00
case COMD_Stop :
2011-07-06 17:11:12 +00:00
if ( xdir < 0 ) xdir + = decel ;
if ( xdir > 0 ) xdir - = decel ;
if ( ( xdir > - decel ) & & ( xdir < + decel ) ) xdir = 0 ;
if ( ydir < 0 ) ydir + = decel ;
if ( ydir > 0 ) ydir - = decel ;
if ( ( ydir > - decel ) & & ( ydir < + decel ) ) ydir = 0 ;
2011-07-05 10:47:07 +00:00
break ;
2010-03-28 18:58:01 +00:00
}
2011-07-06 16:13:39 +00:00
// xdir/ydir bounds, don't apply if COMD_None
if ( Action . ComDir ! = COMD_None )
{
if ( ydir < - limit ) ydir = - limit ; if ( ydir > + limit ) ydir = + limit ;
if ( xdir > + limit ) xdir = + limit ; if ( xdir < - limit ) xdir = - limit ;
}
2011-07-05 10:47:07 +00:00
2010-03-28 18:58:01 +00:00
Mobile = 1 ;
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ATTACH: Force position to target object
2009-05-08 13:28:41 +00:00
// own vertex index is determined by high-order byte of action data
// target vertex index is determined by low-order byte of action data
2010-03-28 18:58:01 +00:00
case DFA_ATTACH :
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// No target
if ( ! Action . Target )
{
if ( Status )
{
SetAction ( 0 ) ;
Call ( PSF_AttachTargetLost ) ;
}
return ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Target incomplete and no incomplete activity
if ( ! ( Action . Target - > OCF & OCF_FullCon ) )
if ( ! Action . Target - > Def - > IncompleteActivity )
{ SetAction ( 0 ) ; return ; }
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Force containment
if ( Action . Target - > Contained ! = Contained )
{
if ( Action . Target - > Contained )
Enter ( Action . Target - > Contained ) ;
else
2013-05-25 12:59:58 +00:00
Exit ( GetX ( ) , GetY ( ) , GetR ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
2013-10-12 21:36:42 +00:00
// Object might have detached in Enter/Exit call
if ( ! Action . Target ) break ;
2012-12-06 19:30:35 +00:00
// Move position (so objects on solidmask move)
MovePosition ( Action . Target - > fix_x + Action . Target - > Shape . VtxX [ Action . Data & 255 ]
- Shape . VtxX [ Action . Data > > 8 ] - fix_x ,
2010-10-10 16:46:23 +00:00
Action . Target - > fix_y + Action . Target - > Shape . VtxY [ Action . Data & 255 ]
2012-12-06 19:30:35 +00:00
- Shape . VtxY [ Action . Data > > 8 ] - fix_y ) ;
2010-03-28 18:58:01 +00:00
// must zero motion...
xdir = ydir = 0 ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
case DFA_CONNECT :
{
2013-05-09 10:02:44 +00:00
bool fBroke = false ;
2016-03-22 20:53:32 +00:00
bool fLineChange = false ;
2009-05-08 13:28:41 +00:00
2013-05-09 10:02:44 +00:00
// Line destruction check: Target missing or incomplete
if ( ! Action . Target | | ( Action . Target - > Con < FullCon ) ) fBroke = true ;
if ( ! Action . Target2 | | ( Action . Target2 - > Con < FullCon ) ) fBroke = true ;
if ( fBroke )
{
2016-03-22 17:58:55 +00:00
Call ( PSF_OnLineBreak , & C4AulParSet ( true ) ) ;
2013-05-09 10:02:44 +00:00
AssignRemoval ( ) ;
return ;
}
// Movement by Target
2010-12-21 18:22:06 +00:00
// Connect to attach vertex
2013-05-09 10:02:44 +00:00
C4Value lineAttachV ; C4ValueArray * lineAttach ;
2010-12-21 18:22:06 +00:00
Action . Target - > GetProperty ( P_LineAttach , & lineAttachV ) ;
2013-05-09 10:02:44 +00:00
lineAttach = lineAttachV . getArray ( ) ;
int32_t iConnectX1 , iConnectY1 ;
iConnectX1 = Action . Target - > GetX ( ) ;
iConnectY1 = Action . Target - > GetY ( ) ;
2010-12-21 18:22:06 +00:00
if ( lineAttach )
2010-03-28 18:58:01 +00:00
{
2013-05-09 10:02:44 +00:00
iConnectX1 + = lineAttach - > GetItem ( 0 ) . getInt ( ) ;
iConnectY1 + = lineAttach - > GetItem ( 1 ) . getInt ( ) ;
2010-03-28 18:58:01 +00:00
}
2013-05-09 10:02:44 +00:00
if ( ( iConnectX1 ! = Shape . VtxX [ 0 ] ) | | ( iConnectY1 ! = Shape . VtxY [ 0 ] ) )
2010-03-28 18:58:01 +00:00
{
// Regular wrapping line
if ( Def - > LineIntersect = = 0 )
2013-05-09 10:02:44 +00:00
if ( ! Shape . LineConnect ( iConnectX1 , iConnectY1 , 0 , + 1 ,
Shape . VtxX [ 0 ] , Shape . VtxY [ 0 ] ) ) fBroke = true ;
2010-03-28 18:58:01 +00:00
// No-intersection line
if ( Def - > LineIntersect = = 1 )
2013-05-09 10:02:44 +00:00
{ Shape . VtxX [ 0 ] = iConnectX1 ; Shape . VtxY [ 0 ] = iConnectY1 ; }
2016-03-22 20:53:32 +00:00
fLineChange = true ;
2010-03-28 18:58:01 +00:00
}
2013-05-09 10:02:44 +00:00
// Movement by Target2
2010-12-21 18:22:06 +00:00
// Connect to attach vertex
Action . Target2 - > GetProperty ( P_LineAttach , & lineAttachV ) ;
2013-05-09 10:02:44 +00:00
lineAttach = lineAttachV . getArray ( ) ;
int32_t iConnectX2 , iConnectY2 ;
iConnectX2 = Action . Target2 - > GetX ( ) ;
iConnectY2 = Action . Target2 - > GetY ( ) ;
2010-12-21 18:22:06 +00:00
if ( lineAttach )
2010-03-28 18:58:01 +00:00
{
2013-05-09 10:02:44 +00:00
iConnectX2 + = lineAttach - > GetItem ( 0 ) . getInt ( ) ;
iConnectY2 + = lineAttach - > GetItem ( 1 ) . getInt ( ) ;
2010-03-28 18:58:01 +00:00
}
2013-05-09 10:02:44 +00:00
if ( ( iConnectX2 ! = Shape . VtxX [ Shape . VtxNum - 1 ] ) | | ( iConnectY2 ! = Shape . VtxY [ Shape . VtxNum - 1 ] ) )
2010-03-28 18:58:01 +00:00
{
// Regular wrapping line
if ( Def - > LineIntersect = = 0 )
2013-05-09 10:02:44 +00:00
if ( ! Shape . LineConnect ( iConnectX2 , iConnectY2 , Shape . VtxNum - 1 , - 1 ,
Shape . VtxX [ Shape . VtxNum - 1 ] , Shape . VtxY [ Shape . VtxNum - 1 ] ) ) fBroke = true ;
2010-03-28 18:58:01 +00:00
// No-intersection line
if ( Def - > LineIntersect = = 1 )
2013-05-09 10:02:44 +00:00
{ Shape . VtxX [ Shape . VtxNum - 1 ] = iConnectX2 ; Shape . VtxY [ Shape . VtxNum - 1 ] = iConnectY2 ; }
2016-03-22 20:53:32 +00:00
fLineChange = true ;
2013-05-09 10:02:44 +00:00
}
2009-05-08 13:28:41 +00:00
2013-05-09 10:02:44 +00:00
// Line fBroke
if ( fBroke )
{
2016-03-22 17:58:55 +00:00
Call ( PSF_OnLineBreak , 0 ) ;
2013-05-09 10:02:44 +00:00
AssignRemoval ( ) ;
return ;
}
2009-05-08 13:28:41 +00:00
2013-05-09 10:02:44 +00:00
// Reduce line segments
if ( ! : : Game . iTick35 )
2016-03-22 20:53:32 +00:00
if ( ReduceLineSegments ( Shape , ! : : Game . iTick2 ) )
fLineChange = true ;
// Line change callback
if ( fLineChange )
Call ( PSF_OnLineChange ) ;
2013-05-09 10:02:44 +00:00
}
2010-03-28 18:58:01 +00:00
break ;
2010-03-27 16:05:02 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2010-03-28 18:58:01 +00:00
default :
// Attach
2012-06-16 01:01:47 +00:00
if ( Action . t_attach )
2010-03-28 18:58:01 +00:00
{
xdir = ydir = 0 ;
Mobile = 1 ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
// Free gravity
else
DoGravity ( this ) ;
break ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}
2009-05-08 13:28:41 +00:00
2009-04-12 12:03:14 +00:00
// Phase Advance (zero delay means no phase advance)
2010-03-18 23:04:29 +00:00
if ( pActionDef - > GetPropertyInt ( P_Delay ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Action . PhaseDelay + = iPhaseAdvance ;
2010-03-18 23:04:29 +00:00
if ( Action . PhaseDelay > = pActionDef - > GetPropertyInt ( P_Delay ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Advance Phase
Action . PhaseDelay = 0 ;
2010-03-18 23:04:29 +00:00
Action . Phase + = pActionDef - > GetPropertyInt ( P_Step ) ;
2009-05-08 13:28:41 +00:00
// Phase call
2010-03-18 23:04:29 +00:00
if ( pActionDef - > GetPropertyStr ( P_PhaseCall ) )
2010-03-28 18:58:01 +00:00
{
2010-03-18 23:04:29 +00:00
Call ( pActionDef - > GetPropertyStr ( P_PhaseCall ) - > GetCStr ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Phase end
2010-03-28 18:58:01 +00:00
if ( Action . Phase > = pActionDef - > GetPropertyInt ( P_Length ) )
{
2010-03-18 23:04:29 +00:00
C4String * next_action = pActionDef - > GetPropertyStr ( P_NextAction ) ;
2009-12-21 12:50:42 +00:00
// Keep current action if there is no NextAction
if ( ! next_action )
Action . Phase = 0 ;
2009-05-08 13:28:41 +00:00
// set new action if it's not Hold
2010-12-06 15:24:41 +00:00
else if ( next_action = = & Strings . P [ P_Hold ] )
2010-03-28 18:58:01 +00:00
{
2010-03-18 23:04:29 +00:00
Action . Phase = pActionDef - > GetPropertyInt ( P_Length ) - 1 ;
Action . PhaseDelay = pActionDef - > GetPropertyInt ( P_Delay ) - 1 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Set new action
2009-12-21 12:50:42 +00:00
SetActionByName ( next_action , NULL , NULL , SAC_StartCall | SAC_EndCall ) ;
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
2009-04-12 12:03:14 +00:00
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : SetOwner ( int32_t iOwner )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check valid owner
2009-08-15 18:50:32 +00:00
if ( ! ( ValidPlr ( iOwner ) | | iOwner = = NO_OWNER ) ) return false ;
2009-05-08 13:28:41 +00:00
// always set color, even if no owner-change is done
if ( iOwner ! = NO_OWNER )
if ( GetGraphics ( ) - > IsColorByOwner ( ) )
2010-03-28 18:58:01 +00:00
{
2009-06-12 23:09:32 +00:00
Color = : : Players . Get ( iOwner ) - > ColorDw ;
2009-05-08 13:28:41 +00:00
UpdateFace ( false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// no change?
2009-08-15 18:50:32 +00:00
if ( Owner = = iOwner ) return true ;
2009-05-08 13:28:41 +00:00
// set new owner
int32_t iOldOwner = Owner ;
2010-03-27 16:05:02 +00:00
Owner = iOwner ;
2009-05-08 13:28:41 +00:00
// this automatically updates controller
Controller = Owner ;
// script callback
2014-05-30 23:03:23 +00:00
Call ( PSF_OnOwnerChanged , & C4AulParSet ( Owner , iOldOwner ) ) ;
2009-05-08 13:28:41 +00:00
// done
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-01-02 00:06:00 +00:00
bool C4Object : : SetLightRange ( int32_t iToRange , int32_t iToFadeoutRange )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// set new range
2015-01-02 00:06:00 +00:00
lightRange = iToRange ;
lightFadeoutRange = iToFadeoutRange ;
2009-05-08 13:28:41 +00:00
// resort into player's FoW-repeller-list
2015-01-02 00:06:00 +00:00
UpdateLight ( ) ;
2009-05-08 13:28:41 +00:00
// success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-07-02 18:59:20 +00:00
bool C4Object : : SetLightColor ( uint32_t iValue )
Colored lights
The color of object lights can now be changed. This includes the following changes:
- added light test scenario, based on DarkCastle, with some lights,
- new functions SetLightColor() and GetLightColor() with C4Script documentation,
- third drawing pass for rendering the light color, the drawing passes are now referenced by enum,
- the blending of light from multiple colored light sources works correctly with alpha blending,
- light color value affects the intensity of the light,
- alpha blending of the light depends on color value and lightness. This means that brighter (= more value) and lighter (= more whiteish) light will be preferred in blending over other lights,
- the object light color is rendered to the lower half of the fow light texture now,
- the shader accesses the brightness/direction information and color information correctly,
The patch was created from the following commits:
dab898a SetLightColor()
f57286e Color texture experiment
d0702f5 Dynamic color
fa14cdf Light test scenario
f99203d Alternate lights
474bade Bugfixes
3113698 Brightness handled better
516fb21 GetLightColor
1d91ec9 Improvements
3cfbf6c Documentation
95ec185 Improvements: Light Shader
a63bffc Scope of alpha
20c7ca0 Improvement: C4FoWLight
17d9123 Undo code style
d79411b Cleaner code
(cherry picked from commit 36dec610e36860b88417e91ce727250673bc2ec2)
Conflicts:
src/landscape/fow/C4FoWRegion.cpp, merged
2015-06-28 18:58:53 +00:00
{
// set new color value
lightColor = iValue ;
// resort into player's FoW-repeller-list
UpdateLight ( ) ;
// success
return true ;
}
2015-01-02 00:06:00 +00:00
void C4Object : : UpdateLight ( )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( Landscape . HasFoW ( ) ) Landscape . GetFoW ( ) - > Add ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-08-28 01:44:23 +00:00
void C4Object : : SetAudibilityAt ( C4TargetFacet & cgo , int32_t iX , int32_t iY , int32_t player )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// target pos (parallax)
2010-09-23 01:51:08 +00:00
float offX , offY , newzoom ;
2010-09-24 17:51:34 +00:00
GetDrawPosition ( cgo , iX , iY , cgo . Zoom , offX , offY , newzoom ) ;
2015-08-28 01:44:23 +00:00
int32_t audible_at_pos = Clamp ( 100 - 100 * Distance ( cgo . X + cgo . Wdt / 2 , cgo . Y + cgo . Hgt / 2 , offX , offY ) / 700 , 0 , 100 ) ;
if ( audible_at_pos > Audible )
{
Audible = audible_at_pos ;
AudiblePan = Clamp < int > ( 200 * ( offX - cgo . X - ( cgo . Wdt / 2 ) ) / cgo . Wdt , - 100 , 100 ) ;
AudiblePlayer = player ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
bool C4Object : : IsVisible ( int32_t iForPlr , bool fAsOverlay ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
bool fDraw ;
2009-07-22 14:31:09 +00:00
C4Value vis ;
2010-12-06 15:19:15 +00:00
if ( ! GetProperty ( P_Visibility , & vis ) )
2009-07-22 14:31:09 +00:00
return true ;
int32_t Visibility ;
C4ValueArray * parameters = vis . getArray ( ) ;
if ( parameters & & parameters - > GetSize ( ) )
{
Visibility = parameters - > GetItem ( 0 ) . getInt ( ) ;
2010-03-28 18:58:01 +00:00
}
else
{
2009-07-22 14:31:09 +00:00
Visibility = vis . getInt ( ) ;
}
2009-05-08 13:28:41 +00:00
// check layer
2010-03-30 21:08:15 +00:00
if ( Layer & & Layer ! = this & & ! fAsOverlay )
2009-07-22 14:31:09 +00:00
{
2010-03-30 21:08:15 +00:00
fDraw = Layer - > IsVisible ( iForPlr , false ) ;
if ( Layer - > GetPropertyInt ( P_Visibility ) & VIS_LayerToggle ) fDraw = ! fDraw ;
2009-05-08 13:28:41 +00:00
if ( ! fDraw ) return false ;
2009-07-22 14:31:09 +00:00
}
2009-05-08 13:28:41 +00:00
// no flags set?
if ( ! Visibility ) return true ;
2011-09-05 15:13:44 +00:00
// check overlay
if ( Visibility & VIS_OverlayOnly )
{
if ( ! fAsOverlay ) return false ;
if ( Visibility = = VIS_OverlayOnly ) return true ;
}
2016-08-02 04:13:53 +00:00
// editor visibility
if ( : : Application . isEditor )
{
if ( Visibility & VIS_Editor ) return true ;
}
2009-05-08 13:28:41 +00:00
// check visibility
fDraw = false ;
if ( Visibility & VIS_Owner ) fDraw = fDraw | | ( iForPlr = = Owner ) ;
if ( iForPlr ! = NO_OWNER )
2009-07-22 14:31:09 +00:00
{
2009-05-08 13:28:41 +00:00
// check all
2010-03-28 18:58:01 +00:00
if ( Visibility & VIS_Allies ) fDraw = fDraw | | ( iForPlr ! = Owner & & ! Hostile ( iForPlr , Owner ) ) ;
if ( Visibility & VIS_Enemies ) fDraw = fDraw | | ( iForPlr ! = Owner & & Hostile ( iForPlr , Owner ) ) ;
if ( parameters )
{
if ( Visibility & VIS_Select ) fDraw = fDraw | | parameters - > GetItem ( 1 + iForPlr ) . getBool ( ) ;
2009-05-08 13:28:41 +00:00
}
2009-07-22 14:31:09 +00:00
}
2009-05-08 13:28:41 +00:00
else fDraw = fDraw | | ( Visibility & VIS_God ) ;
return fDraw ;
2009-07-22 14:31:09 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
bool C4Object : : IsInLiquidCheck ( ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return GBackLiquid ( GetX ( ) , GetY ( ) + Def - > Float * Con / FullCon - 1 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : SetRotation ( int32_t nr )
{
2010-03-28 18:58:01 +00:00
while ( nr < 0 ) nr + = 360 ; nr % = 360 ;
2009-05-08 13:28:41 +00:00
// remove solid mask
2010-04-20 20:38:18 +00:00
if ( pSolidMaskData ) pSolidMaskData - > Remove ( false ) ;
2009-05-08 13:28:41 +00:00
// set rotation
2010-03-27 16:05:02 +00:00
fix_r = itofix ( nr ) ;
2009-05-08 13:28:41 +00:00
// Update face
UpdateFace ( true ) ;
}
2013-08-31 21:23:35 +00:00
void C4Object : : PrepareDrawing ( ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// color modulation
2011-10-03 14:30:18 +00:00
if ( ColorMod ! = 0xffffffff | | ( BlitMode & ( C4GFXBLIT_MOD2 | C4GFXBLIT_CLRSFC_MOD2 ) ) ) pDraw - > ActivateBlitModulation ( ColorMod ) ;
2009-05-08 13:28:41 +00:00
// other blit modes
2011-10-03 14:30:18 +00:00
pDraw - > SetBlitMode ( BlitMode ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
void C4Object : : FinishedDrawing ( ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// color modulation
2011-10-03 14:30:18 +00:00
pDraw - > DeactivateBlitModulation ( ) ;
2009-05-08 13:28:41 +00:00
// extra blitting flags
2011-10-03 14:30:18 +00:00
pDraw - > ResetBlitMode ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
void C4Object : : DrawSolidMask ( C4TargetFacet & cgo ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// mask must exist
if ( ! pSolidMaskData ) return ;
// draw it
pSolidMaskData - > Draw ( cgo ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateSolidMask ( bool fRestoreAttachedObjects )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// solidmask doesn't make sense with non-existant objects
// (the solidmask has already been destroyed in AssignRemoval -
// do not reset it!)
if ( ! Status ) return ;
// Determine necessity, update cSolidMask, put or remove mask
2010-04-20 16:01:40 +00:00
// Mask if enabled, fullcon, not contained
if ( SolidMask . Wdt > 0 & & Con > = FullCon & & ! Contained )
{
// Recheck and put mask
if ( ! pSolidMaskData )
{
pSolidMaskData = new C4SolidMask ( this ) ;
}
else
2010-04-20 20:38:18 +00:00
pSolidMaskData - > Remove ( false ) ;
2010-04-20 16:01:40 +00:00
pSolidMaskData - > Put ( true , NULL , fRestoreAttachedObjects ) ;
}
2009-05-08 13:28:41 +00:00
// Otherwise, remove and destroy mask
2010-04-20 16:01:40 +00:00
else if ( pSolidMaskData )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
delete pSolidMaskData ; pSolidMaskData = NULL ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : Collect ( C4Object * pObj )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Object enter container
bool fRejectCollect ;
2010-03-28 18:58:01 +00:00
if ( ! pObj - > Enter ( this , true , false , & fRejectCollect ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Cancel attach (hacky)
ObjectComCancelAttach ( pObj ) ;
// Container Collection call
2014-05-30 23:03:23 +00:00
Call ( PSF_Collection , & C4AulParSet ( pObj ) ) ;
2009-05-08 13:28:41 +00:00
// Object Hit call
if ( pObj - > Status & & pObj - > OCF & OCF_HitSpeed1 ) pObj - > Call ( PSF_Hit ) ;
if ( pObj - > Status & & pObj - > OCF & OCF_HitSpeed2 ) pObj - > Call ( PSF_Hit2 ) ;
if ( pObj - > Status & & pObj - > OCF & OCF_HitSpeed3 ) pObj - > Call ( PSF_Hit3 ) ;
// post-copy the motion of the new container
if ( pObj - > Contained = = this ) pObj - > CopyMotion ( this ) ;
// done, success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : GrabInfo ( C4Object * pFrom )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
2009-08-15 18:50:32 +00:00
if ( ! pFrom ) return false ; if ( ! Status | | ! pFrom - > Status ) return false ;
2009-05-08 13:28:41 +00:00
// even more safety (own info: success)
2010-03-28 18:58:01 +00:00
if ( pFrom = = this ) return true ;
2009-05-08 13:28:41 +00:00
// only if other object has info
2009-08-15 18:50:32 +00:00
if ( ! pFrom - > Info ) return false ;
2009-05-08 13:28:41 +00:00
// clear own info object
if ( Info )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Info - > Retire ( ) ;
ClearInfo ( Info ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// remove objects from any owning crews
2009-06-12 23:09:32 +00:00
: : Players . ClearPointers ( pFrom ) ;
: : Players . ClearPointers ( this ) ;
2009-05-08 13:28:41 +00:00
// set info
Info = pFrom - > Info ; pFrom - > ClearInfo ( pFrom - > Info ) ;
// set name
2010-10-17 20:13:12 +00:00
SetName ( Info - > Name ) ;
2009-05-08 13:28:41 +00:00
// retire from old crew
Info - > Retire ( ) ;
// if alive, recruit to new crew
if ( Alive ) Info - > Recruit ( ) ;
// make new crew member
2009-06-12 23:09:32 +00:00
C4Player * pPlr = : : Players . Get ( Owner ) ;
2009-05-08 13:28:41 +00:00
if ( pPlr ) pPlr - > MakeCrewMember ( this ) ;
// done, success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Object : : ShiftContents ( bool fShiftBack , bool fDoCalls )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get current object
C4Object * c_obj = Contents . GetObject ( ) ;
2009-08-15 18:50:32 +00:00
if ( ! c_obj ) return false ;
2009-05-08 13:28:41 +00:00
// get next/previous
2014-10-24 21:15:55 +00:00
auto it = fShiftBack ? Contents . reverse ( ) . begin ( ) : + + Contents . begin ( ) ;
while ( ! it . atEnd ( ) )
2010-03-28 18:58:01 +00:00
{
2014-10-24 21:15:55 +00:00
auto pObj = ( * it ) ;
2009-05-08 13:28:41 +00:00
// check object
if ( pObj - > Status )
if ( ! c_obj - > CanConcatPictureWith ( pObj ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// object different: shift to this
DirectComContents ( pObj , ! ! fDoCalls ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// next/prev item
2014-10-24 21:15:55 +00:00
it + + ;
2009-05-08 13:28:41 +00:00
}
2014-10-24 21:15:55 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : DirectComContents ( C4Object * pTarget , bool fDoCalls )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
if ( ! pTarget | | ! pTarget - > Status | | pTarget - > Contained ! = this ) return ;
// Desired object already at front?
if ( Contents . GetObject ( ) = = pTarget ) return ;
// select object via script?
if ( fDoCalls )
2014-05-30 23:03:23 +00:00
if ( Call ( " ~ControlContents " , & C4AulParSet ( pTarget ) ) )
2009-05-08 13:28:41 +00:00
return ;
// default action
if ( ! ( Contents . ShiftContents ( pTarget ) ) ) return ;
// Selection sound
2014-05-30 23:03:23 +00:00
if ( fDoCalls ) if ( ! Contents . GetObject ( ) - > Call ( " ~Selection " , & C4AulParSet ( this ) ) ) StartSoundEffect ( " Clonk::Action::Grab " , false , 100 , this ) ;
2009-05-08 13:28:41 +00:00
// update menu with the new item in "put" entry
if ( Menu & & Menu - > IsActive ( ) & & Menu - > IsContextMenu ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Menu - > Refill ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Done
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
void C4Object : : GetParallaxity ( int32_t * parX , int32_t * parY ) const
2009-07-22 16:03:33 +00:00
{
assert ( parX ) ; assert ( parY ) ;
* parX = 100 ; * parY = 100 ;
2011-08-19 14:50:58 +00:00
if ( Category & C4D_Foreground )
{
* parX = 0 ; * parY = 0 ;
return ;
2010-09-25 20:52:43 +00:00
}
2009-07-22 16:03:33 +00:00
if ( ! ( Category & C4D_Parallax ) ) return ;
2010-12-06 15:19:15 +00:00
C4Value parV ; GetProperty ( P_Parallaxity , & parV ) ;
2009-07-22 16:03:33 +00:00
C4ValueArray * par = parV . getArray ( ) ;
if ( ! par ) return ;
* parX = par - > GetItem ( 0 ) . getInt ( ) ;
* parY = par - > GetItem ( 1 ) . getInt ( ) ;
}
2013-03-03 18:25:18 +00:00
bool C4Object : : GetDragImage ( C4Object * * drag_object , C4Def * * drag_def ) const
2009-12-30 19:16:32 +00:00
{
// drag is possible if MouseDragImage is assigned
2010-12-06 15:19:15 +00:00
C4Value parV ; GetProperty ( P_MouseDragImage , & parV ) ;
2009-12-30 19:16:32 +00:00
if ( ! parV ) return false ;
// determine drag object/id
2013-03-03 18:25:18 +00:00
C4Object * obj = parV . getObj ( ) ;
C4Def * def = NULL ;
if ( ! obj ) def = parV . getDef ( ) ;
2009-12-30 19:16:32 +00:00
if ( drag_object ) * drag_object = obj ;
2013-03-03 18:25:18 +00:00
if ( drag_def ) * drag_def = def ;
2009-12-30 19:16:32 +00:00
// drag possible, even w./o image
return true ;
}
2016-06-20 19:35:51 +00:00
int32_t C4Object : : AddObjectAndContentsToArray ( C4ValueArray * target_array , int32_t index )
{
// add self, contents and child contents count recursively to value array. Return index after last added item.
target_array - > SetItem ( index + + , C4VObj ( this ) ) ;
for ( C4Object * cobj : Contents )
{
index = cobj - > AddObjectAndContentsToArray ( target_array , index ) ;
}
return index ;
}
2010-07-30 20:38:21 +00:00
bool C4Object : : DoSelect ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// selection allowed?
2010-07-30 20:38:21 +00:00
if ( CrewDisabled ) return false ;
2009-05-08 13:28:41 +00:00
// do callback
2014-05-30 23:03:23 +00:00
Call ( PSF_CrewSelection , & C4AulParSet ( false ) ) ;
2009-05-08 13:28:41 +00:00
// done
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-07-30 20:38:21 +00:00
void C4Object : : UnSelect ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// do callback
2014-05-30 23:03:23 +00:00
Call ( PSF_CrewSelection , & C4AulParSet ( true ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 17:44:44 +00:00
void C4Object : : GetViewPos ( float & riX , float & riY , float tx , float ty , const C4Facet & fctViewport ) const // get position this object is seen at (for given scroll)
{
if ( Category & C4D_Parallax ) GetViewPosPar ( riX , riY , tx , ty , fctViewport ) ; else { riX = float ( GetX ( ) ) ; riY = float ( GetY ( ) ) ; }
}
2010-09-24 17:51:34 +00:00
bool C4Object : : GetDrawPosition ( const C4TargetFacet & cgo ,
2013-08-31 21:23:35 +00:00
float & resultx , float & resulty , float & resultzoom ) const
2010-09-23 01:51:08 +00:00
{
2010-09-24 17:51:34 +00:00
return GetDrawPosition ( cgo , fixtof ( fix_x ) , fixtof ( fix_y ) , cgo . Zoom , resultx , resulty , resultzoom ) ;
2010-09-23 01:51:08 +00:00
}
2013-08-31 21:23:35 +00:00
bool C4Object : : GetDrawPosition ( const C4TargetFacet & cgo , float objx , float objy , float zoom , float & resultx , float & resulty , float & resultzoom ) const
2010-09-23 01:51:08 +00:00
{
2011-08-18 17:46:51 +00:00
// for HUD
if ( Category & C4D_Foreground )
{
resultzoom = zoom ;
2010-09-23 01:51:08 +00:00
2011-08-18 17:46:51 +00:00
if ( fix_x < 0 )
resultx = cgo . X + objx + cgo . Wdt ;
else
resultx = cgo . X + objx ;
2010-09-23 01:51:08 +00:00
2011-08-18 17:46:51 +00:00
if ( fix_y < 0 )
resulty = cgo . Y + objy + cgo . Hgt ;
else
resulty = cgo . Y + objy ;
2010-09-23 01:51:08 +00:00
2011-08-18 17:46:51 +00:00
return true ;
}
2010-09-23 01:51:08 +00:00
2011-08-18 17:46:51 +00:00
// zoom with parallaxity
int iParX , iParY ;
GetParallaxity ( & iParX , & iParY ) ;
float targetx = cgo . TargetX ; float targety = cgo . TargetY ;
float parx = iParX / 100.0f ; float pary = iParY / 100.0f ;
float par = parx ; // and pary?
2010-09-23 01:51:08 +00:00
// Step 1: project to landscape coordinates
resultzoom = 1.0 / ( 1.0 - ( par - par / zoom ) ) ;
2010-09-26 18:46:13 +00:00
// it would be par / (1.0 - (par - par/zoom)) if objects would get smaller farther away
2010-09-25 20:52:43 +00:00
if ( resultzoom < = 0 | | resultzoom > 100 ) // FIXME: optimize treshhold
2010-09-23 01:51:08 +00:00
return false ;
2015-10-17 21:35:33 +00:00
float rx = ( ( 1 - parx ) * cgo . ParRefX ) * resultzoom + objx / ( parx + zoom - parx * zoom ) ;
float ry = ( ( 1 - pary ) * cgo . ParRefY ) * resultzoom + objy / ( pary + zoom - pary * zoom ) ;
2010-09-23 01:51:08 +00:00
// Step 2: convert to screen coordinates
if ( parx = = 0 & & fix_x < 0 )
resultx = cgo . X + ( objx + cgo . Wdt ) * zoom / resultzoom ;
else
resultx = cgo . X + ( rx - targetx ) * zoom / resultzoom ;
if ( pary = = 0 & & fix_y < 0 )
resulty = cgo . Y + ( objy + cgo . Hgt ) * zoom / resultzoom ;
else
resulty = cgo . Y + ( ry - targety ) * zoom / resultzoom ;
2011-08-18 17:46:51 +00:00
2010-09-23 01:51:08 +00:00
return true ;
}
2013-08-31 21:23:35 +00:00
void C4Object : : GetViewPosPar ( float & riX , float & riY , float tx , float ty , const C4Facet & fctViewport ) const
2010-03-28 18:58:01 +00:00
{
2009-07-22 16:03:33 +00:00
int iParX , iParY ;
GetParallaxity ( & iParX , & iParY ) ;
2009-05-08 13:28:41 +00:00
// get drawing pos, then subtract original target pos to get drawing pos on landscape
if ( ! iParX & & GetX ( ) < 0 )
// HUD element at right viewport pos
2009-04-28 19:35:53 +00:00
riX = fixtof ( fix_x ) + tx + fctViewport . Wdt ;
2009-05-08 13:28:41 +00:00
else
// regular parallaxity
2009-04-28 19:35:53 +00:00
riX = fixtof ( fix_x ) - ( tx * ( iParX - 100 ) / 100 ) ;
2009-05-08 13:28:41 +00:00
if ( ! iParY & & GetY ( ) < 0 )
// HUD element at bottom viewport pos
2009-04-28 19:35:53 +00:00
riY = fixtof ( fix_y ) + ty + fctViewport . Hgt ;
2009-05-08 13:28:41 +00:00
else
// regular parallaxity
2009-04-28 19:35:53 +00:00
riY = fixtof ( fix_y ) - ( ty * ( iParY - 100 ) / 100 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : PutAwayUnusedObject ( C4Object * pToMakeRoomForObject )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get unused object
C4Object * pUnusedObject ;
2011-10-15 00:06:21 +00:00
C4AulFunc * pFnObj2Drop = GetFunc ( PSF_GetObject2Drop ) ;
if ( pFnObj2Drop )
2014-05-30 23:03:23 +00:00
pUnusedObject = pFnObj2Drop - > Exec ( this , & C4AulParSet ( pToMakeRoomForObject ) ) . getObj ( ) ;
2009-05-08 13:28:41 +00:00
else
{
// is there any unused object to put away?
2014-10-24 21:03:19 +00:00
if ( ! Contents . GetLastObject ( ) ) return false ;
2009-05-08 13:28:41 +00:00
// defaultly, it's the last object in the list
// (contents list cannot have invalid status-objects)
2014-10-24 21:03:19 +00:00
pUnusedObject = Contents . GetLastObject ( ) ;
2009-05-08 13:28:41 +00:00
}
// no object to put away? fail
if ( ! pUnusedObject ) return false ;
// grabbing something?
bool fPushing = ( GetProcedure ( ) = = DFA_PUSH ) ;
if ( fPushing )
// try to put it in there
if ( ObjectComPut ( this , Action . Target , pUnusedObject ) )
return true ;
// in container? put in there
if ( Contained )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// try to put it in directly
// note that this works too, if an object is grabbed inside the container
if ( ObjectComPut ( this , Contained , pUnusedObject ) )
return true ;
// now putting didn't work - drop it outside
AddCommand ( C4CMD_Drop , pUnusedObject ) ;
AddCommand ( C4CMD_Exit ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
// if uncontained, simply try to drop it
// if this doesn't work, it won't ever
return ! ! ObjectComDrop ( this , pUnusedObject ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : SetGraphics ( const char * szGraphicsName , C4Def * pSourceDef )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
if ( ! Status ) return false ;
// default def
if ( ! pSourceDef ) pSourceDef = Def ;
// get graphics
C4DefGraphics * pGrp = pSourceDef - > Graphics . Get ( szGraphicsName ) ;
if ( ! pGrp ) return false ;
// set new graphics
pGraphics = pGrp ;
2014-01-08 00:55:33 +00:00
// update Color, etc.
2009-05-08 13:28:41 +00:00
UpdateGraphics ( true ) ;
// success
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : SetGraphics ( C4DefGraphics * pNewGfx , bool fTemp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
if ( ! pNewGfx ) return false ;
// set it and update related stuff
pGraphics = pNewGfx ;
UpdateGraphics ( true , fTemp ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
C4GraphicsOverlay * C4Object : : GetGraphicsOverlay ( int32_t iForID ) const
{
// search in list until ID is found or passed
2015-01-25 15:43:51 +00:00
C4GraphicsOverlay * pOverlay = pGfxOverlay ;
while ( pOverlay & & pOverlay - > GetID ( ) < iForID ) pOverlay = pOverlay - > GetNext ( ) ;
2013-08-31 21:23:35 +00:00
// exact match found?
if ( pOverlay & & pOverlay - > GetID ( ) = = iForID ) return pOverlay ;
// none found
return NULL ;
}
2009-05-08 13:28:41 +00:00
C4GraphicsOverlay * C4Object : : GetGraphicsOverlay ( int32_t iForID , bool fCreate )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// search in list until ID is found or passed
C4GraphicsOverlay * pOverlay = pGfxOverlay , * pPrevOverlay = NULL ;
while ( pOverlay & & pOverlay - > GetID ( ) < iForID ) { pPrevOverlay = pOverlay ; pOverlay = pOverlay - > GetNext ( ) ; }
// exact match found?
if ( pOverlay & & pOverlay - > GetID ( ) = = iForID ) return pOverlay ;
// ID has been passed: Create new if desired
if ( ! fCreate ) return NULL ;
C4GraphicsOverlay * pNewOverlay = new C4GraphicsOverlay ( ) ;
pNewOverlay - > SetID ( iForID ) ;
pNewOverlay - > SetNext ( pOverlay ) ;
if ( pPrevOverlay ) pPrevOverlay - > SetNext ( pNewOverlay ) ; else pGfxOverlay = pNewOverlay ;
// return newly created overlay
return pNewOverlay ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : RemoveGraphicsOverlay ( int32_t iOverlayID )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// search in list until ID is found or passed
C4GraphicsOverlay * pOverlay = pGfxOverlay , * pPrevOverlay = NULL ;
while ( pOverlay & & pOverlay - > GetID ( ) < iOverlayID ) { pPrevOverlay = pOverlay ; pOverlay = pOverlay - > GetNext ( ) ; }
// exact match found?
if ( pOverlay & & pOverlay - > GetID ( ) = = iOverlayID )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// remove it
if ( pPrevOverlay ) pPrevOverlay - > SetNext ( pOverlay - > GetNext ( ) ) ; else pGfxOverlay = pOverlay - > GetNext ( ) ;
pOverlay - > SetNext ( NULL ) ; // prevents deletion of following overlays
delete pOverlay ;
// removed
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// no match found
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : HasGraphicsOverlayRecursion ( const C4Object * pCheckObj ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Object * pGfxOvrlObj ;
if ( pGfxOverlay )
for ( C4GraphicsOverlay * pGfxOvrl = pGfxOverlay ; pGfxOvrl ; pGfxOvrl = pGfxOvrl - > GetNext ( ) )
2010-01-25 04:00:59 +00:00
if ( ( pGfxOvrlObj = pGfxOvrl - > GetOverlayObject ( ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pGfxOvrlObj = = pCheckObj ) return true ;
if ( pGfxOvrlObj - > HasGraphicsOverlayRecursion ( pCheckObj ) ) return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : StatusActivate ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// readd to main list
2009-06-15 21:47:26 +00:00
: : Objects . InactiveObjects . Remove ( this ) ;
2009-05-08 13:28:41 +00:00
Status = C4OS_NORMAL ;
2009-06-15 21:47:26 +00:00
: : Objects . Add ( this ) ;
2009-05-08 13:28:41 +00:00
// update some values
UpdateGraphics ( false ) ;
UpdateFace ( true ) ;
UpdatePos ( ) ;
2015-01-14 17:03:05 +00:00
UpdateLight ( ) ;
2013-12-17 16:16:11 +00:00
Call ( PSF_OnSynchronized ) ;
2009-05-08 13:28:41 +00:00
// done, success
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : StatusDeactivate ( bool fClearPointers )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// clear particles
2013-12-22 17:51:05 +00:00
ClearParticleLists ( ) ;
2013-10-08 23:28:58 +00:00
2009-05-08 13:28:41 +00:00
// put into inactive list
2009-06-15 21:47:26 +00:00
: : Objects . Remove ( this ) ;
2009-05-08 13:28:41 +00:00
Status = C4OS_INACTIVE ;
2016-04-02 15:50:49 +00:00
if ( Landscape . HasFoW ( ) ) Landscape . GetFoW ( ) - > Remove ( this ) ;
2009-06-15 21:47:26 +00:00
: : Objects . InactiveObjects . Add ( this , C4ObjectList : : stMain ) ;
2009-05-08 13:28:41 +00:00
// if desired, clear game pointers
if ( fClearPointers )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// in this case, the object must also exit any container, and any contained objects must be exited
ClearContentsAndContained ( ) ;
Game . ClearPointers ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// always clear transfer
Game . TransferZones . ClearPointers ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done, success
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : ClearContentsAndContained ( bool fDoCalls )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// exit contents from container
2014-10-24 20:50:14 +00:00
for ( C4Object * cobj : Contents )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
cobj - > Exit ( GetX ( ) , GetY ( ) , 0 , Fix0 , Fix0 , Fix0 , fDoCalls ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// remove from container *after* contents have been removed!
if ( Contained ) Exit ( GetX ( ) , GetY ( ) , 0 , Fix0 , Fix0 , Fix0 , fDoCalls ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : AdjustWalkRotation ( int32_t iRangeX , int32_t iRangeY , int32_t iSpeed )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iDestAngle ;
// attachment at middle (bottom) vertex?
if ( Shape . iAttachVtx < 0 | | ! Def - > Shape . VtxX [ Shape . iAttachVtx ] )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// evaluate floor around attachment pos
int32_t iSolidLeft = 0 , iSolidRight = 0 ;
// left
int32_t iXCheck = Shape . iAttachX - iRangeX ;
if ( GBackSolid ( iXCheck , Shape . iAttachY ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// up
while ( - - iSolidLeft > - iRangeY )
if ( GBackSolid ( iXCheck , Shape . iAttachY + iSolidLeft ) )
{ + + iSolidLeft ; break ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
// down
while ( + + iSolidLeft < iRangeY )
if ( GBackSolid ( iXCheck , Shape . iAttachY + iSolidLeft ) )
{ - - iSolidLeft ; break ; }
// right
iXCheck + = 2 * iRangeX ;
if ( GBackSolid ( iXCheck , Shape . iAttachY ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// up
while ( - - iSolidRight > - iRangeY )
if ( GBackSolid ( iXCheck , Shape . iAttachY + iSolidRight ) )
{ + + iSolidRight ; break ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
// down
while ( + + iSolidRight < iRangeY )
if ( GBackSolid ( iXCheck , Shape . iAttachY + iSolidRight ) )
{ - - iSolidRight ; break ; }
// calculate destination angle
// 100% accurate for large values of Pi ;)
2015-11-15 12:53:01 +00:00
iDestAngle = ( iSolidRight - iSolidLeft ) * ( 35 / std : : max < int32_t > ( iRangeX , 1 ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// attachment at other than horizontal middle vertex: get your feet to the ground!
// rotate target to large angle is OK, because rotation will stop once the real
// bottom vertex hits solid ground
if ( Shape . VtxX [ Shape . iAttachVtx ] > 0 )
iDestAngle = - 50 ;
else
iDestAngle = 50 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// move to destination angle
2013-05-25 12:59:58 +00:00
if ( Abs ( iDestAngle - GetR ( ) ) > 2 )
2010-03-28 18:58:01 +00:00
{
2015-02-12 22:05:55 +00:00
rdir = itofix ( Clamp < int32_t > ( iDestAngle - GetR ( ) , - 15 , + 15 ) ) ;
2009-05-08 13:28:41 +00:00
rdir / = ( 10000 / iSpeed ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else rdir = 0 ;
// done, success
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-12-19 00:17:40 +00:00
static void BubbleOut ( int32_t tx , int32_t ty )
{
// No bubbles from nowhere
if ( ! GBackSemiSolid ( tx , ty ) ) return ;
// Enough bubbles out there already
if ( : : Objects . ObjectCount ( C4ID : : Bubble ) > = 150 ) return ;
// Create bubble
Game . CreateObject ( C4ID : : Bubble , NULL , NO_OWNER , tx , ty ) ;
}
void C4Object : : Splash ( )
{
int32_t tx = GetX ( ) ; int32_t ty = GetY ( ) + 1 ;
int32_t amt = std : : min ( Shape . Wdt * Shape . Hgt / 10 , 20 ) ;
// Splash only if there is free space above
if ( GBackSemiSolid ( tx , ty - 15 ) ) return ;
// get back mat
int32_t iMat = GBackMat ( tx , ty ) ;
// check liquid
if ( MatValid ( iMat ) )
if ( DensityLiquid ( : : MaterialMap . Map [ iMat ] . Density ) & & : : MaterialMap . Map [ iMat ] . Instable )
{
int32_t sy = ty ;
while ( GBackLiquid ( tx , sy ) & & sy > ty - 20 & & sy > = 0 ) sy - - ;
// Splash bubbles and liquid
for ( int32_t cnt = 0 ; cnt < amt ; cnt + + )
{
int32_t bubble_x = tx + Random ( 16 ) - 8 ;
int32_t bubble_y = ty + Random ( 16 ) - 6 ;
BubbleOut ( bubble_x , bubble_y ) ;
if ( GBackLiquid ( tx , ty ) & & ! GBackSemiSolid ( tx , sy ) )
{
C4Real xdir = C4REAL100 ( Random ( 151 ) - 75 ) ;
2016-08-30 22:56:46 +00:00
C4Real ydir = C4REAL100 ( - int32_t ( Random ( 200 ) ) ) ;
2015-12-19 00:17:40 +00:00
: : PXS . Create ( : : Landscape . ExtractMaterial ( tx , ty , false ) ,
itofix ( tx ) , itofix ( sy ) ,
xdir ,
ydir ) ;
}
}
}
// Splash sound
if ( amt > = 20 )
StartSoundEffect ( " Liquids::Splash2 " , false , 50 , this ) ;
else if ( amt > 1 ) StartSoundEffect ( " Liquids::Splash1 " , false , 50 , this ) ;
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateInLiquid ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// InLiquid check
if ( IsInLiquidCheck ( ) ) // In Liquid
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! InLiquid ) // Enter liquid
2010-03-28 18:58:01 +00:00
{
2015-12-19 00:17:40 +00:00
if ( OCF & OCF_HitSpeed2 )
if ( Mass > 3 ) Splash ( ) ;
2010-03-27 16:05:02 +00:00
InLiquid = 1 ;
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
else // Out of liquid
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( InLiquid ) // Leave liquid
InLiquid = 0 ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
StdStrBuf C4Object : : GetInfoString ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sResult ;
// no info for invalid objects
if ( ! Status ) return sResult ;
// go through all effects and add their desc
for ( C4Effect * pEff = pEffects ; pEff ; pEff = pEff - > pNext )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Value par [ 7 ] ;
C4Value vInfo = pEff - > DoCall ( this , PSFS_FxInfo , par [ 0 ] , par [ 1 ] , par [ 2 ] , par [ 3 ] , par [ 4 ] , par [ 5 ] , par [ 6 ] ) ;
if ( ! vInfo ) continue ;
// debug: warn for wrong return types
if ( vInfo . GetType ( ) ! = C4V_String )
2011-03-16 18:07:18 +00:00
DebugLogF ( " Effect %s(#%d) on object %s (#%d) returned wrong info type %d. " , pEff - > GetName ( ) , pEff - > Number , GetName ( ) , Number , vInfo . GetType ( ) ) ;
2009-05-08 13:28:41 +00:00
// get string val
C4String * psInfo = vInfo . getStr ( ) ; const char * szEffInfo ;
if ( psInfo & & ( szEffInfo = psInfo - > GetCStr ( ) ) )
if ( * szEffInfo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// OK; this effect has a desc. Add it!
if ( sResult . getLength ( ) ) sResult . AppendChar ( ' | ' ) ;
sResult . Append ( szEffInfo ) ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
// done
return sResult ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : GrabContents ( C4Object * pFrom )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// create a temp list of all objects and transfer it
// this prevents nasty deadlocks caused by RejectEntrance-scripts
C4ObjectList tmpList ; tmpList . Copy ( pFrom - > Contents ) ;
2014-10-24 20:50:14 +00:00
for ( C4Object * obj : tmpList )
if ( obj - > Status )
obj - > Enter ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
bool C4Object : : CanConcatPictureWith ( C4Object * pOtherObject ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check current definition ID
if ( id ! = pOtherObject - > id ) return false ;
// def overwrite of stack conditions
int32_t allow_picture_stack = Def - > AllowPictureStack ;
if ( ! ( allow_picture_stack & APS_Color ) )
{
// check color if ColorByOwner (flags)
if ( Color ! = pOtherObject - > Color & & Def - > ColorByOwner ) return false ;
// check modulation
if ( ColorMod ! = pOtherObject - > ColorMod ) return false ;
if ( BlitMode ! = pOtherObject - > BlitMode ) return false ;
}
if ( ! ( allow_picture_stack & APS_Graphics ) )
{
// check graphics
if ( pGraphics ! = pOtherObject - > pGraphics ) return false ;
// check any own picture rect
if ( PictureRect ! = pOtherObject - > PictureRect ) return false ;
}
if ( ! ( allow_picture_stack & APS_Name ) )
{
// check name, so zagabar's sandwiches don't stack
2009-04-03 19:06:29 +00:00
if ( GetName ( ) ! = pOtherObject - > GetName ( ) ) return false ;
2009-05-08 13:28:41 +00:00
}
if ( ! ( allow_picture_stack & APS_Overlay ) )
{
// check overlay graphics
for ( C4GraphicsOverlay * pOwnOverlay = pGfxOverlay ; pOwnOverlay ; pOwnOverlay = pOwnOverlay - > GetNext ( ) )
if ( pOwnOverlay - > IsPicture ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4GraphicsOverlay * pOtherOverlay = pOtherObject - > GetGraphicsOverlay ( pOwnOverlay - > GetID ( ) , false ) ;
if ( ! pOtherOverlay | | ! ( * pOtherOverlay = = * pOwnOverlay ) ) return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
for ( C4GraphicsOverlay * pOtherOverlay = pOtherObject - > pGfxOverlay ; pOtherOverlay ; pOtherOverlay = pOtherOverlay - > GetNext ( ) )
if ( pOtherOverlay - > IsPicture ( ) )
2013-08-31 21:23:35 +00:00
if ( ! GetGraphicsOverlay ( pOtherOverlay - > GetID ( ) ) ) return false ;
2009-05-08 13:28:41 +00:00
}
// concat OK
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 17:44:44 +00:00
bool C4Object : : IsMoveableBySolidMask ( int ComparisonPlane ) const
{
return ( Status = = C4OS_NORMAL )
& & ! ( Category & C4D_StaticBack )
& & ( ComparisonPlane < GetPlane ( ) )
& & ! Contained
;
}
2009-05-08 13:28:41 +00:00
void C4Object : : UpdateScriptPointers ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pEffects )
pEffects - > ReAssignAllCallbackFunctions ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-08-31 21:23:35 +00:00
bool C4Object : : IsPlayerObject ( int32_t iPlayerNumber ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
bool fAnyPlr = ( iPlayerNumber = = NO_OWNER ) ;
// if an owner is specified: only owned objects
if ( fAnyPlr & & ! ValidPlr ( Owner ) ) return false ;
// and crew objects
if ( fAnyPlr | | Owner = = iPlayerNumber )
2010-03-28 18:58:01 +00:00
{
2009-06-12 23:09:32 +00:00
C4Player * pOwner = : : Players . Get ( Owner ) ;
2009-05-08 13:28:41 +00:00
if ( pOwner )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pOwner & & pOwner - > Crew . IsContained ( this ) ) return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Do not force that the owner exists because the function must work for unjoined players (savegame resume)
2010-10-11 18:18:38 +00:00
if ( Def - > CrewMember )
2009-05-08 13:28:41 +00:00
return true ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// otherwise, not a player object
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : IsUserPlayerObject ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// must be a player object at all
if ( ! IsPlayerObject ( ) ) return false ;
// and the owner must not be a script player
2009-06-12 23:09:32 +00:00
C4Player * pOwner = : : Players . Get ( Owner ) ;
2009-05-08 13:28:41 +00:00
if ( ! pOwner | | pOwner - > GetType ( ) ! = C4PT_User ) return false ;
// otherwise, it's a user playeer object
return true ;
2010-03-28 18:58:01 +00:00
}
2010-12-27 19:15:55 +00:00
void C4Object : : SetPropertyByS ( C4String * k , const C4Value & to )
{
if ( k > = & Strings . P [ 0 ] & & k < & Strings . P [ P_LAST ] )
{
switch ( k - & Strings . P [ 0 ] )
{
case P_Plane :
2015-12-07 14:15:49 +00:00
if ( ! to . getInt ( ) ) throw C4AulExecError ( " invalid Plane 0 " ) ;
2010-12-27 19:15:55 +00:00
SetPlane ( to . getInt ( ) ) ;
return ;
}
}
C4PropListNumbered : : SetPropertyByS ( k , to ) ;
}
void C4Object : : ResetProperty ( C4String * k )
{
if ( k > = & Strings . P [ 0 ] & & k < & Strings . P [ P_LAST ] )
{
switch ( k - & Strings . P [ 0 ] )
{
case P_Plane :
SetPlane ( GetPropertyInt ( P_Plane ) ) ;
return ;
}
}
return C4PropListNumbered : : ResetProperty ( k ) ;
}
2016-04-25 20:17:10 +00:00
bool C4Object : : GetPropertyByS ( const C4String * k , C4Value * pResult ) const
2010-12-27 19:15:55 +00:00
{
if ( k > = & Strings . P [ 0 ] & & k < & Strings . P [ P_LAST ] )
{
switch ( k - & Strings . P [ 0 ] )
{
case P_Plane : * pResult = C4VInt ( Plane ) ; return true ;
}
}
return C4PropListNumbered : : GetPropertyByS ( k , pResult ) ;
}
2012-05-25 23:32:43 +00:00
C4ValueArray * C4Object : : GetProperties ( ) const
{
C4ValueArray * a = C4PropList : : GetProperties ( ) ;
int i ;
i = a - > GetSize ( ) ;
a - > SetSize ( i + 1 ) ;
( * a ) [ i + + ] = C4VString ( & : : Strings . P [ P_Plane ] ) ;
return a ;
}
2014-05-04 12:14:42 +00:00
int32_t C4Object : : GetSolidMaskPlane ( ) const
{
// use SolidMaskPlane property. Fallback to object plane if unassigned.
int32_t plane = GetPropertyInt ( P_SolidMaskPlane ) ;
return plane ? plane : GetPlane ( ) ;
}