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.

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