region_map_v1.cpp 25 KB

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