From 2a9b4810874b1aa8f867b185c851fc63ac0dc36b Mon Sep 17 00:00:00 2001 From: Julius Michaelis Date: Sun, 30 Aug 2015 22:19:36 +0900 Subject: [PATCH] Add a new variant of vehicle that can be passed from below but be walked on from above. --- planet/Material.ocg/HalfVehicle.ocm | 5 +++ planet/System.ocg/Vertices.c | 63 ++++++++++++++++++++++++++++- src/config/C4Constants.h | 5 ++- src/landscape/C4Material.cpp | 13 +++--- src/landscape/C4Material.h | 11 +++++ src/landscape/C4SolidMask.cpp | 29 ++++++++----- src/landscape/C4SolidMask.h | 6 ++- src/object/C4Movement.cpp | 6 +-- src/object/C4Object.cpp | 6 +++ src/object/C4Object.h | 3 +- src/object/C4ObjectScript.cpp | 8 ++++ src/object/C4Shape.cpp | 44 +++++++++++--------- src/object/C4Shape.h | 4 +- 13 files changed, 157 insertions(+), 46 deletions(-) create mode 100644 planet/Material.ocg/HalfVehicle.ocm diff --git a/planet/Material.ocg/HalfVehicle.ocm b/planet/Material.ocg/HalfVehicle.ocm new file mode 100644 index 000000000..4c1d88ada --- /dev/null +++ b/planet/Material.ocg/HalfVehicle.ocm @@ -0,0 +1,5 @@ +[Material] +Name=HalfVehicle +Density=100 +Friction=100 +KeepSinglePixels=1 diff --git a/planet/System.ocg/Vertices.c b/planet/System.ocg/Vertices.c index 1aa1e267d..437191660 100644 --- a/planet/System.ocg/Vertices.c +++ b/planet/System.ocg/Vertices.c @@ -30,8 +30,67 @@ global func VerticesStuck() // Returns whether the object has a vertex with the given CNAT value global func HasCNAT(int cnat) { - for(var i = -1; i < GetVertexNum(); i++) + for (var i = -1; i < GetVertexNum(); i++) if (GetVertex(i, VTX_CNAT) == cnat) return true; return false; -} \ No newline at end of file +} + +// e.g. clonk->SetVertexCNAT(2, CNAT_CollideHalfVehicle, true); makes the clonk behave correctly wrt. to HalfVehicle +global func SetVertexCNAT(int vtx, int val, bool set) +{ + if (val == nil || set == nil) + return FatalError("this function requires its second and third parameter to be non-nil"); + if (!this) + return FatalError("this function requires object context"); + if (vtx == nil) + for (var i = GetVertexNum(); i-->0;) + SetVertexCNAT(i, val, set); + else + SetVertex(vtx, VTX_CNAT, GetVertex(vtx, VTX_CNAT) & ~val | (set && val), 2); +} + +// Allow falling down throughg a HalfVehicle platform +global func HalfVehicleFadeJump() +{ + if (!this) + return FatalError("this function requires object context"); + AddEffect("IntHalfVehicleFadeJump", this, 1, 1); +} + +global func FxIntHalfVehicleFadeJumpStart(object target, proplist effect, int temp) +{ + if (temp) + return FX_OK; + if (!target) { + return FX_Start_Deny; + } + effect.collideverts = CreateArray(); + for (var i = target->GetVertexNum(); i-->0;) + if(target->GetVertex(i, VTX_CNAT) & CNAT_CollideHalfVehicle) { + PushBack(effect.collideverts, i); + target->SetVertexCNAT(i, CNAT_CollideHalfVehicle, false); + } + effect.origpos = target->GetPosition(); + return FX_OK; +} + +global func FxIntHalfVehicleFadeJumpTimer(object target, proplist effect, int time) +{ + if (DeepEqual(target->GetPosition(), effect.origpos)) + return FX_OK; + for (var i = GetLength(effect.collideverts); i-->0;) { + if (target->GetMaterial(target->GetVertex(effect.collideverts[i], VTX_X), + target->GetVertex(effect.collideverts[i], VTX_Y)) == Material("HalfVehicle")) + return FX_OK; + } + return FX_Execute_Kill; +} + +global func FxIntHalfVehicleFadeJumpStop(object target, proplist effect, int reason, bool temp) +{ + if (reason == FX_Call_RemoveClear) + return; + for (var i = GetLength(effect.collideverts); i-->0;) + target->SetVertexCNAT(effect.collideverts[i], CNAT_CollideHalfVehicle, true); +} diff --git a/src/config/C4Constants.h b/src/config/C4Constants.h index d11005e1e..27336d4b8 100644 --- a/src/config/C4Constants.h +++ b/src/config/C4Constants.h @@ -129,9 +129,10 @@ const BYTE // Directional CNAT_Center = 16, // Additional flags CNAT_MultiAttach = 32, // new attachment behaviour; see C4Shape::Attach - CNAT_NoCollision = 64; // turn off collision for this vertex + CNAT_NoCollision = 64, // turn off collision for this vertex + CNAT_CollideHalfVehicle = 128; -const BYTE CNAT_Flags = CNAT_MultiAttach | CNAT_NoCollision; // all attchment flags that can be combined with regular attachment +const BYTE CNAT_Flags = CNAT_MultiAttach | CNAT_NoCollision | CNAT_CollideHalfVehicle; // all attchment flags that can be combined with regular attachment //=============================== Keyboard Input Controls ===================================================== diff --git a/src/landscape/C4Material.cpp b/src/landscape/C4Material.cpp index 749ae7c38..4d3198885 100644 --- a/src/landscape/C4Material.cpp +++ b/src/landscape/C4Material.cpp @@ -34,9 +34,9 @@ #include // For GravAccel -int32_t MVehic=MNone,MTunnel=MNone,MWater=MNone,MEarth=MNone; +int32_t MVehic=MNone,MHalfVehic=MNone,MTunnel=MNone,MWater=MNone,MEarth=MNone; BYTE MCVehic=0; - +BYTE MCHalfVehic=0; // -------------------------------------- C4MaterialReaction @@ -677,10 +677,11 @@ bool C4MaterialMap::CrossMapMaterials(const char* szEarthMaterial) // Called aft if(!earth_entry) { LogFatal(FormatString("Earth material \"%s\" not found!", szEarthMaterial).getData()); return false; } - MVehic = Get("Vehicle"); MCVehic = Mat2PixColDefault(MVehic); - MTunnel = Get("Tunnel"); - MWater = Get("Water"); - MEarth = Get(earth_entry->GetMaterialName()); + MVehic = Get("Vehicle"); MCVehic = Mat2PixColDefault(MVehic); + MHalfVehic = Get("HalfVehicle"); MCHalfVehic = Mat2PixColDefault(MHalfVehic); + MTunnel = Get("Tunnel"); + MWater = Get("Water"); + MEarth = Get(earth_entry->GetMaterialName()); if ((MVehic==MNone) || (MTunnel==MNone)) { LogFatal(LoadResStr("IDS_PRC_NOSYSMATS")); return false; } diff --git a/src/landscape/C4Material.h b/src/landscape/C4Material.h index cbe56bcc7..70b674bb0 100644 --- a/src/landscape/C4Material.h +++ b/src/landscape/C4Material.h @@ -263,6 +263,7 @@ const int32_t MNone = -1; extern int32_t MVehic,MTunnel,MWater,MEarth; // presearched materials extern BYTE MCVehic; // precalculated material color +extern BYTE MCHalfVehic; // precalculated material color inline bool MatValid(int32_t mat) { @@ -274,6 +275,16 @@ inline bool MatVehicle(int32_t iMat) return iMat == MVehic; } +inline bool IsMCVehicle(BYTE mat) { + return mat == MCVehic; +} +inline bool IsMCHalfVehicle(BYTE mat) { + return mat == MCHalfVehic; +} +inline bool IsSomeVehicle(BYTE mat) { + return IsMCVehicle(mat) || IsMCHalfVehicle(mat); +} + inline BYTE MatTex2PixCol(int32_t tex) { return BYTE(tex); diff --git a/src/landscape/C4SolidMask.cpp b/src/landscape/C4SolidMask.cpp index 1ea8bc68b..5a0591fe5 100644 --- a/src/landscape/C4SolidMask.cpp +++ b/src/landscape/C4SolidMask.cpp @@ -96,11 +96,11 @@ void C4SolidMask::Put(bool fCauseInstability, C4TargetRect *pClipRect, bool fRes byPixel=GBackPix(iTx,iTy); // store it. If MCVehic, also store in initial put, but won't be used in restore // do not overwrite current value in re-put issued by SolidMask-remover - if (byPixel != MCVehic || RegularPut) + if (!IsSomeVehicle(byPixel) || RegularPut) pSolidMaskMatBuff[(ycnt+pClipRect->ty)*MatBuffPitch+xcnt+pClipRect->tx]=byPixel; } // and set mask - ::Landscape.SetPix2(iTx,iTy,MCVehic,::Landscape.Transparent); + ::Landscape.SetPix2(iTx,iTy,MaskMaterial,::Landscape.Transparent); } else // no SolidMask: mark buffer as unused here @@ -162,11 +162,11 @@ void C4SolidMask::Put(bool fCauseInstability, C4TargetRect *pClipRect, bool fRes byPixel=_GBackPix(iTx,iTy); // store it. If MCVehic, also store in initial put, but won't be used in restore // do not overwrite current value in re-put issued by SolidMask-remover - if (byPixel != MCVehic || RegularPut) + if (IsSomeVehicle(byPixel) || RegularPut) pSolidMaskMatBuff[i + xcnt] = byPixel; } // set mask pix - ::Landscape.SetPix2(iTx, iTy, MCVehic, ::Landscape.Transparent); + ::Landscape.SetPix2(iTx, iTy, MaskMaterial, ::Landscape.Transparent); } else if (!MaskPut) // mark pix as unused in buf @@ -229,7 +229,7 @@ int32_t C4SolidMask::DensityProvider::GetDensity(int32_t x, int32_t y) const // Using put-buffer for rotated masks // for SolidMask-pixels not put because there was another SolidMask already, this will not return solid pix=*(rSolidMaskData.pSolidMaskMatBuff+(y+rSolidMaskData.MaskPutRect.ty)*rSolidMaskData.MatBuffPitch+rSolidMaskData.MaskPutRect.tx+x); - if (pix == MCVehic) + if (IsSomeVehicle(pix)) return 0; else return C4M_Solid; @@ -259,8 +259,8 @@ void C4SolidMask::Remove(bool fBackupAttachment) // The pPix-check ensures that only pixels that hads been overwritten by this SolidMask are restored // Non-SolidMask-pixels should not happen here, because all relevant landscape change routines should // temp remove SolidMasks before - assert(_GBackPix(iTx,iTy) == MCVehic); - if (::Landscape._GetPix(iTx, iTy) == MCVehic) + assert(IsSomeVehicle(_GBackPix(iTx,iTy))); + if (IsSomeVehicle(::Landscape._GetPix(iTx, iTy))) ::Landscape._SetPix2(iTx, iTy, *pPix, ::Landscape.Transparent); // Instability ::Landscape.CheckInstabilityRange(iTx,iTy); @@ -340,10 +340,10 @@ void C4SolidMask::RemoveTemporary(C4Rect where) { BYTE *pPix = pSolidMaskMatBuff + (y - MaskPutRect.y + MaskPutRect.ty) * MatBuffPitch + x - MaskPutRect.x + MaskPutRect.tx; // only if mask was used here - if (*pPix != MCVehic) + if (*pPix != MCVehic) // { // restore - assert(GBackPix(x,y)==MCVehic); + assert(IsSomeVehicle(GBackPix(x,y))); ::Landscape.SetPix2(x, y, *pPix, ::Landscape.Transparent); } } @@ -365,7 +365,7 @@ void C4SolidMask::PutTemporary(C4Rect where) { // put assert(GBackPix(x,y)==*pPix); - ::Landscape.SetPix2(x, y, MCVehic, ::Landscape.Transparent); + ::Landscape.SetPix2(x, y, MaskMaterial, ::Landscape.Transparent); } } } @@ -387,7 +387,7 @@ void C4SolidMask::Repair(C4Rect where) // record changed landscape in MatBuff *pPix = GBackPix(x,y); // put - ::Landscape.SetPix2(x, y, MCVehic, ::Landscape.Transparent); + ::Landscape.SetPix2(x, y, MaskMaterial, ::Landscape.Transparent); } } } @@ -401,6 +401,7 @@ C4SolidMask::C4SolidMask(C4Object *pForObject) : pForObject(pForObject) MaskRemovalX=MaskRemovalY=Fix0; ppAttachingObjects=NULL; iAttachingObjectsCount=iAttachingObjectsCapacity=0; + MaskMaterial=MCVehic; // Update linked list Next = 0; Prev = Last; @@ -455,6 +456,7 @@ C4SolidMask * C4SolidMask::Last = 0; bool C4SolidMask::CheckConsistency() { + assert(IsSomeVehicle(MaskMaterial)); C4Rect SolidMaskRect(0,0,GBackWdt,GBackHgt); C4SolidMask *pSolid; for (pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev) @@ -487,3 +489,8 @@ CSurface8 *C4SolidMask::LoadMaskFromFile(class C4Group &hGroup, const char *szFi return result; } +void C4SolidMask::SetHalfVehicle(bool set) +{ + MaskMaterial = set ? MCHalfVehic : MCVehic; + // TODO: Redraw +} diff --git a/src/landscape/C4SolidMask.h b/src/landscape/C4SolidMask.h index 45bd62174..0926b8517 100644 --- a/src/landscape/C4SolidMask.h +++ b/src/landscape/C4SolidMask.h @@ -35,7 +35,9 @@ protected: C4TargetRect MaskPutRect; // absolute bounding screen rect at which the mask is put - tx and ty are offsets within pSolidMask (for rects outside the landscape) - BYTE *pSolidMaskMatBuff; // material replaced by this solidmask. MCVehic if no solid mask data at this position OR another solidmask was already present during put + BYTE *pSolidMaskMatBuff; // material replaced by this solidmask. MCVehic if no solid mask data at this position OR another solidmask was already present during put (independent of MaskMaterial) + + BYTE MaskMaterial; // Either MCVehicle or MCHalfVehicle C4Object *pForObject; @@ -86,6 +88,8 @@ public: static void PutSolidMasks(); static CSurface8 *LoadMaskFromFile(class C4Group &hGroup, const char *szFilename); + + void SetHalfVehicle(bool set); }; #endif diff --git a/src/object/C4Movement.cpp b/src/object/C4Movement.cpp index 802800efa..137d79fc7 100644 --- a/src/object/C4Movement.cpp +++ b/src/object/C4Movement.cpp @@ -152,10 +152,10 @@ void C4Object::TargetBounds(C4Real &ctco, int32_t limit_low, int32_t limit_hi, i } } -int32_t C4Object::ContactCheck(int32_t iAtX, int32_t iAtY, uint32_t *border_hack_contacts) +int32_t C4Object::ContactCheck(int32_t iAtX, int32_t iAtY, uint32_t *border_hack_contacts, bool collide_halfvehic) { // Check shape contact at given position - Shape.ContactCheck(iAtX,iAtY,border_hack_contacts); + Shape.ContactCheck(iAtX,iAtY,border_hack_contacts,collide_halfvehic); // Store shape contact values in object t_contact t_contact=Shape.ContactCNAT; @@ -281,7 +281,7 @@ void C4Object::DoMovement() { // Next step int step = Sign(new_y - fix_y); - if ((iContact=ContactCheck(GetX(), GetY() + step))) + if ((iContact=ContactCheck(GetX(), GetY() + step, nullptr, ydir > 0))) { fAnyContact=true; iContacts |= t_contact; new_y = fix_y; diff --git a/src/object/C4Object.cpp b/src/object/C4Object.cpp index 4e06205a6..bf2608373 100644 --- a/src/object/C4Object.cpp +++ b/src/object/C4Object.cpp @@ -2602,6 +2602,12 @@ void C4Object::SetSolidMask(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, if (CheckSolidMaskRect()) UpdateSolidMask(false); } +void C4Object::SetHalfVehicleSolidMask(bool set) +{ + if (!pSolidMaskData) return; + pSolidMaskData->SetHalfVehicle(set); +} + bool C4Object::CheckSolidMaskRect() { // Ensure SolidMask rect lies within bounds of SolidMask bitmap in definition diff --git a/src/object/C4Object.h b/src/object/C4Object.h index b2b1c1138..6b601b1f5 100644 --- a/src/object/C4Object.h +++ b/src/object/C4Object.h @@ -212,6 +212,7 @@ public: void UpdateActionFace(); void SyncClearance(); void SetSolidMask(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, int32_t iTX, int32_t iTY); + void SetHalfVehicleSolidMask(bool set); bool CheckSolidMaskRect(); // clip bounds of SolidMask in graphics - return whether the solidmask still exists C4Object *ComposeContents(C4ID id); bool MenuCommand(const char *szCommand); @@ -269,7 +270,7 @@ public: void GetOCFForPos(int32_t ctx, int32_t cty, DWORD &ocf) const; bool CloseMenu(bool fForce); bool ActivateMenu(int32_t iMenu, int32_t iMenuSelect=0, int32_t iMenuData=0, int32_t iMenuPosition=0, C4Object *pTarget=NULL); - int32_t ContactCheck(int32_t atx, int32_t aty, uint32_t *border_hack_contacts=0); + int32_t ContactCheck(int32_t atx, int32_t aty, uint32_t *border_hack_contacts=0, bool collide_halfvehic=false); bool Contact(int32_t cnat); void TargetBounds(C4Real &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 }; diff --git a/src/object/C4ObjectScript.cpp b/src/object/C4ObjectScript.cpp index 5334430cb..e86ea6c64 100644 --- a/src/object/C4ObjectScript.cpp +++ b/src/object/C4ObjectScript.cpp @@ -46,6 +46,12 @@ static C4Void FnSetSolidMask(C4Object *Obj, long iX, long iY, long iWdt, long iH return C4Void(); } +static C4Void FnSetHalfVehicleSolidMask(C4Object *Obj, bool set) +{ + Obj->SetHalfVehicleSolidMask(set); + return C4Void(); +} + static C4Void FnDeathAnnounce(C4Object *Obj) { const long MaxDeathMsg=7; @@ -2498,6 +2504,7 @@ C4ScriptConstDef C4ScriptObjectConstMap[]= { "CNAT_Center" ,C4V_Int, CNAT_Center }, { "CNAT_MultiAttach" ,C4V_Int, CNAT_MultiAttach }, { "CNAT_NoCollision" ,C4V_Int, CNAT_NoCollision }, + { "CNAT_CollideHalfVehicle" ,C4V_Int, CNAT_CollideHalfVehicle }, // vertex data { "VTX_X" ,C4V_Int, VTX_X }, @@ -2711,6 +2718,7 @@ void InitObjectFunctionMap(C4AulScriptEngine *pEngine) AddFunc(pEngine, "Enter", FnEnter); AddFunc(pEngine, "DeathAnnounce", FnDeathAnnounce); AddFunc(pEngine, "SetSolidMask", FnSetSolidMask); + AddFunc(pEngine, "SetHalfVehicleSolidMask", FnSetHalfVehicleSolidMask); AddFunc(pEngine, "Exit", FnExit); AddFunc(pEngine, "Collect", FnCollect); AddFunc(pEngine, "DoNoCollectDelay", FnDoNoCollectDelay); diff --git a/src/object/C4Shape.cpp b/src/object/C4Shape.cpp index c31f2bfe1..2d46d317f 100644 --- a/src/object/C4Shape.cpp +++ b/src/object/C4Shape.cpp @@ -187,6 +187,11 @@ void C4Shape::GetVertexOutline(C4Rect &rRect) } +inline bool C4Shape::CheckTouchableMaterial(int32_t x, int32_t y, int32_t vtx_i, int32_t ydir, const C4DensityProvider &rDensityProvider) { + return rDensityProvider.GetDensity(x,y) >= ContactDensity && + ((ydir > 0 && (CNAT_CollideHalfVehicle & VtxCNAT[vtx_i])) || !IsMCHalfVehicle(GBackPix(x,y))); +} + // Adjust given position to one pixel before contact // at vertices matching CNAT request. bool C4Shape::Attach(int32_t &cx, int32_t &cy, BYTE cnat_pos) @@ -219,13 +224,13 @@ bool C4Shape::Attach(int32_t &cx, int32_t &cy, BYTE cnat_pos) { // get new vertex pos int32_t ax = testx + VtxX[i], ay = testy + VtxY[i]; - if (GBackDensity(ax, ay) >= ContactDensity) + if (CheckTouchableMaterial(ax, ay, i)) { found = false; break; } // can attach here? - if (GBackDensity(ax + xcd, ay + ycd) >= ContactDensity) + if (CheckTouchableMaterial(ax + xcd, ay + ycd, i, ycd)) { found = true; any_contact = true; @@ -348,14 +353,14 @@ bool C4Shape::CheckContact(int32_t cx, int32_t cy) for (int32_t cvtx=0; cvtx= ContactDensity) + if (CheckTouchableMaterial(cx+VtxX[cvtx],cy+VtxY[cvtx], cvtx)) return true; return false; } -bool C4Shape::ContactCheck(int32_t cx, int32_t cy, uint32_t *border_hack_contacts) +bool C4Shape::ContactCheck(int32_t cx, int32_t cy, uint32_t *border_hack_contacts, bool collide_halfvehic) { // Check all vertices at given object position. // Set ContactCNAT and ContactCount. @@ -377,25 +382,25 @@ bool C4Shape::ContactCheck(int32_t cx, int32_t cy, uint32_t *border_hack_contact int32_t y = cy+VtxY[cvtx]; VtxContactMat[cvtx]=GBackMat(x,y); - if (GBackDensity(x,y) >= ContactDensity) + if (CheckTouchableMaterial(x, y, cvtx, collide_halfvehic? 1:0)) { ContactCNAT |= VtxCNAT[cvtx]; VtxContactCNAT[cvtx]|=CNAT_Center; ContactCount++; // Vertex center contact, now check top,bottom,left,right - if (GBackDensity(x,y-1) >= ContactDensity) + if (CheckTouchableMaterial(x,y-1,cvtx)) VtxContactCNAT[cvtx]|=CNAT_Top; - if (GBackDensity(x,y+1) >= ContactDensity) + if (CheckTouchableMaterial(x,y+1,cvtx)) VtxContactCNAT[cvtx]|=CNAT_Bottom; - if (GBackDensity(x-1,y) >= ContactDensity) + if (CheckTouchableMaterial(x-1,y,cvtx)) VtxContactCNAT[cvtx]|=CNAT_Left; - if (GBackDensity(x+1,y) >= ContactDensity) + if (CheckTouchableMaterial(x+1,y,cvtx)) VtxContactCNAT[cvtx]|=CNAT_Right; } if (border_hack_contacts) { - if (x == 0 && GBackDensity(x-1, y) >= ContactDensity) *border_hack_contacts |= CNAT_Left; - else if (x == ::Landscape.Width && GBackDensity(x+1, y) >= ContactDensity) *border_hack_contacts |= CNAT_Right; + if (x == 0 && CheckTouchableMaterial(x-1, y, cvtx)) *border_hack_contacts |= CNAT_Left; + else if (x == ::Landscape.Width && CheckTouchableMaterial(x+1, y, cvtx)) *border_hack_contacts |= CNAT_Right; } } @@ -412,15 +417,15 @@ bool C4Shape::CheckScaleToWalk(int x, int y) if (VtxCNAT[i] & CNAT_Bottom) { // no ground under the feet? - if (GBackDensity(x + VtxX[i], y + VtxY[i] + 1) < ContactDensity) + if (CheckTouchableMaterial(x + VtxX[i], y + VtxY[i] + 1, i)) return false; } else { // can climb with hands? - if (GBackDensity(x + VtxX[i] - 1, y + VtxY[i]) >= ContactDensity) + if (CheckTouchableMaterial(x + VtxX[i] - 1, y + VtxY[i], i)) return false; - if (GBackDensity(x + VtxX[i] + 1, y + VtxY[i]) >= ContactDensity) + if (CheckTouchableMaterial(x + VtxX[i] + 1, y + VtxY[i], i)) return false; } } @@ -504,11 +509,11 @@ int32_t C4Shape::GetVertexContact(int32_t iVtx, DWORD dwCheckMask, int32_t tx, i // check all directions for solid mat if (~VtxCNAT[iVtx] & CNAT_NoCollision) { - if (dwCheckMask & CNAT_Center) if (rDensityProvider.GetDensity(tx, ty) >= ContactDensity) iContact |= CNAT_Center; - if (dwCheckMask & CNAT_Left) if (rDensityProvider.GetDensity(tx-1, ty) >= ContactDensity) iContact |= CNAT_Left; - if (dwCheckMask & CNAT_Right) if (rDensityProvider.GetDensity(tx+1, ty) >= ContactDensity) iContact |= CNAT_Right; - if (dwCheckMask & CNAT_Top) if (rDensityProvider.GetDensity(tx, ty-1) >= ContactDensity) iContact |= CNAT_Top; - if (dwCheckMask & CNAT_Bottom) if (rDensityProvider.GetDensity(tx, ty+1) >= ContactDensity) iContact |= CNAT_Bottom; + if (dwCheckMask & CNAT_Center) if (CheckTouchableMaterial(tx, ty , iVtx, 0, rDensityProvider)) iContact |= CNAT_Center; + if (dwCheckMask & CNAT_Left) if (CheckTouchableMaterial(tx-1, ty, iVtx, 0, rDensityProvider)) iContact |= CNAT_Left; + if (dwCheckMask & CNAT_Right) if (CheckTouchableMaterial(tx+1, ty, iVtx, 0, rDensityProvider)) iContact |= CNAT_Right; + if (dwCheckMask & CNAT_Top) if (CheckTouchableMaterial(tx, ty-1, iVtx, 0, rDensityProvider)) iContact |= CNAT_Top; + if (dwCheckMask & CNAT_Bottom) if (CheckTouchableMaterial(tx, ty+1, iVtx, 1, rDensityProvider)) iContact |= CNAT_Bottom; } // return resulting bitmask return iContact; @@ -539,6 +544,7 @@ void C4Shape::CompileFunc(StdCompiler *pComp, const C4Shape *default_shape) { "CNAT_Center", CNAT_Center }, { "CNAT_MultiAttach", CNAT_MultiAttach }, { "CNAT_NoCollision", CNAT_NoCollision }, + { "CNAT_CollideHalfVehicle", CNAT_CollideHalfVehicle }, { NULL, 0 } }; diff --git a/src/object/C4Shape.h b/src/object/C4Shape.h index 131baa907..d89a4e796 100644 --- a/src/object/C4Shape.h +++ b/src/object/C4Shape.h @@ -68,7 +68,7 @@ public: int32_t GetY() const { return y; } bool AddVertex(int32_t iX, int32_t iY); bool CheckContact(int32_t cx, int32_t cy); - bool ContactCheck(int32_t cx, int32_t cy, uint32_t *border_hack_contacts=0); + bool ContactCheck(int32_t cx, int32_t cy, uint32_t *border_hack_contacts=0, bool collide_halfvehic=false); bool Attach(int32_t &cx, int32_t &cy, BYTE cnat_pos); bool LineConnect(int32_t tx, int32_t ty, int32_t cvtx, int32_t ld, int32_t oldx, int32_t oldy); bool InsertVertex(int32_t iPos, int32_t tx, int32_t ty); @@ -80,6 +80,8 @@ public: bool CheckScaleToWalk(int x, int y); void CreateOwnOriginalCopy(C4Shape &rFrom); // create copy of all vertex members in back area of own buffers void CompileFunc(StdCompiler *pComp, const C4Shape *default_shape); +private: + bool CheckTouchableMaterial(int32_t x, int32_t y, int32_t vtx_i, int32_t y_dir = 0, const C4DensityProvider &rDensityProvider = DefaultDensityProvider); }; #endif // INC_C4Shape