2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2009-06-05 13:41:20 +00:00
* Copyright ( c ) 1998 - 2001 , 2003 - 2004 , 2007 - 2008 Matthes Bender
2010-12-23 00:01:24 +00:00
* Copyright ( c ) 2001 - 2010 Sven Eberhardt
2011-09-01 14:58:52 +00:00
* Copyright ( c ) 2001 - 2007 Peter Wortmann
2009-06-05 13:41:20 +00:00
* Copyright ( c ) 2001 Carlo Teubner
2010-12-23 00:01:24 +00:00
* Copyright ( c ) 2001 Michael K ä ser
2011-09-01 14:58:52 +00:00
* Copyright ( c ) 2004 - 2011 G ü nther Brammer
* Copyright ( c ) 2005 , 2009 - 2011 Tobias Zwick
* Copyright ( c ) 2006 , 2009 - 2011 Armin Burgmeier
2010-12-23 00:01:24 +00:00
* Copyright ( c ) 2009 - 2010 Nicolas Hake
* Copyright ( c ) 2010 Benjamin Herr
2011-09-01 14:58:52 +00:00
* Copyright ( c ) 2010 - 2011 Maikel de Vries
* Copyright ( c ) 2011 David Dormagen
2009-05-08 13:28:41 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
* See isc_license . txt for full license and disclaimer .
*
* " Clonk " is a registered trademark of Matthes Bender .
* See clonk_trademark_license . txt for full license .
*/
/* That which fills the world with life */
# include <C4Include.h>
# include <C4Object.h>
2011-03-03 16:10:22 +00:00
# include <C4DefList.h>
2012-04-27 17:04:43 +00:00
# include <C4Effect.h>
2009-05-08 13:28:41 +00:00
# include <C4ObjectInfo.h>
# include <C4Physics.h>
# include <C4ObjectCom.h>
# include <C4Command.h>
# include <C4Viewport.h>
# include <C4MaterialList.h>
# ifdef DEBUGREC
# include <C4Record.h>
# endif
# include <C4SolidMask.h>
# include <C4Random.h>
2009-06-12 18:52:21 +00:00
# include <C4Log.h>
2009-05-08 13:28:41 +00:00
# include <C4Player.h>
# include <C4ObjectMenu.h>
2009-06-05 18:00:23 +00:00
# include <C4RankSystem.h>
2009-06-05 18:12:43 +00:00
# include <C4GameMessage.h>
2009-06-12 18:52:21 +00:00
# include <C4GraphicsResource.h>
# include <C4GraphicsSystem.h>
# include <C4Game.h>
2009-06-12 23:09:32 +00:00
# include <C4PlayerList.h>
2009-06-15 21:47:26 +00:00
# include <C4GameObjects.h>
2009-06-15 22:06:37 +00:00
# include <C4Record.h>
2010-01-22 18:27:02 +00:00
# include <C4MeshAnimation.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 ;
}
}
2010-09-24 00:35:26 +00:00
static void DrawVertex ( C4Facet & cgo , int32_t tx , int32_t 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
{
2011-10-03 14:30:18 +00:00
pDraw - > DrawLineDw ( cgo . Surface , tx - 1 , ty , tx + 1 , ty , col ) ;
pDraw - > DrawLineDw ( cgo . Surface , tx , ty - 1 , tx , ty + 1 , col ) ;
if ( contact ) pDraw - > DrawFrameDw ( cgo . Surface , tx - 2 , ty - 2 , tx + 2 , ty + 2 , 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
2009-06-05 18:46:03 +00:00
iBridgeMaterial = Min < int32_t > ( iBridgeMaterial , : : MaterialMap . Num - 1 ) ;
2009-05-08 13:28:41 +00:00
if ( iBridgeMaterial < 0 ) iBridgeMaterial = 0xff ;
iBridgeTime = BoundBy < int32_t > ( iBridgeTime , 0 , 0xffff ) ;
// 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
{
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 ;
NoCollectDelay = 0 ;
Con = 0 ;
Mass = OwnMass = 0 ;
Damage = 0 ;
Energy = 0 ;
Alive = 0 ;
Breath = 0 ;
InMat = MNone ;
Color = 0 ;
PlrViewRange = 0 ;
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 ;
Audible = 0 ;
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 ( ) ;
Component . 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 ;
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 ) ;
2010-03-28 18:58:01 +00:00
r = nr ;
2009-05-08 13:28:41 +00:00
fix_r = itofix ( r ) ;
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
2010-03-27 16:05:02 +00:00
Mass = 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
// Components
2010-03-27 16:05:02 +00:00
Component = Def - > Component ;
ComponentConCutoff ( ) ;
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
2010-09-29 01:44:05 +00:00
Audible = : : Viewports . GetAudibility ( GetX ( ) , GetY ( ) , & AudiblePan ) ;
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
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 ;
# ifdef DEBUGREC
C4RCCreateObj rc ;
2011-10-08 21:47:07 +00:00
memset ( & rc , ' \0 ' , sizeof ( rc ) ) ;
2009-05-08 13:28:41 +00:00
rc . oei = Number ;
2011-10-08 21:47:07 +00:00
if ( Def & & Def - > GetName ( ) ) strncpy ( rc . id , Def - > GetName ( ) , 32 + 1 ) ;
2009-05-08 13:28:41 +00:00
rc . x = GetX ( ) ; rc . y = GetY ( ) ; rc . ownr = Owner ;
AddDbgRec ( RCT_DsObj , & rc , sizeof ( rc ) ) ;
# endif
// Destruction call in container
if ( Contained )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4AulParSet pars ( C4VObj ( this ) ) ;
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
{
2009-05-08 13:28:41 +00:00
pEffects - > ClearAll ( this , C4FxCall_RemoveClear ) ;
// 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
if ( FrontParticles ) FrontParticles . Clear ( ) ;
if ( BackParticles ) BackParticles . Clear ( ) ;
// 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 - - ;
2010-03-27 16:05:02 +00:00
// Kill contents
C4Object * cobj ; C4ObjectLink * clnk , * next ;
for ( clnk = Contents . First ; clnk & & ( cobj = clnk - > Obj ) ; clnk = next )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
next = clnk - > Next ;
2009-05-08 13:28:41 +00:00
if ( fExitContents )
cobj - > Exit ( GetX ( ) , GetY ( ) ) ;
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Contents . Remove ( cobj ) ;
cobj - > AssignRemoval ( ) ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// remove from container *after* contents have been removed!
C4Object * pCont ;
2010-01-25 04:00:59 +00:00
if ( ( pCont = Contained ) )
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
2010-10-29 22:05:36 +00:00
while ( FirstRef ) FirstRef - > Set0 ( ) ;
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 )
if ( r ! = 0 )
Shape . Rotate ( 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 )
if ( ! Def - > Rotateable | | ( r = = 0 ) )
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 ;
// new grafics: update face + solidmask
if ( fGraphicsChanged )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// update solid
if ( pSolidMaskData & & ! fTemp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
delete pSolidMaskData ; pSolidMaskData = NULL ;
// ensure SolidMask-rect lies within new graphics-rect
CheckSolidMaskRect ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-07-10 23:10:18 +00:00
2011-08-19 22:01:08 +00:00
// Keep mesh instance if it uses the same underlying mesh
if ( ! pMeshInstance | | ! pGraphics - > Type = = C4DefGraphics : : TYPE_Mesh | |
& pMeshInstance - > GetMesh ( ) ! = pGraphics - > Mesh )
2010-03-28 18:58:01 +00:00
{
2011-08-19 22:01:08 +00:00
delete pMeshInstance ;
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
2009-07-10 23:10:18 +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 )
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 )
{
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
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
2009-05-08 13:28:41 +00:00
void C4Object : : DrawFace ( C4TargetFacet & cgo , float offX , float offY , int32_t iPhaseX , int32_t iPhaseY )
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
// Straight
if ( ( ! Def - > Rotateable | | ( r = = 0 ) ) & & ! pDrawTransform )
2010-03-28 18:58:01 +00:00
{
2009-07-10 23:10:18 +00:00
DrawFaceImpl ( cgo , false , fx , fy , fwdt , fhgt , tx , ty , twdt , thgt , NULL ) ;
2011-10-03 14:30:18 +00:00
/* pDraw->Blit(GetGraphics()->GetBitmap(Color),
2010-03-28 18:58:01 +00:00
fx , fy , fwdt , fhgt ,
cgo . Surface , tx , ty , twdt , thgt ,
true , NULL ) ; */
}
2009-05-08 13:28:41 +00:00
// Rotated or transformed
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4DrawTransform rot ;
if ( pDrawTransform )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
rot . SetTransformAt ( * pDrawTransform , offX , offY ) ;
if ( r ) rot . Rotate ( r * 100 , offX , offY ) ;
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
rot . SetRotate ( r * 100 , offX , offY ) ;
}
2010-03-28 18:58:01 +00:00
DrawFaceImpl ( cgo , false , fx , fy , fwdt , fhgt , tx , ty , twdt , thgt , & rot ) ;
2011-10-03 14:30:18 +00:00
/* pDraw->Blit(GetGraphics()->GetBitmap(Color),
2010-03-28 18:58:01 +00:00
fx , fy , fwdt , fhgt ,
cgo . Surface , tx , ty , twdt , thgt ,
true , & rot ) ; */
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 : : DrawActionFace ( C4TargetFacet & cgo , float offX , float offY )
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 ;
float offset_from_top = shgt * Max < float > ( float ( FullCon - Con ) , 0 ) / FullCon ;
fy + = offset_from_top ;
fhgt - = offset_from_top ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Straight
if ( ( ! Def - > Rotateable | | ( r = = 0 ) ) & & ! pDrawTransform )
2010-03-28 18:58:01 +00:00
{
2009-07-10 23:10:18 +00:00
DrawFaceImpl ( cgo , true , fx , fy , fwdt , fhgt , tx , ty , twdt , thgt , NULL ) ;
2011-10-03 14:30:18 +00:00
/*pDraw->Blit(Action.Facet.Surface,
2010-03-28 18:58:01 +00:00
fx , fy , fwdt , fhgt ,
cgo . Surface , tx , ty , twdt , thgt ,
true , NULL ) ; */
}
2009-05-08 13:28:41 +00:00
// Rotated or transformed
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// rotate midpoint of action facet around center of shape
// combine with existing transform if necessary
C4DrawTransform rot ;
if ( pDrawTransform )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
rot . SetTransformAt ( * pDrawTransform , offX , offY ) ;
if ( r ) rot . Rotate ( r * 100 , offX , offY ) ;
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
rot . SetRotate ( r * 100 , offX , offY ) ;
}
2010-03-28 18:58:01 +00:00
DrawFaceImpl ( cgo , true , fx , fy , fwdt , fhgt , tx , ty , twdt , thgt , & rot ) ;
2011-10-03 14:30:18 +00:00
/* pDraw->Blit(Action.Facet.Surface,
2010-03-28 18:58:01 +00:00
fx , fy , fwdt , fhgt ,
cgo . Surface , tx , ty , twdt , thgt ,
true , & rot ) ; */
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 : : UpdateMass ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
Mass = Max < int32_t > ( ( Def - > Mass + OwnMass ) * Con / FullCon , 1 ) ;
if ( ! Def - > NoComponentMass ) Mass + = Contents . Mass ;
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
void C4Object : : ComponentConCutoff ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// this is not ideal, since it does not know about custom builder components
2010-03-27 16:05:02 +00:00
int32_t cnt ;
for ( cnt = 0 ; Component . GetID ( cnt ) ; cnt + + )
Component . SetCount ( cnt ,
2010-03-28 18:58:01 +00:00
Min < int32_t > ( Component . GetCount ( cnt ) , Def - > Component . GetCount ( cnt ) * Con / FullCon ) ) ;
}
2009-05-08 13:28:41 +00:00
void C4Object : : ComponentConGain ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// this is not ideal, since it does not know about custom builder components
2010-03-27 16:05:02 +00:00
int32_t cnt ;
for ( cnt = 0 ; Component . GetID ( cnt ) ; cnt + + )
Component . SetCount ( cnt ,
2010-03-28 18:58:01 +00:00
Max < int32_t > ( Component . GetCount ( cnt ) , Def - > Component . GetCount ( cnt ) * Con / FullCon ) ) ;
}
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 )
{
Call ( PSF_OnMaterialChanged , & C4AulParSet ( C4VInt ( newmat ) , C4VInt ( InMat ) ) ) ;
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 )
2010-03-28 18:58:01 +00:00
& & ( r = = 0 ) & & ! OnFire )
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 ) )
if ( ( OCF & OCF_FullCon ) & & ( ( Def - > RotatedEntrance = = 1 ) | | ( r < = Def - > RotatedEntrance ) ) )
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 ) ) )
if ( NoCollectDelay = = 0 )
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
C4RCOCF rc = { dwOCFOld , OCF , false } ;
AddDbgRec ( RCT_OCF , & rc , sizeof ( rc ) ) ;
# 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)
2011-07-05 11:40:40 +00:00
OCF = OCF & ( OCF_Normal | OCF_Exclusive | OCF_Grab | OCF_FullCon | OCF_Rotate | OCF_OnFire
| OCF_Inflammable | OCF_Alive | OCF_CrewMember | OCF_AttractLightning ) ;
2010-03-27 16:05:02 +00:00
// OCF_Carryable: Can be picked up
if ( GetPropertyInt ( P_Collectible ) )
OCF | = OCF_Carryable ;
// OCF_Construct: Can be built outside
if ( Def - > Constructable & & ( Con < FullCon )
2010-03-28 18:58:01 +00:00
& & ( r = = 0 ) & & ! OnFire )
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 ) )
if ( ( OCF & OCF_FullCon ) & & ( ( Def - > RotatedEntrance = = 1 ) | | ( r < = Def - > RotatedEntrance ) ) )
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 ) ) )
if ( NoCollectDelay = = 0 )
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
C4RCOCF rc = { dwOCFOld , OCF , true } ;
AddDbgRec ( RCT_OCF , & rc , sizeof ( rc ) ) ;
# 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 )
2009-06-05 18:46:03 +00:00
if ( : : MaterialMap . Map [ InMat ] . Incindiary )
2012-04-29 08:21:16 +00:00
if ( GetPropertyInt ( P_ContactIncinerate ) > 0 )
2011-03-12 17:38:47 +00:00
{
2011-10-15 00:27:02 +00:00
C4AulFunc * pCallFunc = GetFunc ( PSF_OnInIncendiaryMaterial ) ;
2011-03-12 18:29:25 +00:00
if ( pCallFunc )
{
pCallFunc - > Exec ( this , & 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 ) ;
2009-05-08 13:28:41 +00:00
StartSoundEffect ( " Trumpet " , false , 100 , this ) ;
}
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
{
2009-05-08 13:28:41 +00:00
# ifdef 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 ) ) ;
# endif
// reset temporary marker
Marker = 0 ;
// 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
// particles
if ( BackParticles ) BackParticles . Exec ( this ) ;
if ( FrontParticles ) FrontParticles . Exec ( this ) ;
// effects
if ( pEffects )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pEffects - > Execute ( this ) ;
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
2009-08-15 18:50:32 +00:00
bool C4Object : : At ( int32_t ctx , int32_t cty )
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
2009-08-15 18:50:32 +00:00
bool C4Object : : At ( int32_t ctx , int32_t cty , DWORD & ocf )
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
void C4Object : : GetOCFForPos ( int32_t ctx , int32_t cty , DWORD & ocf )
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 ;
if ( pEffects ) pEffects - > ClearAll ( this , C4FxCall_RemoveDeath ) ;
// 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
// Lose contents
while ( ( thing = Contents . GetObject ( ) ) ) thing - > Exit ( thing - > GetX ( ) , thing - > GetY ( ) ) ;
// 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 ) ;
2009-05-08 13:28:41 +00:00
// ensure objects that won't be affected by dead-plrview-decay are handled properly
if ( ! pPlr | | ! ( Category & C4D_Living ) | | ! pPlr - > FoWViewObjs . IsContained ( this ) )
SetPlrViewRange ( 0 ) ;
// Engine script call
C4AulParSet pars ( C4VInt ( iDeathCausingPlayer ) ) ;
2010-03-27 16:05:02 +00:00
Call ( PSF_Death , & pars ) ;
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 ( ) )
: : GameScript . GRBroadcast ( PSF_RelaunchPlayer ,
& C4AulParSet ( C4VInt ( Owner ) , C4VInt ( iDeathCausingPlayer ) ) ) ;
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 ;
2009-05-08 13:28:41 +00:00
if ( ! Def - > Rotateable ) { r = 0 ; fix_r = rdir = Fix0 ; }
// 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...
if ( Game . pGlobalEffects ) Game . pGlobalEffects - > OnObjectChangedDef ( this ) ;
2009-06-15 21:47:26 +00:00
for ( C4ObjectLink * pLnk = : : Objects . First ; pLnk ; pLnk = pLnk - > Next )
2009-05-08 13:28:41 +00:00
if ( pLnk - > Obj - > pEffects ) pLnk - > Obj - > pEffects - > OnObjectChangedDef ( this ) ;
// 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
{
2009-05-08 13:28:41 +00:00
pEffects - > DoDamage ( this , iChange , iCause , iCausedBy ) ;
if ( ! iChange ) return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Change value
2010-03-27 16:05:02 +00:00
Damage = Max < int32_t > ( Damage + iChange , 0 ) ;
2009-05-08 13:28:41 +00:00
// Engine script call
2012-05-06 12:45:35 +00:00
Call ( PSF_Damage , & C4AulParSet ( C4VInt ( iChange ) , C4VInt ( iCause ) , C4VInt ( 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
{
2009-05-08 13:28:41 +00:00
// iChange 100% = Physical 100000
2010-03-27 16:05:02 +00:00
if ( ! fExact ) iChange = iChange * C4MaxPhysical / 100 ;
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 )
pEffects - > DoDamage ( this , iChange , iCause , iCausedByPlr ) ;
// Do change
2010-12-12 21:38:15 +00:00
iChange = BoundBy < 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
Call ( PSF_EnergyChange , & C4AulParSet ( C4VInt ( iChange ) , C4VInt ( iCause ) , C4VInt ( 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
2010-12-12 22:01:08 +00:00
iChange = BoundBy < 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
Call ( PSF_BreathChange , & C4AulParSet ( C4VInt ( iChange ) ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-01-02 01:03:44 +00:00
void C4Object : : DoCon ( int32_t iChange )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iStepSize = FullCon / 100 ;
int32_t lRHgt = Shape . Hgt , lRy = Shape . GetY ( ) ;
int32_t iLastStep = Con / iStepSize ;
2010-05-04 15:35:18 +00:00
C4Real strgt_con_b = fix_y + Shape . GetY ( ) + Shape . Hgt ;
2009-08-15 18:50:32 +00:00
bool fWasFull = ( Con > = FullCon ) ;
2009-05-08 13:28:41 +00:00
// Change con
if ( Def - > Oversize )
Con = Max < int32_t > ( Con + iChange , 0 ) ;
else
Con = BoundBy < int32_t > ( Con + iChange , 0 , FullCon ) ;
int32_t iStepDiff = Con / iStepSize - iLastStep ;
// Update OCF
SetOCF ( ) ;
2010-03-27 16:05:02 +00:00
// If step changed or limit reached or degraded from full: update mass, face, components, etc.
if ( iStepDiff | | ( Con > = FullCon ) | | ( Con = = 0 ) | | ( fWasFull & & ( Con < FullCon ) ) )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Mass
UpdateMass ( ) ;
// Decay from full remove mask before face is changed
if ( fWasFull & & ( Con < FullCon ) )
2010-04-20 20:38:18 +00:00
if ( pSolidMaskData ) pSolidMaskData - > Remove ( false ) ;
2010-03-27 16:05:02 +00:00
// Face
UpdateFace ( true ) ;
2009-05-08 13:28:41 +00:00
// component update
2011-01-02 01:03:44 +00:00
// Decay: reduce components
if ( iChange < 0 )
ComponentConCutoff ( ) ;
// Growth: gain components
else
ComponentConGain ( ) ;
2010-03-27 16:05:02 +00:00
// Unfullcon
if ( Con < FullCon )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Lose contents
if ( ! Def - > IncompleteActivity )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Object * cobj ;
2010-01-25 04:00:59 +00:00
while ( ( cobj = Contents . GetObject ( ) ) )
2009-05-08 13:28:41 +00:00
if ( Contained ) cobj - > Enter ( Contained ) ;
else cobj - > Exit ( cobj - > GetX ( ) , cobj - > GetY ( ) ) ;
2010-03-28 18:58:01 +00:00
}
}
2009-04-12 12:03:14 +00:00
// Decay from full stop action
if ( fWasFull & & ( Con < FullCon ) )
2009-05-08 13:28:41 +00:00
if ( ! Def - > IncompleteActivity )
2009-04-12 12:03:14 +00:00
SetAction ( 0 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-01-02 01:03:44 +00:00
// bottom y-adjust
if ( ( Shape . Hgt ! = lRHgt ) | | ( Shape . GetY ( ) ! = lRy ) )
2010-03-28 18:58:01 +00:00
{
2011-01-02 01:03:44 +00:00
fix_y = strgt_con_b - Shape . Hgt - Shape . GetY ( ) ;
UpdatePos ( ) ; UpdateSolidMask ( false ) ;
2010-03-28 18:58:01 +00:00
}
2011-01-02 01:03:44 +00:00
2009-05-08 13:28:41 +00:00
// Completion (after bottom GetY()-adjust for correct position)
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
2010-03-27 16:05:02 +00:00
Info - > Experience = BoundBy < 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
r = iR ;
fix_x = itofix ( iX ) ; fix_y = itofix ( iY ) ; fix_r = itofix ( r ) ;
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 ( ) ;
2009-05-08 13:28:41 +00:00
// Engine calls
if ( fCalls ) pContainer - > Call ( PSF_Ejection , & C4AulParSet ( C4VObj ( this ) ) ) ;
if ( fCalls ) Call ( PSF_Departure , & C4AulParSet ( C4VObj ( pContainer ) ) ) ;
// 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.
// No 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
2009-08-15 18:50:32 +00:00
if ( ! ! Call ( PSF_RejectEntrance , & C4AulParSet ( C4VObj ( 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
{
2011-02-05 22:09:09 +00:00
if ( ! ! pTarget - > Call ( PSF_RejectCollection , & C4AulParSet ( C4VPropList ( Def ) , C4VObj ( 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
CloseMenu ( true ) ;
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 ( ) ;
2009-05-08 13:28:41 +00:00
// Collection call
if ( fCalls ) pTarget - > Call ( PSF_Collection2 , & C4AulParSet ( C4VObj ( 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
if ( fCalls ) Call ( PSF_Entrance , & C4AulParSet ( C4VObj ( 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 )
if ( ! ! Call ( PSF_ActivateEntrance , & C4AulParSet ( C4VObj ( by_obj ) ) ) )
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
{
2010-03-27 16:05:02 +00:00
if ( Inside < int32_t > ( r , - 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
{
2010-03-27 16:05:02 +00:00
if ( r > 0 ) { if ( rdir > - RotateAccel ) rdir - = dforce ; }
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
//CloseMenu(true);
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 ) ;
//pTarget->Def->Draw(fctSymbol,false,pTarget->Color,pTarget);
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 ) ;
//pTarget->Def->Draw(fctSymbol,false,pTarget->Color,pTarget);
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!!!
2010-04-26 23:32:45 +00:00
if ( pViewport ) Menu - > SetLocation ( ( pTarget - > GetX ( ) + pTarget - > Shape . GetX ( ) + pTarget - > Shape . Wdt + 10 - pViewport - > ViewX ) * pViewport - > GetZoom ( ) ,
( pTarget - > GetY ( ) + pTarget - > Shape . GetY ( ) - pViewport - > ViewY ) * 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
BYTE C4Object : : GetArea ( int32_t & aX , int32_t & aY , int32_t & aWdt , int32_t & aHgt )
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
BYTE C4Object : : GetEntranceArea ( int32_t & aX , int32_t & aY , int32_t & aWdt , int32_t & aHgt )
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
2010-05-04 15:35:18 +00:00
BYTE C4Object : : GetMomentum ( C4Real & rxdir , C4Real & rydir )
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
2010-05-04 15:35:18 +00:00
C4Real C4Object : : GetSpeed ( )
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
{
2011-10-14 23:59:15 +00:00
C4Value r = Call ( PSF_CalcValue , & C4AulParSet ( C4VObj ( pInBase ) , C4VInt ( 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
{
2011-10-14 23:59:15 +00:00
r = pInBase - > Call ( PSF_CalcSellValue , & C4AulParSet ( C4VObj ( this ) , C4VInt ( iValue ) ) ) ;
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 ) ;
2009-05-08 13:28:41 +00:00
StartSoundEffect ( " 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
{
2012-04-21 22:22:05 +00:00
// TODO: Clear pointers on mesh instance:
// Check for attach children using pObj's mesh instance
// Check for animation nodes refering to pObj (Anim_X, ...).
2009-05-08 13:28:41 +00:00
// effects
if ( pEffects ) pEffects - > ClearPointers ( pObj ) ;
// contents/contained: not necessary, because it's done in AssignRemoval and StatusDeactivate
// 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 ) ;
2009-07-28 01:49:33 +00:00
Action . Phase = BoundBy < 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
{
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
2010-03-28 18:58:01 +00:00
if ( Def - > Line ) { DrawLine ( cgo ) ; return ; }
2009-05-08 13:28:41 +00:00
// background particles (bounds not checked)
if ( BackParticles & & ! Contained & & eDrawMode ! = ODM_BaseOnly ) BackParticles . Draw ( cgo , this ) ;
// Object output position
2010-09-23 01:51:08 +00:00
float newzoom ;
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
if ( ! eDrawMode ) SetAudibilityAt ( cgo , GetX ( ) , GetY ( ) ) ;
2010-03-27 16:05:02 +00:00
// Output boundary
2009-05-08 13:28:41 +00:00
if ( ! fYStretchObject & & ! eDrawMode )
2010-03-28 18:58:01 +00:00
{
2010-03-18 23:04:29 +00:00
if ( pActionDef & & ! r & & ! pActionDef - > GetPropertyInt ( P_FacetBase ) & & Con < = FullCon )
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 ) ) )
2009-05-08 13:28:41 +00:00
{ if ( FrontParticles & & ! Contained ) FrontParticles . Draw ( cgo , this ) ; 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 ) ) )
2009-05-08 13:28:41 +00:00
{ if ( FrontParticles & & ! Contained ) FrontParticles . Draw ( cgo , this ) ; 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 ;
//sprintf(szCommand,"%s %d/%d",CommandName(pCom->Command),pCom->Tx,pCom->Ty,iAngle);
break ;
case C4CMD_Put :
sprintf ( szCommand , " %s %s to %s " , CommandName ( pCom - > Command ) , pCom - > Target2 ? pCom - > Target2 - > GetName ( ) : pCom - > Data ? pCom - > Data . getC4ID ( ) . ToString ( ) : " Content " , pCom - > Target ? pCom - > Target - > GetName ( ) : " " ) ;
break ;
case C4CMD_Buy : case C4CMD_Sell :
sprintf ( szCommand , " %s %s at %s " , CommandName ( pCom - > Command ) , pCom - > Data . getC4ID ( ) . ToString ( ) , pCom - > Target ? pCom - > Target - > GetName ( ) : " closest base " ) ;
break ;
case C4CMD_Acquire :
sprintf ( szCommand , " %s %s " , CommandName ( pCom - > Command ) , pCom - > Data . getC4ID ( ) . ToString ( ) ) ;
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)
2009-06-05 15:14:20 +00:00
if ( : : GraphicsSystem . ShowSolidMask )
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
bool fOldClrModEnabled = ! ! ( Category & C4D_IgnoreFoW ) ;
if ( fOldClrModEnabled )
2010-03-28 18:58:01 +00:00
{
2011-10-03 14:30:18 +00:00
fOldClrModEnabled = pDraw - > GetClrModMapEnabled ( ) ;
pDraw - > SetClrModMapEnabled ( false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Fire facet - always draw, even if particles are drawn as well
2009-06-05 15:22:28 +00:00
if ( OnFire /*&& !::Particles.IsFireParticleLoaded()*/ ) if ( eDrawMode ! = ODM_BaseOnly )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
C4Facet fgo ;
// Straight: Full Shape.Rect on fire
if ( r = = 0 )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
fgo . Set ( cgo . Surface , offX + Shape . GetX ( ) , offY + Shape . GetY ( ) ,
Shape . Wdt , Shape . Hgt - Shape . FireTop ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
// Rotated: Reduced fire rect
else
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
C4Rect fr ;
Shape . GetVertexOutline ( fr ) ;
fgo . Set ( cgo . Surface ,
offX + fr . x ,
offY + fr . y ,
fr . Wdt , fr . Hgt ) ;
2009-05-08 13:28:41 +00:00
}
2011-03-12 19:49:36 +00:00
: : GraphicsResource . fctFire . Draw ( fgo , false , ( Number + Game . FrameCounter ) % MaxFirePhase ) ;
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
if ( FrontParticles ) if ( eDrawMode ! = ODM_BaseOnly ) FrontParticles . Draw ( cgo , this ) ;
// 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
2011-10-03 14:30:18 +00:00
if ( fOldClrModEnabled ) pDraw - > SetClrModMapEnabled ( fOldClrModEnabled ) ;
2009-05-08 13:28:41 +00:00
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
{
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)
2010-09-23 01:51:08 +00:00
float newzoom ;
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
// Clonk name
// Name of Owner/Clonk (only when Crew Member; never in films)
2010-09-23 01:51:08 +00:00
if ( OCF & OCF_CrewMember )
if ( ( Config . Graphics . ShowCrewNames | | Config . Graphics . ShowCrewCNames ) & & ( ! Game . C4S . Head . Film | | ! Game . C4S . Head . Replay ) )
if ( ! eDrawMode )
2010-03-28 18:58:01 +00:00
if ( Owner ! = iByPlayer & & ! Contained )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
// inside screen range?
2010-09-23 01:51:08 +00:00
if ( ! Inside < int > ( offX + Shape . GetX ( ) , cgo . X - Shape . Wdt , cgo . X + cgo . Wdt )
| | ! Inside < int > ( offY + Shape . GetY ( ) , cgo . Y - Shape . Hgt , cgo . Y + cgo . Hgt ) ) return ;
2010-03-28 18:58:01 +00:00
// get player
C4Player * pOwner = : : Players . Get ( Owner ) ;
2010-09-23 01:51:08 +00:00
if ( pOwner )
if ( ! Hostile ( Owner , iByPlayer ) )
if ( ! pOwner - > IsInvisible ( ) )
2010-03-28 18:58:01 +00:00
{
// compose string
char szText [ C4GM_MaxText + 1 ] ;
if ( Config . Graphics . ShowCrewNames )
if ( Config . Graphics . ShowCrewCNames )
sprintf ( szText , " %s (%s) " , GetName ( ) , pOwner - > GetName ( ) ) ;
else
SCopy ( pOwner - > GetName ( ) , szText ) ;
else
SCopy ( GetName ( ) , szText ) ;
// Word wrap to cgo width
int32_t iCharWdt , dummy ; : : GraphicsResource . FontRegular . GetTextExtent ( " m " , iCharWdt , dummy , false ) ;
int32_t iMaxLine = Max < int32_t > ( cgo . Wdt / iCharWdt , 20 ) ;
SWordWrap ( szText , ' ' , ' | ' , iMaxLine ) ;
// Adjust position by output boundaries
2010-09-23 01:51:08 +00:00
float iTX , iTY ;
int iTWdt , iTHgt ;
2010-03-28 18:58:01 +00:00
: : GraphicsResource . FontRegular . GetTextExtent ( szText , iTWdt , iTHgt , true ) ;
2010-09-23 01:51:08 +00:00
iTX = BoundBy < int > ( offX , cgo . X + iTWdt / 2 , cgo . X + cgo . Wdt - iTWdt / 2 ) ;
iTY = BoundBy < int > ( offY - Def - > Shape . Hgt / 2 - 20 - iTHgt , cgo . Y , cgo . Y + cgo . Hgt - iTHgt ) ;
2010-03-28 18:58:01 +00:00
// Draw
2011-10-03 14:30:18 +00:00
pDraw - > TextOut ( szText , : : GraphicsResource . FontRegular , 1.0 , cgo . Surface , iTX , iTY ,
2010-03-28 18:58:01 +00:00
pOwner - > ColorDw | 0x7f000000 , ACenter ) ;
}
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)
2010-09-23 01:51:08 +00:00
if ( : : GraphicsSystem . ShowSolidMask & & SolidMask . Wdt ) return ;
2009-05-08 13:28:41 +00:00
// Contained
if ( Contained ) if ( eDrawMode ! = ODM_Overlay ) return ;
// Construction sign
2010-09-23 01:51:08 +00:00
if ( OCF & OCF_Construct & & r = = 0 )
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 ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : DrawLine ( C4TargetFacet & cgo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Audibility
SetAudibilityAt ( cgo , Shape . VtxX [ 0 ] , Shape . VtxY [ 0 ] ) ;
SetAudibilityAt ( cgo , Shape . VtxX [ Shape . VtxNum - 1 ] , Shape . VtxY [ Shape . VtxNum - 1 ] ) ;
// 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 ( ) ;
2010-03-28 18:58:01 +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 ( ) ;
color1 = colors - > GetItem ( 1 ) . getInt ( ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
for ( int32_t vtx = 0 ; vtx + 1 < Shape . VtxNum ; vtx + + )
2010-12-21 18:22:06 +00:00
cgo . DrawLineDw ( Shape . VtxX [ vtx ] , Shape . VtxY [ vtx ] ,
Shape . VtxX [ vtx + 1 ] , Shape . VtxY [ vtx + 1 ] ,
color0 , color1 ) ;
2009-05-08 13:28:41 +00:00
// reset blit mode
FinishedDrawing ( ) ;
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 ( r , " Rotation " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( iLastAttachMovementFrame , " LastSolidAtchFrame " , - 1 ) ) ;
pComp - > Value ( mkNamingAdapt ( NoCollectDelay , " NoCollectDelay " , 0 ) ) ;
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 ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkParAdapt ( Shape , true ) ) ;
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 ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( Component , " Component " ) ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( Contents , numbers ) , " Contents " ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( PlrViewRange , " PlrViewRange " , 0 ) ) ;
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 " ) ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkParAdapt ( mkNamingPtrAdapt ( pEffects , " Effects " ) , 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
2010-06-28 20:34:34 +00:00
void C4Object : : DrawPicture ( C4Facet & cgo , bool fSelected , C4RegionList * pRegions , 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 ) ;
2009-05-08 13:28:41 +00:00
// Region
if ( pRegions ) pRegions - > Add ( cgo . X , cgo . Y , cgo . Wdt , cgo . Hgt , GetName ( ) , COM_None , this ) ;
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
2009-08-15 18:50:32 +00:00
bool C4Object : : AssignPlrViewRange ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no range?
2009-08-15 18:50:32 +00:00
if ( ! PlrViewRange ) return true ;
2009-05-08 13:28:41 +00:00
// add to FoW-repellers
PlrFoWActualize ( ) ;
// 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
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
{
2009-05-08 13:28:41 +00:00
if ( pEffects ) { delete pEffects ; pEffects = NULL ; }
if ( FrontParticles ) FrontParticles . Clear ( ) ;
if ( BackParticles ) BackParticles . Clear ( ) ;
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 ;
2009-05-08 13:28:41 +00:00
return ! ! Def - > Script . DirectExec ( this , szCommand , " MenuCommand " ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Object * C4Object : : ComposeContents ( C4ID id )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t cnt , cnt2 ;
C4ID c_id ;
2009-08-15 18:50:32 +00:00
bool fInsufficient = false ;
2009-05-08 13:28:41 +00:00
C4Object * pObj ;
2010-01-25 03:14:52 +00:00
C4ID idNeeded = C4ID : : None ;
2009-05-08 13:28:41 +00:00
int32_t iNeeded = 0 ;
// Get def
C4Def * pDef = C4Id2Def ( id ) ; if ( ! pDef ) return NULL ;
// get needed contents
C4IDList NeededComponents ;
2011-07-31 00:22:29 +00:00
pDef - > GetComponents ( & NeededComponents , NULL ) ;
2009-05-08 13:28:41 +00:00
// Check for sufficient components
2010-03-27 16:05:02 +00:00
StdStrBuf Needs ; Needs . Format ( LoadResStr ( " IDS_CON_BUILDMATNEED " ) , pDef - > GetName ( ) ) ;
2010-01-25 04:00:59 +00:00
for ( cnt = 0 ; ( c_id = NeededComponents . GetID ( cnt ) ) ; cnt + + )
2009-05-08 13:28:41 +00:00
if ( NeededComponents . GetCount ( cnt ) > Contents . ObjectCount ( c_id ) )
2010-03-28 18:58:01 +00:00
{
2010-01-25 15:57:57 +00:00
Needs . AppendFormat ( " |%ix %s " , NeededComponents . GetCount ( cnt ) - Contents . ObjectCount ( c_id ) , C4Id2Def ( c_id ) ? C4Id2Def ( c_id ) - > GetName ( ) : c_id . ToString ( ) ) ;
2009-05-08 13:28:41 +00:00
if ( ! idNeeded ) { idNeeded = c_id ; iNeeded = NeededComponents . GetCount ( cnt ) - Contents . ObjectCount ( c_id ) ; }
2009-08-15 18:50:32 +00:00
fInsufficient = true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Insufficient
if ( fInsufficient )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// BuildNeedsMaterial call to object...
2011-02-05 22:09:09 +00:00
if ( ! Call ( PSF_BuildNeedsMaterial , & C4AulParSet ( C4VPropList ( C4Id2Def ( idNeeded ) ) , C4VInt ( iNeeded ) ) ) )
2009-05-08 13:28:41 +00:00
// ...game message if not overloaded
2010-06-28 23:02:16 +00:00
GameMsgObjectError ( Needs . getData ( ) , this ) ;
2009-05-08 13:28:41 +00:00
// Return
return NULL ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Remove components
2010-01-25 04:00:59 +00:00
for ( cnt = 0 ; ( c_id = NeededComponents . GetID ( cnt ) ) ; cnt + + )
2009-05-08 13:28:41 +00:00
for ( cnt2 = 0 ; cnt2 < NeededComponents . GetCount ( cnt ) ; cnt2 + + )
if ( ! ( pObj = Contents . Find ( c_id ) ) )
return NULL ;
else
pObj - > AssignRemoval ( ) ;
// Create composed object
// the object is created with default components instead of builder components
// this is done because some objects (e.g. arrow packs) will set custom components during initialization, which should not be overriden
2009-04-12 12:04:28 +00:00
return CreateContents ( C4Id2Def ( id ) ) ;
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
{
2009-05-08 13:28:41 +00:00
// remove osld
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
bool C4Object : : CheckSolidMaskRect ( )
2010-03-28 18:58:01 +00:00
{
2009-07-10 23:10:18 +00:00
// SolidMasks are only supported for bitmap graphics
2010-03-28 18:58:01 +00:00
if ( GetGraphics ( ) - > Type ! = C4DefGraphics : : TYPE_Bitmap ) return false ;
2009-07-10 23:10:18 +00:00
2009-05-08 13:28:41 +00:00
// check NewGfx only, because invalid SolidMask-rects are OK in OldGfx
2011-10-03 14:34:08 +00:00
// the bounds-check is done in C4Draw::GetPixel()
2011-10-03 14:06:41 +00:00
C4Surface * sfcGraphics = GetGraphics ( ) - > GetBitmap ( ) ;
2009-05-08 13:28:41 +00:00
SolidMask . Set ( Max < int32_t > ( SolidMask . x , 0 ) , Max < int32_t > ( SolidMask . y , 0 ) ,
Min < int32_t > ( SolidMask . Wdt , sfcGraphics - > Wdt - SolidMask . x ) , Min < int32_t > ( SolidMask . Hgt , sfcGraphics - > Hgt - SolidMask . y ) ,
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 ;
// Fixed point values - precision reduction
fix_r = itofix ( r ) ;
// 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
2010-09-24 17:51:34 +00:00
void C4Object : : DrawSelectMark ( C4TargetFacet & cgo )
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
//sprintf(OSTR,"%s command %s added: %i/%i %s %s (%i)",GetName(),CommandName(iCommand),iTx,iTy,pTarget ? pTarget->GetName() : "O",pTarget2 ? pTarget2->GetName() : "O",iUpdateInterval); Log(OSTR);
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 )
{
2010-03-27 16:05:02 +00:00
// Decrease NoCollectDelay
if ( NoCollectDelay > 0 ) NoCollectDelay - - ;
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 )
if ( ! ! Call ( PSF_ControlCommand , & C4AulParSet ( C4VString ( CommandName ( iCommand ) ) ,
2010-03-28 18:58:01 +00:00
C4VObj ( pTarget ) ,
iTx ,
C4VInt ( iTy ) ,
C4VObj ( pTarget2 ) ,
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 ;
if ( ! ! Contained - > Call ( PSF_ControlCommand , & C4AulParSet ( C4VString ( CommandName ( iCommand ) ) ,
2010-03-28 18:58:01 +00:00
C4VObj ( pTarget ) ,
iTx ,
C4VInt ( iTy ) ,
C4VObj ( pTarget2 ) ,
iData ,
C4VObj ( 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 ;
if ( ! ! Action . Target - > Call ( PSF_ControlCommand , & C4AulParSet ( C4VString ( CommandName ( iCommand ) ) ,
C4VObj ( pTarget ) ,
iTx ,
C4VInt ( iTy ) ,
C4VObj ( pTarget2 ) ,
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
C4Command * C4Object : : FindCommand ( int32_t iCommandType )
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 )
2009-07-20 20:42:38 +00:00
Call ( PSF_ControlCommandFinished , & C4AulParSet ( C4VString ( CommandName ( Command - > Command ) ) , C4VObj ( Command - > Target ) , Command - > Tx , C4VInt ( Command - > Ty ) , C4VObj ( 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
2010-02-02 18:25:51 +00:00
Action . Animation = pMeshInstance - > PlayAnimation ( Animation - > GetData ( ) , 0 , NULL , new C4ValueProviderAction ( this ) , new C4ValueProviderConst ( itofix ( 1 ) ) ) ;
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 ;
// reset action data if procedure is changed
2010-12-08 22:17:00 +00:00
if ( ( Act ? Act - > GetPropertyP ( P_Procedure ) : - 1 )
! = ( LastAction ? LastAction - > GetPropertyP ( P_Procedure ) : - 1 ) )
2010-03-28 18:58:01 +00:00
Action . Data = 0 ;
}
2009-04-12 12:03:14 +00:00
// Set new action
2010-03-28 18:58:01 +00:00
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 ;
Call ( LastAction - > GetPropertyStr ( P_AbortCall ) - > GetCStr ( ) , & C4AulParSet ( C4VInt ( iLastPhase ) , C4VObj ( pLastTarget ) , C4VObj ( 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 ;
Call ( PSF_OnActionChanged , & C4AulParSet ( C4VString ( LastAction ? LastAction - > GetName ( ) : " Idle " ) ) ) ;
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
int32_t C4Object : : GetProcedure ( )
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
void GrabLost ( C4Object * cObj )
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...)
cObj - > Action . Target - > Call ( PSF_GrabLost ) ;
2010-07-29 19:11:04 +00:00
// Also, delete the target from the clonk's action (Newton)
cObj - > Action . Target = NULL ;
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 ( ) ;
// 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
if ( iProcedure = = DFA_PUSH ) GrabLost ( this ) ;
// 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
2009-08-15 18:50:32 +00:00
bool ContactVtxCNAT ( C4Object * cobj , BYTE cnat_dir ) ;
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.
2010-05-04 15:35:18 +00:00
C4Real last_xdir ;
2009-05-08 13:28:41 +00:00
int32_t iDir ;
// 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 :
if ( ydir < 0 ) break ;
// Jump: FlatHit / HardHit / Walk
if ( ( OCF & OCF_HitSpeed4 ) | | fDisabled )
if ( ObjectActionFlat ( this , Action . Dir ) ) return ;
if ( OCF & OCF_HitSpeed3 )
if ( ObjectActionKneel ( this ) ) return ;
// Walk, but keep horizontal momentum (momentum is reset
// by ObjectActionWalk) to avoid walk-jump-flipflop on
// sideways corner hit if initial walk acceleration is
// not enough to reach the next pixel for attachment.
// Urks, all those special cases...
last_xdir = xdir ;
ObjectActionWalk ( this ) ;
xdir = last_xdir ;
return ;
case DFA_SCALE :
// Scale up: try corner scale
if ( ! ComDirLike ( Action . ComDir , COMD_Down ) )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
if ( ObjectActionCornerScale ( this ) ) return ;
2009-05-08 13:28:41 +00:00
return ;
}
2010-03-28 18:58:01 +00:00
// Any other: Stand
ObjectActionStand ( this ) ;
return ;
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
if ( ! GBackLiquid ( GetX ( ) , GetY ( ) - 1 ) )
if ( ObjectActionCornerScale ( this ) ) return ;
return ;
}
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 ) )
{
2010-12-12 00:09:29 +00:00
iDir = DIR_Left ;
if ( Action . Dir = = DIR_Left ) { iDir = DIR_Right ; }
if ( ObjectActionHangle ( this , iDir ) ) return ;
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 )
{ ObjectActionTumble ( this , Action . Dir , Fix0 , Fix0 ) ; break ; }
2010-12-12 00:09:29 +00:00
if ( ObjectActionHangle ( this , Action . Dir ) ) 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 )
2010-05-19 03:19:49 +00:00
{ ObjectActionTumble ( this , DIR_Left , C4REAL100 ( + 150 ) , Fix0 ) ; break ; }
2010-03-28 18:58:01 +00:00
// Else
2010-12-12 00:09:29 +00:00
else if ( ObjectActionScale ( this , DIR_Left ) ) return ;
2010-03-28 18:58:01 +00:00
break ;
case DFA_WALK :
// Walk: Try scale, else stop
if ( ComDirLike ( Action . ComDir , COMD_Left ) )
2009-05-08 13:28:41 +00:00
{
2010-12-12 00:09:29 +00:00
if ( ObjectActionScale ( this , DIR_Left ) ) return ;
2010-03-28 18:58:01 +00:00
// Else stop
Action . ComDir = COMD_Stop ;
}
// 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 :
// Try scale
if ( ComDirLike ( Action . ComDir , COMD_Left ) )
2010-12-12 00:09:29 +00:00
if ( ObjectActionScale ( this , DIR_Left ) ) return ;
2010-03-28 18:58:01 +00:00
// Try corner scale out
if ( ObjectActionCornerScale ( this ) ) return ;
return ;
case DFA_HANGLE :
// Hangle: Try scale, else stop
2010-12-12 00:09:29 +00:00
if ( ObjectActionScale ( this , DIR_Left ) )
return ;
2010-03-28 18:58:01 +00:00
Action . ComDir = COMD_Stop ;
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 )
2010-05-19 03:19:49 +00:00
{ ObjectActionTumble ( this , DIR_Right , C4REAL100 ( - 150 ) , Fix0 ) ; break ; }
2010-03-28 18:58:01 +00:00
// Else Scale
2010-12-12 00:09:29 +00:00
else if ( ObjectActionScale ( this , DIR_Right ) ) return ;
2010-03-28 18:58:01 +00:00
break ;
case DFA_WALK :
// Walk: Try scale, else stop
if ( ComDirLike ( Action . ComDir , COMD_Right ) )
2009-05-08 13:28:41 +00:00
{
2010-12-12 00:09:29 +00:00
if ( ObjectActionScale ( this , DIR_Right ) ) return ;
2009-05-08 13:28:41 +00:00
Action . ComDir = COMD_Stop ;
}
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 :
// Try scale
if ( ComDirLike ( Action . ComDir , COMD_Right ) )
2010-12-12 00:09:29 +00:00
if ( ObjectActionScale ( this , DIR_Right ) ) return ;
2010-03-28 18:58:01 +00:00
// Try corner scale out
if ( ObjectActionCornerScale ( this ) ) return ;
// Skip to enable walk out
return ;
case DFA_HANGLE :
// Hangle: Try scale, else stop
2010-12-12 00:09:29 +00:00
if ( ObjectActionScale ( this , DIR_Right ) )
return ;
2010-03-28 18:58:01 +00:00
Action . ComDir = COMD_Stop ;
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
{
2009-05-08 13:28:41 +00:00
// special for roof above Clonk: The nonmoving roof is started at bridgelength before the Clonkl
// 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 ;
2010-03-27 16:05:02 +00:00
if ( ! GBackLiquid ( cobj - > GetX ( ) , cobj - > GetY ( ) - 1 + cobj - > Def - > Float * cobj - > GetCon ( ) / FullCon - 1 ) )
if ( cobj - > ydir < 0 ) 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-03-27 16:05:02 +00:00
Action . t_attach = CNAT_None ;
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 )
if ( Inside < int32_t > ( r , - 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
2009-04-12 12:03:14 +00:00
// Idle objects do natural gravity only
2010-03-18 23:04:29 +00:00
C4PropList * pActionDef = GetAction ( ) ;
if ( ! pActionDef )
2010-03-28 18:58:01 +00:00
{
2009-04-12 12:03:14 +00:00
if ( Mobile ) DoGravity ( this ) ;
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// No IncompleteActivity? Reset action
if ( ! ( OCF & OCF_FullCon ) & & ! Def - > IncompleteActivity )
2009-04-12 12:03:14 +00:00
{ SetAction ( 0 ) ; return ; }
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
C4Real fWalk , fMove ;
2009-04-12 12:03:14 +00:00
int32_t smpx , smpy ;
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
2009-04-12 12:03:14 +00:00
// InLiquidAction check
if ( InLiquid )
2010-03-18 23:04:29 +00:00
if ( pActionDef - > GetPropertyStr ( P_InLiquidAction ) )
{ SetActionByName ( pActionDef - > GetPropertyStr ( P_InLiquidAction ) ) ; return ; }
2009-05-08 13:28:41 +00:00
// assign extra action attachment (CNAT_MultiAttach)
// regular attachment values cannot be set for backwards compatibility reasons
// this parameter had always been ignored for actions using an internal procedure,
// but is for some obscure reasons set in the KneelDown-actions of the golems
2010-03-18 23:04:29 +00:00
Action . t_attach | = ( pActionDef - > GetPropertyInt ( P_Attach ) & CNAT_MultiAttach ) ;
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 ) ) ;
C4Real decel = C4REAL100 ( pActionDef - > GetPropertyInt ( P_Decel ) ) ;
2011-07-05 10:47:07 +00:00
C4Real limit = C4REAL100 ( pActionDef - > GetPropertyInt ( P_Speed ) ) ;
2010-05-04 15:35:18 +00:00
2011-07-05 10:47:07 +00:00
C4Real lFlightAccel ;
C4Real rFlightAccel ;
2010-01-23 22:58:25 +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
Action . t_attach | = CNAT_Bottom ;
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 ;
Action . t_attach | = CNAT_Bottom ;
Mobile = 1 ;
break ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_SCALE :
{
int ComDir = Action . ComDir ;
if ( Action . Dir = = DIR_Left & & ComDir = = COMD_Left )
ComDir = COMD_Up ;
else if ( Action . Dir = = DIR_Right & & ComDir = = COMD_Right )
ComDir = COMD_Up ;
switch ( ComDir )
{
case COMD_Up : case COMD_UpRight : case COMD_UpLeft :
2011-07-05 10:47:07 +00:00
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 :
2011-07-05 10:47:07 +00:00
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 :
2010-12-11 21:00:06 +00:00
if ( ydir < 0 ) ydir + = accel ;
if ( ydir > 0 ) ydir - = accel ;
if ( ( ydir > - accel ) & & ( ydir < + accel ) ) 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 ;
if ( Action . Dir = = DIR_Left ) Action . t_attach | = CNAT_Left ;
if ( Action . Dir = = DIR_Right ) Action . t_attach | = CNAT_Right ;
Mobile = 1 ;
break ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_HANGLE :
switch ( Action . ComDir )
{
case COMD_Left : case COMD_UpLeft : case COMD_DownLeft :
2011-07-05 10:47:07 +00:00
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 :
2011-07-05 10:47:07 +00:00
xdir + = accel ; if ( xdir > + limit ) xdir = + limit ;
2010-03-28 18:58:01 +00:00
break ;
case COMD_Up :
2010-12-11 21:00:06 +00:00
xdir + = ( Action . Dir = = DIR_Left ) ? - accel : accel ;
2011-07-05 10:47:07 +00:00
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 :
2010-12-11 21:00:06 +00:00
if ( xdir < 0 ) xdir + = accel ;
if ( xdir > 0 ) xdir - = accel ;
if ( ( xdir > - accel ) & & ( xdir < + accel ) ) 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 ;
Action . t_attach | = CNAT_Top ;
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
2011-07-05 10:47:07 +00:00
lFlightAccel = Max ( Min ( limit + xdir , accel ) , itofix ( 0 ) ) ;
rFlightAccel = Max ( Min ( limit - xdir , accel ) , itofix ( 0 ) ) ;
2010-03-28 18:58:01 +00:00
switch ( Action . ComDir )
{
case COMD_Left : case COMD_UpLeft : case COMD_DownLeft :
2011-07-05 10:47:07 +00:00
xdir - = lFlightAccel ;
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 :
2011-07-05 10:47:07 +00:00
xdir + = rFlightAccel ;
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 :
{
if ( pActionDef - > GetPropertyInt ( P_Attach ) )
{
Action . t_attach | = pActionDef - > GetPropertyInt ( P_Attach ) ;
}
else
{
Action . t_attach | = CNAT_Bottom ;
}
smpx = GetX ( ) ; smpy = GetY ( ) ;
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
Action . t_attach = CNAT_None ;
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 :
//ydir=0; xdir=0;
Action . t_attach | = CNAT_Bottom ;
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 ;
Action . t_attach | = CNAT_Bottom ;
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
iPushDistance = Max ( Shape . Wdt / 2 - 8 , 0 ) ;
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 ) )
{
// Wait command (why, anyway?)
StopActionDelayCommand ( this ) ;
// Grab lost action
GrabLost ( this ) ;
// 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
iTargetX = BoundBy ( GetX ( ) , sax - iPushDistance , sax + sawdt - 1 + iPushDistance ) ;
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 ;
// Attachment
Action . t_attach | = CNAT_Bottom ;
// Mobile
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
2010-03-28 18:58:01 +00:00
iTXDir = fMove + fWalk * BoundBy < 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
iPushDistance = Max ( Shape . Wdt / 2 - 8 , 0 ) ;
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 ) )
{
// Wait command (why, anyway?)
StopActionDelayCommand ( this ) ;
// Grab lost action
GrabLost ( this ) ;
// 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
xdir = fMove + fWalk * BoundBy < int32_t > ( iTargetX - GetX ( ) , - 10 , + 10 ) / 10 ;
// 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 ;
// Attachment
Action . t_attach | = CNAT_Bottom ;
// Mobile
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 )
{
2011-07-05 10:47:07 +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 ;
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
Exit ( GetX ( ) , GetY ( ) , r ) ;
}
2010-03-27 16:05:02 +00:00
2010-03-28 18:58:01 +00:00
// Force position
2010-10-10 16:46:23 +00:00
ForcePosition ( Action . Target - > fix_x + Action . Target - > Shape . VtxX [ Action . Data & 255 ]
2010-03-28 18:58:01 +00:00
- Shape . VtxX [ Action . Data > > 8 ] ,
2010-10-10 16:46:23 +00:00
Action . Target - > fix_y + Action . Target - > Shape . VtxY [ Action . Data & 255 ]
2010-03-28 18:58:01 +00:00
- Shape . VtxY [ Action . Data > > 8 ] ) ;
// 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 :
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
bool fBroke ;
fBroke = false ;
2010-12-21 18:22:06 +00:00
int32_t iConnectX , iConnectY ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +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 )
{
Call ( PSF_LineBreak , & C4AulParSet ( C4VBool ( true ) ) ) ;
AssignRemoval ( ) ;
return ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Movement by Target
if ( Action . Target )
{
2010-12-21 18:22:06 +00:00
// Connect to attach vertex
C4Value lineAttachV ;
Action . Target - > GetProperty ( P_LineAttach , & lineAttachV ) ;
C4ValueArray * lineAttach = lineAttachV . getArray ( ) ;
iConnectX = Action . Target - > GetX ( ) ;
iConnectY = Action . Target - > GetY ( ) ;
if ( lineAttach )
2010-03-28 18:58:01 +00:00
{
2010-12-21 18:22:06 +00:00
iConnectX + = lineAttach - > GetItem ( 0 ) . getInt ( ) ;
iConnectY + = lineAttach - > GetItem ( 1 ) . getInt ( ) ;
2010-03-28 18:58:01 +00:00
}
if ( ( iConnectX ! = Shape . VtxX [ 0 ] ) | | ( iConnectY ! = Shape . VtxY [ 0 ] ) )
{
// Regular wrapping line
if ( Def - > LineIntersect = = 0 )
if ( ! Shape . LineConnect ( iConnectX , iConnectY , 0 , + 1 ,
Shape . VtxX [ 0 ] , Shape . VtxY [ 0 ] ) ) fBroke = true ;
// No-intersection line
if ( Def - > LineIntersect = = 1 )
{ Shape . VtxX [ 0 ] = iConnectX ; Shape . VtxY [ 0 ] = iConnectY ; }
}
}
// Movement by Target2
if ( Action . Target2 )
{
2010-12-21 18:22:06 +00:00
// Connect to attach vertex
C4Value lineAttachV ;
Action . Target2 - > GetProperty ( P_LineAttach , & lineAttachV ) ;
C4ValueArray * lineAttach = lineAttachV . getArray ( ) ;
iConnectX = Action . Target2 - > GetX ( ) ;
iConnectY = Action . Target2 - > GetY ( ) ;
if ( lineAttach )
2010-03-28 18:58:01 +00:00
{
2010-12-21 18:22:06 +00:00
iConnectX + = lineAttach - > GetItem ( 0 ) . getInt ( ) ;
iConnectY + = lineAttach - > GetItem ( 1 ) . getInt ( ) ;
2010-03-28 18:58:01 +00:00
}
if ( ( iConnectX ! = Shape . VtxX [ Shape . VtxNum - 1 ] ) | | ( iConnectY ! = Shape . VtxY [ Shape . VtxNum - 1 ] ) )
{
// Regular wrapping line
if ( Def - > LineIntersect = = 0 )
if ( ! Shape . LineConnect ( iConnectX , iConnectY , Shape . VtxNum - 1 , - 1 ,
Shape . VtxX [ Shape . VtxNum - 1 ] , Shape . VtxY [ Shape . VtxNum - 1 ] ) ) fBroke = true ;
// No-intersection line
if ( Def - > LineIntersect = = 1 )
{ Shape . VtxX [ Shape . VtxNum - 1 ] = iConnectX ; Shape . VtxY [ Shape . VtxNum - 1 ] = iConnectY ; }
}
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Line fBroke
if ( fBroke )
{
Call ( PSF_LineBreak , 0 ) ;
AssignRemoval ( ) ;
return ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Reduce line segments
if ( ! : : Game . iTick35 )
ReduceLineSegments ( Shape , ! : : Game . iTick2 ) ;
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
default :
// Attach
if ( pActionDef - > GetPropertyInt ( P_Attach ) )
{
Action . t_attach | = pActionDef - > GetPropertyInt ( P_Attach ) ;
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
C4Player * pPlr ;
// 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
// remove old owner view
if ( ValidPlr ( Owner ) )
2010-03-28 18:58:01 +00:00
{
2009-06-12 23:09:32 +00:00
pPlr = : : Players . Get ( Owner ) ;
2009-05-08 13:28:41 +00:00
while ( pPlr - > FoWViewObjs . Remove ( this ) ) { }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2009-06-12 23:09:32 +00:00
for ( pPlr = : : Players . First ; pPlr ; pPlr = pPlr - > Next )
2009-05-08 13:28:41 +00:00
while ( pPlr - > FoWViewObjs . Remove ( this ) ) { }
// 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
if ( Owner ! = NO_OWNER )
// add to plr view
PlrFoWActualize ( ) ;
// this automatically updates controller
Controller = Owner ;
// script callback
Call ( PSF_OnOwnerChanged , & C4AulParSet ( C4VInt ( Owner ) , C4VInt ( iOldOwner ) ) ) ;
// 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
2009-08-15 18:50:32 +00:00
bool C4Object : : SetPlrViewRange ( int32_t iToRange )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// set new range
PlrViewRange = iToRange ;
// resort into player's FoW-repeller-list
PlrFoWActualize ( ) ;
// 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
void C4Object : : PlrFoWActualize ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Player * pPlr ;
// single owner?
if ( ValidPlr ( Owner ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// single player's FoW-list
2009-06-12 23:09:32 +00:00
pPlr = : : Players . Get ( Owner ) ;
2009-05-08 13:28:41 +00:00
while ( pPlr - > FoWViewObjs . Remove ( this ) ) { }
if ( PlrViewRange ) pPlr - > FoWViewObjs . Add ( this , C4ObjectList : : stNone ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// no owner?
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// all players!
2009-06-12 23:09:32 +00:00
for ( pPlr = : : Players . First ; pPlr ; pPlr = pPlr - > Next )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
while ( pPlr - > FoWViewObjs . Remove ( this ) ) { }
if ( PlrViewRange ) pPlr - > FoWViewObjs . Add ( this , C4ObjectList : : stNone ) ;
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Object : : SetAudibilityAt ( C4TargetFacet & cgo , int32_t iX , int32_t iY )
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 ) ;
2010-09-23 01:51:08 +00:00
Audible = Max < int > ( Audible , BoundBy ( 100 - 100 * Distance ( cgo . X + cgo . Wdt / 2 , cgo . Y + cgo . Hgt / 2 , offX , offY ) / 700 , 0 , 100 ) ) ;
AudiblePan = BoundBy < int > ( 200 * ( offX - cgo . X - ( cgo . Wdt / 2 ) ) / cgo . Wdt , - 100 , 100 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : IsVisible ( int32_t iForPlr , bool fAsOverlay )
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 ;
}
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
bool C4Object : : IsInLiquidCheck ( )
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
r = nr ;
fix_r = itofix ( nr ) ;
2009-05-08 13:28:41 +00:00
// Update face
UpdateFace ( true ) ;
}
void C4Object : : PrepareDrawing ( )
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
void C4Object : : FinishedDrawing ( )
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
void C4Object : : DrawSolidMask ( C4TargetFacet & cgo )
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
Call ( PSF_Collection , & C4AulParSet ( C4VObj ( pObj ) ) ) ;
// 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
C4ObjectLink * pLnk = fShiftBack ? ( Contents . Last ) : ( Contents . First - > Next ) ;
2010-03-28 18:58:01 +00:00
for ( ; ; )
{
2009-05-08 13:28:41 +00:00
// end reached without success
2009-08-15 18:50:32 +00:00
if ( ! pLnk ) return false ;
2009-05-08 13:28:41 +00:00
// check object
C4Object * pObj = pLnk - > Obj ;
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
pLnk = fShiftBack ? ( pLnk - > Prev ) : ( pLnk - > Next ) ;
}
2010-03-28 18:58:01 +00:00
// not reached
}
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 )
2011-02-05 22:09:09 +00:00
if ( Call ( " ~ControlContents " , & C4AulParSet ( C4VPropList ( pTarget ) ) ) )
2009-05-08 13:28:41 +00:00
return ;
// default action
if ( ! ( Contents . ShiftContents ( pTarget ) ) ) return ;
// Selection sound
if ( fDoCalls ) if ( ! Contents . GetObject ( ) - > Call ( " ~Selection " , & C4AulParSet ( C4VObj ( this ) ) ) ) StartSoundEffect ( " Grab " , false , 100 , this ) ;
// 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
2009-07-22 16:03:33 +00:00
void C4Object : : GetParallaxity ( int32_t * parX , int32_t * parY )
{
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 ( ) ;
}
2009-12-30 19:16:32 +00:00
bool C4Object : : GetDragImage ( C4Object * * drag_object , C4ID * drag_id )
{
// 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
2010-01-25 03:14:52 +00:00
C4Object * obj = NULL ; C4ID id ;
2011-09-26 18:22:31 +00:00
if ( parV . CheckConversion ( C4V_Object ) ) obj = parV . getObj ( ) ;
2011-09-24 16:37:28 +00:00
else if ( parV . CheckConversion ( C4V_Def ) ) id = parV . getC4ID ( ) ;
2009-12-30 19:16:32 +00:00
if ( drag_object ) * drag_object = obj ;
if ( drag_id ) * drag_id = id ;
// drag possible, even w./o image
return true ;
}
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
2010-07-30 20:38:21 +00:00
Call ( PSF_CrewSelection , & C4AulParSet ( C4VBool ( 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
2010-07-30 20:38:21 +00:00
Call ( PSF_CrewSelection , & C4AulParSet ( C4VBool ( true ) ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-09-24 17:51:34 +00:00
bool C4Object : : GetDrawPosition ( const C4TargetFacet & cgo ,
2010-09-23 01:51:08 +00:00
float & resultx , float & resulty , float & resultzoom )
{
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
}
bool C4Object : : GetDrawPosition ( const C4TargetFacet & cgo , float objx , float objy , float zoom , float & resultx , float & resulty , float & resultzoom )
{
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 ;
2010-09-26 18:46:13 +00:00
float rx = ( ( 1 - parx ) * targetx ) * resultzoom + objx / ( parx + zoom - parx * zoom ) ;
float ry = ( ( 1 - pary ) * targety ) * 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 ;
}
2009-05-08 13:28:41 +00:00
void C4Object : : GetViewPosPar ( float & riX , float & riY , float tx , float ty , const C4Facet & fctViewport )
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 )
2009-05-08 13:28:41 +00:00
pUnusedObject = pFnObj2Drop - > Exec ( this , pToMakeRoomForObject ? & C4AulParSet ( C4VObj ( pToMakeRoomForObject ) ) : NULL ) . getObj ( ) ;
else
{
// is there any unused object to put away?
2010-03-28 18:58:01 +00:00
if ( ! Contents . Last ) 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)
pUnusedObject = Contents . Last - > Obj ;
}
// 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 ;
// no change? (no updates need to be done, then)
2011-08-19 22:01:08 +00:00
//if (pGraphics == pGrp) return true; // that's not exactly true because the graphics itself might have changed, for example on def reload
2009-05-08 13:28:41 +00:00
// set new graphics
pGraphics = pGrp ;
// update Color, SolidMask, etc.
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
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 ( ) ;
Call ( PSF_UpdateTransferZone ) ;
// 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
if ( FrontParticles ) FrontParticles . Clear ( ) ;
if ( BackParticles ) BackParticles . Clear ( ) ;
// 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 ;
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
C4Object * cobj ; C4ObjectLink * clnk , * next ;
for ( clnk = Contents . First ; clnk & & ( cobj = clnk - > Obj ) ; clnk = next )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
next = clnk - > Next ;
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 ;)
iDestAngle = ( iSolidRight - iSolidLeft ) * ( 35 / 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
if ( Abs ( iDestAngle - r ) > 2 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
rdir = itofix ( BoundBy < int32_t > ( iDestAngle - r , - 15 , + 15 ) ) ;
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
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
{
2010-03-27 16:05:02 +00:00
if ( OCF & OCF_HitSpeed2 ) if ( Mass > 3 )
2010-03-28 18:58:01 +00:00
Splash ( GetX ( ) , GetY ( ) + 1 , Min ( Shape . Wdt * Shape . Hgt / 10 , 20 ) , this ) ;
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 ;
// first part always description
2010-08-23 13:20:27 +00:00
//sResult.Copy(Def->GetDesc());
2009-05-08 13:28:41 +00:00
// 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 ) ;
C4ObjectLink * cLnk ;
for ( cLnk = tmpList . First ; cLnk ; cLnk = cLnk - > Next )
if ( cLnk - > Obj - > Status )
cLnk - > Obj - > Enter ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : CanConcatPictureWith ( C4Object * pOtherObject )
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 ( ) )
if ( ! GetGraphicsOverlay ( pOtherOverlay - > GetID ( ) , false ) ) return false ;
}
// concat OK
return true ;
2010-03-28 18:58:01 +00:00
}
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
2011-07-31 00:22:29 +00:00
StdStrBuf C4Object : : GetNeededMatStr ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Def * pComponent ;
int32_t cnt , ncnt ;
StdStrBuf NeededMats ;
C4IDList NeededComponents ;
2011-07-31 00:22:29 +00:00
Def - > GetComponents ( & NeededComponents , NULL ) ;
2009-05-08 13:28:41 +00:00
C4ID idComponent ;
2010-03-28 18:58:01 +00:00
for ( cnt = 0 ; ( idComponent = NeededComponents . GetID ( cnt ) ) ; cnt + + )
{
if ( NeededComponents . GetCount ( cnt ) ! = 0 )
2009-05-08 13:28:41 +00:00
{
ncnt = NeededComponents . GetCount ( cnt ) - Component . GetIDCount ( idComponent ) ;
2010-03-28 18:58:01 +00:00
if ( ncnt > 0 )
{
2009-05-08 13:28:41 +00:00
//if(!NeededMats) NeededMats.Append(", "); what was this for...?
2010-03-27 16:05:02 +00:00
NeededMats . AppendFormat ( " |%dx " , ncnt ) ;
2010-03-28 18:58:01 +00:00
if ( ( pComponent = C4Id2Def ( idComponent ) ) )
2009-05-08 13:28:41 +00:00
NeededMats . Append ( pComponent - > GetName ( ) ) ;
else
2010-01-25 15:57:57 +00:00
NeededMats . Append ( idComponent . ToString ( ) ) ;
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 result ;
2010-03-28 18:58:01 +00:00
if ( ! ! NeededMats )
2009-05-08 13:28:41 +00:00
{ result . Format ( LoadResStr ( " IDS_CON_BUILDMATNEED " ) , GetName ( ) ) ; result . Append ( NeededMats . getData ( ) ) ; }
else
result . Format ( LoadResStr ( " IDS_CON_BUILDMATNONE " ) , GetName ( ) ) ;
return result ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Object : : IsPlayerObject ( int32_t iPlayerNumber )
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
{
// flags are player objects
if ( id = = C4ID : : Flag ) return true ;
2009-05-08 13:28:41 +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 :
2012-05-15 01:11:23 +00:00
if ( ! to . getInt ( ) ) throw new 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 ) ;
}
bool C4Object : : GetPropertyByS ( C4String * k , C4Value * pResult ) const
{
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 ;
}