Example #1
0
int32_t C4DensityProvider::GetDensity(int32_t x, int32_t y) const {
#ifdef C4ENGINE
  // default density provider checks the landscape
  return GBackDensity(x, y);
#else
  return 0;
#endif
}
Example #2
0
BOOL C4Shape::ContactCheck(int32_t cx, int32_t cy) {
// Check all vertices at given object position.
// Set ContactCNAT and ContactCount.
// Set VtxContactCNAT and VtxContactMat.
// Return TRUE on any contact.

#ifdef C4ENGINE

  ContactCNAT = CNAT_None;
  ContactCount = 0;

  for (int32_t cvtx = 0; cvtx < VtxNum; cvtx++)

    // Ignore vertex if collision has been flagged out
    if (!(VtxCNAT[cvtx] & CNAT_NoCollision))

    {
      VtxContactCNAT[cvtx] = CNAT_None;
      VtxContactMat[cvtx] = GBackMat(cx + VtxX[cvtx], cy + VtxY[cvtx]);

      if (GBackDensity(cx + VtxX[cvtx], cy + VtxY[cvtx]) >= ContactDensity) {
        ContactCNAT |= VtxCNAT[cvtx];
        VtxContactCNAT[cvtx] |= CNAT_Center;
        ContactCount++;
        // Vertex center contact, now check top,bottom,left,right
        if (GBackDensity(cx + VtxX[cvtx], cy + VtxY[cvtx] - 1) >=
            ContactDensity)
          VtxContactCNAT[cvtx] |= CNAT_Top;
        if (GBackDensity(cx + VtxX[cvtx], cy + VtxY[cvtx] + 1) >=
            ContactDensity)
          VtxContactCNAT[cvtx] |= CNAT_Bottom;
        if (GBackDensity(cx + VtxX[cvtx] - 1, cy + VtxY[cvtx]) >=
            ContactDensity)
          VtxContactCNAT[cvtx] |= CNAT_Left;
        if (GBackDensity(cx + VtxX[cvtx] + 1, cy + VtxY[cvtx]) >=
            ContactDensity)
          VtxContactCNAT[cvtx] |= CNAT_Right;
      }
    }

#endif

  return ContactCount;
}
Example #3
0
bool SimFlightHitsLiquid(C4Real fcx, C4Real fcy, C4Real xdir, C4Real ydir)
{
	// Start in water?
	int temp;
	if (DensityLiquid(GBackDensity(fixtoi(fcx), fixtoi(fcy))))
		if (!SimFlight(fcx, fcy, xdir, ydir, 0, C4M_Liquid - 1, temp=10))
			return false;
	// Hits liquid?
	if (!SimFlight(fcx, fcy, xdir, ydir, C4M_Liquid, 100, temp=-1))
		return false;
	// liquid & deep enough?
	return GBackLiquid(fixtoi(fcx), fixtoi(fcy)) && GBackLiquid(fixtoi(fcx), fixtoi(fcy) + 9);
}
Example #4
0
BOOL C4Shape::CheckContact(int32_t cx, int32_t cy) {
// Check all vertices at given object position.
// Return TRUE on any contact.

#ifdef C4ENGINE

  for (int32_t cvtx = 0; cvtx < VtxNum; cvtx++)
    if (!(VtxCNAT[cvtx] & CNAT_NoCollision))
      if (GBackDensity(cx + VtxX[cvtx], cy + VtxY[cvtx]) >= ContactDensity)
        return TRUE;

#endif

  return FALSE;
}
Example #5
0
bool SimFlight(C4Real &x, C4Real &y, C4Real &xdir, C4Real &ydir, int32_t iDensityMin, int32_t iDensityMax, int32_t &iIter)
{
	bool hitOnTime = true;
	bool fBreak = false;
	int32_t ctcox,ctcoy,cx,cy,i;
	cx = fixtoi(x); cy = fixtoi(y);
	i = iIter;
	do
	{
		if (!--i) {hitOnTime = false; break;}
		// If the object isn't moving and there is no gravity either, abort
		if (xdir == 0 && ydir == 0 && GravAccel == 0)
			return false;
		// If the object is above the landscape flying upwards in no/negative gravity, abort
		if (ydir <= 0 && GravAccel <= 0 && cy < 0)
			return false;
		// Set target position by momentum
		x+=xdir; y+=ydir;
		// Movement to target
		ctcox=fixtoi(x); ctcoy=fixtoi(y);
		// Bounds
		if (!Inside<int32_t>(ctcox,0,GBackWdt) || (ctcoy>=GBackHgt))
			return false;
		// Move to target
		do
		{
			// Set next step target
			cx+=Sign(ctcox-cx); cy+=Sign(ctcoy-cy);
			// Contact check
			if (Inside(GBackDensity(cx,cy), iDensityMin, iDensityMax))
				{ fBreak = true; break; }
		}
		while ((cx!=ctcox) || (cy!=ctcoy));
		// Adjust GravAccel once per frame
		ydir+=GravAccel;
	}
	while (!fBreak);
	// write position back
	x = itofix(cx); y = itofix(cy);

	// how many steps did it take to get here?
	iIter -= i;

	return hitOnTime;
}
Example #6
0
BOOL C4Shape::Attach(int32_t &cx, int32_t &cy, BYTE cnat_pos) {
  // Adjust given position to one pixel before contact
  // at vertices matching CNAT request.

  BOOL fAttached = FALSE;

#ifdef C4ENGINE

  int32_t vtx, xcnt, ycnt, xcrng, ycrng, xcd, ycd;
  int32_t motion_x = 0;
  BYTE cpix;

  // reset attached material
  AttachMat = MNone;

  // New attachment behaviour in CE:
  // Before, attachment was done by searching through all vertices,
  // and doing attachment to any vertex with a matching CNAT.
  // While this worked well for normal Clonk attachment, it caused nonsense
  // behaviour if multiple vertices matched the same CNAT. In effect, attachment
  // was then done to the last vertex only, usually stucking the object sooner
  // or later.
  // For instance, the scaling procedure of regular Clonks uses two CNAT_Left-
  // vertices (shoulder+belly), which "block" each other in situations like
  // scaling up battlements of towers. That way, the 2px-overhang of the
  // battlement is sufficient for keeping out scaling Clonks. The drawback is
  // that sometimes Clonks get stuck scaling in very sharp edges or single
  // floating material pixels; occuring quite often in Caverace, or maps where
  // you blast Granite and many single pixels remain.
  //
  // Until a better solution for designing battlements is found, the old-style
  // behaviour will be used for Clonks.	Both code variants should behave equally
  // for objects with only one matching vertex to cnat_pos.
  if (!(cnat_pos & CNAT_MultiAttach)) {
    // old-style attachment
    for (vtx = 0; vtx < VtxNum; vtx++)
      if (VtxCNAT[vtx] & cnat_pos) {
        xcd = ycd = 0;
        switch (cnat_pos & (~CNAT_Flags)) {
          case CNAT_Top:
            ycd = -1;
            break;
          case CNAT_Bottom:
            ycd = +1;
            break;
          case CNAT_Left:
            xcd = -1;
            break;
          case CNAT_Right:
            xcd = +1;
            break;
        }
        xcrng = AttachRange * xcd * (-1);
        ycrng = AttachRange * ycd * (-1);
        for (xcnt = xcrng, ycnt = ycrng; (xcnt != -xcrng) || (ycnt != -ycrng);
             xcnt += xcd, ycnt += ycd) {
          int32_t ax = cx + VtxX[vtx] + xcnt + xcd,
                  ay = cy + VtxY[vtx] + ycnt + ycd;
          if (GBackDensity(ax, ay) >= ContactDensity && ax >= 0 &&
              ax < GBackWdt) {
            cpix = GBackPix(ax, ay);
            AttachMat = PixCol2Mat(cpix);
            iAttachX = ax;
            iAttachY = ay;
            iAttachVtx = vtx;
            cx += xcnt;
            cy += ycnt;
            fAttached = 1;
            break;
          }
        }
      }
  } else  // CNAT_MultiAttach
  {
    // new-style attachment
    // determine attachment direction
    xcd = ycd = 0;
    switch (cnat_pos & (~CNAT_Flags)) {
      case CNAT_Top:
        ycd = -1;
        break;
      case CNAT_Bottom:
        ycd = +1;
        break;
      case CNAT_Left:
        xcd = -1;
        break;
      case CNAT_Right:
        xcd = +1;
        break;
    }
    // check within attachment range
    xcrng = AttachRange * xcd * (-1);
    ycrng = AttachRange * ycd * (-1);
    for (xcnt = xcrng, ycnt = ycrng; (xcnt != -xcrng) || (ycnt != -ycrng);
         xcnt += xcd, ycnt += ycd)
      // check all vertices with matching CNAT
      for (vtx = 0; vtx < VtxNum; vtx++)
        if (VtxCNAT[vtx] & cnat_pos) {
          // get new vertex pos
          int32_t ax = cx + VtxX[vtx] + xcnt + xcd,
                  ay = cy + VtxY[vtx] + ycnt + ycd;
          // can attach here?
          cpix = GBackPix(ax, ay);
          if (MatDensity(PixCol2Mat(cpix)) >= ContactDensity && ax >= 0 &&
              ax < GBackWdt) {
            // store attachment material
            AttachMat = PixCol2Mat(cpix);
            // store absolute attachment position
            iAttachX = ax;
            iAttachY = ay;
            iAttachVtx = vtx;
            // move position here
            cx += xcnt;
            cy += ycnt;
            // mark attachment
            fAttached = 1;
            // break both looops
            xcnt = -xcrng - xcd;
            ycnt = -ycrng - ycd;
            break;
          }
        }
  }
  // both attachments: apply motion done by SolidMasks
  if (motion_x) cx += BoundBy<int32_t>(motion_x, -1, 1);

#endif

  return fAttached;
}
Example #7
0
void C4PXS::Execute()
{
#ifdef DEBUGREC_PXS
	if (Config.General.DebugRec)
	{
		C4RCExecPXS rc;
		rc.x=x; rc.y=y; rc.iMat=Mat;
		rc.pos = 0;
		AddDbgRec(RCT_ExecPXS, &rc, sizeof(rc));
	}
#endif
	int32_t inmat;

	// Safety
	if (!MatValid(Mat))
		{ Deactivate(); return; }

	// Out of bounds
	if ((x<0) || (x>=::Landscape.GetWidth()) || (y<-10) || (y>=::Landscape.GetHeight()))
		{ Deactivate(); return; }

	// Material conversion
	int32_t iX = fixtoi(x), iY = fixtoi(y);
	inmat=GBackMat(iX,iY);
	C4MaterialReaction *pReact = ::MaterialMap.GetReactionUnsafe(Mat, inmat);
	if (pReact && (*pReact->pFunc)(pReact, iX,iY, iX,iY, xdir,ydir, Mat,inmat, meePXSPos, NULL))
		{ Deactivate(); return; }

	// Gravity
	ydir+=GravAccel;

	if (GBackDensity(iX, iY + 1) < ::MaterialMap.Map[Mat].Density)
	{
		// Air speed: Wind plus some random
		int32_t iWind = Weather.GetWind(iX, iY);
		C4Real txdir = itofix(iWind, 15) + C4REAL256(Random(1200) - 600);
		C4Real tydir = C4REAL256(Random(1200) - 600);

		// Air friction, based on WindDrift. MaxSpeed is ignored.
		int32_t iWindDrift = std::max(::MaterialMap.Map[Mat].WindDrift - 20, 0);
		xdir += ((txdir - xdir) * iWindDrift) * WindDrift_Factor;
		ydir += ((tydir - ydir) * iWindDrift) * WindDrift_Factor;
	}

	C4Real ctcox = x + xdir;
	C4Real ctcoy = y + ydir;

	int32_t iToX = fixtoi(ctcox), iToY = fixtoi(ctcoy);

	// In bounds?
	if (Inside<int32_t>(iToX, 0, ::Landscape.GetWidth()-1) && Inside<int32_t>(iToY, 0, ::Landscape.GetHeight()-1))
		// Check path
		if (::Landscape._PathFree(iX, iY, iToX, iToY))
		{
			x=ctcox; y=ctcoy;
			return;
		}

	// Test path to target position
	int32_t iX0 = iX, iY0 = iY;
	bool fStopMovement = false;
	do
	{
		// Step
		int32_t inX = iX + Sign(iToX - iX), inY = iY + Sign(iToY - iY);
		// Contact?
		inmat = GBackMat(inX, inY);
		C4MaterialReaction *pReact = ::MaterialMap.GetReactionUnsafe(Mat, inmat);
		if (pReact)
		{
			if ((*pReact->pFunc)(pReact, iX,iY, inX,inY, xdir,ydir, Mat,inmat, meePXSMove, &fStopMovement))
			{
				// destructive contact
				Deactivate();
				return;
			}
			else
			{
				// no destructive contact, but speed or position changed: Stop moving for now
				if (fStopMovement)
				{
					// But keep fractional positions to allow proper movement on moving ground
					if (iX != iX0) x = itofix(iX);
					if (iY != iY0) y = itofix(iY);
					return;
				}
				// there was a reaction func, but it didn't do anything - continue movement
			}
		}
		iX = inX; iY = inY;
	}
	while (iX != iToX || iY != iToY);

	// No contact? Free movement
	x=ctcox; y=ctcoy;
#ifdef DEBUGREC_PXS
	if (Config.General.DebugRec)
	{
		C4RCExecPXS rc;
		rc.x=x; rc.y=y; rc.iMat=Mat;
		rc.pos = 1;
		AddDbgRec(RCT_ExecPXS, &rc, sizeof(rc));
	}
#endif
	return;
}
bool C4Particle::Exec(C4Object *obj, float timeDelta, C4ParticleDef *sourceDef)
{
	// die of old age? :<
	lifetime -= timeDelta;
	// check only if we had a maximum lifetime to begin with (for permanent particles)
	if (startingLifetime > 0.f)
	{
		if (lifetime <= 0.f) return false;
	}

	// movement
	float currentForceX = properties.forceX.GetValue(this);
	float currentForceY = properties.forceY.GetValue(this);

	currentSpeedX += currentForceX;
	currentSpeedY += currentForceY;

	if (currentSpeedX != 0.f || currentSpeedY != 0.f)
	{
		float currentDampingX = properties.speedDampingX.GetValue(this);
		float currentDampingY = properties.speedDampingY.GetValue(this);
		float size = properties.size.GetValue(this);

		currentSpeedX *= currentDampingX;
		currentSpeedY *= currentDampingY;

		// move & collision check
		// note: accessing Landscape.GetDensity here is not protected by locks
		// it is assumed that the particle system is cleaned up before, f.e., the landscape memory is freed
		bool collided = false;
		if (properties.hasCollisionVertex)
		{
			float collisionPoint = properties.collisionVertex.GetValue(this);
			float size_x = (currentSpeedX > 0.f ? size : -size) * 0.5f * collisionPoint;
			float size_y = (currentSpeedY > 0.f ? size : -size) * 0.5f * collisionPoint;
			float density = static_cast<float>(GBackDensity(positionX + size_x + timeDelta * currentSpeedX, positionY + size_y + timeDelta * currentSpeedY));
			
			if (density + 0.5f >= properties.collisionDensity.GetValue(this)) // Small offset against floating point insanities.
			{
				// exec collision func
				if (properties.collisionCallback != 0 && !(properties.*properties.collisionCallback)(this)) return false;
				collided = true;
			}
		}

		if (!collided)
		{
			positionX += timeDelta * currentSpeedX;
			positionY += timeDelta * currentSpeedY;
		}
		drawingData.SetPosition(positionX, positionY, size, properties.rotation.GetValue(this), properties.stretch.GetValue(this));

	}
	else if(!properties.size.IsConstant() || !properties.rotation.IsConstant() || !properties.stretch.IsConstant())
	{
		drawingData.SetPosition(positionX, positionY, properties.size.GetValue(this), properties.rotation.GetValue(this), properties.stretch.GetValue(this));
	}

	// adjust color
	if (!properties.hasConstantColor)
	{
		drawingData.SetColor(properties.colorR.GetValue(this), properties.colorG.GetValue(this), properties.colorB.GetValue(this), properties.colorAlpha.GetValue(this));
	}

	int currentPhase = (int)(properties.phase.GetValue(this) + 0.5f);
	if (currentPhase != drawingData.phase)
		drawingData.SetPhase(currentPhase, sourceDef);

	return true;
}