bool ObjectComJump(C4Object *cObj) // by ObjectComUp, ExecCMDFMoveTo, FnJump { // Only if walking if (cObj->GetProcedure()!=DFA_WALK) return false; // Calculate direction & forces C4Real TXDir=Fix0; C4PropList *pActionWalk = cObj->GetAction(); C4Real iPhysicalWalk = C4REAL100(pActionWalk->GetPropertyInt(P_Speed)) * itofix(cObj->GetCon(), FullCon); C4Real iPhysicalJump = C4REAL100(cObj->GetPropertyInt(P_JumpSpeed)) * itofix(cObj->GetCon(), FullCon); if (cObj->Action.ComDir==COMD_Left || cObj->Action.ComDir==COMD_UpLeft) TXDir=-iPhysicalWalk; else if (cObj->Action.ComDir==COMD_Right || cObj->Action.ComDir==COMD_UpRight) TXDir=+iPhysicalWalk; C4Real x = cObj->fix_x, y = cObj->fix_y; // find bottom-most vertex, correct starting position for simulation int32_t iBtmVtx = cObj->Shape.GetBottomVertex(); if (iBtmVtx != -1) { x += cObj->Shape.GetVertexX(iBtmVtx); y += cObj->Shape.GetVertexY(iBtmVtx); } // Try dive if (cObj->Shape.ContactDensity > C4M_Liquid) if (SimFlightHitsLiquid(x,y,TXDir,-iPhysicalJump)) if (ObjectActionDive(cObj,TXDir,-iPhysicalJump)) return true; // Regular jump return ObjectActionJump(cObj,TXDir,-iPhysicalJump,true); }
bool C4ValueProviderAction::Execute() { // Object might have been removed if(!Object) return false; const C4Action& Action = Object->Action; C4PropList* pActionDef = Object->GetAction(); // TODO: We could cache these... const StdMeshAnimation* animation = Action.Animation->GetAnimation(); 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) * ftofix(animation->Length) / (delay * length); else Value = itofix(Action.Phase) * ftofix(animation->Length) / length; return true; }
void C4GraphicsOverlay::UpdateFacet() { // special: Nothing to update for object and pSourceGfx may be NULL // If there will ever be something to init here, UpdateFacet() will also need to be called when objects have been loaded if (eMode == MODE_Object) return; // otherwise, source graphics must be specified if (!pSourceGfx) return; C4Def *pDef = pSourceGfx->pDef; assert(pDef); fZoomToShape = false; // Clear old mesh instance, if any delete pMeshInstance; pMeshInstance = NULL; // update by mode switch (eMode) { case MODE_None: break; case MODE_Base: // def base graphics if (pSourceGfx->Type == C4DefGraphics::TYPE_Bitmap) fctBlit.Set(pSourceGfx->GetBitmap(), 0, 0, pDef->Shape.Wdt, pDef->Shape.Hgt, pDef->Shape.x+pDef->Shape.Wdt/2, pDef->Shape.y+pDef->Shape.Hgt/2); else if (pSourceGfx->Type == C4DefGraphics::TYPE_Mesh) pMeshInstance = new StdMeshInstance(*pSourceGfx->Mesh, 1.0f); break; case MODE_Action: // graphics of specified action { // Clear old facet fctBlit.Default(); // Ensure there is actually an action set if (!Action[0]) return; C4Value v; pDef->GetProperty(P_ActMap, &v); C4PropList *actmap = v.getPropList(); if (!actmap) return; actmap->GetPropertyByS(::Strings.RegString(Action), &v); C4PropList *action = v.getPropList(); if (!action) return; if (pSourceGfx->Type == C4DefGraphics::TYPE_Bitmap) { fctBlit.Set(pSourceGfx->GetBitmap(), action->GetPropertyInt(P_X), action->GetPropertyInt(P_Y), action->GetPropertyInt(P_Wdt), action->GetPropertyInt(P_Hgt)); // FIXME: fctBlit.TargetX has to be set here } else if (pSourceGfx->Type == C4DefGraphics::TYPE_Mesh) { C4String* AnimationName = action->GetPropertyStr(P_Animation); if (!AnimationName) return; pMeshInstance = new StdMeshInstance(*pSourceGfx->Mesh, 1.0f); const StdMeshAnimation* Animation = pSourceGfx->Mesh->GetSkeleton().GetAnimationByName(AnimationName->GetData()); if (!Animation) return; pMeshInstance->PlayAnimation(*Animation, 0, NULL, new C4ValueProviderRef<int32_t>(iPhase, ftofix(Animation->Length / action->GetPropertyInt(P_Length))), new C4ValueProviderConst(itofix(1)), true); } break; } case MODE_ObjectPicture: // ingame picture of object // calculated at runtime break; case MODE_IngamePicture: case MODE_Picture: // def picture fZoomToShape = true; // drawn at runtime break; case MODE_ExtraGraphics: // like ColorByOwner-sfc // calculated at runtime break; case MODE_Rank: // drawn at runtime break; case MODE_Object: // TODO break; } }
void C4Object::DoMovement() { int32_t iContact=0; bool fAnyContact=false; int iContacts = 0; BYTE fTurned=0,fRedirectYR=0,fNoAttach=0; // Restrictions if (Def->NoHorizontalMove) xdir=0; // Dig free target area C4PropList* pActionDef = GetAction(); if (pActionDef) if (pActionDef->GetPropertyInt(P_DigFree)) { int ctcox, ctcoy; // Shape size square 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,this); } // Free size round (variable size) else { ctcox=fixtoi(fix_x+xdir); ctcoy=fixtoi(fix_y+ydir); int32_t rad = pActionDef->GetPropertyInt(P_DigFree); if (Con<FullCon) rad = rad*6*Con/5/FullCon; ::Landscape.DigFree(ctcox,ctcoy-1,rad,this); } } // store previous movement and ocf C4Real oldxdir(xdir), oldydir(ydir); uint32_t old_ocf = OCF; bool fMoved = false; C4Real new_x = fix_x + xdir; C4Real new_y = fix_y + ydir; SideBounds(new_x); if (!Action.t_attach) // Unattached movement = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = { // Horizontal movement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Move to target while (fixtoi(new_x) != fixtoi(fix_x)) { // Next step int step = Sign(new_x - fix_x); uint32_t border_hack_contacts = 0; iContact=ContactCheck(GetX() + step, GetY(), &border_hack_contacts); if (iContact || border_hack_contacts) { fAnyContact=true; iContacts |= t_contact | border_hack_contacts; } if (iContact) { // Abort horizontal movement new_x = fix_x; // Vertical redirection (always) RedirectForce(xdir,ydir,-1); ApplyFriction(ydir,ContactVtxFriction(this)); } else // Free horizontal movement { DoMotion(step, 0); fMoved = true; } } // Vertical movement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Movement target new_y = fix_y + ydir; // Movement bounds (vertical) VerticalBounds(new_y); // Move to target while (fixtoi(new_y) != fixtoi(fix_y)) { // Next step int step = Sign(new_y - fix_y); if ((iContact=ContactCheck(GetX(), GetY() + step, nullptr, ydir > 0))) { fAnyContact=true; iContacts |= t_contact; new_y = fix_y; // Vertical contact horizontal friction ApplyFriction(xdir,ContactVtxFriction(this)); // Redirection slide or rotate if (!ContactVtxCNAT(this,CNAT_Left)) RedirectForce(ydir,xdir,-1); else if (!ContactVtxCNAT(this,CNAT_Right)) RedirectForce(ydir,xdir,+1); else { // living things are always capable of keeping their rotation if (OCF & OCF_Rotate) if (iContact==1) if (!Alive) { RedirectForce(ydir,rdir,-ContactVtxWeight(this)); fRedirectYR=1; } ydir=0; } } else // Free vertical movement { DoMotion(0,step); fMoved = true; } } } if (Action.t_attach) // Attached movement = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = { VerticalBounds(new_y); // Move to target do { // Set next step target int step_x = 0, step_y = 0; if (fixtoi(new_x) != GetX()) step_x = Sign(fixtoi(new_x) - GetX()); else if (fixtoi(new_y) != GetY()) step_y = Sign(fixtoi(new_y) - GetY()); int32_t ctx = GetX() + step_x; int32_t cty = GetY() + step_y; // Attachment check if (!Shape.Attach(ctx,cty,Action.t_attach)) fNoAttach=1; else { // Attachment change to ctx/cty overrides target if (ctx != GetX() + step_x) { xdir = Fix0; new_x = itofix(ctx); } if (cty != GetY() + step_y) { ydir = Fix0; new_y = itofix(cty); } } // Contact check & evaluation uint32_t border_hack_contacts = 0; iContact=ContactCheck(ctx,cty,&border_hack_contacts); if (iContact || border_hack_contacts) { fAnyContact=true; iContacts |= border_hack_contacts | t_contact; } if (iContact) { // Abort movement if (ctx != GetX()) { ctx = GetX(); new_x = fix_x; } if (cty != GetY()) { cty = GetY(); new_y = fix_y; } } DoMotion(ctx - GetX(), cty - GetY()); fMoved = true; } while (fixtoi(new_x) != GetX() || fixtoi(new_y) != GetY()); } if(fix_x != new_x || fix_y != new_y) { fMoved = true; if (pSolidMaskData) pSolidMaskData->Remove(true); fix_x = new_x; fix_y = new_y; } // Rotation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (OCF & OCF_Rotate && !!rdir) { C4Real target_r = fix_r + rdir * 5; // Rotation limit if (Def->Rotateable>1) { if (target_r > itofix(Def->Rotateable)) { target_r = itofix(Def->Rotateable); rdir=0; } if (target_r < itofix(-Def->Rotateable)) { target_r = itofix(-Def->Rotateable); rdir=0; } } int32_t ctx=GetX(); int32_t cty=GetY(); // Move to target while (fixtoi(fix_r) != fixtoi(target_r)) { // Save step undos C4Real lcobjr = fix_r; C4Shape lshape=Shape; // Try next step fix_r += Sign(target_r - fix_r); UpdateShape(); // attached rotation: rotate around attachment pos if (Action.t_attach && !fNoAttach) { // more accurately, attachment should be evaluated by a rotation around the attachment vertex // however, as long as this code is only used for some surfaces adjustment for large vehicles, // it's enough to assume rotation around the center ctx=GetX(); cty=GetY(); // evaluate attachment, but do not bother about attachment loss // that will then be done in next execution cycle Shape.Attach(ctx,cty,Action.t_attach); } // check for contact if ((iContact=ContactCheck(ctx,cty))) // Contact { fAnyContact=true; iContacts |= t_contact; // Undo step and abort movement Shape=lshape; target_r = fix_r = lcobjr; // last UpdateShape-call might have changed sector lists! UpdatePos(); // Redirect to GetY() if (iContact==1) if (!fRedirectYR) RedirectForce(rdir,ydir,-1); // Stop rotation rdir=0; } else { fTurned=1; if (ctx != GetX() || cty != GetY()) { fix_x = itofix(ctx); fix_y = itofix(cty); } } } // Circle bounds if (target_r < -FixHalfCircle) { target_r += FixFullCircle; } if (target_r > +FixHalfCircle) { target_r -= FixFullCircle; } fix_r = target_r; } // Reput solid mask if moved by motion if (fMoved || fTurned) UpdateSolidMask(true); // Misc checks =========================================================================================== // InLiquid check // this equals C4Object::UpdateLiquid, but the "fNoAttach=false;"-line if (IsInLiquidCheck()) // In Liquid { if (!InLiquid) // Enter liquid { if (OCF & OCF_HitSpeed2) if (Mass>3) Splash(GetX(),GetY()+1,std::min(Shape.Wdt*Shape.Hgt/10,20),this); fNoAttach=false; InLiquid=1; } } else // Out of liquid { if (InLiquid) // Leave liquid InLiquid=0; } // Contact Action if (fAnyContact) { t_contact = iContacts; ContactAction(); } // Attachment Loss Action if (fNoAttach) NoAttachAction(); // Movement Script Execution if (fAnyContact) { C4AulParSet pars(C4VInt(fixtoi(oldxdir, 100)), C4VInt(fixtoi(oldydir, 100))); if (old_ocf & OCF_HitSpeed1) Call(PSF_Hit, &pars); if (old_ocf & OCF_HitSpeed2) Call(PSF_Hit2, &pars); if (old_ocf & OCF_HitSpeed3) Call(PSF_Hit3, &pars); } // Rotation gfx if (fTurned) UpdateFace(true); else // pos changed? if (fMoved) UpdatePos(); }
bool C4SoundModifier::GetBoolProp(C4PropertyName key, bool default_value) { // get scaled property and fill in default value C4PropList *p = props._getPropList(); return (p->GetPropertyInt(key, int32_t(default_value ? 1 : 0)) != 0); }
float C4SoundModifier::GetFloatProp(C4PropertyName key, float ratio, float default_value) { // get scaled property and fill in default value C4PropList *p = props._getPropList(); return float(p->GetPropertyInt(key, int32_t(default_value * ratio))) / ratio; }