2009-05-08 13:28:41 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2009-06-05 13:41:20 +00:00
|
|
|
* Copyright (c) 1998-2000 Matthes Bender
|
|
|
|
* Copyright (c) 2001-2002, 2004-2006, 2008 Sven Eberhardt
|
|
|
|
* Copyright (c) 2002-2004 Peter Wortmann
|
2013-01-09 23:23:06 +00:00
|
|
|
* Copyright (c) 2006, 2008-2009, 2012 Günther Brammer
|
2010-12-23 00:01:24 +00:00
|
|
|
* Copyright (c) 2010 Benjamin Herr
|
2013-01-09 23:23:06 +00:00
|
|
|
* Copyright (c) 2010, 2012 Armin Burgmeier
|
|
|
|
* Copyright (c) 2010, 2012 Nicolas Hake
|
2010-12-23 00:01:24 +00:00
|
|
|
* Copyright (c) 2010 Peewee
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Object motion, collision, friction */
|
|
|
|
|
|
|
|
#include <C4Include.h>
|
|
|
|
#include <C4Object.h>
|
|
|
|
|
2012-04-27 17:04:43 +00:00
|
|
|
#include <C4Effect.h>
|
2009-05-08 13:28:41 +00:00
|
|
|
#include <C4Physics.h>
|
|
|
|
#include <C4SolidMask.h>
|
2009-06-12 18:52:21 +00:00
|
|
|
#include <C4Landscape.h>
|
|
|
|
#include <C4Game.h>
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
/* Some physical constants */
|
|
|
|
|
2010-05-19 03:19:49 +00:00
|
|
|
const C4Real FRedirect=C4REAL100(50);
|
|
|
|
const C4Real FFriction=C4REAL100(30);
|
2010-05-04 15:35:18 +00:00
|
|
|
const C4Real FixFullCircle=itofix(360),FixHalfCircle=FixFullCircle/2;
|
2010-05-19 03:19:49 +00:00
|
|
|
const C4Real FloatFriction=C4REAL100(2);
|
|
|
|
const C4Real RotateAccel=C4REAL100(20);
|
|
|
|
const C4Real HitSpeed1=C4REAL100(150); // Hit Event
|
2010-05-04 15:35:18 +00:00
|
|
|
const C4Real HitSpeed2=itofix(2); // Cross Check Hit
|
|
|
|
const C4Real HitSpeed3=itofix(6); // Scale disable, kneel
|
|
|
|
const C4Real HitSpeed4=itofix(8); // Flat
|
2012-07-25 15:02:10 +00:00
|
|
|
const C4Real DefaultGravAccel=C4REAL100(20);
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
/* Some helper functions */
|
|
|
|
|
2010-05-04 15:35:18 +00:00
|
|
|
void RedirectForce(C4Real &from, C4Real &to, int32_t tdir)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-05-04 15:35:18 +00:00
|
|
|
C4Real fred;
|
2010-03-27 16:05:02 +00:00
|
|
|
fred=Min(Abs(from), FRedirect);
|
|
|
|
from-=fred*Sign(from);
|
|
|
|
to+=fred*tdir;
|
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 ApplyFriction(C4Real &tval, int32_t percent)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-05-04 15:35:18 +00:00
|
|
|
C4Real ffric=FFriction*percent/100;
|
2010-03-27 16:05:02 +00:00
|
|
|
if (tval>+ffric) { tval-=ffric; return; }
|
|
|
|
if (tval<-ffric) { tval+=ffric; return; }
|
|
|
|
tval=0;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Compares all Shape.VtxContactCNAT[] CNAT flags to search flag.
|
|
|
|
// Returns true if CNAT match has been found.
|
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
bool ContactVtxCNAT(C4Object *cobj, BYTE cnat_dir)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
int32_t cnt;
|
|
|
|
bool fcontact=false;
|
|
|
|
for (cnt=0; cnt<cobj->Shape.VtxNum; cnt++)
|
|
|
|
if (cobj->Shape.VtxContactCNAT[cnt] & cnat_dir)
|
|
|
|
fcontact=true;
|
|
|
|
return fcontact;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Finds first vertex with contact flag set.
|
|
|
|
// Returns -1/0/+1 for relation on vertex to object center.
|
|
|
|
|
|
|
|
int32_t ContactVtxWeight(C4Object *cobj)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
int32_t cnt;
|
|
|
|
for (cnt=0; cnt<cobj->Shape.VtxNum; cnt++)
|
|
|
|
if (cobj->Shape.VtxContactCNAT[cnt])
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
if (cobj->Shape.VtxX[cnt]<0) return -1;
|
|
|
|
if (cobj->Shape.VtxX[cnt]>0) return +1;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2010-03-27 16:05:02 +00:00
|
|
|
return 0;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// ContactVtxFriction: Returns 0-100 friction value of first
|
|
|
|
// contacted vertex;
|
|
|
|
|
|
|
|
int32_t ContactVtxFriction(C4Object *cobj)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
int32_t cnt;
|
|
|
|
for (cnt=0; cnt<cobj->Shape.VtxNum; cnt++)
|
|
|
|
if (cobj->Shape.VtxContactCNAT[cnt])
|
|
|
|
return cobj->Shape.VtxFriction[cnt];
|
|
|
|
return 0;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
const char *CNATName(int32_t cnat)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
switch (cnat)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
|
|
|
case CNAT_None: return "None";
|
|
|
|
case CNAT_Left: return "Left";
|
|
|
|
case CNAT_Right: return "Right";
|
|
|
|
case CNAT_Top: return "Top";
|
|
|
|
case CNAT_Bottom: return "Bottom";
|
|
|
|
case CNAT_Center: return "Center";
|
2010-03-27 16:05:02 +00:00
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
return "Undefined";
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
bool C4Object::Contact(int32_t iCNAT)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
if (Def->ContactFunctionCalls)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-11 13:09:53 +00:00
|
|
|
return !! Call(FormatString(PSF_Contact, CNATName(iCNAT)).getData());
|
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
|
|
|
|
|
|
|
void C4Object::DoMotion(int32_t mx, int32_t my)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-04-20 20:38:18 +00:00
|
|
|
if (pSolidMaskData) pSolidMaskData->Remove(true);
|
2010-03-27 16:05:02 +00:00
|
|
|
fix_x += mx; fix_y += my;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-05-04 15:35:18 +00:00
|
|
|
static inline int32_t ForceLimits(C4Real &rVal, int32_t iLow, int32_t iHi)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-07-12 00:33:58 +00:00
|
|
|
if (rVal<iLow) { rVal=iLow; return -1; }
|
|
|
|
if (rVal>iHi) { rVal=iHi; return +1; }
|
|
|
|
return 0;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-07-12 00:33:58 +00:00
|
|
|
|
2010-05-04 15:35:18 +00:00
|
|
|
void C4Object::TargetBounds(C4Real &ctco, int32_t limit_low, int32_t limit_hi, int32_t cnat_low, int32_t cnat_hi)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
switch (ForceLimits(ctco,limit_low,limit_hi))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
// stop
|
|
|
|
if (cnat_low==CNAT_Left) xdir=0; else ydir=0;
|
|
|
|
// do calls
|
|
|
|
Contact(cnat_low);
|
|
|
|
break;
|
|
|
|
case +1:
|
|
|
|
// stop
|
|
|
|
if (cnat_hi==CNAT_Right) xdir=0; else ydir=0;
|
|
|
|
// do calls
|
|
|
|
Contact(cnat_hi);
|
|
|
|
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
|
|
|
|
2012-10-10 19:28:25 +00:00
|
|
|
int32_t C4Object::ContactCheck(int32_t iAtX, int32_t iAtY, uint32_t *border_hack_contacts)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Check shape contact at given position
|
2012-10-10 19:28:25 +00:00
|
|
|
Shape.ContactCheck(iAtX,iAtY,border_hack_contacts);
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Store shape contact values in object t_contact
|
|
|
|
t_contact=Shape.ContactCNAT;
|
|
|
|
|
2010-03-27 16:05:02 +00:00
|
|
|
// Contact script call for the first contacted cnat
|
|
|
|
if (Shape.ContactCNAT)
|
|
|
|
for (int32_t ccnat=0; ccnat<4; ccnat++) // Left, right, top bottom
|
|
|
|
if (Shape.ContactCNAT & (1<<ccnat))
|
2009-05-08 13:28:41 +00:00
|
|
|
if (Contact(1<<ccnat))
|
|
|
|
break; // Will stop on first positive return contact call!
|
|
|
|
|
|
|
|
// Return shape contact count
|
|
|
|
return Shape.ContactCount;
|
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::SideBounds(C4Real &ctcox)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// layer bounds
|
2010-03-30 21:08:15 +00:00
|
|
|
if (Layer) if (Layer->Def->BorderBound & C4D_Border_Layer)
|
2010-03-18 23:04:29 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
C4PropList* pActionDef = GetAction();
|
2010-12-08 22:17:00 +00:00
|
|
|
if (!pActionDef || pActionDef->GetPropertyP(P_Procedure) != DFA_ATTACH)
|
2010-01-25 04:00:59 +00:00
|
|
|
{
|
2011-01-02 00:24:35 +00:00
|
|
|
TargetBounds(ctcox, Layer->GetX() + Layer->Shape.GetX() - Shape.GetX(), Layer->GetX() + Layer->Shape.GetX() + Layer->Shape.Wdt + Shape.GetX(), CNAT_Left, CNAT_Right);
|
2010-01-25 04:00:59 +00:00
|
|
|
}
|
2010-03-18 23:04:29 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// landscape bounds
|
2010-03-27 16:05:02 +00:00
|
|
|
if (Def->BorderBound & C4D_Border_Sides)
|
2009-05-08 13:28:41 +00:00
|
|
|
TargetBounds(ctcox,0-Shape.GetX(),GBackWdt+Shape.GetX(),CNAT_Left,CNAT_Right);
|
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::VerticalBounds(C4Real &ctcoy)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// layer bounds
|
2010-03-30 21:08:15 +00:00
|
|
|
if (Layer) if (Layer->Def->BorderBound & C4D_Border_Layer)
|
2010-03-18 23:04:29 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
C4PropList* pActionDef = GetAction();
|
2010-12-08 22:17:00 +00:00
|
|
|
if (!pActionDef || pActionDef->GetPropertyP(P_Procedure) != DFA_ATTACH)
|
2010-01-25 04:00:59 +00:00
|
|
|
{
|
2011-01-02 00:24:35 +00:00
|
|
|
TargetBounds(ctcoy, Layer->GetY() + Layer->Shape.GetY() - Shape.GetY(), Layer->GetY() + Layer->Shape.GetY() + Layer->Shape.Hgt + Shape.GetY(), CNAT_Top, CNAT_Bottom);
|
2010-01-25 04:00:59 +00:00
|
|
|
}
|
2010-03-18 23:04:29 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// landscape bounds
|
2010-03-27 16:05:02 +00:00
|
|
|
if (Def->BorderBound & C4D_Border_Top)
|
2009-05-08 13:28:41 +00:00
|
|
|
TargetBounds(ctcoy,0-Shape.GetY(),+1000000,CNAT_Top,CNAT_Bottom);
|
2010-03-27 16:05:02 +00:00
|
|
|
if (Def->BorderBound & C4D_Border_Bottom)
|
2009-05-08 13:28:41 +00:00
|
|
|
TargetBounds(ctcoy,-1000000,GBackHgt+Shape.GetY(),CNAT_Top,CNAT_Bottom);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4Object::DoMovement()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
int32_t ctcox,ctcoy,ctcor/*,ctx,cty*/,iContact=0;
|
2009-08-25 23:21:54 +00:00
|
|
|
bool fAnyContact=false; int iContacts = 0;
|
2009-05-08 13:28:41 +00:00
|
|
|
BYTE fTurned=0,fRedirectYR=0,fNoAttach=0;
|
|
|
|
// Restrictions
|
|
|
|
if (Def->NoHorizontalMove) xdir=0;
|
|
|
|
// Dig free target area
|
2010-03-18 23:04:29 +00:00
|
|
|
C4PropList* pActionDef = GetAction();
|
|
|
|
if (pActionDef)
|
|
|
|
if (pActionDef->GetPropertyInt(P_DigFree))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Shape size square
|
2010-03-18 23:04:29 +00:00
|
|
|
if (pActionDef->GetPropertyInt(P_DigFree)==1)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
ctcox=fixtoi(fix_x+xdir); ctcoy=fixtoi(fix_y+ydir);
|
2011-05-30 22:33:35 +00:00
|
|
|
::Landscape.DigFreeRect(ctcox+Shape.GetX(),ctcoy+Shape.GetY(),Shape.Wdt,Shape.Hgt,this);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Free size round (variable size)
|
|
|
|
else
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
ctcox=fixtoi(fix_x+xdir); ctcoy=fixtoi(fix_y+ydir);
|
2010-03-18 23:04:29 +00:00
|
|
|
int32_t rad = pActionDef->GetPropertyInt(P_DigFree);
|
2009-05-08 13:28:41 +00:00
|
|
|
if (Con<FullCon) rad = rad*6*Con/5/FullCon;
|
2011-05-30 22:33:35 +00:00
|
|
|
::Landscape.DigFree(ctcox,ctcoy-1,rad,this);
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// store previous position
|
2012-01-11 23:49:12 +00:00
|
|
|
C4Real ix0=GetFixedX(); C4Real iy0=GetFixedY();
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// store previous movement and ocf
|
2010-05-04 15:35:18 +00:00
|
|
|
C4Real oldxdir(xdir), oldydir(ydir);
|
2009-05-08 13:28:41 +00:00
|
|
|
uint32_t old_ocf = OCF;
|
|
|
|
|
2010-05-04 15:35:18 +00:00
|
|
|
C4Real new_x = fix_x + xdir;
|
|
|
|
C4Real new_y = fix_y + ydir;
|
2010-03-18 17:05:02 +00:00
|
|
|
SideBounds(new_x);
|
|
|
|
ctcox = fixtoi(new_x);
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
if (!Action.t_attach) // Unattached movement = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Horizontal movement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// Move to target
|
2010-05-19 03:19:49 +00:00
|
|
|
while (Abs<C4Real>(fix_x - ctcox) > C4REAL10(5))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Next step
|
2010-05-04 15:35:18 +00:00
|
|
|
int step = Sign<C4Real>(new_x - fix_x);
|
2012-10-10 19:28:25 +00:00
|
|
|
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)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Abort horizontal movement
|
|
|
|
ctcox = GetX();
|
|
|
|
new_x = fix_x;
|
|
|
|
// Vertical redirection (always)
|
|
|
|
RedirectForce(xdir,ydir,-1);
|
|
|
|
ApplyFriction(ydir,ContactVtxFriction(this));
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
else // Free horizontal movement
|
|
|
|
DoMotion(step, 0);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Vertical movement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// Movement target
|
|
|
|
new_y = fix_y + ydir;
|
|
|
|
// Movement bounds (vertical)
|
2010-03-18 17:05:02 +00:00
|
|
|
VerticalBounds(new_y);
|
|
|
|
ctcoy=fixtoi(new_y);
|
2009-05-08 13:28:41 +00:00
|
|
|
// Move to target
|
2010-05-19 03:19:49 +00:00
|
|
|
while (Abs<C4Real>(fix_y - ctcoy) > C4REAL10(5))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Next step
|
2010-05-04 15:35:18 +00:00
|
|
|
int step = Sign<C4Real>(new_y - fix_y);
|
2010-01-25 04:00:59 +00:00
|
|
|
if ((iContact=ContactCheck(GetX(), GetY() + step)))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
fAnyContact=true; iContacts |= t_contact;
|
2009-05-08 13:28:41 +00:00
|
|
|
ctcoy=GetY(); 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
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// living things are always capable of keeping their rotation
|
|
|
|
if (OCF & OCF_Rotate) if (iContact==1) if (!Alive)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
|
|
|
RedirectForce(ydir,rdir,-ContactVtxWeight(this));
|
|
|
|
fRedirectYR=1;
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
ydir=0;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
else // Free vertical movement
|
|
|
|
DoMotion(0,step);
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
if (Action.t_attach) // Attached movement = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-18 17:05:02 +00:00
|
|
|
VerticalBounds(new_y);
|
2009-05-08 13:28:41 +00:00
|
|
|
ctcoy=fixtoi(new_y);
|
|
|
|
// Move to target
|
|
|
|
do
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Set next step target
|
2010-03-18 17:05:02 +00:00
|
|
|
int step_x = 0, step_y = 0;
|
2012-06-08 14:17:42 +00:00
|
|
|
if (ctcox != GetX())
|
|
|
|
step_x = Sign(ctcox - GetX());
|
|
|
|
else if (ctcoy != GetY())
|
|
|
|
step_y = Sign(ctcoy - GetY());
|
|
|
|
int32_t ctx = GetX() + step_x;
|
|
|
|
int32_t cty = GetY() + step_y;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Attachment check
|
|
|
|
if (!Shape.Attach(ctx,cty,Action.t_attach))
|
|
|
|
fNoAttach=1;
|
|
|
|
else
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Attachment change to ctx/cty overrides ctco target
|
2012-06-08 14:17:42 +00:00
|
|
|
if (ctx != GetX() + step_x)
|
|
|
|
{
|
|
|
|
ctcox = ctx; xdir = Fix0; new_x = itofix(ctx);
|
|
|
|
}
|
|
|
|
if (cty != GetY() + step_y)
|
|
|
|
{
|
|
|
|
ctcoy = cty; ydir = Fix0; new_y = itofix(cty);
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Contact check & evaluation
|
2012-10-10 19:28:25 +00:00
|
|
|
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)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Abort movement
|
2012-06-08 14:17:42 +00:00
|
|
|
if (ctx != GetX())
|
|
|
|
{
|
|
|
|
ctx = ctcox = GetX(); new_x = fix_x;
|
|
|
|
}
|
|
|
|
if (cty != GetY())
|
|
|
|
{
|
|
|
|
cty = ctcoy = GetY(); new_y = fix_y;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2012-06-08 14:17:42 +00:00
|
|
|
DoMotion(ctx - GetX(), cty - GetY());
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2012-06-08 14:17:42 +00:00
|
|
|
while (ctcox != GetX() || ctcoy != GetY());
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2012-01-11 23:49:12 +00:00
|
|
|
|
|
|
|
if(fix_x != new_x || fix_y != new_y)
|
|
|
|
if (pSolidMaskData)
|
|
|
|
pSolidMaskData->Remove(true);
|
2009-05-08 13:28:41 +00:00
|
|
|
fix_x = new_x;
|
|
|
|
fix_y = new_y;
|
|
|
|
// Rotation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
if (OCF & OCF_Rotate && !!rdir)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Set target
|
|
|
|
fix_r+=rdir*5;
|
|
|
|
// Rotation limit
|
|
|
|
if (Def->Rotateable>1)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
if (fix_r > itofix(Def->Rotateable))
|
|
|
|
{ fix_r = itofix(Def->Rotateable); rdir=0; }
|
|
|
|
if (fix_r < itofix(-Def->Rotateable))
|
|
|
|
{ fix_r = itofix(-Def->Rotateable); rdir=0; }
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
ctcor=fixtoi(fix_r);
|
|
|
|
int32_t ctx=GetX(); int32_t cty=GetY();
|
|
|
|
// Move to target
|
|
|
|
while (r!=ctcor)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Save step undos
|
|
|
|
int32_t lcobjr=r; C4Shape lshape=Shape;
|
|
|
|
// Try next step
|
|
|
|
r+=Sign(ctcor-r);
|
|
|
|
UpdateShape();
|
|
|
|
// attached rotation: rotate around attachment pos
|
|
|
|
if (Action.t_attach && !fNoAttach)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// 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);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// check for contact
|
2010-01-25 04:00:59 +00:00
|
|
|
if ((iContact=ContactCheck(ctx,cty))) // Contact
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
fAnyContact=true; iContacts |= t_contact;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Undo step and abort movement
|
|
|
|
Shape=lshape;
|
|
|
|
r=lcobjr;
|
|
|
|
ctcor=r;
|
|
|
|
fix_r=itofix(r);
|
|
|
|
// last UpdateShape-call might have changed sector lists!
|
|
|
|
UpdatePos();
|
|
|
|
// Redirect to GetY()
|
|
|
|
if (iContact==1) if (!fRedirectYR)
|
2010-03-28 18:58:01 +00:00
|
|
|
RedirectForce(rdir,ydir,-1);
|
2009-05-08 13:28:41 +00:00
|
|
|
// Stop rotation
|
|
|
|
rdir=0;
|
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
|
|
|
fTurned=1;
|
|
|
|
fix_x=itofix(ctx); fix_y=itofix(cty);
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Circle bounds
|
|
|
|
if (fix_r<-FixHalfCircle) { fix_r+=FixFullCircle; r=fixtoi(fix_r); }
|
|
|
|
if (fix_r>+FixHalfCircle) { fix_r-=FixFullCircle; r=fixtoi(fix_r); }
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Reput solid mask: Might have been removed by motion or
|
|
|
|
// motion might be out of date from last frame.
|
|
|
|
UpdateSolidMask(true);
|
|
|
|
// Misc checks ===========================================================================================
|
|
|
|
// InLiquid check
|
2009-08-15 18:50:32 +00:00
|
|
|
// this equals C4Object::UpdateLiquid, but the "fNoAttach=false;"-line
|
2009-05-08 13:28:41 +00:00
|
|
|
if (IsInLiquidCheck()) // In Liquid
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
if (!InLiquid) // Enter liquid
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +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);
|
2009-08-15 18:50:32 +00:00
|
|
|
fNoAttach=false;
|
2009-05-08 13:28:41 +00:00
|
|
|
InLiquid=1;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
else // Out of liquid
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
if (InLiquid) // Leave liquid
|
|
|
|
InLiquid=0;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Contact Action
|
|
|
|
if (fAnyContact)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
t_contact = iContacts;
|
|
|
|
ContactAction();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Attachment Loss Action
|
|
|
|
if (fNoAttach)
|
|
|
|
NoAttachAction();
|
|
|
|
// Movement Script Execution
|
|
|
|
if (fAnyContact)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
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);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Rotation gfx
|
|
|
|
if (fTurned)
|
|
|
|
UpdateFace(true);
|
|
|
|
else
|
|
|
|
// pos changed?
|
2012-01-11 23:49:12 +00:00
|
|
|
if ((ix0-GetFixedX())|(iy0-GetFixedY())) UpdatePos();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4Object::Stabilize()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// def allows stabilization?
|
|
|
|
if (Def->NoStabilize) return;
|
|
|
|
// normalize angle
|
2010-03-28 18:58:01 +00:00
|
|
|
int32_t nr = r; while (nr < -180) nr+=360; while (nr > 180) nr-=360;
|
2009-05-08 13:28:41 +00:00
|
|
|
if (nr!=0)
|
2010-03-27 16:05:02 +00:00
|
|
|
if (Inside<int32_t>(nr,-StableRange,+StableRange))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
// Save step undos
|
|
|
|
int32_t lcobjr=r;
|
|
|
|
C4Shape lshape=Shape;
|
|
|
|
// Try rotation
|
|
|
|
r=0;
|
|
|
|
UpdateShape();
|
|
|
|
if (ContactCheck(GetX(),GetY()))
|
2010-03-28 18:58:01 +00:00
|
|
|
{ // Undo rotation
|
2010-03-27 16:05:02 +00:00
|
|
|
Shape=lshape;
|
|
|
|
r=lcobjr;
|
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
|
|
|
{ // Stabilization okay
|
2010-03-27 16:05:02 +00:00
|
|
|
fix_r=itofix(r);
|
|
|
|
UpdateFace(true);
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4Object::CopyMotion(C4Object *from)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Designed for contained objects, no static
|
|
|
|
if (fix_x != from->fix_x || fix_y != from->fix_y)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
fix_x=from->fix_x; fix_y=from->fix_y;
|
|
|
|
// Resort into sectors
|
|
|
|
UpdatePos();
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
xdir=from->xdir; ydir=from->ydir;
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-10-10 16:46:23 +00:00
|
|
|
void C4Object::ForcePosition(C4Real tx, C4Real ty)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-10-10 16:46:23 +00:00
|
|
|
fix_x=tx; fix_y=ty;
|
2010-08-15 13:24:24 +00:00
|
|
|
UpdatePos();
|
|
|
|
UpdateSolidMask(false);
|
|
|
|
}
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
void C4Object::MovePosition(int32_t dx, int32_t dy)
|
2012-01-11 23:49:12 +00:00
|
|
|
{
|
|
|
|
MovePosition(itofix(dx), itofix(dy));
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Object::MovePosition(C4Real dx, C4Real dy)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// move object position; repositions SolidMask
|
2010-04-20 20:38:18 +00:00
|
|
|
if (pSolidMaskData) pSolidMaskData->Remove(true);
|
2009-05-08 13:28:41 +00:00
|
|
|
fix_x+=dx;
|
|
|
|
fix_y+=dy;
|
|
|
|
UpdatePos();
|
|
|
|
UpdateSolidMask(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::ExecMovement() // Every Tick1 by Execute
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-09-12 14:03:49 +00:00
|
|
|
// update in which material this object is
|
|
|
|
UpdateInMat();
|
2010-03-27 16:05:02 +00:00
|
|
|
|
|
|
|
// Containment check
|
|
|
|
if (Contained)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
CopyMotion(Contained);
|
|
|
|
|
|
|
|
return true;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2010-03-27 16:05:02 +00:00
|
|
|
|
|
|
|
// General mobility check
|
|
|
|
if (Category & C4D_StaticBack) return false;
|
|
|
|
|
|
|
|
// Movement execution
|
|
|
|
if (Mobile) // Object is moving
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
// Move object
|
|
|
|
DoMovement();
|
|
|
|
// Demobilization check
|
|
|
|
if ((xdir==0) && (ydir==0) && (rdir==0)) Mobile=0;
|
|
|
|
// Check for stabilization
|
|
|
|
if (rdir==0) Stabilize();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2010-03-27 16:05:02 +00:00
|
|
|
else // Object is static
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
// Check for stabilization
|
|
|
|
Stabilize();
|
|
|
|
// Check for mobilization
|
|
|
|
if (!::Game.iTick10)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
// Gravity mobilization
|
|
|
|
xdir=ydir=rdir=0;
|
|
|
|
fix_r=itofix(r);
|
|
|
|
Mobile=1;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2010-03-27 16:05:02 +00:00
|
|
|
|
|
|
|
// Enforce zero rotation
|
|
|
|
if (!Def->Rotateable) r=0;
|
|
|
|
|
|
|
|
// Out of bounds check
|
|
|
|
if ((!Inside<int32_t>(GetX(),0,GBackWdt) && !(Def->BorderBound & C4D_Border_Sides)) || (GetY()>GBackHgt && !(Def->BorderBound & C4D_Border_Bottom)))
|
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
|
|
|
// Never remove attached objects: If they are truly outside landscape, their target will be removed,
|
|
|
|
// and the attached objects follow one frame later
|
2010-12-08 22:17:00 +00:00
|
|
|
if (!pActionDef || !Action.Target || pActionDef->GetPropertyP(P_Procedure) != DFA_ATTACH)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
bool fRemove = true;
|
|
|
|
// never remove HUD objects
|
|
|
|
if (Category & C4D_Parallax)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-07-22 16:03:33 +00:00
|
|
|
int parX, parY;
|
|
|
|
GetParallaxity(&parX, &parY);
|
2009-05-08 13:28:41 +00:00
|
|
|
fRemove = false;
|
|
|
|
if (GetX()>GBackWdt || GetY()>GBackHgt) fRemove = true; // except if they are really out of the viewport to the right...
|
2009-07-22 16:03:33 +00:00
|
|
|
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
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
if (fRemove)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
AssignDeath(true);
|
|
|
|
AssignRemoval();
|
|
|
|
}
|
2010-03-18 23:04:29 +00:00
|
|
|
}
|
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
|
|
|
|
2010-10-02 00:30:59 +00:00
|
|
|
bool SimFlight(C4Real &x, C4Real &y, C4Real &xdir, C4Real &ydir, int32_t iDensityMin, int32_t iDensityMax, int32_t &iIter)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
2010-10-02 00:30:59 +00:00
|
|
|
bool hitOnTime = true;
|
2010-03-27 16:05:02 +00:00
|
|
|
bool fBreak = false;
|
2010-10-02 00:30:59 +00:00
|
|
|
int32_t ctcox,ctcoy,cx,cy,i;
|
2009-05-08 13:28:41 +00:00
|
|
|
cx = fixtoi(x); cy = fixtoi(y);
|
2010-10-02 00:30:59 +00:00
|
|
|
i = iIter;
|
2010-03-27 16:05:02 +00:00
|
|
|
do
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-10-02 00:30:59 +00:00
|
|
|
if (!--i) {hitOnTime = false; break;}
|
2010-03-27 16:05:02 +00:00
|
|
|
// 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
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
// Set next step target
|
|
|
|
cx+=Sign(ctcox-cx); cy+=Sign(ctcoy-cy);
|
|
|
|
// Contact check
|
2010-03-28 18:58:01 +00:00
|
|
|
if (Inside(GBackDensity(cx,cy), iDensityMin, iDensityMax))
|
2009-05-08 13:28:41 +00:00
|
|
|
{ fBreak = true; break; }
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2010-03-27 16:05:02 +00:00
|
|
|
while ((cx!=ctcox) || (cy!=ctcoy));
|
|
|
|
// Adjust GravAccel once per frame
|
|
|
|
ydir+=GravAccel;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
|
|
|
while (!fBreak);
|
2009-05-08 13:28:41 +00:00
|
|
|
// write position back
|
|
|
|
x = itofix(cx); y = itofix(cy);
|
2010-10-02 00:30:59 +00:00
|
|
|
|
|
|
|
// how many steps did it take to get here?
|
2010-10-02 17:02:21 +00:00
|
|
|
iIter -= i;
|
2010-10-02 00:30:59 +00:00
|
|
|
|
|
|
|
return hitOnTime;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-04 15:35:18 +00:00
|
|
|
bool SimFlightHitsLiquid(C4Real fcx, C4Real fcy, C4Real xdir, C4Real ydir)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Start in water?
|
2010-10-02 00:30:59 +00:00
|
|
|
int temp;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (DensityLiquid(GBackDensity(fixtoi(fcx), fixtoi(fcy))))
|
2010-10-02 00:30:59 +00:00
|
|
|
if (!SimFlight(fcx, fcy, xdir, ydir, 0, C4M_Liquid - 1, temp=10))
|
2009-08-15 18:50:32 +00:00
|
|
|
return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Hits liquid?
|
2010-10-02 00:30:59 +00:00
|
|
|
if (!SimFlight(fcx, fcy, xdir, ydir, C4M_Liquid, 100, temp=-1))
|
2009-08-15 18:50:32 +00:00
|
|
|
return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
// liquid & deep enough?
|
|
|
|
return GBackLiquid(fixtoi(fcx), fixtoi(fcy)) && GBackLiquid(fixtoi(fcx), fixtoi(fcy) + 9);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|