All user data for FoundryVTT. Includes worlds, systems, modules, and any asset in the "foundryuserdata" directory. Does NOT include the FoundryVTT installation itself.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

285 lines
10 KiB

  1. export function registerWrappers() {
  2. const LevelsConfig = CONFIG.Levels
  3. const computeUI = LevelsConfig.handlers.UIHandler.UIVisible
  4. /*Hooks.on("refreshTile", (placeable) => {
  5. const visible = LevelsConfig.handlers.TileHandler.isTileVisible(placeable);
  6. placeable.visible = placeable.visible && visible;
  7. computeUI(placeable);
  8. })*/
  9. Hooks.on("refreshTile", (placeable) => {
  10. const visible = LevelsConfig.handlers.TileHandler.isTileVisible(placeable);
  11. if (CONFIG.Levels.currentToken || canvas.tokens.controlled.length) {
  12. if ((CONFIG.Levels.currentToken ?? canvas.tokens.controlled[0]).losHeight < placeable.document.elevation) {
  13. if (!visible) {
  14. if (placeable.mesh) {
  15. placeable.mesh.occluded = true;
  16. placeable.mesh.shader.enabled = false;
  17. placeable.mesh.alpha = 0;
  18. }
  19. placeable.visible = placeable.visible && visible;
  20. }
  21. } else {
  22. placeable.visible = placeable.visible && visible;
  23. }
  24. } else {
  25. placeable.visible = placeable.visible && visible;
  26. }
  27. computeUI(placeable);
  28. })
  29. Hooks.on("refreshDrawing", (placeable) => {
  30. const visible = LevelsConfig.handlers.DrawingHandler.isDrawingVisible(placeable);
  31. placeable.visible = placeable.visible && visible;
  32. computeUI(placeable);
  33. })
  34. Hooks.on("refreshToken", (placeable, renderFlags) => {
  35. LevelsConfig.handlers.TokenHandler.refreshTooltip(placeable);
  36. CONFIG.Levels.FoWHandler.lazyCreateBubble(placeable);
  37. LevelsConfig.handlers.TokenHandler.setScale(placeable, renderFlags);
  38. computeUI(placeable);
  39. })
  40. Hooks.on("updateToken", (token, updates) => {
  41. if ("elevation" in updates && CONFIG.Levels.settings.get("tokenElevScale")) {
  42. LevelsConfig.handlers.RefreshHandler.refresh(canvas.tokens)
  43. }
  44. })
  45. Hooks.on("controlToken", (token, control) => {
  46. CONFIG.Levels.settings.get("tokenElevScale") && LevelsConfig.handlers.RefreshHandler.refresh(canvas.tokens)
  47. })
  48. Hooks.on("refreshAmbientLight", (placeable) => {
  49. computeUI(placeable);
  50. })
  51. Hooks.on("refreshNote", (placeable) => {
  52. computeUI(placeable);
  53. })
  54. Hooks.on("refreshWall", (placeable) => {
  55. computeUI(placeable);
  56. })
  57. Hooks.on("refreshAmbientSound", (placeable) => {
  58. computeUI(placeable);
  59. })
  60. libWrapper.register(
  61. LevelsConfig.MODULE_ID,
  62. "TokenLayer.prototype._getOccludableTokens",
  63. function (wrapped, ...args) {
  64. if (game.user.isGM) return wrapped(...args);
  65. else {
  66. return CONFIG.Levels.currentToken ? [CONFIG.Levels.currentToken] : wrapped(...args);
  67. }
  68. },
  69. "MIXED",
  70. );
  71. libWrapper.register(
  72. LevelsConfig.MODULE_ID,
  73. "CONFIG.Tile.objectClass.prototype.isRoof", function isRoof(wrapped, ...args){
  74. if(this.document.flags?.levels?.noCollision || this.document.flags["tile-scroll"]?.enableRotate || this.document.flags["tile-scroll"]?.enableScroll) return wrapped(...args);
  75. return wrapped(...args) || (this.document.overhead && Number.isFinite(this.document.flags?.levels?.rangeBottom));
  76. },
  77. "WRAPPER",
  78. { perf_mode: "FAST" }
  79. );
  80. libWrapper.register(
  81. LevelsConfig.MODULE_ID,
  82. "CONFIG.Wall.objectClass.prototype.identifyInteriorState", function disableInteriorState(wrapped,...args){
  83. this.roof = null;
  84. for (const tile of canvas.tiles.roofs) {
  85. const allWallBlockSight = tile.document?.flags?.levels?.allWallBlockSight ?? true;
  86. if (tile.document.hidden || !allWallBlockSight) continue;
  87. const isBottomFinite = Number.isFinite(tile.document.flags?.levels?.rangeBottom);
  88. if (isBottomFinite && Number.isFinite(tile.document?.flags?.levels?.rangeTop)) continue;
  89. if(isBottomFinite){
  90. const bottom = tile.document.flags?.levels?.rangeBottom;
  91. const wallBottom = this.document.flags["wall-height"]?.bottom ?? -Infinity;
  92. if(wallBottom >= bottom) continue;
  93. }
  94. const [x1, y1, x2, y2] = this.document.c;
  95. const isInterior = tile.mesh?.containsPixel(x1, y1) && tile.mesh?.containsPixel(x2, y2);
  96. if (isInterior) {
  97. this.roof = tile;
  98. break;
  99. }
  100. }
  101. },
  102. "OVERRIDE",
  103. { perf_mode: "FAST" }
  104. );
  105. libWrapper.register(
  106. LevelsConfig.MODULE_ID,
  107. "TilesLayer.prototype.displayRoofs", function displayRoofs(wrapped, ...args){
  108. const res = wrapped(...args);
  109. return res || (CONFIG.Levels.UI?.rangeEnabled && !canvas.tokens.controlled.length);
  110. },
  111. "WRAPPER"
  112. );
  113. Hooks.on("activateTilesLayer ", () => {
  114. if(CONFIG.Levels.UI?.rangeEnabled){
  115. ui.controls.control.foreground = true;
  116. canvas.tiles._activateSubLayer(true);
  117. }
  118. })
  119. const visibilityTestObjectStack = [];
  120. libWrapper.register(
  121. LevelsConfig.MODULE_ID,
  122. "CanvasVisibility.prototype.testVisibility",
  123. function visibilityWrapper(wrapped, ...args) {
  124. const options = args[1] ??= {};
  125. if (options.object instanceof Token) options.tolerance = 0;
  126. visibilityTestObjectStack.push(LevelsConfig.visibilityTestObject);
  127. LevelsConfig.visibilityTestObject = args[1].object;
  128. const res = wrapped(...args);
  129. LevelsConfig.visibilityTestObject = visibilityTestObjectStack.pop();
  130. return !!res;
  131. },
  132. "WRAPPER"
  133. );
  134. function elevatePoints(config, visionSource) {
  135. const object = config.object;
  136. const unitsToPixel = canvas.dimensions.size / canvas.dimensions.distance;
  137. if (object instanceof Token) {
  138. if (config.tests._levels !== object) {
  139. config.tests.length = 0;
  140. for (const p of LevelsConfig.handlers.SightHandler.getTestPoints(object)) {
  141. config.tests.push({ point: { x: p.x, y: p.y, z: p.z * unitsToPixel }, los: new Map() });
  142. }
  143. config.tests._levels = object;
  144. }
  145. } else {
  146. let z;
  147. if (object instanceof PlaceableObject) {
  148. z = object.document.elevation ?? object.document.flags.levels?.rangeBottom;
  149. } else if (object instanceof DoorControl) {
  150. z = visionSource?.elevation;
  151. }
  152. z ??= canvas.primary.background.elevation;
  153. z *= unitsToPixel;
  154. for (const test of config.tests) {
  155. test.point.z = z;
  156. }
  157. }
  158. return config;
  159. }
  160. libWrapper.register(
  161. LevelsConfig.MODULE_ID,
  162. "DetectionMode.prototype.testVisibility",
  163. function (wrapped, visionSource, mode, config) {
  164. return wrapped(visionSource, mode, elevatePoints(config, visionSource));
  165. },
  166. "WRAPPER",
  167. { perf_mode: "FAST" }
  168. );
  169. libWrapper.register(
  170. LevelsConfig.MODULE_ID,
  171. "LightSource.prototype.testVisibility",
  172. function (wrapped, config) {
  173. return wrapped(elevatePoints(config, CONFIG.Levels.currentToken?.vision));
  174. },
  175. "WRAPPER",
  176. { perf_mode: "FAST" }
  177. );
  178. if(!game.modules.get("perfect-vision")?.active){
  179. libWrapper.register(
  180. LevelsConfig.MODULE_ID,
  181. "DetectionMode.prototype._testRange",
  182. LevelsConfig.handlers.SightHandler._testRange,
  183. "OVERRIDE",
  184. { perf_mode: "FAST" }
  185. );
  186. }
  187. libWrapper.register(
  188. LevelsConfig.MODULE_ID,
  189. "ClockwiseSweepPolygon.prototype.contains",
  190. LevelsConfig.handlers.SightHandler.containsWrapper,
  191. "MIXED"
  192. );
  193. libWrapper.register(
  194. LevelsConfig.MODULE_ID,
  195. "ClockwiseSweepPolygon.prototype._testCollision",
  196. LevelsConfig.handlers.SightHandler._testCollision,
  197. "MIXED"
  198. );
  199. libWrapper.register(
  200. LevelsConfig.MODULE_ID,
  201. "CONFIG.AmbientLight.objectClass.prototype.emitsLight",
  202. LevelsConfig.handlers.LightHandler.isLightVisibleWrapper,
  203. "WRAPPER"
  204. );
  205. libWrapper.register(
  206. LevelsConfig.MODULE_ID,
  207. "CONFIG.Token.objectClass.prototype.emitsLight",
  208. LevelsConfig.handlers.LightHandler.isLightVisibleWrapper,
  209. "WRAPPER"
  210. );
  211. libWrapper.register(
  212. LevelsConfig.MODULE_ID,
  213. "CONFIG.AmbientSound.objectClass.prototype.isAudible",
  214. LevelsConfig.handlers.SoundHandler.isAudible,
  215. "WRAPPER"
  216. );
  217. libWrapper.register(
  218. LevelsConfig.MODULE_ID,
  219. "CONFIG.Note.objectClass.prototype.isVisible",
  220. LevelsConfig.handlers.NoteHandler.isVisible,
  221. "WRAPPER"
  222. );
  223. libWrapper.register(
  224. LevelsConfig.MODULE_ID,
  225. "CONFIG.MeasuredTemplate.objectClass.prototype.draw",
  226. LevelsConfig.handlers.TemplateHandler.drawTooltip,
  227. "WRAPPER"
  228. );
  229. libWrapper.register(
  230. LevelsConfig.MODULE_ID,
  231. "CONFIG.MeasuredTemplate.objectClass.prototype._refreshRulerText",
  232. LevelsConfig.handlers.TemplateHandler._refreshRulerText,
  233. "OVERRIDE"
  234. );
  235. libWrapper.register(
  236. LevelsConfig.MODULE_ID,
  237. "CONFIG.MeasuredTemplate.objectClass.prototype.isVisible",
  238. LevelsConfig.handlers.TemplateHandler.isVisible,
  239. "WRAPPER"
  240. );
  241. libWrapper.register(
  242. LevelsConfig.MODULE_ID,
  243. "CanvasOcclusionMask.prototype._identifyOccludedTiles",
  244. LevelsConfig.handlers.TileHandler._identifyOccludedTiles,
  245. "OVERRIDE"
  246. );
  247. libWrapper.register(LevelsConfig.MODULE_ID, "CONFIG.Token.objectClass.prototype.isVisible", LevelsConfig.handlers.UIHandler.tokenUIWrapperIsVisible, "WRAPPER");
  248. }