2009-05-08 13:28:41 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2013-12-17 20:01:09 +00:00
|
|
|
* Copyright (c) 1998-2000, Matthes Bender
|
|
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
|
|
|
|
* Copyright (c) 2009-2013, The OpenClonk Team and contributors
|
2009-05-08 13:28:41 +00:00
|
|
|
*
|
2013-12-17 20:01:09 +00:00
|
|
|
* Distributed under the terms of the ISC license; see accompanying file
|
|
|
|
* "COPYING" for details.
|
2009-05-08 13:28:41 +00:00
|
|
|
*
|
2013-12-17 20:01:09 +00:00
|
|
|
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
|
|
|
|
* See accompanying file "TRADEMARK" for details.
|
2009-05-08 13:28:41 +00:00
|
|
|
*
|
2013-12-17 20:01:09 +00:00
|
|
|
* To redistribute this file separately, substitute the full license texts
|
|
|
|
* for the above references.
|
2009-05-08 13:28:41 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Special regions to extend the pathfinder */
|
|
|
|
|
|
|
|
#include <C4Include.h>
|
|
|
|
#include <C4TransferZone.h>
|
|
|
|
|
|
|
|
#include <C4FacetEx.h>
|
2009-06-12 18:52:21 +00:00
|
|
|
#include <C4Landscape.h>
|
2009-06-15 21:47:26 +00:00
|
|
|
#include <C4GameObjects.h>
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4TransferZone::C4TransferZone()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2015-12-29 00:45:37 +00:00
|
|
|
Object = NULL;
|
|
|
|
X = Y = Wdt = Hgt = 0;
|
|
|
|
Next = NULL;
|
|
|
|
Used = false;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4TransferZone::~C4TransferZone()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4TransferZones::C4TransferZones()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
Default();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4TransferZones::~C4TransferZones()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
Clear();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4TransferZones::Default()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
First=NULL;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4TransferZones::Clear()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
C4TransferZone *pZone,*pNext;
|
|
|
|
for (pZone=First; pZone; pZone=pNext) { pNext=pZone->Next; delete pZone; }
|
|
|
|
First=NULL;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4TransferZones::ClearPointers(C4Object *pObj)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Clear object pointers
|
|
|
|
for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
|
|
|
|
if (pZone->Object==pObj)
|
|
|
|
pZone->Object=NULL;
|
|
|
|
// Remove cleared zones immediately
|
|
|
|
RemoveNullZones();
|
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 C4TransferZones::Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, C4Object *pObj)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
C4TransferZone *pZone;
|
|
|
|
// Empty zone: clear existing object zones
|
2009-08-15 18:50:32 +00:00
|
|
|
if (!iWdt || !iHgt) { ClearPointers(pObj); return true; }
|
2009-05-08 13:28:41 +00:00
|
|
|
// Update existing zone
|
2010-01-25 04:00:59 +00:00
|
|
|
if ((pZone=Find(pObj)))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
pZone->X=iX; pZone->Y=iY;
|
|
|
|
pZone->Wdt=iWdt; pZone->Hgt=iHgt;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Allocate and add new zone
|
|
|
|
else
|
|
|
|
Add(iX,iY,iWdt,iHgt,pObj);
|
|
|
|
// Success
|
2009-08-15 18:50:32 +00:00
|
|
|
return 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 C4TransferZones::Add(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, C4Object *pObj)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
C4TransferZone *pZone;
|
|
|
|
// Allocate and add new zone
|
|
|
|
pZone = new C4TransferZone;
|
|
|
|
pZone->X=iX; pZone->Y=iY;
|
|
|
|
pZone->Wdt=iWdt; pZone->Hgt=iHgt;
|
|
|
|
pZone->Object=pObj;
|
|
|
|
pZone->Next=First;
|
|
|
|
First=pZone;
|
|
|
|
// Success
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4TransferZones::Synchronize()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
Clear();
|
2013-12-17 16:16:11 +00:00
|
|
|
::Objects.OnSynchronized();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4TransferZone* C4TransferZones::Find(int32_t iX, int32_t iY)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
|
|
|
|
if (Inside<int32_t>(iX-pZone->X,0,pZone->Wdt-1))
|
|
|
|
if (Inside<int32_t>(iY-pZone->Y,0,pZone->Hgt-1))
|
|
|
|
return pZone;
|
|
|
|
return NULL;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4TransferZones::Draw(C4TargetFacet &cgo)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
|
|
|
|
pZone->Draw(cgo);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
void C4TransferZone::Draw(C4TargetFacet &cgo, bool fHighlight)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
if (Used) fHighlight=true;
|
2011-10-03 14:30:18 +00:00
|
|
|
pDraw->DrawFrameDw(cgo.Surface,
|
2010-03-28 18:58:01 +00:00
|
|
|
int(cgo.X+X-cgo.TargetX),int(cgo.Y+Y-cgo.TargetY),
|
|
|
|
int(cgo.X+X-cgo.TargetX+Wdt-1),int(cgo.Y+Y-cgo.TargetY+Hgt-1),
|
2010-06-28 23:02:16 +00:00
|
|
|
fHighlight ? C4RGB(0, 0xca, 0) : C4RGB(0xca, 0, 0));
|
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 C4TransferZone::At(int32_t iX, int32_t iY)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
return (Inside<int32_t>(iX-X,0,Wdt-1) && Inside<int32_t>(iY-Y,0,Hgt-1));
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
int32_t C4TransferZones::RemoveNullZones()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
int32_t iResult=0;
|
|
|
|
C4TransferZone *pZone,*pNext,*pPrev=NULL;
|
|
|
|
for (pZone=First; pZone; pZone=pNext)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
pNext=pZone->Next;
|
|
|
|
if (!pZone->Object)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
delete pZone;
|
|
|
|
if (pPrev) pPrev->Next=pNext;
|
|
|
|
else First=pNext;
|
|
|
|
iResult++;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
else
|
|
|
|
pPrev=pZone;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
return iResult;
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
void AdjustMoveToTarget(int32_t &rX, int32_t &rY, bool fFreeMove, int32_t iShapeHgt);
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
bool C4TransferZone::GetEntryPoint(int32_t &rX, int32_t &rY, int32_t iToX, int32_t iToY)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Target inside zone: move outside horizontally
|
|
|
|
if (Inside<int32_t>(iToX-X,0,Wdt-1) && Inside<int32_t>(iToY-Y,0,Hgt-1))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-01-25 04:00:59 +00:00
|
|
|
if (iToX<X+Wdt/2) iToX=X-1;
|
|
|
|
else iToX=X+Wdt;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Get closest adjacent point
|
2015-02-12 22:05:55 +00:00
|
|
|
rX=Clamp<int32_t>(iToX,X-1,X+Wdt);
|
|
|
|
rY=Clamp<int32_t>(iToY,Y-1,Y+Hgt);
|
2009-05-08 13:28:41 +00:00
|
|
|
// Search around zone for free
|
|
|
|
int32_t iX1=rX,iY1=rY,iX2=rX,iY2=rY;
|
|
|
|
int32_t iXIncr1=0,iYIncr1=-1,iXIncr2=0,iYIncr2=+1;
|
|
|
|
int32_t cnt;
|
|
|
|
for (cnt=0; cnt<2*Wdt+2*Hgt; cnt++)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Found free
|
|
|
|
if (!GBackSolid(iX1,iY1)) { rX=iX1; rY=iY1; break; }
|
|
|
|
if (!GBackSolid(iX2,iY2)) { rX=iX2; rY=iY2; break; }
|
|
|
|
// Advance
|
|
|
|
iX1+=iXIncr1; iY1+=iYIncr1;
|
|
|
|
iX2+=iXIncr2; iY2+=iYIncr2;
|
|
|
|
// Corners
|
|
|
|
if (iY1<Y-1) { iY1=Y-1; iXIncr1=+1; iYIncr1=0; }
|
|
|
|
if (iX1>X+Wdt) { iX1=X+Wdt; iXIncr1=0; iYIncr1=+1; }
|
|
|
|
if (iY1>Y+Hgt) { iY1=Y+Hgt; iXIncr1=-1; iYIncr1=0; }
|
|
|
|
if (iX1<X-1) { iX1=X-1; iXIncr1=0; iYIncr1=-1; }
|
|
|
|
if (iY2<Y-1) { iY2=Y-1; iXIncr2=-1; iYIncr2=0; }
|
|
|
|
if (iX2>X+Wdt) { iX2=X+Wdt; iXIncr2=0; iYIncr2=-1; }
|
|
|
|
if (iY2>Y+Hgt) { iY2=Y+Hgt; iXIncr2=+1; iYIncr2=0; }
|
|
|
|
if (iX2<X-1) { iX2=X-1; iXIncr2=0; iYIncr2=+1; }
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// No free found
|
2009-08-15 18:50:32 +00:00
|
|
|
if (cnt>=2*Wdt+2*Hgt) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Vertical walk-to adjust (only if at the side of zone)
|
|
|
|
if (!Inside<int32_t>(rX-X,0,Wdt-1))
|
2009-08-15 18:50:32 +00:00
|
|
|
AdjustMoveToTarget(rX,rY,false,20);
|
2009-05-08 13:28:41 +00:00
|
|
|
// Success
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4TransferZones::ClearUsed()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
|
2009-08-15 18:50:32 +00:00
|
|
|
pZone->Used=false;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4TransferZone* C4TransferZones::Find(C4Object *pObj)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
|
|
|
|
if (pZone->Object==pObj)
|
|
|
|
return pZone;
|
|
|
|
return NULL;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|