OpenClonk
C4TransferZone.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Special regions to extend the pathfinder */
19 
20 #include "C4Include.h"
22 
23 #include "graphics/C4Draw.h"
24 #include "graphics/C4FacetEx.h"
25 #include "landscape/C4Landscape.h"
26 #include "lib/StdColors.h"
27 #include "object/C4GameObjects.h"
28 
30 {
31  Object = nullptr;
32  X = Y = Wdt = Hgt = 0;
33  Next = nullptr;
34  Used = false;
35 }
36 
38 
40 {
41  Default();
42 }
43 
45 {
46  Clear();
47 }
48 
50 {
51  First=nullptr;
52 }
53 
55 {
56  C4TransferZone *pZone,*pNext;
57  for (pZone=First; pZone; pZone=pNext) { pNext=pZone->Next; delete pZone; }
58  First=nullptr;
59 }
60 
62 {
63  // Clear object pointers
64  for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
65  if (pZone->Object==pObj)
66  pZone->Object=nullptr;
67  // Remove cleared zones immediately
69 }
70 
71 bool C4TransferZones::Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, C4Object *pObj)
72 {
73  C4TransferZone *pZone;
74  // Empty zone: clear existing object zones
75  if (!iWdt || !iHgt) { ClearPointers(pObj); return true; }
76  // Update existing zone
77  if ((pZone=Find(pObj)))
78  {
79  pZone->X=iX; pZone->Y=iY;
80  pZone->Wdt=iWdt; pZone->Hgt=iHgt;
81  }
82  // Allocate and add new zone
83  else
84  Add(iX,iY,iWdt,iHgt,pObj);
85  // Success
86  return true;
87 }
88 
89 bool C4TransferZones::Add(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, C4Object *pObj)
90 {
91  C4TransferZone *pZone;
92  // Allocate and add new zone
93  pZone = new C4TransferZone;
94  pZone->X=iX; pZone->Y=iY;
95  pZone->Wdt=iWdt; pZone->Hgt=iHgt;
96  pZone->Object=pObj;
97  pZone->Next=First;
98  First=pZone;
99  // Success
100  return true;
101 }
102 
104 {
105  Clear();
107 }
108 
109 C4TransferZone* C4TransferZones::Find(int32_t iX, int32_t iY)
110 {
111  for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
112  if (Inside<int32_t>(iX-pZone->X,0,pZone->Wdt-1))
113  if (Inside<int32_t>(iY-pZone->Y,0,pZone->Hgt-1))
114  return pZone;
115  return nullptr;
116 }
117 
119 {
120  for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
121  pZone->Draw(cgo);
122 }
123 
124 void C4TransferZone::Draw(C4TargetFacet &cgo, bool fHighlight)
125 {
126  if (Used) fHighlight=true;
128  int(cgo.X+X-cgo.TargetX),int(cgo.Y+Y-cgo.TargetY),
129  int(cgo.X+X-cgo.TargetX+Wdt-1),int(cgo.Y+Y-cgo.TargetY+Hgt-1),
130  fHighlight ? C4RGB(0, 0xca, 0) : C4RGB(0xca, 0, 0));
131 }
132 
133 bool C4TransferZone::At(int32_t iX, int32_t iY)
134 {
135  return (Inside<int32_t>(iX-X,0,Wdt-1) && Inside<int32_t>(iY-Y,0,Hgt-1));
136 }
137 
139 {
140  int32_t iResult=0;
141  C4TransferZone *pZone,*pNext,*pPrev=nullptr;
142  for (pZone=First; pZone; pZone=pNext)
143  {
144  pNext=pZone->Next;
145  if (!pZone->Object)
146  {
147  delete pZone;
148  if (pPrev) pPrev->Next=pNext;
149  else First=pNext;
150  iResult++;
151  }
152  else
153  pPrev=pZone;
154  }
155  return iResult;
156 }
157 
158 void AdjustMoveToTarget(int32_t &rX, int32_t &rY, bool fFreeMove, int32_t iShapeHgt);
159 
160 bool C4TransferZone::GetEntryPoint(int32_t &rX, int32_t &rY, int32_t iToX, int32_t iToY)
161 {
162  // Target inside zone: move outside horizontally
163  if (Inside<int32_t>(iToX-X,0,Wdt-1) && Inside<int32_t>(iToY-Y,0,Hgt-1))
164  {
165  if (iToX<X+Wdt/2) iToX=X-1;
166  else iToX=X+Wdt;
167  }
168  // Get closest adjacent point
169  rX=Clamp<int32_t>(iToX,X-1,X+Wdt);
170  rY=Clamp<int32_t>(iToY,Y-1,Y+Hgt);
171  // Search around zone for free
172  int32_t iX1=rX,iY1=rY,iX2=rX,iY2=rY;
173  int32_t iXIncr1=0,iYIncr1=-1,iXIncr2=0,iYIncr2=+1;
174  int32_t cnt;
175  for (cnt=0; cnt<2*Wdt+2*Hgt; cnt++)
176  {
177  // Found free
178  if (!GBackSolid(iX1,iY1)) { rX=iX1; rY=iY1; break; }
179  if (!GBackSolid(iX2,iY2)) { rX=iX2; rY=iY2; break; }
180  // Advance
181  iX1+=iXIncr1; iY1+=iYIncr1;
182  iX2+=iXIncr2; iY2+=iYIncr2;
183  // Corners
184  if (iY1<Y-1) { iY1=Y-1; iXIncr1=+1; iYIncr1=0; }
185  if (iX1>X+Wdt) { iX1=X+Wdt; iXIncr1=0; iYIncr1=+1; }
186  if (iY1>Y+Hgt) { iY1=Y+Hgt; iXIncr1=-1; iYIncr1=0; }
187  if (iX1<X-1) { iX1=X-1; iXIncr1=0; iYIncr1=-1; }
188  if (iY2<Y-1) { iY2=Y-1; iXIncr2=-1; iYIncr2=0; }
189  if (iX2>X+Wdt) { iX2=X+Wdt; iXIncr2=0; iYIncr2=-1; }
190  if (iY2>Y+Hgt) { iY2=Y+Hgt; iXIncr2=+1; iYIncr2=0; }
191  if (iX2<X-1) { iX2=X-1; iXIncr2=0; iYIncr2=+1; }
192  }
193  // No free found
194  if (cnt>=2*Wdt+2*Hgt) return false;
195  // Vertical walk-to adjust (only if at the side of zone)
196  if (!Inside<int32_t>(rX-X,0,Wdt-1))
197  AdjustMoveToTarget(rX,rY,false,20);
198  // Success
199  return true;
200 }
201 
203 {
204  for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
205  pZone->Used=false;
206 }
207 
209 {
210  for (C4TransferZone *pZone=First; pZone; pZone=pZone->Next)
211  if (pZone->Object==pObj)
212  return pZone;
213  return nullptr;
214 }
C4Draw * pDraw
Definition: C4Draw.cpp:42
C4GameObjects Objects
Definition: C4Globals.cpp:48
int iResult
Definition: C4GroupMain.cpp:40
bool GBackSolid(int32_t x, int32_t y)
Definition: C4Landscape.h:229
void AdjustMoveToTarget(int32_t &rX, int32_t &rY, bool fFreeMove, int32_t iShapeHgt)
Definition: C4Command.cpp:142
#define C4RGB(r, g, b)
Definition: StdColors.h:26
void DrawFrameDw(C4Surface *sfcDest, int x1, int y1, int x2, int y2, DWORD dwClr, float width=1.0f)
Definition: C4Draw.cpp:635
C4Surface * Surface
Definition: C4Facet.h:117
float Y
Definition: C4Facet.h:118
float X
Definition: C4Facet.h:118
float TargetY
Definition: C4Facet.h:165
float TargetX
Definition: C4Facet.h:165
bool GetEntryPoint(int32_t &rX, int32_t &rY, int32_t iToX, int32_t iToY)
C4TransferZone * Next
C4Object * Object
bool At(int32_t iX, int32_t iY)
void Draw(C4TargetFacet &cgo, bool fHighlight=false)
C4TransferZone * First
void ClearPointers(C4Object *pObj)
bool Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, C4Object *pObj)
void Draw(C4TargetFacet &cgo)
int32_t RemoveNullZones()
C4TransferZone * Find(C4Object *pObj)
bool Add(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, C4Object *pObj)