region_map_v1.cpp 24 KB

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