Make an object's current action a property

This fixes a crash on reload since the Action.pActionDef pointer becomes
invalid otherwise
stable-5.1
Armin Burgmeier 2010-03-19 00:04:29 +01:00
parent 6613bdb129
commit 56e33cc626
17 changed files with 173 additions and 123 deletions

View File

@ -1137,12 +1137,13 @@ void C4Game::BlastObjects(int32_t tx, int32_t ty, int32_t level, C4Object *inobj
if (Abs(tx-cObj->GetX())<=level)
{
// vehicles and floating objects only if grab+pushable (no throne, no tower entrances...)
C4PropList* pActionDef = cObj->GetAction();
if (cObj->Def->Grab !=1)
{
if (cObj->Category & C4D_Vehicle)
continue;
if (cObj->Action.pActionDef)
if (cObj->Action.pActionDef->GetPropertyInt(P_Procedure) == DFA_FLOAT)
if (pActionDef)
if (pActionDef->GetPropertyInt(P_Procedure) == DFA_FLOAT)
continue;
}
if (cObj->Category & C4D_Living)
@ -1233,7 +1234,7 @@ C4Object* C4Game::FindObject(C4ID id,
// Scan all objects
for (cLnk=Objects.First; cLnk && (cObj=cLnk->Obj); cLnk=cLnk->Next)
{
C4PropList* pActionDef = cObj->GetAction();
// Not skipping to find next
if (!pFindNext)
// Status
@ -1245,9 +1246,9 @@ C4Object* C4Game::FindObject(C4ID id,
// Exclude
if (cObj!=pExclude)
// Action
if (!szAction || !szAction[0] || (bFindActIdle && !cObj->Action.pActionDef) || (cObj->Action.pActionDef && SEqual(szAction,cObj->Action.pActionDef->GetName())) )
if (!szAction || !szAction[0] || (bFindActIdle && !pActionDef) || (pActionDef && SEqual(szAction,pActionDef->GetName())) )
// ActionTarget
if(!pActionTarget || (cObj->Action.pActionDef && ((cObj->Action.Target==pActionTarget) || (cObj->Action.Target2==pActionTarget)) ))
if(!pActionTarget || (pActionDef && ((cObj->Action.Target==pActionTarget) || (cObj->Action.Target2==pActionTarget)) ))
// Container
if ( !pContainer || (cObj->Contained == pContainer) || ((reinterpret_cast<long>(pContainer)==NO_CONTAINER) && !cObj->Contained) || ((reinterpret_cast<long>(pContainer)==ANY_CONTAINER) && cObj->Contained) )
// Owner

View File

@ -220,11 +220,11 @@ bool C4PropertyDlg::Update()
Output.Append(static_cast<const StdStrBuf &>(cobj->Contents.GetNameList(::Definitions)));
}
// Action
if (cobj->Action.pActionDef)
if (cobj->GetAction())
{
Output.Append(LineFeed);
Output.Append(LoadResStr("IDS_CNS_ACTION"));
Output.Append(cobj->Action.pActionDef->GetName());
Output.Append(cobj->GetAction()->GetName());
}
// Locals
int cnt; bool fFirstLocal = true;

View File

@ -34,7 +34,7 @@ C4Action::~C4Action()
void C4Action::Default()
{
pActionDef = 0;
//pActionDef = 0;
Dir=DIR_None;
DrawDir=Dir;
ComDir=COMD_None;

View File

@ -308,7 +308,7 @@ void C4Command::MoveTo()
}
// Idles can't move to
if (!cObj->Action.pActionDef)
if (!cObj->GetAction())
{ Finish(); return; }
// Action
@ -1695,9 +1695,10 @@ bool C4Command::FlightControl() // Called by DFA_WALK, DFA_FLIGHT
if (!((cObj->OCF & OCF_CrewMember) || cObj->Def->Pathfinder)) return false;
// Not while in a disabled action
if (cObj->Action.pActionDef)
C4PropList* pActionDef = cObj->GetAction();
if (pActionDef)
{
if (cObj->Action.pActionDef->GetPropertyInt(P_ObjectDisabled)) return false;
if (pActionDef->GetPropertyInt(P_ObjectDisabled)) return false;
}
// Target angle

View File

@ -176,7 +176,8 @@ void C4GameObjects::CrossCheck() // Every Tick1 by ExecObjects
iHitEnergy = Max<int32_t>(iHitEnergy/3, !!iHitEnergy); // hit energy reduced to 1/3rd, but do not drop to zero because of this division
obj1->DoEnergy(-iHitEnergy/5, false, C4FxCall_EngObjHit, obj2->Controller);
int tmass=Max<int32_t>(obj1->Mass,50);
if (!::Game.iTick3 || (obj1->Action.pActionDef && obj1->Action.pActionDef->GetPropertyInt(P_Procedure) != DFA_FLIGHT))
C4PropList* pActionDef = obj1->GetAction();
if (!::Game.iTick3 || (pActionDef && pActionDef->GetPropertyInt(P_Procedure) != DFA_FLIGHT))
obj1->Fling(obj2->xdir*50/tmass,-Abs(obj2->ydir/2)*50/tmass, false);
obj1->Call(PSF_CatchBlow,&C4AulParSet(C4VInt(-iHitEnergy/5),
C4VObj(obj2)));

View File

@ -303,17 +303,20 @@ bool C4ValueProviderSinV::Execute()
return true;
}
C4ValueProviderAction::C4ValueProviderAction(const C4Object* object):
Action(object->Action)
C4ValueProviderAction::C4ValueProviderAction(C4Object* object):
Object(object)
{
}
bool C4ValueProviderAction::Execute()
{
const C4Action& Action = Object->Action;
C4PropList* pActionDef = Object->GetAction();
// TODO: We could cache these...
const StdMeshAnimation* animation = Action.Animation->GetAnimation();
const int32_t length = Action.pActionDef->GetPropertyInt(P_Length);
const int32_t delay = Action.pActionDef->GetPropertyInt(P_Delay);
const int32_t length = pActionDef->GetPropertyInt(P_Length);
const int32_t delay = pActionDef->GetPropertyInt(P_Delay);
if(delay)
Value = itofix(Action.Phase * delay + Action.PhaseDelay) / (delay * length) * ftofix(animation->Length);

View File

@ -230,11 +230,11 @@ private:
class C4ValueProviderAction: public StdMeshInstance::ValueProvider
{
public:
C4ValueProviderAction(const C4Object* object);
C4ValueProviderAction(C4Object* object);
virtual bool Execute();
private:
const C4Action& Action;
C4Object* Object;
};
// Reference another value (which is convertible to FIXED), and optionally scale it

View File

@ -182,13 +182,16 @@ void C4Object::SideBounds(FIXED &ctcox)
{
// layer bounds
if (pLayer) if (pLayer->Def->BorderBound & C4D_Border_Layer)
if (!Action.pActionDef || Action.pActionDef->GetPropertyInt(P_Procedure) != DFA_ATTACH)
{
C4PropList* pActionDef = GetAction();
if (!pActionDef || pActionDef->GetPropertyInt(P_Procedure) != DFA_ATTACH)
{
if (Category & C4D_StaticBack)
TargetBounds(ctcox,pLayer->GetX()+pLayer->Shape.GetX(),pLayer->GetX()+pLayer->Shape.GetX()+pLayer->Shape.Wdt,CNAT_Left,CNAT_Right);
else
TargetBounds(ctcox,pLayer->GetX()+pLayer->Shape.GetX()-Shape.GetX(),pLayer->GetX()+pLayer->Shape.GetX()+pLayer->Shape.Wdt+Shape.GetX(),CNAT_Left,CNAT_Right);
}
}
// landscape bounds
if (Def->BorderBound & C4D_Border_Sides)
TargetBounds(ctcox,0-Shape.GetX(),GBackWdt+Shape.GetX(),CNAT_Left,CNAT_Right);
@ -198,13 +201,16 @@ void C4Object::VerticalBounds(FIXED &ctcoy)
{
// layer bounds
if (pLayer) if (pLayer->Def->BorderBound & C4D_Border_Layer)
if (!Action.pActionDef || Action.pActionDef->GetPropertyInt(P_Procedure) != DFA_ATTACH)
{
C4PropList* pActionDef = GetAction();
if (!pActionDef || pActionDef->GetPropertyInt(P_Procedure) != DFA_ATTACH)
{
if (Category & C4D_StaticBack)
TargetBounds(ctcoy,pLayer->GetY()+pLayer->Shape.GetY(),pLayer->GetY()+pLayer->Shape.GetY()+pLayer->Shape.Hgt,CNAT_Top,CNAT_Bottom);
else
TargetBounds(ctcoy,pLayer->GetY()+pLayer->Shape.GetY()-Shape.GetY(),pLayer->GetY()+pLayer->Shape.GetY()+pLayer->Shape.Hgt+Shape.GetY(),CNAT_Top,CNAT_Bottom);
}
}
// landscape bounds
if (Def->BorderBound & C4D_Border_Top)
TargetBounds(ctcoy,0-Shape.GetY(),+1000000,CNAT_Top,CNAT_Bottom);
@ -220,11 +226,12 @@ void C4Object::DoMovement()
// Restrictions
if (Def->NoHorizontalMove) xdir=0;
// Dig free target area
if (Action.pActionDef)
if (Action.pActionDef->GetPropertyInt(P_DigFree))
C4PropList* pActionDef = GetAction();
if (pActionDef)
if (pActionDef->GetPropertyInt(P_DigFree))
{
// Shape size square
if (Action.pActionDef->GetPropertyInt(P_DigFree)==1)
if (pActionDef->GetPropertyInt(P_DigFree)==1)
{
ctcox=fixtoi(fix_x+xdir); ctcoy=fixtoi(fix_y+ydir);
::Landscape.DigFreeRect(ctcox+Shape.GetX(),ctcoy+Shape.GetY(),Shape.Wdt,Shape.Hgt,Action.Data,this);
@ -233,7 +240,7 @@ void C4Object::DoMovement()
else
{
ctcox=fixtoi(fix_x+xdir); ctcoy=fixtoi(fix_y+ydir);
int32_t rad = Action.pActionDef->GetPropertyInt(P_DigFree);
int32_t rad = pActionDef->GetPropertyInt(P_DigFree);
if (Con<FullCon) rad = rad*6*Con/5/FullCon;
::Landscape.DigFree(ctcox,ctcoy-1,rad,Action.Data,this);
}
@ -558,9 +565,11 @@ bool C4Object::ExecMovement() // Every Tick1 by Execute
// Out of bounds check
if ((!Inside<int32_t>(GetX(),0,GBackWdt) && !(Def->BorderBound & C4D_Border_Sides)) || (GetY()>GBackHgt && !(Def->BorderBound & C4D_Border_Bottom)))
{
C4PropList* pActionDef = GetAction();
// Never remove attached objects: If they are truly outside landscape, their target will be removed,
// and the attached objects follow one frame later
if (!Action.pActionDef || !Action.Target || Action.pActionDef->GetPropertyInt(P_Procedure) != DFA_ATTACH)
if (!pActionDef || !Action.Target || pActionDef->GetPropertyInt(P_Procedure) != DFA_ATTACH)
{
bool fRemove = true;
// never remove HUD objects
@ -579,7 +588,7 @@ bool C4Object::ExecMovement() // Every Tick1 by Execute
AssignRemoval();
}
}
}
return true;
}

View File

@ -443,9 +443,10 @@ void C4Object::UpdateFlipDir()
{
int32_t iFlipDir;
// We're active
if (Action.pActionDef)
C4PropList* pActionDef = GetAction();
if (pActionDef)
// Get flipdir value from action
if ((iFlipDir = Action.pActionDef->GetPropertyInt(P_FlipDir)))
if ((iFlipDir = pActionDef->GetPropertyInt(P_FlipDir)))
// Action dir is in flipdir range
if (Action.Dir >= iFlipDir)
{
@ -562,12 +563,13 @@ void C4Object::DrawActionFace(C4TargetFacet &cgo, float offX, float offY)
// 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);
C4PropList* pActionDef = GetAction();
// Regular action facet
const float swdt = float(Action.Facet.Wdt);
const float shgt = float(Action.Facet.Hgt);
int32_t iPhase = Action.Phase;
if (Action.pActionDef->GetPropertyInt(P_Reverse)) iPhase = Action.pActionDef->GetPropertyInt(P_Length) - 1 - Action.Phase;
if (pActionDef->GetPropertyInt(P_Reverse)) iPhase = pActionDef->GetPropertyInt(P_Length) - 1 - Action.Phase;
// Grow Type Display
float fx = float(Action.Facet.X + swdt * iPhase);
@ -662,6 +664,7 @@ void C4Object::ComponentConGain()
void C4Object::SetOCF()
{
C4PropList* pActionDef = GetAction();
#ifdef DEBUGREC_OCF
uint32_t dwOCFOld = OCF;
#endif
@ -726,7 +729,7 @@ void C4Object::SetOCF()
// OCF_Collection
if ((OCF & OCF_FullCon) || Def->IncompleteActivity)
if ((Def->Collection.Wdt>0) && (Def->Collection.Hgt>0))
if (!Action.pActionDef || (!Action.pActionDef->GetPropertyInt(P_ObjectDisabled)))
if (!pActionDef || (!pActionDef->GetPropertyInt(P_ObjectDisabled)))
if (NoCollectDelay==0)
OCF|=OCF_Collection;
// OCF_Living
@ -737,7 +740,7 @@ void C4Object::SetOCF()
}
// OCF_FightReady
if (OCF & OCF_Alive)
if (!Action.pActionDef || (!Action.pActionDef->GetPropertyInt(P_ObjectDisabled)))
if (!pActionDef || (!pActionDef->GetPropertyInt(P_ObjectDisabled)))
if (!Def->NoFight)
OCF|=OCF_FightReady;
// OCF_LineConstruct
@ -800,6 +803,7 @@ void C4Object::SetOCF()
void C4Object::UpdateOCF()
{
C4PropList* pActionDef = GetAction();
#ifdef DEBUGREC_OCF
uint32_t dwOCFOld = OCF;
#endif
@ -846,12 +850,12 @@ void C4Object::UpdateOCF()
// OCF_Collection
if ((OCF & OCF_FullCon) || Def->IncompleteActivity)
if ((Def->Collection.Wdt>0) && (Def->Collection.Hgt>0))
if (!Action.pActionDef || (!Action.pActionDef->GetPropertyInt(P_ObjectDisabled)))
if (!pActionDef || (!pActionDef->GetPropertyInt(P_ObjectDisabled)))
if (NoCollectDelay==0)
OCF|=OCF_Collection;
// OCF_FightReady
if (OCF & OCF_Alive)
if (!Action.pActionDef || (!Action.pActionDef->GetPropertyInt(P_ObjectDisabled)))
if (!pActionDef || (!pActionDef->GetPropertyInt(P_ObjectDisabled)))
if (!Def->NoFight)
OCF|=OCF_FightReady;
// OCF_NotContained
@ -1221,7 +1225,7 @@ bool C4Object::ChangeDef(C4ID idNew)
if (Contained) Exit(0,0,0,Fix0,Fix0,Fix0,false);
// Pre change resets
SetAction(0);
Action.pActionDef = 0; // Enforce ActIdle because SetAction may have failed due to NoOtherAction
ResetProperty(::Strings.P[P_Action]); // Enforce ActIdle because SetAction may have failed due to NoOtherAction
SetDir(0); // will drop any outdated flipdir
if (pSolidMaskData) { pSolidMaskData->Remove(true, false); delete pSolidMaskData; pSolidMaskData=NULL; }
Def->Count--;
@ -2201,8 +2205,9 @@ C4Value C4Object::Call(const char *szFunctionCall, C4AulParSet *pPars, bool fPas
bool C4Object::SetPhase(int32_t iPhase)
{
if (!Action.pActionDef) return false;
const int32_t length = Action.pActionDef->GetPropertyInt(P_Length);
C4PropList* pActionDef = GetAction();
if (!pActionDef) return false;
const int32_t length = pActionDef->GetPropertyInt(P_Length);
Action.Phase=BoundBy<int32_t>(iPhase,0,length);
Action.PhaseDelay = 0;
return true;
@ -2230,8 +2235,9 @@ void C4Object::Draw(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDrawMode)
float offX = cgo.X + fixtof(fix_x) - cotx, offY = cgo.Y + fixtof(fix_y) - coty;
bool fYStretchObject=false;
if (Action.pActionDef)
if (Action.pActionDef->GetPropertyInt(P_FacetTargetStretch))
C4PropList* pActionDef = GetAction();
if (pActionDef)
if (pActionDef->GetPropertyInt(P_FacetTargetStretch))
fYStretchObject=true;
// Set audibility
@ -2240,7 +2246,7 @@ void C4Object::Draw(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDrawMode)
// Output boundary
if (!fYStretchObject && !eDrawMode)
{
if (Action.pActionDef && !r && !Action.pActionDef->GetPropertyInt(P_FacetBase) && Con<=FullCon)
if (pActionDef && !r && !pActionDef->GetPropertyInt(P_FacetBase) && Con<=FullCon)
{
// active
if ( !Inside<float>(cox+Action.FacetX,1-Action.Facet.Wdt,cgo.Wdt)
@ -2385,7 +2391,7 @@ void C4Object::Draw(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDrawMode)
if (ColorMod != 0xffffffff || BlitMode) if (!eDrawMode) PrepareDrawing();
// Not active or rotated: BaseFace only
if (!Action.pActionDef)
if (!pActionDef)
{
DrawFace(cgo, offX, offY);
}
@ -2394,11 +2400,11 @@ void C4Object::Draw(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDrawMode)
else
{
// FacetBase
if (Action.pActionDef->GetPropertyInt(P_FacetBase) || GetGraphics()->Type != C4DefGraphics::TYPE_Bitmap)
if (pActionDef->GetPropertyInt(P_FacetBase) || GetGraphics()->Type != C4DefGraphics::TYPE_Bitmap)
DrawFace(cgo, offX, offY, 0, Action.DrawDir);
// Special: stretched action facet
if (Action.Facet.Surface && Action.pActionDef->GetPropertyInt(P_FacetTargetStretch))
if (Action.Facet.Surface && pActionDef->GetPropertyInt(P_FacetTargetStretch))
{
if (Action.Target)
lpDDraw->Blit(Action.Facet.Surface,
@ -2474,10 +2480,10 @@ void C4Object::Draw(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDrawMode)
if (::GraphicsSystem.ShowAction) if (eDrawMode!=ODM_BaseOnly)
{
if (Action.pActionDef)
if (pActionDef)
{
StdStrBuf str;
str.Format("%s (%d)",Action.pActionDef->GetName(),Action.Phase);
str.Format("%s (%d)",pActionDef->GetName(),Action.Phase);
int32_t cmwdt,cmhgt; ::GraphicsResource.FontRegular.GetTextExtent(str.getData(),cmwdt,cmhgt,true);
Application.DDraw->TextOut(str.getData(), ::GraphicsResource.FontRegular, 1.0, cgo.Surface,cgo.X+cox-Shape.GetX(),cgo.Y+coy-cmhgt,InLiquid ? 0xfa0000FF : CStdDDraw::DEFAULT_MESSAGE_COLOR,ACenter);
}
@ -2561,12 +2567,13 @@ void C4Object::DrawTopFace(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDraw
fctConSign.Wdt, fctConSign.Hgt, true);
}
// FacetTopFace: Override TopFace.GetX()/GetY()
if (Action.pActionDef && Action.pActionDef->GetPropertyInt(P_FacetTopFace))
C4PropList* pActionDef = GetAction();
if (pActionDef && pActionDef->GetPropertyInt(P_FacetTopFace))
{
int32_t iPhase = Action.Phase;
if (Action.pActionDef->GetPropertyInt(P_Reverse)) iPhase = Action.pActionDef->GetPropertyInt(P_Length) - 1 - Action.Phase;
TopFace.X = Action.pActionDef->GetPropertyInt(P_X) + Def->TopFace.x + Action.pActionDef->GetPropertyInt(P_Wdt) * iPhase;
TopFace.Y = Action.pActionDef->GetPropertyInt(P_Y) + Def->TopFace.y + Action.pActionDef->GetPropertyInt(P_Hgt) * Action.DrawDir;
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);
@ -3263,9 +3270,16 @@ void C4Object::Resort()
// Must not immediately resort - link change/removal would crash Game::ExecObjects
}
C4PropList* C4Object::GetAction()
{
C4Value value;
GetProperty(::Strings.P[P_Action], value);
return value.getPropList();
}
bool C4Object::SetAction(C4PropList * Act, C4Object *pTarget, C4Object *pTarget2, int32_t iCalls, bool fForce)
{
C4PropList * LastAction = Action.pActionDef;
C4PropList * LastAction = GetAction();
int32_t iLastPhase=Action.Phase;
// No other action
if (LastAction)
@ -3305,7 +3319,8 @@ bool C4Object::SetAction(C4PropList * Act, C4Object *pTarget, C4Object *pTarget2
Action.Data = 0;
}
// Set new action
Action.pActionDef = Act;
SetProperty(::Strings.P[P_Action], C4VPropList(Act));
Action.Phase=Action.PhaseDelay=0;
// Set target if specified
if (pTarget) Action.Target=pTarget;
@ -3316,10 +3331,10 @@ bool C4Object::SetAction(C4PropList * Act, C4Object *pTarget, C4Object *pTarget2
if ((LastAction ? LastAction->GetPropertyInt(P_FlipDir) : 0)
!= (Act ? Act->GetPropertyInt(P_FlipDir) : 0)) UpdateFlipDir();
// Start act sound
if (Action.pActionDef)
if (Action.pActionDef != LastAction)
if (Action.pActionDef->GetPropertyStr(P_Sound))
StartSoundEffect(Action.pActionDef->GetPropertyStr(P_Sound)->GetCStr(),+1,100,this);
if (Act)
if (Act != LastAction)
if (Act->GetPropertyStr(P_Sound))
StartSoundEffect(Act->GetPropertyStr(P_Sound)->GetCStr(),+1,100,this);
// Reset OCF
SetOCF();
// issue calls
@ -3349,12 +3364,12 @@ bool C4Object::SetAction(C4PropList * Act, C4Object *pTarget, C4Object *pTarget2
}
// Execute StartCall for new action
if (iCalls & SAC_StartCall)
if (Action.pActionDef)
if (Act)
{
if (Action.pActionDef->GetPropertyStr(P_StartCall))
if (Act->GetPropertyStr(P_StartCall))
{
C4Def *pOldDef = Def;
Call(Action.pActionDef->GetPropertyStr(P_StartCall)->GetCStr());
Call(Act->GetPropertyStr(P_StartCall)->GetCStr());
// abort exeution if def changed
if (Def != pOldDef || !Status) return true;
}
@ -3367,15 +3382,16 @@ void C4Object::UpdateActionFace()
// Default: no action face
Action.Facet.Default();
// Active: get action facet from action definition
if (Action.pActionDef)
C4PropList* pActionDef = GetAction();
if (pActionDef)
{
if (Action.pActionDef->GetPropertyInt(P_Wdt)>0)
if (pActionDef->GetPropertyInt(P_Wdt)>0)
{
Action.Facet.Set(GetGraphics()->GetBitmap(Color),
Action.pActionDef->GetPropertyInt(P_X),Action.pActionDef->GetPropertyInt(P_Y),
Action.pActionDef->GetPropertyInt(P_Wdt),Action.pActionDef->GetPropertyInt(P_Hgt));
Action.FacetX=Action.pActionDef->GetPropertyInt(P_OffX);
Action.FacetY=Action.pActionDef->GetPropertyInt(P_OffY);
pActionDef->GetPropertyInt(P_X),pActionDef->GetPropertyInt(P_Y),
pActionDef->GetPropertyInt(P_Wdt),pActionDef->GetPropertyInt(P_Hgt));
Action.FacetX=pActionDef->GetPropertyInt(P_OffX);
Action.FacetY=pActionDef->GetPropertyInt(P_OffY);
}
}
}
@ -3409,17 +3425,18 @@ bool C4Object::SetActionByName(const char * szActName,
void C4Object::SetDir(int32_t iDir)
{
// Not active
if (!Action.pActionDef) return;
C4PropList* pActionDef = GetAction();
if (!pActionDef) return;
// Invalid direction
if (!Inside<int32_t>(iDir,0,Action.pActionDef->GetPropertyInt(P_Directions)-1)) return;
if (!Inside<int32_t>(iDir,0,pActionDef->GetPropertyInt(P_Directions)-1)) return;
// Execute turn action
if (iDir != Action.Dir)
if (Action.pActionDef->GetPropertyStr(P_TurnAction))
{ SetActionByName(Action.pActionDef->GetPropertyStr(P_TurnAction)); }
if (pActionDef->GetPropertyStr(P_TurnAction))
{ SetActionByName(pActionDef->GetPropertyStr(P_TurnAction)); }
// Set dir
Action.Dir=iDir;
// update by flipdir?
if (Action.pActionDef->GetPropertyInt(P_FlipDir))
if (pActionDef->GetPropertyInt(P_FlipDir))
UpdateFlipDir();
else
Action.DrawDir=iDir;
@ -3427,8 +3444,9 @@ void C4Object::SetDir(int32_t iDir)
int32_t C4Object::GetProcedure()
{
if (!Action.pActionDef) return DFA_NONE;
return Action.pActionDef->GetPropertyInt(P_Procedure);
C4PropList* pActionDef = GetAction();
if (!pActionDef) return DFA_NONE;
return pActionDef->GetPropertyInt(P_Procedure);
}
void GrabLost(C4Object *cObj)
@ -3449,7 +3467,7 @@ void DoGravity(C4Object *cobj, bool fFloatFriction=true);
void C4Object::NoAttachAction()
{
// Active objects
if (Action.pActionDef)
if (GetAction())
{
int32_t iProcedure = GetProcedure();
// Scaling upwards: corner scale
@ -3491,9 +3509,10 @@ void C4Object::ContactAction()
C4PhysicalInfo *pPhysical=GetPhysical();
// Determine Procedure
if (!Action.pActionDef) return;
int32_t iProcedure=Action.pActionDef->GetPropertyInt(P_Procedure);
int32_t fDisabled=Action.pActionDef->GetPropertyInt(P_ObjectDisabled);
C4PropList* pActionDef = GetAction();
if (!pActionDef) return;
int32_t iProcedure=pActionDef->GetPropertyInt(P_Procedure);
int32_t fDisabled=pActionDef->GetPropertyInt(P_ObjectDisabled);
//------------------------------- Hit Bottom ---------------------------------------------
if (t_contact & CNAT_Bottom)
@ -3572,7 +3591,7 @@ void C4Object::ContactAction()
break;
case DFA_DIG:
// Dig: Stop
if (!(Action.pActionDef->GetPropertyInt(P_Attach) & CNAT_Top)) ObjectComStopDig(this); return;
if (!(pActionDef->GetPropertyInt(P_Attach) & CNAT_Top)) ObjectComStopDig(this); return;
case DFA_HANGLE:
Action.ComDir=COMD_Stop;
break;
@ -3624,7 +3643,7 @@ void C4Object::ContactAction()
return;
case DFA_DIG:
// Dig: Stop
if (!(Action.pActionDef->GetPropertyInt(P_Attach) & CNAT_Left)) ObjectComStopDig(this);
if (!(pActionDef->GetPropertyInt(P_Attach) & CNAT_Left)) ObjectComStopDig(this);
return;
}
}
@ -3675,7 +3694,7 @@ void C4Object::ContactAction()
return;
case DFA_DIG:
// Dig: Stop
if (!(Action.pActionDef->GetPropertyInt(P_Attach) & CNAT_Right)) ObjectComStopDig(this);
if (!(pActionDef->GetPropertyInt(P_Attach) & CNAT_Right)) ObjectComStopDig(this);
return;
}
}
@ -3858,7 +3877,8 @@ void C4Object::ExecAction()
}
// Idle objects do natural gravity only
if (!Action.pActionDef)
C4PropList* pActionDef = GetAction();
if (!pActionDef)
{
if (Mobile) DoGravity(this);
return;
@ -3869,7 +3889,7 @@ void C4Object::ExecAction()
{ SetAction(0); return; }
// Determine ActDef & Physical Info
C4PropList * pAction = Action.pActionDef;
//C4PropList * pAction = Action.pActionDef;
C4PhysicalInfo *pPhysical=GetPhysical();
FIXED lLimit;
FIXED fWalk,fMove;
@ -3877,11 +3897,11 @@ void C4Object::ExecAction()
// Energy usage
if (Game.Rules & C4RULE_StructuresNeedEnergy)
if (pAction->GetPropertyInt(P_EnergyUsage))
if (pActionDef->GetPropertyInt(P_EnergyUsage))
{
if (pAction->GetPropertyInt(P_EnergyUsage) <= Energy )
if (pActionDef->GetPropertyInt(P_EnergyUsage) <= Energy )
{
Energy -= pAction->GetPropertyInt(P_EnergyUsage);
Energy -= pActionDef->GetPropertyInt(P_EnergyUsage);
// No general DoEnergy-Process
NeedEnergy=0;
}
@ -3899,19 +3919,19 @@ void C4Object::ExecAction()
// InLiquidAction check
if (InLiquid)
if (pAction->GetPropertyStr(P_InLiquidAction))
{ SetActionByName(pAction->GetPropertyStr(P_InLiquidAction)); return; }
if (pActionDef->GetPropertyStr(P_InLiquidAction))
{ SetActionByName(pActionDef->GetPropertyStr(P_InLiquidAction)); return; }
// 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
Action.t_attach |= (pAction->GetPropertyInt(P_Attach) & CNAT_MultiAttach);
Action.t_attach |= (pActionDef->GetPropertyInt(P_Attach) & CNAT_MultiAttach);
// 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
if (!pAction->GetPropertyInt(P_ObjectDisabled) && pAction->GetPropertyInt(P_Procedure) != DFA_FLIGHT && !OnFire)
if (!pActionDef->GetPropertyInt(P_ObjectDisabled) && pActionDef->GetPropertyInt(P_Procedure) != DFA_FLIGHT && !OnFire)
LastEnergyLossCausePlayer = NO_OWNER;
// Handle Default Action Procedure: evaluates Procedure and Action.ComDir
@ -3926,7 +3946,7 @@ void C4Object::ExecAction()
FIXED lFloatAccel;
FIXED rFloatAccel;
switch (pAction->GetPropertyInt(P_Procedure))
switch (pActionDef->GetPropertyInt(P_Procedure))
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_WALK:
@ -4077,9 +4097,9 @@ void C4Object::ExecAction()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_DIG:
{
if (pAction->GetPropertyInt(P_Attach))
if (pActionDef->GetPropertyInt(P_Attach))
{
Action.t_attach |= pAction->GetPropertyInt(P_Attach);
Action.t_attach |= pActionDef->GetPropertyInt(P_Attach);
}
else
{
@ -4585,9 +4605,9 @@ void C4Object::ExecAction()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
default:
// Attach
if (pAction->GetPropertyInt(P_Attach))
if (pActionDef->GetPropertyInt(P_Attach))
{
Action.t_attach |= pAction->GetPropertyInt(P_Attach);
Action.t_attach |= pActionDef->GetPropertyInt(P_Attach);
xdir = ydir = 0;
Mobile = 1;
}
@ -4599,31 +4619,31 @@ void C4Object::ExecAction()
}
// Phase Advance (zero delay means no phase advance)
if (pAction->GetPropertyInt(P_Delay))
if (pActionDef->GetPropertyInt(P_Delay))
{
Action.PhaseDelay+=iPhaseAdvance;
if (Action.PhaseDelay >= pAction->GetPropertyInt(P_Delay))
if (Action.PhaseDelay >= pActionDef->GetPropertyInt(P_Delay))
{
// Advance Phase
Action.PhaseDelay=0;
Action.Phase += pAction->GetPropertyInt(P_Step);
Action.Phase += pActionDef->GetPropertyInt(P_Step);
// Phase call
if (pAction->GetPropertyStr(P_PhaseCall))
if (pActionDef->GetPropertyStr(P_PhaseCall))
{
Call(pAction->GetPropertyStr(P_PhaseCall)->GetCStr());
Call(pActionDef->GetPropertyStr(P_PhaseCall)->GetCStr());
}
// Phase end
if (Action.Phase>=pAction->GetPropertyInt(P_Length))
if (Action.Phase>=pActionDef->GetPropertyInt(P_Length))
{
C4String *next_action = pAction->GetPropertyStr(P_NextAction);
C4String *next_action = pActionDef->GetPropertyStr(P_NextAction);
// Keep current action if there is no NextAction
if (!next_action)
Action.Phase = 0;
// set new action if it's not Hold
else if (next_action == Strings.P[P_Hold])
{
Action.Phase = pAction->GetPropertyInt(P_Length)-1;
Action.PhaseDelay = pAction->GetPropertyInt(P_Delay)-1;
Action.Phase = pActionDef->GetPropertyInt(P_Length)-1;
Action.PhaseDelay = pActionDef->GetPropertyInt(P_Delay)-1;
}
else
{
@ -4638,14 +4658,14 @@ void C4Object::ExecAction()
// then this will already have happened for the new action.
if(pMeshInstance && !set_new_action)
{
C4String* AnimationName = pAction->GetPropertyStr(P_Animation);
C4String* AnimationName = pActionDef->GetPropertyStr(P_Animation);
if(AnimationName)
{
StdMeshInstance::AnimationRef ref(pMeshInstance, AnimationName->GetData());
if(ref)
{
float delay = pAction->GetPropertyInt(P_Delay);
float length = pAction->GetPropertyInt(P_Length);
float delay = pActionDef->GetPropertyInt(P_Delay);
float length = pActionDef->GetPropertyInt(P_Length);
ref.SetPosition(static_cast<float>(Action.Phase * delay + Action.PhaseDelay) / (delay * length) * ref.GetAnimation().Length);
}
}

View File

@ -90,7 +90,7 @@ class C4Action
C4Action();
~C4Action();
public:
C4PropList * pActionDef;
//C4PropList * pActionDef;
int32_t Dir;
int32_t DrawDir; // NoSave // - needs to be calculated for old-style objects.txt anyway
int32_t ComDir;
@ -285,6 +285,7 @@ class C4Object: public C4PropList
bool Contact(int32_t cnat);
void TargetBounds(FIXED &ctco, int32_t limit_low, int32_t limit_hi, int32_t cnat_low, int32_t cnat_hi);
enum { SAC_StartCall = 1, SAC_EndCall = 2, SAC_AbortCall = 4 };
C4PropList* GetAction();
bool SetAction(C4PropList * Act, C4Object *pTarget=NULL, C4Object *pTarget2=NULL, int32_t iCalls = SAC_StartCall | SAC_AbortCall, bool fForce = false);
bool SetActionByName(C4String * ActName, C4Object *pTarget=NULL, C4Object *pTarget2=NULL, int32_t iCalls = SAC_StartCall | SAC_AbortCall, bool fForce = false);
bool SetActionByName(const char * szActName, C4Object *pTarget=NULL, C4Object *pTarget2=NULL, int32_t iCalls = SAC_StartCall | SAC_AbortCall, bool fForce = false);
@ -397,11 +398,12 @@ class C4Object: public C4PropList
bool IsMoveableBySolidMask()
{
C4PropList* pActionDef = GetAction();
return (Status == C4OS_NORMAL)
&& !(Category & (C4D_StaticBack | C4D_Structure))
&& !Contained
&& ((~Category & C4D_Vehicle) || (OCF & OCF_Grab))
&& (!Action.pActionDef || Action.pActionDef->GetPropertyInt(P_Procedure) != DFA_FLOAT)
&& (!pActionDef || pActionDef->GetPropertyInt(P_Procedure) != DFA_FLOAT)
;
}

View File

@ -663,9 +663,10 @@ bool ObjectComDrop(C4Object *cObj, C4Object *pThing)
int32_t tdir=0; int right=0;
bool isHanglingOrSwimming = false;
int32_t iProc = DFA_NONE;
if (cObj->Action.pActionDef)
C4PropList* pActionDef = cObj->GetAction();
if (pActionDef)
{
iProc = cObj->Action.pActionDef->GetPropertyInt(P_Procedure);
iProc = pActionDef->GetPropertyInt(P_Procedure);
if (iProc == DFA_HANGLE || iProc == DFA_SWIM) isHanglingOrSwimming = true;
}
int32_t iOutposReduction = 1; // don't exit object too far forward during jump
@ -703,7 +704,7 @@ bool ObjectComBuild(C4Object *cObj, C4Object *pTarget)
{
if (!pTarget) return false;
// Needs to be idle or walking
if (cObj->Action.pActionDef)
if (cObj->GetAction())
if (cObj->GetProcedure()!=DFA_WALK)
return false;
return ObjectActionBuild(cObj,pTarget);

View File

@ -427,7 +427,7 @@ int32_t C4ObjectMenu::AddContextFunctions(C4Object *pTarget, bool fCountOnly)
C4FacetSurface fctSymbol;
// ActionContext functions of target's action target (for first target only, because otherwise strange stuff can happen with outdated Target2s...)
if (pTarget->Action.pActionDef)
if (pTarget->GetAction())
if ((cObj = pTarget->Action.Target))
for (iFunction=0; (pFunction=cObj->Def->Script.GetSFunc(iFunction, "ActionContext")); iFunction++)
if (!pFunction->OverloadedBy)
@ -471,8 +471,10 @@ int32_t C4ObjectMenu::AddContextFunctions(C4Object *pTarget, bool fCountOnly)
// Script context functions of any objects attached to target (search global list, because attachment objects might be moved just about anywhere...)
for (clnk=::Objects.First; clnk && (cObj=clnk->Obj); clnk=clnk->Next)
if (cObj->Status && cObj->Action.Target == pTarget)
if (cObj->Action.pActionDef)
if (cObj->Action.pActionDef->GetPropertyInt(P_Procedure) == DFA_ATTACH)
{
C4PropList* pActionDef = cObj->GetAction();
if (pActionDef)
if (pActionDef->GetPropertyInt(P_Procedure) == DFA_ATTACH)
for (iFunction=0; (pFunction=cObj->Def->Script.GetSFunc(iFunction, "AttachContext")); iFunction++)
if (!pFunction->OverloadedBy)
if (!pFunction->Condition || !! pFunction->Condition->Exec(cObj, &C4AulParSet(C4VObj(Object), C4VID(pFunction->idImage), C4VObj(pTarget))))
@ -488,6 +490,7 @@ int32_t C4ObjectMenu::AddContextFunctions(C4Object *pTarget, bool fCountOnly)
else
iResult++;
}
}
// 'Activate' and 'ControlDigDouble' script functions of target
const char *func, *funcs[] = { "Activate", "ControlDigDouble", 0 };

View File

@ -588,8 +588,11 @@ int32_t FnFxFireStart(C4AulContext *ctx, C4Object *pObj, int32_t iNumber, int32_
cobj = 0;
if (!pObj->Def->IncompleteActivity && !pObj->Def->NoBurnDecay)
while ((cobj = Game.FindObject(C4ID::None, 0, 0, 0, 0, OCF_All, 0, pObj, 0, 0, ANY_OWNER, cobj)))
if (cobj->Action.pActionDef && (cobj->Action.pActionDef->GetPropertyInt(P_Procedure) == DFA_ATTACH))
{
C4PropList* pActionDef = cobj->GetAction();
if (pActionDef && (pActionDef->GetPropertyInt(P_Procedure) == DFA_ATTACH))
cobj->SetAction(0);
}
// fire caused?
if (!fFireCaused)
{

View File

@ -621,7 +621,7 @@ bool C4FindObjectCategory::IsEnsured()
bool C4FindObjectAction::Check(C4Object *pObj)
{
return SEqual(pObj->Action.pActionDef->GetName(), szAction);
return SEqual(pObj->GetAction()->GetName(), szAction);
}
bool C4FindObjectActionTarget::Check(C4Object *pObj)
@ -638,7 +638,7 @@ bool C4FindObjectActionTarget::Check(C4Object *pObj)
bool C4FindObjectProcedure::Check(C4Object *pObj)
{
C4Value v;
pObj->Action.pActionDef->GetProperty(::Strings.P[P_Procedure], v);
pObj->GetAction()->GetProperty(::Strings.P[P_Procedure], v);
return v != C4VNull && v.getInt() == procedure;
}

View File

@ -787,9 +787,10 @@ static bool FnSetAction(C4AulObjectContext *cthr, C4String *szAction,
static bool FnSetBridgeActionData(C4AulObjectContext *cthr, long iBridgeLength, bool fMoveClonk, bool fWall, long iBridgeMaterial)
{
if (!cthr->Obj->Status) return false;
C4PropList* pActionDef = cthr->Obj->GetAction();
// action must be BRIDGE
if (!cthr->Obj->Action.pActionDef) return false;
if (cthr->Obj->Action.pActionDef->GetPropertyInt(P_Procedure) != DFA_BRIDGE) return false;
if (!pActionDef) return false;
if (pActionDef->GetPropertyInt(P_Procedure) != DFA_BRIDGE) return false;
// set data
cthr->Obj->Action.SetBridgeData(iBridgeLength, fMoveClonk, fWall, iBridgeMaterial);
return true;
@ -798,11 +799,12 @@ static bool FnSetBridgeActionData(C4AulObjectContext *cthr, long iBridgeLength,
static bool FnSetActionData(C4AulObjectContext *cthr, long iData)
{
if (!cthr->Obj->Status) return false;
C4PropList* pActionDef = cthr->Obj->GetAction();
// bridge: Convert from old style
if (cthr->Obj->Action.pActionDef && (cthr->Obj->Action.pActionDef->GetPropertyInt(P_Procedure) == DFA_BRIDGE))
if (pActionDef && (pActionDef->GetPropertyInt(P_Procedure) == DFA_BRIDGE))
return FnSetBridgeActionData(cthr, 0, false, false, iData);
// attach: check for valid vertex indices
if (cthr->Obj->Action.pActionDef && (cthr->Obj->Action.pActionDef->GetPropertyInt(P_Procedure) == DFA_ATTACH)) // Fixed Action.Act check here... matthes
if (pActionDef && (pActionDef->GetPropertyInt(P_Procedure) == DFA_ATTACH)) // Fixed Action.Act check here... matthes
if (((iData&255) >= C4D_MaxVertex) || ((iData>>8) >= C4D_MaxVertex))
return false;
// set data
@ -990,8 +992,9 @@ static C4Value FnPlayerObjectCommand(C4AulContext *cthr, C4Value *pPars)
static C4String *FnGetAction(C4AulObjectContext *cthr)
{
if (!cthr->Obj->Action.pActionDef) return String("Idle");
return String(cthr->Obj->Action.pActionDef->GetName());
C4PropList* pActionDef = cthr->Obj->GetAction();
if (!pActionDef) return String("Idle");
return String(pActionDef->GetName());
}
static C4PropList * FnCreatePropList(C4AulContext *cthr, C4PropList * prototype)
@ -1787,7 +1790,7 @@ static C4Object *FnFindOtherContents(C4AulObjectContext *cthr, C4ID c_id)
static bool FnActIdle(C4AulObjectContext *cthr)
{
return !cthr->Obj->Action.pActionDef;
return !cthr->Obj->GetAction();
}
static bool FnCheckEnergyNeedChain(C4AulObjectContext *cthr)
@ -3334,9 +3337,10 @@ static C4Void FnSetPicture(C4AulObjectContext *cthr, long iX, long iY, long iWdt
static C4String *FnGetProcedure(C4AulObjectContext *cthr)
{
// no action?
if (!cthr->Obj->Action.pActionDef) return NULL;
C4PropList* pActionDef = cthr->Obj->GetAction();
if (!pActionDef) return NULL;
// get proc
long iProc = cthr->Obj->Action.pActionDef->GetPropertyInt(P_Procedure);
long iProc = pActionDef->GetPropertyInt(P_Procedure);
// NONE?
if (iProc <= DFA_NONE) return NULL;
// return procedure name

View File

@ -113,6 +113,7 @@ C4StringTable::C4StringTable()
P[P_Reverse] = RegString("Reverse");
P[P_Step] = RegString("Step");
P[P_Animation] = RegString("Animation");
P[P_Action] = RegString("Action");
P[P_Visibility] = RegString("Visibility");
P[P_Parallaxity] = RegString("Parallaxity");
P[P_LineColors] = RegString("LineColors");

View File

@ -208,6 +208,7 @@ P_Reverse,
P_Step,
P_MouseDragImage,
P_Animation,
P_Action,
P_LAST };
// There is only one Stringtable in Game.ScriptEngine