Pol  Revision:4b29d2b
realmlos.cpp
Go to the documentation of this file.
1 
5 #include <stdlib.h>
6 
7 #include "../../clib/compilerspecifics.h"
8 #include "../../clib/rawtypes.h"
9 #include "../../plib/mapcell.h"
10 #include "../baseobject.h"
11 #include "../item/item.h"
12 #include "../mobile/charactr.h"
13 #include "../uworld.h"
14 #include "realm.h"
15 
16 namespace Pol
17 {
18 namespace Realms
19 {
20 const int los_range = 20;
21 // const int z_los_range = 60; // unused as yet
22 
55 bool Realm::dynamic_item_blocks_los( unsigned short x, unsigned short y, short z, LosCache& cache )
56 {
57  for ( const auto& item : cache.dyn_items )
58  {
59  if ( ( item->x == x ) && ( item->y == y ) )
60  {
61  if ( item->z <= z && z < item->z + item->height )
62  {
63 #if ENABLE_POLTEST_OUTPUT
64  INFO_PRINT << "LOS blocked by " << item->description() << "\n";
65 #endif
66  return true;
67  }
68  }
69  }
70  return false;
71 }
72 
76 bool Realm::static_item_blocks_los( unsigned short x, unsigned short y, short z,
77  LosCache& cache ) const
78 {
79  if ( cache.last_x != x || cache.last_y != y )
80  {
81  cache.shapes.clear();
82  cache.last_x = x;
83  cache.last_y = y;
86  }
87  for ( const auto& shape : cache.shapes )
88  {
89  short ob_ht = shape.height;
90  short ob_z = shape.z;
91 #if ENABLE_POLTEST_OUTPUT
92  INFO_PRINT << "static type 0x" << fmt::hexu( itr->graphic ) << " (flags 0x"
93  << fmt::hexu( tile_flags( itr->graphic ) ) << ", ht=" << ob_ht << ")"
94  << " at z-coord " << (int)itr->z << "\n";
95 #endif
96 
97  if ( ob_ht == 0 ) // treat a 0-height object as a 1-height object at position z-1
98  {
99  --ob_z;
100  ++ob_ht;
101  }
102 
103  if ( ob_z <= z && z < ob_z + ob_ht )
104  {
105 #if ENABLE_POLTEST_OUTPUT
106  INFO_PRINT << "LOS blocked by static object\n";
107 #endif
108  return true;
109  }
110  }
111  return false;
112 }
113 
119 bool Realm::los_blocked( const Core::ULWObject& att, const Core::ULWObject& target,
120  unsigned short x, unsigned short y, short z, LosCache& cache ) const
121 {
122  // if the target inhabits the location, LOS can't be blocked:
123  if ( att.x == x && att.y == y && att.z <= z &&
124  z <= att.z + att.height ) // LE to allow for 0-height target
125  {
126  return false;
127  }
128  if ( target.x == x && target.y == y && target.z <= z &&
129  z <= target.z + target.height ) // LE to allow for 0-height target
130  {
131  return false;
132  }
133 
134  return dynamic_item_blocks_los( x, y, z, cache ) || static_item_blocks_los( x, y, z, cache );
135 }
136 
138 #define ABS( a ) ( ( ( a ) < 0 ) ? -( a ) : ( a ) )
139 
141 #define ZSGN( a ) ( ( ( a ) < 0 ) ? -1 : ( a ) > 0 ? 1 : 0 )
142 
146 bool Realm::has_los( const Core::ULWObject& att, const Core::ULWObject& tgt ) const
147 {
149  {
150  const Mobile::Character& chr = static_cast<const Mobile::Character&>( att );
151  if ( tgt.serial ) // remotes fail the realm check :(
152  {
153  bool remote;
154  Items::Item* remote_container = chr.search_remote_containers( tgt.serial, &remote );
155  if ( ( remote_container != nullptr ) && remote )
156  return true;
157  }
158  if ( att.realm != tgt.realm )
159  return false;
160  if ( chr.ignores_line_of_sight() )
161  return true;
162  }
163  else
164  {
165  if ( att.realm != tgt.realm )
166  return false;
167  }
168  // due to the nature of los check the same x,y coordinates get checked, cache the last used
169  // coords to reduce the expensive map/multi read per coordinate
170 
171 #if ( !defined( _MSC_VER ) || _MSC_VER >= 1900 )
172  static THREADLOCAL LosCache cache;
173 #else // older ms support only primitive types :(
174  LosCache cache;
175 #endif
176  cache.last_x = 0xFFFF;
177  cache.last_y = 0xFFFF;
178  cache.shapes.clear();
179  cache.dyn_items.clear();
180  // pre filter dynitems
182  std::min( att.x, tgt.x ), std::min( att.y, tgt.y ), std::max( att.x, tgt.x ),
183  std::max( att.y, tgt.y ), att.realm, [&]( Items::Item* item ) {
184  u32 flags = Core::tile_flags( item->graphic );
185  if ( flags & Plib::FLAG::BLOCKSIGHT )
186  {
187  if ( item->serial != tgt.serial && item->serial != att.serial )
188  cache.dyn_items.push_back( item );
189  }
190  } );
191 
192  short x1, y1, z1; // one of the endpoints
193  short x2, y2, z2; // the other endpoint
194  short xd, yd, zd;
195  short x, y, z;
196  short ax, ay, az;
197  short sx, sy, sz;
198  short dx, dy, dz;
199 
200  const u8 att_look_height( att.look_height() );
201  const u8 tgt_look_height( tgt.look_height() );
202 
203  if ( ( att.y < tgt.y ) || ( att.y == tgt.y && att.z < tgt.z ) )
204  {
205  x1 = att.x;
206  y1 = att.y;
207  z1 = att.z + att_look_height;
208  x2 = tgt.x;
209  y2 = tgt.y;
210  z2 = tgt.z + tgt_look_height;
211  }
212  else
213  {
214  x1 = tgt.x;
215  y1 = tgt.y;
216  z1 = tgt.z + tgt_look_height;
217  x2 = att.x;
218  y2 = att.y;
219  z2 = att.z + att_look_height;
220  }
221 
222  dx = x2 - x1;
223  dy = y2 - y1;
224  dz = z2 - z1;
225 
226  if ( abs( dx ) > los_range || abs( dy ) > los_range )
227  return false;
228 
229  if ( !dx && !dy )
230  {
231  if ( !dz )
232  return true;
233  if ( att.z <= tgt.z && tgt.z <= att.z + att.height )
234  {
235  return true;
236  }
237  if ( att.z <= tgt.z + tgt_look_height && tgt.z + tgt_look_height <= att.z + att.height )
238  {
239  return true;
240  }
241  }
242 
243  ax = ABS( dx ) << 1;
244  ay = ABS( dy ) << 1;
245  az = ABS( dz ) << 1;
246 
247  sx = ZSGN( dx );
248  sy = ZSGN( dy );
249  sz = ZSGN( dz );
250 
251  x = x1;
252  y = y1;
253  z = z1;
254 
255  if ( ax >= ay && ax >= az ) // x dominant
256  {
257  yd = ay - ( ax >> 1 );
258  zd = az - ( ax >> 1 );
259 
260  for ( ;; )
261  {
262  if ( los_blocked( att, tgt, x, y, z, cache ) )
263  return false;
264 
265  if ( x == x2 )
266  {
267  return true;
268  }
269 
270  if ( yd >= 0 )
271  {
272  y += sy;
273  yd -= ax;
274  }
275 
276  if ( zd >= 0 )
277  {
278  z += sz;
279  zd -= ax;
280  }
281 
282  x += sx;
283  yd += ay;
284  zd += az;
285  }
286  }
287  else if ( ay >= ax && ay >= az ) // y dominant
288  {
289  xd = ax - ( ay >> 1 );
290  zd = az - ( ay >> 1 );
291 
292  for ( ;; )
293  {
294  if ( los_blocked( att, tgt, x, y, z, cache ) )
295  return false;
296 
297  if ( y == y2 )
298  {
299  return true;
300  }
301 
302  if ( xd >= 0 )
303  {
304  x += sx;
305  xd -= ay;
306  }
307 
308  if ( zd >= 0 )
309  {
310  z += sz;
311  zd -= ay;
312  }
313 
314  y += sy;
315  xd += ax;
316  zd += az;
317  }
318  }
319  else // z dominant
320  {
321  xd = ax - ( az >> 1 );
322  yd = ay - ( az >> 1 );
323 
324  for ( ;; )
325  {
326  if ( los_blocked( att, tgt, x, y, z, cache ) )
327  return false;
328 
329  if ( z == z2 )
330  {
331  return true;
332  }
333 
334  if ( xd >= 0 )
335  {
336  x += sx;
337  xd -= az;
338  }
339 
340  if ( yd >= 0 )
341  {
342  y += sy;
343  yd -= az;
344  }
345 
346  z += sz;
347  xd += ax;
348  yd += ay;
349  }
350  }
351 }
352 }
353 }
354 
355 
356 /****************************************************************************/
357 
358 /* Original 3D bresenham algorithm from comp.unix.sources
359 
360 //
361 // line3d was dervied from DigitalLine.c published as "Digital Line Drawing"
362 // by Paul Heckbert from "Graphics Gems", Academic Press, 1990
363 //
364 // 3D modifications by Bob Pendleton. The original source code was in the public
365 // domain, the author of the 3D version places his modifications in the
366 // public domain as well.
367 //
368 // line3d uses Bresenham's algorithm to generate the 3 dimensional points on a
369 // line from (x1, y1, z1) to (x2, y2, z2)
370 //
371 //
372 
373 // find maximum of a and b
374 #define MAX(a,b) (((a)>(b))?(a):(b))
375 
376 // absolute value of a
377 #define ABS(a) (((a)<0) ? -(a) : (a))
378 
379 // take sign of a, either -1, 0, or 1
380 #define ZSGN(a) (((a)<0) ? -1 : (a)>0 ? 1 : 0)
381 
382 point3d(x, y, z)
383  int x, y, z;
384 {
385 
386  //output the point as you see fit
387 
388 }
389 
390 line3d(x1, y1, x2, y2, z1, z2)
391  int x1, y1, x2, y2, z1, z2;
392 {
393  int xd, yd, zd;
394  int x, y, z;
395  int ax, ay, az;
396  int sx, sy, sz;
397  int dx, dy, dz;
398 
399  dx = x2 - x1;
400  dy = y2 - y1;
401  dz = z2 - z1;
402 
403  ax = ABS(dx) << 1;
404  ay = ABS(dy) << 1;
405  az = ABS(dz) << 1;
406 
407  sx = ZSGN(dx);
408  sy = ZSGN(dy);
409  sz = ZSGN(dz);
410 
411  x = x1;
412  y = y1;
413  z = z1;
414 
415  if (ax >= MAX(ay, az)) // x dominant
416  {
417  yd = ay - (ax >> 1);
418  zd = az - (ax >> 1);
419  for (;;)
420  {
421  point3d(x, y, z);
422  if (x == x2)
423  {
424  return;
425  }
426 
427  if (yd >= 0)
428  {
429  y += sy;
430  yd -= ax;
431  }
432 
433  if (zd >= 0)
434  {
435  z += sz;
436  zd -= ax;
437  }
438 
439  x += sx;
440  yd += ay;
441  zd += az;
442  }
443  }
444  else if (ay >= MAX(ax, az)) //y dominant
445  {
446  xd = ax - (ay >> 1);
447  zd = az - (ay >> 1);
448  for (;;)
449  {
450  point3d(x, y, z);
451  if (y == y2)
452  {
453  return;
454  }
455 
456  if (xd >= 0)
457  {
458  x += sx;
459  xd -= ay;
460  }
461 
462  if (zd >= 0)
463  {
464  z += sz;
465  zd -= ay;
466  }
467 
468  y += sy;
469  xd += ax;
470  zd += az;
471  }
472  }
473  else if (az >= MAX(ax, ay)) // z dominant
474  {
475  xd = ax - (az >> 1);
476  yd = ay - (az >> 1);
477  for (;;)
478  {
479  point3d(x, y, z);
480  if (z == z2)
481  {
482  return;
483  }
484 
485  if (xd >= 0)
486  {
487  x += sx;
488  xd -= az;
489  }
490 
491  if (yd >= 0)
492  {
493  y += sy;
494  yd -= az;
495  }
496 
497  z += sz;
498  xd += ax;
499  yd += ay;
500  }
501  }
502 }
503 
504 */
unsigned char u8
Definition: rawtypes.h:25
unsigned int tile_flags(unsigned short tilenum)
Definition: polfile2.cpp:49
bool los_blocked(const Core::ULWObject &att, const Core::ULWObject &target, unsigned short x, unsigned short y, short z, LosCache &cache) const
Definition: realmlos.cpp:119
static bool dynamic_item_blocks_los(unsigned short x, unsigned short y, short z, LosCache &cache)
Definition: realmlos.cpp:55
void getmapshapes(Plib::MapShapeList &shapes, unsigned short x, unsigned short y, unsigned int anyflags) const
Definition: realmfunc.cpp:780
unsigned short last_y
Definition: realm.h:145
#define ZSGN(a)
take sign of a, either -1, 0, or 1
Definition: realmlos.cpp:141
const int los_range
Definition: realmlos.cpp:20
bool has_los(const Core::ULWObject &att, const Core::ULWObject &tgt) const
Definition: realmlos.cpp:146
std::vector< Items::Item * > dyn_items
Definition: realm.h:147
void readmultis(Plib::MapShapeList &vec, unsigned short x, unsigned short y, unsigned int flags) const
Definition: realmfunc.cpp:623
Realms::Realm * realm
Definition: baseobject.h:56
Items::Item * search_remote_containers(u32 find_serial, bool *isRemoteContainer) const
Definition: charactr.cpp:3986
bool isa(UOBJ_CLASS uobj_class) const
Definition: baseobject.h:99
bool ignores_line_of_sight() const
Definition: charactr.h:1028
#define ABS(a)
absolute value of a
Definition: realmlos.cpp:138
unsigned short last_x
Definition: realm.h:143
bool static_item_blocks_los(unsigned short x, unsigned short y, short z, LosCache &cache) const
Definition: realmlos.cpp:76
#define INFO_PRINT
Definition: logfacility.h:223
#define THREADLOCAL
Definition: berror.cpp:12
Plib::MapShapeList shapes
Definition: realm.h:146
static void InBox(u16 x1, u16 y1, u16 x2, u16 y2, const Realms::Realm *realm, F &&f)
Definition: uworld.h:252