bool C4Object::ExecMovement() // Every Tick1 by Execute { // update in which material this object is UpdateInMat(); // Containment check if (Contained) { CopyMotion(Contained); return true; } // General mobility check if (Category & C4D_StaticBack) return false; // Movement execution if (Mobile) // Object is moving { // Move object DoMovement(); // Demobilization check if ((xdir==0) && (ydir==0) && (rdir==0)) Mobile=0; // Check for stabilization if (rdir==0) Stabilize(); } else // Object is static { // Check for stabilization Stabilize(); // Check for mobilization if (!::Game.iTick10) { // Gravity mobilization xdir=ydir=rdir=0; Mobile=1; } } // Enforce zero rotation if (!Def->Rotateable) fix_r=Fix0; // Out of bounds check if ((!Inside<int32_t>(GetX() + Shape.GetX(), -Shape.Wdt, GBackWdt) && !(GetPropertyInt(P_BorderBound) & C4D_Border_Sides)) || ((GetY() + Shape.GetY() > GBackHgt) && !(GetPropertyInt(P_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 (!pActionDef || !Action.Target || pActionDef->GetPropertyP(P_Procedure) != DFA_ATTACH) { bool fRemove = true; // never remove HUD objects if (Category & C4D_Parallax) { int parX, parY; GetParallaxity(&parX, &parY); fRemove = false; if (GetX()>GBackWdt || GetY()>GBackHgt) fRemove = true; // except if they are really out of the viewport to the right... else if (GetX()<0 && !!parX) fRemove = true; // ...or it's not HUD horizontally and it's out to the left else if (!parX && GetX()<-GBackWdt) fRemove = true; // ...or it's HUD horizontally and it's out to the left } if (fRemove) { AssignDeath(true); AssignRemoval(); } } } return true; }
bool C4Object::Enter(C4Object *pTarget, bool fCalls, bool fCopyMotion, bool *pfRejectCollect) { // 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 valid target or target is self if (!pTarget || (pTarget==this)) return false; // check if entrance is allowed if (!! Call(PSF_RejectEntrance, &C4AulParSet(pTarget))) return false; // check if we end up in an endless container-recursion for (C4Object *pCnt=pTarget->Contained; pCnt; pCnt=pCnt->Contained) if (pCnt==this) return false; // Check RejectCollect, if desired if (pfRejectCollect) { if (!!pTarget->Call(PSF_RejectCollection,&C4AulParSet(Def, this))) { *pfRejectCollect = true; return false; } *pfRejectCollect = false; } // Exit if contained if (Contained) if (!Exit(GetX(),GetY())) return false; if (Contained || !Status || !pTarget->Status) return false; // Failsafe updates if (Menu) { CloseMenu(true); // CloseMenu might do bad stuff if (Contained || !Status || !pTarget->Status) return false; } SetOCF(); // Set container Contained=pTarget; // Enter if (!Contained->Contents.Add(this, C4ObjectList::stContents)) { Contained=nullptr; return false; } // 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 if (!Alive) 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) { // remove any solidmask before copying the motion... UpdateSolidMask(false); CopyMotion(Contained); } SetOCF(); UpdateFace(true); // Update container Contained->UpdateMass(); Contained->SetOCF(); // Object list callback (before script callbacks, because script callbacks may exit again) ObjectListChangeListener.OnObjectContainerChanged(this, nullptr, Contained); // Collection call if (fCalls) pTarget->Call(PSF_Collection2,&C4AulParSet(this)); if (!Contained || !Contained->Status || !pTarget->Status) return true; // Entrance call if (fCalls) Call(PSF_Entrance,&C4AulParSet(Contained)); if (!Contained || !Contained->Status || !pTarget->Status) return true; // Success return true; }