region_map_v1.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. #include "region_map_v1.h"
  2. #include "../../common/Log.h"
  3. #include "../client.h"
  4. #include "../Spawn.h"
  5. #include "../LuaInterface.h"
  6. #undef snprintf
  7. #include <boost/filesystem.hpp>
  8. extern LuaInterface* lua_interface;
  9. RegionMapV1::RegionMapV1() {
  10. mVersion = 1;
  11. }
  12. RegionMapV1::~RegionMapV1() {
  13. map<Region_Node*, ZBSP_Node*>::const_iterator itr;
  14. int region_num = 0;
  15. for (itr = Regions.begin(); itr != Regions.end();)
  16. {
  17. Region_Node* node = itr->first;
  18. ZBSP_Node* bsp_node = itr->second;
  19. map<Region_Node*, ZBSP_Node*>::const_iterator deleteItr = itr;
  20. itr++;
  21. Regions.erase(deleteItr);
  22. safe_delete(node);
  23. safe_delete_array(bsp_node);
  24. }
  25. Regions.clear();
  26. }
  27. WaterRegionType RegionMapV1::ReturnRegionType(const glm::vec3& location, int32 gridid) const {
  28. return BSPReturnRegionType(1, glm::vec3(location.x, location.y, location.z), gridid);
  29. }
  30. bool RegionMapV1::InWater(const glm::vec3& location, int32 gridid) const {
  31. return ReturnRegionType(location, gridid) == RegionTypeWater;
  32. }
  33. bool RegionMapV1::InLava(const glm::vec3& location, int32 gridid) const {
  34. return ReturnRegionType(location, gridid) == RegionTypeLava;
  35. }
  36. bool RegionMapV1::InLiquid(const glm::vec3& location) const {
  37. return InWater(location) || InLava(location);
  38. }
  39. bool RegionMapV1::InPvP(const glm::vec3& location) const {
  40. return ReturnRegionType(location) == RegionTypePVP;
  41. }
  42. bool RegionMapV1::InZoneLine(const glm::vec3& location) const {
  43. return ReturnRegionType(location) == RegionTypeZoneLine;
  44. }
  45. std::string RegionMapV1::TestFile(std::string testFile)
  46. {
  47. std::string tmpStr(testFile);
  48. std::size_t pos = tmpStr.find(".");
  49. if ( pos != testFile.npos )
  50. tmpStr = testFile.substr (0, pos);
  51. string tmpScript("RegionScripts/");
  52. tmpScript.append(mZoneNameLower);
  53. tmpScript.append("/" + tmpStr + ".lua");
  54. printf("File to test : %s\n",tmpScript.c_str());
  55. std::ifstream f(tmpScript.c_str());
  56. return f.good() ? tmpScript : string("");
  57. }
  58. bool RegionMapV1::Load(FILE* fp, std::string inZoneNameLwr, int32 version) {
  59. mZoneNameLower = string(inZoneNameLwr.c_str());
  60. uint32 region_size;
  61. if (fread(&region_size, sizeof(uint32), 1, fp) != 1) {
  62. return false;
  63. }
  64. LogWrite(REGION__DEBUG, 0, "RegionMap", "region count = %u", region_size);
  65. for (int i = 0; i < region_size; i++)
  66. {
  67. uint32 region_num;
  68. if (fread(&region_num, sizeof(uint32), 1, fp) != 1) {
  69. return false;
  70. }
  71. uint32 region_type;
  72. if (fread(&region_type, sizeof(uint32), 1, fp) != 1) {
  73. return false;
  74. }
  75. float x, y, z, dist;
  76. if (fread(&x, sizeof(float), 1, fp) != 1) {
  77. return false;
  78. }
  79. if (fread(&y, sizeof(float), 1, fp) != 1) {
  80. return false;
  81. }
  82. if (fread(&z, sizeof(float), 1, fp) != 1) {
  83. return false;
  84. }
  85. if (fread(&dist, sizeof(float), 1, fp) != 1) {
  86. return false;
  87. }
  88. int8 strSize;
  89. char envName[256] = {""};
  90. char regionName[256] = {""};
  91. uint32 grid_id = 0;
  92. if ( version > 1 )
  93. {
  94. fread(&strSize, sizeof(int8), 1, fp);
  95. LogWrite(REGION__DEBUG, 7, "Region", "Region environment strSize = %u", strSize);
  96. if(strSize)
  97. {
  98. size_t len = fread(&envName, sizeof(char), strSize, fp);
  99. envName[len] = '\0';
  100. }
  101. LogWrite(REGION__DEBUG, 7, "Region", "Region environment file name = %s", envName);
  102. fread(&strSize, sizeof(int8), 1, fp);
  103. LogWrite(REGION__DEBUG, 7, "Region", "Region name strSize = %u", strSize);
  104. if(strSize)
  105. {
  106. size_t len = fread(&regionName, sizeof(char), strSize, fp);
  107. regionName[len] = '\0';
  108. }
  109. LogWrite(REGION__DEBUG, 7, "Region", "Region name file name = %s", regionName);
  110. if (fread(&grid_id, sizeof(uint32), 1, fp) != 1) {
  111. return false;
  112. }
  113. }
  114. int32 bsp_tree_size;
  115. if (fread(&bsp_tree_size, sizeof(int32), 1, fp) != 1) {
  116. return false;
  117. }
  118. LogWrite(REGION__DEBUG, 7, "Region", "region x,y,z,dist = %f, %f, %f, %f, region bsp tree size: %i\n", x, y, z, dist, bsp_tree_size);
  119. ZBSP_Node* BSP_Root = new ZBSP_Node[bsp_tree_size];
  120. if (fread(BSP_Root, sizeof(ZBSP_Node), bsp_tree_size, fp) != bsp_tree_size) {
  121. LogWrite(REGION__ERROR, 0, "RegionMap", "Failed to load region.");
  122. return false;
  123. }
  124. Region_Node* tmpNode = new Region_Node;
  125. tmpNode->x = x;
  126. tmpNode->y = y;
  127. tmpNode->z = z;
  128. tmpNode->dist = dist;
  129. tmpNode->region_type = region_type;
  130. tmpNode->regionName = string(regionName);
  131. tmpNode->regionEnvFileName = string(envName);
  132. tmpNode->grid_id = grid_id;
  133. tmpNode->regionScriptName = string("");
  134. tmpNode->regionScriptName = TestFile(regionName);
  135. if ( tmpNode->regionScriptName.size() < 1 )
  136. {
  137. tmpNode->regionScriptName = TestFile(envName);
  138. }
  139. if ( tmpNode->regionScriptName.size() < 1 )
  140. {
  141. tmpNode->regionScriptName = TestFile("default");
  142. }
  143. tmpNode->vert_count = bsp_tree_size;
  144. Regions.insert(make_pair(tmpNode, BSP_Root));
  145. }
  146. fclose(fp);
  147. LogWrite(REGION__DEBUG, 0, "RegionMap", "completed load!");
  148. return true;
  149. }
  150. void RegionMapV1::IdentifyRegionsInGrid(Client *client, const glm::vec3 &location) const
  151. {
  152. map<Region_Node*, ZBSP_Node*>::const_iterator itr;
  153. int region_num = 0;
  154. int32 grid = 0;
  155. if (client->GetPlayer()->GetMap() != nullptr && client->GetPlayer()->GetMap()->IsMapLoaded())
  156. {
  157. grid = client->GetPlayer()->GetMap()->GetGrid()->GetGridIDByLocation(location.x, location.y, location.z);
  158. }
  159. else
  160. client->SimpleMessage(CHANNEL_COLOR_RED, "No map to establish grid id, using grid id 0 (attempt match all).");
  161. client->Message(2, "Region check against location %f / %f / %f. Grid to try: %u, player grid is %u", location.x, location.y, location.z, grid, client->GetPlayer()->appearance.pos.grid_id);
  162. for (itr = Regions.begin(); itr != Regions.end(); itr++)
  163. {
  164. Region_Node *node = itr->first;
  165. ZBSP_Node *BSP_Root = itr->second;
  166. if (grid == 0 || node->grid_id == grid)
  167. {
  168. float x1 = node->x - location.x;
  169. float y1 = node->y - location.y;
  170. float z1 = node->z - location.z;
  171. float dist = sqrt(x1 *x1 + y1 *y1 + z1 *z1);
  172. glm::vec3 testLoc(location.x, location.y, location.z);
  173. if (dist <= node->dist)
  174. {
  175. WaterRegionType regionType = RegionTypeUntagged;
  176. if (node->region_type == ClassWaterRegion)
  177. regionType = BSPReturnRegionWaterRegion(node, BSP_Root, 1, testLoc, dist);
  178. else
  179. regionType = BSPReturnRegionTypeNode(node, BSP_Root, 1, testLoc, dist);
  180. if (regionType != RegionTypeNormal)
  181. {
  182. client->Message(CHANNEL_COLOR_YELLOW, "[DETECTED IN REGION %i] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", regionType, region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  183. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  184. }
  185. else
  186. {
  187. client->Message(CHANNEL_COLOR_RED, "[IN DIST RANGE] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  188. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  189. }
  190. }
  191. else
  192. client->Message(CHANNEL_COLOR_RED, "[OUT OF RANGE] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  193. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  194. }
  195. else
  196. client->Message(CHANNEL_COLOR_RED, "[OUT OF GRID] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  197. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  198. region_num++;
  199. }
  200. }
  201. void RegionMapV1::MapRegionsNearSpawn(Spawn *spawn, Client *client) const
  202. {
  203. map<Region_Node*, ZBSP_Node*>::const_iterator itr;
  204. int region_num = 0;
  205. spawn->RegionMutex.writelock();
  206. glm::vec3 testLoc(spawn->GetX(), spawn->GetY(), spawn->GetZ());
  207. for (itr = Regions.begin(); itr != Regions.end(); itr++)
  208. {
  209. Region_Node *node = itr->first;
  210. ZBSP_Node *BSP_Root = itr->second;
  211. if (node->regionScriptName.size() < 1) // only track ones that are used with LUA scripting
  212. continue;
  213. float x1 = node->x - testLoc.x;
  214. float y1 = node->y - testLoc.y;
  215. float z1 = node->z - testLoc.z;
  216. float dist = sqrt(x1 *x1 + y1 *y1 + z1 *z1);
  217. if (dist <= node->dist)
  218. {
  219. WaterRegionType regionType = RegionTypeUntagged;
  220. if (node->region_type == ClassWaterRegion)
  221. regionType = BSPReturnRegionWaterRegion(node, BSP_Root, 1, testLoc, dist);
  222. else
  223. regionType = BSPReturnRegionTypeNode(node, BSP_Root, 1, testLoc, dist);
  224. if (regionType != RegionTypeNormal)
  225. {
  226. if (!spawn->InRegion(node, BSP_Root))
  227. {
  228. spawn->DeleteRegion(node, BSP_Root);
  229. std::map<Region_Node*, ZBSP_Node*> newMap;
  230. newMap.insert(make_pair(node, BSP_Root));
  231. Region_Status status;
  232. status.inRegion = true;
  233. status.regionType = regionType;
  234. int32 returnValue = 0;
  235. lua_interface->RunRegionScript(node->regionScriptName, "EnterRegion", spawn->GetZone(), spawn, regionType, &returnValue);
  236. status.timerTic = returnValue;
  237. status.lastTimerTic = returnValue ? Timer::GetCurrentTime2() : 0;
  238. spawn->Regions.insert(make_pair(newMap, status));
  239. if (client)
  240. client->Message(CHANNEL_COLOR_YELLOW, "[ENTER REGION %i %u] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", regionType, returnValue, region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  241. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  242. }
  243. }
  244. else
  245. {
  246. if (spawn->InRegion(node, BSP_Root))
  247. {
  248. if (client)
  249. client->Message(CHANNEL_COLOR_RED, "[LEAVE REGION] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  250. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  251. WaterRegionType whatWasRegionType = (WaterRegionType) spawn->GetRegionType(node, BSP_Root);
  252. lua_interface->RunRegionScript(node->regionScriptName, "LeaveRegion", spawn->GetZone(), spawn, whatWasRegionType);
  253. }
  254. spawn->DeleteRegion(node, BSP_Root);
  255. std::map<Region_Node*, ZBSP_Node*> newMap;
  256. newMap.insert(make_pair(node, BSP_Root));
  257. Region_Status status;
  258. status.inRegion = false;
  259. status.timerTic = 0;
  260. status.lastTimerTic = 0;
  261. status.regionType = RegionTypeNormal;
  262. spawn->Regions.insert(make_pair(newMap, status));
  263. if (client)
  264. client->Message(CHANNEL_COLOR_RED, "[NEAR REGION] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  265. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  266. }
  267. }
  268. region_num++;
  269. }
  270. spawn->RegionMutex.releasewritelock();
  271. }
  272. void RegionMapV1::UpdateRegionsNearSpawn(Spawn *spawn, Client *client) const
  273. {
  274. map<map<Region_Node*, ZBSP_Node*>, Region_Status>::iterator testitr;
  275. int region_num = 0;
  276. spawn->RegionMutex.writelock();
  277. glm::vec3 testLoc(spawn->GetX(), spawn->GetY(), spawn->GetZ());
  278. map<Region_Node*, ZBSP_Node*> deleteNodes;
  279. for (testitr = spawn->Regions.begin(); testitr != spawn->Regions.end(); testitr++)
  280. {
  281. map<Region_Node*, ZBSP_Node*>::const_iterator actualItr = testitr->first.begin();
  282. Region_Node *node = actualItr->first;
  283. ZBSP_Node *BSP_Root = actualItr->second;
  284. float x1 = node->x - testLoc.x;
  285. float y1 = node->y - testLoc.y;
  286. float z1 = node->z - testLoc.z;
  287. float dist = sqrt(x1 *x1 + y1 *y1 + z1 *z1);
  288. if (dist <= node->dist)
  289. {
  290. WaterRegionType regionType = RegionTypeUntagged;
  291. if (node->region_type == ClassWaterRegion)
  292. regionType = BSPReturnRegionWaterRegion(node, BSP_Root, 1, testLoc, dist);
  293. else
  294. regionType = BSPReturnRegionTypeNode(node, BSP_Root, 1, testLoc, dist);
  295. if (regionType != RegionTypeNormal)
  296. {
  297. if (!testitr->second.inRegion)
  298. {
  299. testitr->second.inRegion = true;
  300. int32 returnValue = 0;
  301. lua_interface->RunRegionScript(node->regionScriptName, "EnterRegion", spawn->GetZone(), spawn, regionType, &returnValue);
  302. if (client)
  303. client->Message(CHANNEL_COLOR_YELLOW, "[ENTER RANGE %i %u] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", regionType, returnValue, region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  304. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  305. testitr->second.timerTic = returnValue;
  306. testitr->second.lastTimerTic = returnValue ? Timer::GetCurrentTime2() : 0;
  307. }
  308. }
  309. else
  310. {
  311. if (testitr->second.inRegion)
  312. {
  313. testitr->second.inRegion = false;
  314. testitr->second.timerTic = 0;
  315. testitr->second.lastTimerTic = 0;
  316. if (client)
  317. client->Message(CHANNEL_COLOR_RED, "[LEAVE RANGE] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  318. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  319. WaterRegionType whatWasRegionType = (WaterRegionType) spawn->GetRegionType(node, BSP_Root);
  320. lua_interface->RunRegionScript(node->regionScriptName, "LeaveRegion", spawn->GetZone(), spawn, whatWasRegionType);
  321. }
  322. }
  323. }
  324. else
  325. {
  326. if (client)
  327. client->Message(CHANNEL_COLOR_RED, "[LEAVE RANGE - OOR] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  328. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  329. deleteNodes.insert(make_pair(node, BSP_Root));
  330. }
  331. region_num++;
  332. }
  333. map<Region_Node*, ZBSP_Node*>::const_iterator deleteItr;
  334. for (deleteItr = deleteNodes.begin(); deleteItr != deleteNodes.end(); deleteItr++)
  335. {
  336. Region_Node *tmpNode = deleteItr->first;
  337. ZBSP_Node *bspNode = deleteItr->second;
  338. spawn->DeleteRegion(tmpNode, bspNode);
  339. }
  340. spawn->RegionMutex.releasewritelock();
  341. }
  342. void RegionMapV1::TicRegionsNearSpawn(Spawn *spawn, Client *client) const
  343. {
  344. map<map<Region_Node*, ZBSP_Node*>, Region_Status>::iterator testitr;
  345. int region_num = 0;
  346. spawn->RegionMutex.writelock();
  347. for (testitr = spawn->Regions.begin(); testitr != spawn->Regions.end(); testitr++)
  348. {
  349. map<Region_Node*, ZBSP_Node*>::const_iterator actualItr = testitr->first.begin();
  350. Region_Node *node = actualItr->first;
  351. ZBSP_Node *BSP_Root = actualItr->second;
  352. if (testitr->second.timerTic && testitr->second.inRegion && Timer::GetCurrentTime2() >= (testitr->second.lastTimerTic + testitr->second.timerTic))
  353. {
  354. testitr->second.lastTimerTic = Timer::GetCurrentTime2();
  355. if (client)
  356. client->Message(CHANNEL_COLOR_RED, "[TICK] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  357. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  358. WaterRegionType whatWasRegionType = RegionTypeNormal; // default will be 0
  359. if (BSP_Root->special == SPECIAL_REGION_LAVA_OR_DEATH)
  360. whatWasRegionType = RegionTypeLava; // 2
  361. else if (BSP_Root->special == SPECIAL_REGION_WATER)
  362. whatWasRegionType = RegionTypeWater; // 1
  363. int32 returnValue = 0;
  364. lua_interface->RunRegionScript(node->regionScriptName, "Tick", spawn->GetZone(), spawn, whatWasRegionType, &returnValue);
  365. if (returnValue == 1)
  366. {
  367. testitr->second.lastTimerTic = 0;
  368. testitr->second.timerTic = 0;
  369. }
  370. }
  371. region_num++;
  372. }
  373. spawn->RegionMutex.releasewritelock();
  374. }
  375. WaterRegionType RegionMapV1::BSPReturnRegionType(int32 node_number, const glm::vec3& location, int32 gridid) const {
  376. map<Region_Node*, ZBSP_Node*>::const_iterator itr;
  377. int region_num = 0;
  378. for (itr = Regions.begin(); itr != Regions.end(); itr++)
  379. {
  380. Region_Node* node = itr->first;
  381. // did not match grid id of current region, skip
  382. //if ( gridid > 0 && gridid != node->grid_id)
  383. // continue;
  384. ZBSP_Node* BSP_Root = itr->second;
  385. float x1 = node->x - location.x;
  386. float y1 = node->y - location.y;
  387. float z1 = node->z - location.z;
  388. float dist = sqrt(x1 * x1 + y1 * y1 + z1 * z1);
  389. #ifdef REGIONDEBUG
  390. printf("Region %i (%i) dist %f / node dist %f. NodeXYZ: %f %f %f, XYZ: %f %f %f.\n", region_num, node->region_type, dist, node->dist, node->x, node->y, node->z, location.x, location.y, location.z);
  391. #endif
  392. if (dist <= node->dist)
  393. {
  394. ZBSP_Node* BSP_Root = itr->second;
  395. WaterRegionType regionType = RegionTypeUntagged;
  396. if (node->region_type == ClassWaterRegion)
  397. regionType = BSPReturnRegionWaterRegion(node, BSP_Root, node_number, location, dist);
  398. else
  399. regionType = BSPReturnRegionTypeNode(node, BSP_Root, node_number, location, dist);
  400. if (regionType != RegionTypeNormal)
  401. return regionType;
  402. }
  403. region_num++;
  404. }
  405. return(RegionTypeNormal);
  406. }
  407. WaterRegionType RegionMapV1::BSPReturnRegionTypeNode(const Region_Node* region_node, const ZBSP_Node* BSP_Root, int32 node_number, const glm::vec3& location, float distToNode) const {
  408. if(node_number > region_node->vert_count)
  409. {
  410. LogWrite(REGION__DEBUG, 0, "Region", "Region %s grid %u (%s) - Node %u is out of range for region max vert count of %i. Hit at location %f %f %f.",
  411. region_node->regionName.c_str(), region_node->grid_id, region_node->regionScriptName.c_str(), node_number, region_node->vert_count,
  412. location.x, location.y, location.z);
  413. return (RegionTypeWater);
  414. }
  415. const ZBSP_Node* current_node = &BSP_Root[node_number - 1];
  416. float distance;
  417. #ifdef REGIONDEBUG
  418. printf("left = %u, right %u (Size: %i)\n", current_node->left, current_node->right, region_node->vert_count);
  419. #endif
  420. if (region_node->region_type == ClassWaterRegion2)
  421. {
  422. distance = (location.x * current_node->normal[0]) +
  423. (location.y * current_node->normal[1]) +
  424. (location.z * current_node->normal[2]) +
  425. current_node->splitdistance;
  426. }
  427. else {
  428. distance = (location.x * current_node->normal[0]) +
  429. (location.y * current_node->normal[1]) +
  430. (location.z * current_node->normal[2]) -
  431. current_node->splitdistance;
  432. }
  433. float absDistance = distance;
  434. if (absDistance < 0.0f)
  435. absDistance *= -1.0f;
  436. float absSplitDist = current_node->splitdistance;
  437. if (absSplitDist < 0.0f)
  438. absSplitDist *= -1.0f;
  439. #ifdef REGIONDEBUG
  440. printf("distance = %f, normals: %f %f %f, location: %f %f %f, split distance: %f\n", distance, current_node->left, current_node->right, current_node->normal[0], current_node->normal[1], current_node->normal[2],
  441. location.x, location.y, location.z, current_node->splitdistance);
  442. #endif
  443. if ((current_node->left == -2) &&
  444. (current_node->right == -1 || current_node->right == -2)) {
  445. if (region_node->region_type == ClassWaterOcean || region_node->region_type == ClassWaterOcean2)
  446. {
  447. if ( region_node->region_type == ClassWaterOcean && current_node->right == -1 &&
  448. current_node->normal[1] >= 0.9f && distance > 0 )
  449. return RegionTypeWater;
  450. else
  451. return EstablishDistanceAtAngle(region_node, current_node, distance, absDistance, absSplitDist, true);
  452. }
  453. else
  454. {
  455. if (distance > 0)
  456. return(RegionTypeWater);
  457. else
  458. return RegionTypeNormal;
  459. }
  460. }
  461. else if ((region_node->region_type == ClassWaterOcean || region_node->region_type == ClassWaterOcean2) && current_node->normal[1] != 1.0f && current_node->normal[1] != -1.0f)
  462. {
  463. float fraction = abs(current_node->normal[0] * current_node->normal[2]);
  464. float diff = distToNode / region_node->dist;
  465. if (distance > 0)
  466. diff = distance * diff;
  467. #ifdef REGIONDEBUG
  468. printf("Diff: %f (%f + %f), fraction %f\n", diff, distToNode, distance, fraction);
  469. #endif
  470. if ((abs(diff) / 2.0f) > (absSplitDist * (1.0f / fraction)) * 2.0f)
  471. return RegionTypeNormal;
  472. }
  473. if (distance == 0.0f) {
  474. return(RegionTypeNormal);
  475. }
  476. if (distance > 0.0f) {
  477. #ifdef REGIONDEBUG
  478. printf("to left node %i\n", current_node->left);
  479. #endif
  480. if (current_node->left == -2)
  481. {
  482. switch(region_node->region_type)
  483. {
  484. case ClassWaterVolume:
  485. case ClassWaterOcean:
  486. return RegionTypeWater;
  487. break;
  488. case ClassWaterOcean2:
  489. return EstablishDistanceAtAngle(region_node, current_node, distance, absDistance, absSplitDist, false);
  490. break;
  491. case ClassWaterCavern:
  492. return EstablishDistanceAtAngle(region_node, current_node, distance, absDistance, absSplitDist, true);
  493. break;
  494. default:
  495. return RegionTypeNormal;
  496. break;
  497. }
  498. }
  499. else if (current_node->left == -1) {
  500. return(RegionTypeNormal);
  501. }
  502. return BSPReturnRegionTypeNode(region_node, BSP_Root, current_node->left + 1, location, distToNode);
  503. }
  504. #ifdef REGIONDEBUG
  505. printf("to right node %i, sign bit %i\n", current_node->right, signbit(current_node->normal[1]));
  506. #endif
  507. if (current_node->right == -1) {
  508. if (region_node->region_type == ClassWaterOcean2 && signbit(current_node->normal[1]) == 0 && absDistance < absSplitDist)
  509. return RegionTypeWater;
  510. else if ((region_node->region_type == ClassWaterOcean || region_node->region_type == ClassWaterOcean2) &&
  511. (current_node->normal[1] > 0.0f && distance < 0.0f && absDistance < absSplitDist))
  512. {
  513. return(RegionTypeWater);
  514. }
  515. return(RegionTypeNormal);
  516. }
  517. return BSPReturnRegionTypeNode(region_node, BSP_Root, current_node->right + 1, location, distToNode);
  518. }
  519. WaterRegionType RegionMapV1::BSPReturnRegionWaterRegion(const Region_Node* region_node, const ZBSP_Node* BSP_Root, int32 node_number, const glm::vec3& location, float distToNode) const {
  520. if(node_number > region_node->vert_count)
  521. {
  522. LogWrite(REGION__DEBUG, 0, "Region", "Region %s grid %u (%s) - Node %u is out of range for region max vert count of %i. Hit at location %f %f %f.",
  523. region_node->regionName.c_str(), region_node->grid_id, region_node->regionScriptName.c_str(), node_number, region_node->vert_count,
  524. location.x, location.y, location.z);
  525. return (RegionTypeNormal);
  526. }
  527. const ZBSP_Node* current_node = &BSP_Root[node_number - 1];
  528. float distance;
  529. #ifdef REGIONDEBUG
  530. printf("left = %u, right %u\n", current_node->left, current_node->right);
  531. #endif
  532. distance = (location.x * current_node->normal[0]) +
  533. (location.y * current_node->normal[1]) +
  534. (location.z * current_node->normal[2]) -
  535. current_node->splitdistance;
  536. #ifdef REGIONDEBUG
  537. printf("distance = %f, normals: %f %f %f, location: %f %f %f, split distance: %f\n", distance, current_node->left, current_node->right, current_node->normal[0], current_node->normal[1], current_node->normal[2],
  538. location.x, location.y, location.z, current_node->splitdistance);
  539. #endif
  540. if (distance > 0.0f) {
  541. #ifdef REGIONDEBUG
  542. printf("to left node %i\n", current_node->left);
  543. #endif
  544. if (current_node->left == -1) {
  545. return(RegionTypeNormal);
  546. }
  547. else if (current_node->left == -2) {
  548. switch(current_node->special)
  549. {
  550. case SPECIAL_REGION_LAVA_OR_DEATH:
  551. return(RegionTypeLava);
  552. break;
  553. case SPECIAL_REGION_WATER:
  554. return(RegionTypeWater);
  555. break;
  556. default:
  557. return(RegionTypeUntagged);
  558. break;
  559. }
  560. }
  561. return BSPReturnRegionWaterRegion(region_node, BSP_Root, current_node->left + 1, location, distToNode);
  562. }
  563. #ifdef REGIONDEBUG
  564. printf("to right node %i, sign bit %i\n", current_node->right, signbit(current_node->normal[1]));
  565. #endif
  566. if (current_node->right == -1) {
  567. return(RegionTypeNormal);
  568. }
  569. return BSPReturnRegionWaterRegion(region_node, BSP_Root, current_node->right + 1, location, distToNode);
  570. }
  571. WaterRegionType RegionMapV1::EstablishDistanceAtAngle(const Region_Node* region_node, const ZBSP_Node* current_node, float distance, float absDistance, float absSplitDist, bool checkEdgedAngle) const {
  572. float fraction = abs(current_node->normal[0] * current_node->normal[2]);
  573. #ifdef REGIONDEBUG
  574. printf("Distcheck: %f < %f\n", absDistance, absSplitDist);
  575. #endif
  576. if (absDistance < absSplitDist &&
  577. (current_node->normal[0] >= 1.0f || current_node->normal[0] <= -1.0f ||
  578. (current_node->normal[1] >= .9f && distance < 0.0f) ||
  579. (current_node->normal[1] <= -.9f && distance > 0.0f)))
  580. {
  581. return RegionTypeWater;
  582. }
  583. else if (fraction > 0.0f && (region_node->region_type == ClassWaterOcean2 || checkEdgedAngle))
  584. {
  585. if (current_node->normal[2] >= 1.0f || current_node->normal[2] <= -1.0f)
  586. return RegionTypeNormal;
  587. else if (current_node->normal[1] == 0.0f && (current_node->normal[0] < -0.5f || current_node->normal[0] > 0.5f) &&
  588. ((abs(absDistance * current_node->normal[0]) / 2.0f) < ((abs(absSplitDist * (1.0f / fraction))))))
  589. {
  590. return RegionTypeWater;
  591. }
  592. else if (current_node->normal[1] == 0.0f && (current_node->normal[2] < -0.5f || current_node->normal[2] > 0.5f) &&
  593. ((abs(absDistance * current_node->normal[2]) / 2.0f) < ((abs(absSplitDist * (1.0f / fraction))))))
  594. {
  595. return RegionTypeWater;
  596. }
  597. }
  598. return RegionTypeNormal;
  599. }