From 32ffc99c1ba3e8597ee8e6b6e15f08b9b40b693a Mon Sep 17 00:00:00 2001 From: Gambit Date: Sat, 21 Sep 2024 21:28:51 -0400 Subject: [PATCH] 0.5.48 --- .github/workflows/main.yml | 9 +- .../{001303.log => 001323.log} | 0 .../{001070.ldb => 001325.ldb} | Bin 19284 -> 19424 bytes packs/gps-3rd-party-features/CURRENT | 2 +- packs/gps-3rd-party-features/LOG | 23 +- packs/gps-3rd-party-features/LOG.old | 11 +- packs/gps-3rd-party-features/MANIFEST-001301 | Bin 226 -> 0 bytes packs/gps-3rd-party-features/MANIFEST-001321 | Bin 0 -> 453 bytes .../{001307.log => 001327.log} | 0 packs/gps-3rd-party-items/CURRENT | 2 +- packs/gps-3rd-party-items/LOG | 16 +- packs/gps-3rd-party-items/LOG.old | 11 +- .../{MANIFEST-001305 => MANIFEST-001325} | Bin 258 -> 258 bytes .../{001322.log => 001342.log} | 0 .../{001295.ldb => 001344.ldb} | Bin 80010 -> 80111 bytes packs/gps-3rd-party-spells/CURRENT | 2 +- packs/gps-3rd-party-spells/LOG | 23 +- packs/gps-3rd-party-spells/LOG.old | 11 +- packs/gps-3rd-party-spells/MANIFEST-001320 | Bin 235 -> 0 bytes packs/gps-3rd-party-spells/MANIFEST-001340 | Bin 0 -> 461 bytes packs/gps-actors/{001771.log => 001791.log} | 0 packs/gps-actors/CURRENT | 2 +- packs/gps-actors/LOG | 16 +- packs/gps-actors/LOG.old | 11 +- .../{MANIFEST-001769 => MANIFEST-001789} | Bin 272 -> 272 bytes .../{002982.log => 003002.log} | 0 .../{002973.ldb => 003004.ldb} | Bin 109704 -> 112294 bytes packs/gps-class-features/CURRENT | 2 +- packs/gps-class-features/LOG | 23 +- packs/gps-class-features/LOG.old | 11 +- packs/gps-class-features/MANIFEST-002980 | Bin 262 -> 0 bytes packs/gps-class-features/MANIFEST-003000 | Bin 0 -> 491 bytes .../{003034.log => 003054.log} | 0 .../{003025.ldb => 003056.ldb} | Bin 18818 -> 18975 bytes packs/gps-generic-features/CURRENT | 2 +- packs/gps-generic-features/LOG | 23 +- packs/gps-generic-features/LOG.old | 11 +- packs/gps-generic-features/MANIFEST-003032 | Bin 235 -> 0 bytes packs/gps-generic-features/MANIFEST-003052 | Bin 0 -> 461 bytes .../{002938.log => 002958.log} | 0 packs/gps-homebrew-features/CURRENT | 2 +- packs/gps-homebrew-features/LOG | 16 +- packs/gps-homebrew-features/LOG.old | 11 +- .../{MANIFEST-002936 => MANIFEST-002956} | Bin 287 -> 287 bytes .../{002944.log => 002965.log} | 0 packs/gps-homebrew-items/CURRENT | 2 +- packs/gps-homebrew-items/LOG | 23 +- packs/gps-homebrew-items/LOG.old | 11 +- packs/gps-homebrew-items/MANIFEST-002942 | Bin 511 -> 0 bytes packs/gps-homebrew-items/MANIFEST-002963 | Bin 0 -> 260 bytes .../{002605.log => 002625.log} | 0 packs/gps-homebrew-spells/CURRENT | 2 +- packs/gps-homebrew-spells/LOG | 16 +- packs/gps-homebrew-spells/LOG.old | 11 +- .../{MANIFEST-002603 => MANIFEST-002623} | Bin 225 -> 225 bytes packs/gps-items/{002943.log => 002963.log} | 0 packs/gps-items/CURRENT | 2 +- packs/gps-items/LOG | 16 +- packs/gps-items/LOG.old | 11 +- .../{MANIFEST-002941 => MANIFEST-002961} | Bin 201 -> 201 bytes .../{002937.log => 002957.log} | 0 packs/gps-monster-features/CURRENT | 2 +- packs/gps-monster-features/LOG | 16 +- packs/gps-monster-features/LOG.old | 11 +- .../{MANIFEST-002935 => MANIFEST-002955} | Bin 287 -> 287 bytes .../{000641.log => 000661.log} | 0 packs/gps-race-features/CURRENT | 2 +- packs/gps-race-features/LOG | 16 +- packs/gps-race-features/LOG.old | 11 +- .../{MANIFEST-000639 => MANIFEST-000659} | Bin 225 -> 225 bytes packs/gps-spells/{003026.log => 003047.log} | 0 packs/gps-spells/{003003.ldb => 003049.ldb} | Bin 153928 -> 154092 bytes packs/gps-spells/CURRENT | 2 +- packs/gps-spells/LOG | 23 +- packs/gps-spells/LOG.old | 11 +- packs/gps-spells/MANIFEST-003024 | Bin 235 -> 0 bytes packs/gps-spells/MANIFEST-003045 | Bin 0 -> 461 bytes scripts/helpers.js | 124 +++++++--- scripts/macros/ballBearings.js | 9 +- scripts/macros/biohazard.js | 8 +- scripts/macros/blackTentacles.js | 16 +- scripts/macros/caltrops.js | 9 +- scripts/macros/caltropsFeyGlass.js | 9 +- scripts/macros/cloudRune.js | 220 +++++++++--------- scripts/macros/counterspell.js | 95 +++----- scripts/macros/cuttingWords.js | 62 +++-- scripts/macros/indomitable.js | 54 ++--- scripts/macros/instinctiveCharm.js | 66 +++--- scripts/macros/interception.js | 51 ++-- scripts/macros/mageSlayer.js | 51 ++-- scripts/macros/opportunityAttack.js | 55 ++--- scripts/macros/poetryInMisery.js | 45 ++-- scripts/macros/powerWordRebound.js | 52 ++--- scripts/macros/protection.js | 45 ++-- scripts/macros/rainOfCinders.js | 51 ++-- scripts/macros/riposte.js | 55 ++--- scripts/macros/runicShield.js | 55 ++--- scripts/macros/sentinel.js | 51 ++-- scripts/macros/silveryBarbs.js | 63 +++-- scripts/macros/witchesHex.js | 57 ++--- scripts/module.js | 168 ++++++------- scripts/settings.js | 39 +++- templates/generalSettingsMenu.html | 34 ++- 103 files changed, 1022 insertions(+), 950 deletions(-) rename packs/gps-3rd-party-features/{001303.log => 001323.log} (100%) rename packs/gps-3rd-party-features/{001070.ldb => 001325.ldb} (80%) delete mode 100644 packs/gps-3rd-party-features/MANIFEST-001301 create mode 100644 packs/gps-3rd-party-features/MANIFEST-001321 rename packs/gps-3rd-party-items/{001307.log => 001327.log} (100%) rename packs/gps-3rd-party-items/{MANIFEST-001305 => MANIFEST-001325} (76%) rename packs/gps-3rd-party-spells/{001322.log => 001342.log} (100%) rename packs/gps-3rd-party-spells/{001295.ldb => 001344.ldb} (92%) delete mode 100644 packs/gps-3rd-party-spells/MANIFEST-001320 create mode 100644 packs/gps-3rd-party-spells/MANIFEST-001340 rename packs/gps-actors/{001771.log => 001791.log} (100%) rename packs/gps-actors/{MANIFEST-001769 => MANIFEST-001789} (70%) rename packs/gps-class-features/{002982.log => 003002.log} (100%) rename packs/gps-class-features/{002973.ldb => 003004.ldb} (60%) delete mode 100644 packs/gps-class-features/MANIFEST-002980 create mode 100644 packs/gps-class-features/MANIFEST-003000 rename packs/gps-generic-features/{003034.log => 003054.log} (100%) rename packs/gps-generic-features/{003025.ldb => 003056.ldb} (85%) delete mode 100644 packs/gps-generic-features/MANIFEST-003032 create mode 100644 packs/gps-generic-features/MANIFEST-003052 rename packs/gps-homebrew-features/{002938.log => 002958.log} (100%) rename packs/gps-homebrew-features/{MANIFEST-002936 => MANIFEST-002956} (66%) rename packs/gps-homebrew-items/{002944.log => 002965.log} (100%) delete mode 100644 packs/gps-homebrew-items/MANIFEST-002942 create mode 100644 packs/gps-homebrew-items/MANIFEST-002963 rename packs/gps-homebrew-spells/{002605.log => 002625.log} (100%) rename packs/gps-homebrew-spells/{MANIFEST-002603 => MANIFEST-002623} (56%) rename packs/gps-items/{002943.log => 002963.log} (100%) rename packs/gps-items/{MANIFEST-002941 => MANIFEST-002961} (63%) rename packs/gps-monster-features/{002937.log => 002957.log} (100%) rename packs/gps-monster-features/{MANIFEST-002935 => MANIFEST-002955} (66%) rename packs/gps-race-features/{000641.log => 000661.log} (100%) rename packs/gps-race-features/{MANIFEST-000639 => MANIFEST-000659} (56%) rename packs/gps-spells/{003026.log => 003047.log} (100%) rename packs/gps-spells/{003003.ldb => 003049.ldb} (91%) delete mode 100644 packs/gps-spells/MANIFEST-003024 create mode 100644 packs/gps-spells/MANIFEST-003045 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3c8e98f6..61e93824 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,8 +18,15 @@ jobs: - name: Set Release Notes for Github id: set-release-notes-github run: | + echo "- General:" >> release_notes.txt + echo " - 3rd Party Reactions: 3rd Party Reactions now support multiple GMs in the same world at the same time. After updating, the first active GM will be set as your Primary GM. This can then be modified in GPS Settings, which will give a list of GMs to choose from if more than one is present in a world. If this primary gm logs out or is no longer present in the world, the gm will fallback to the first active gm." >> release_notes.txt + echo " - 3rd Party Reactions: Item renaming is now possible as matching is done based on an ID stored on the item. This does mean the item needs to either be pulled from my compendiums or medkitted via cpr in order to work properly moving forward." >> release_notes.txt + echo " - Region Wrapping: Added setting (default true) for Region Wrapping. This wrapping is done to test additional points on a token when moving in/through a region (Foundry only tests the token center point). This was previously always on with my module in v12, you now have the ability to turn it off but I would not recommend it if trying to stay close to 5e rules." >> release_notes.txt + echo " - Cardinal Movement Helper: Added a return that will give the total movement that occurred." >> release_notes.txt + echo "- Updates:" >> release_notes.txt + echo " - Opportunity Attack: Add handling to temporarily disable Levels UI Picker on region deployment because it overrides default region handling" >> release_notes.txt echo "- Bugfixes:" >> release_notes.txt - echo " - Opportunity Attack: Additional turn end bugfix causing permissions errors" >> release_notes.txt + echo " - Vicious Mockery: Fix dialog not submitting with enter key correctly" >> release_notes.txt echo "release-notes-github<> $GITHUB_ENV cat release_notes.txt >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV diff --git a/packs/gps-3rd-party-features/001303.log b/packs/gps-3rd-party-features/001323.log similarity index 100% rename from packs/gps-3rd-party-features/001303.log rename to packs/gps-3rd-party-features/001323.log diff --git a/packs/gps-3rd-party-features/001070.ldb b/packs/gps-3rd-party-features/001325.ldb similarity index 80% rename from packs/gps-3rd-party-features/001070.ldb rename to packs/gps-3rd-party-features/001325.ldb index 4bac886dd929c5a521391cbbe9aab6e049b99b0f..38ca8fc0c8d1743abca6e93c4f01627fe0024970 100644 GIT binary patch delta 857 zcmZY6Z%7ki9KiAC$!R;cdz{xiXQp$fhS_c0|J#X%&S~Y0qLl;@a^CKArEcxEbeKr5 zqJk2xH2Q<|(tHyP3WDfG1ijKX6;VV*5WNWcgV8^TrY1%{@O$~d@AvsWo`SEZ;jP++ znx~Cv;GJvq#nbwb>D$-M4n#ZJ_w1L9HgVVP5!jwN)F|xc^U}cUMcvh4+F(}gLox>hC;#F03k|N1W zP>}@|Wt~nly(fYBKnO{t&8fuxaCRijD#;AjGdkFgG|Xuv24mCPb^{vgiAhs3NjnkBw$vqJxMHB1g$&k~v z;(p&T$#8}yG7RIF4Kd~yBu@7$f~xriPUU1n5P3Cdth#@50FyZECT8)x;=N@>&{I0% zqLv`ZuXbBXuOMB^=!NC(71asyJtnY{!iW;1$PyQnXmn?pwXBMkxg}VU5ra$+b^Zgp zupai|tLheHiza5Tk{?}b$phuUlfQO}oH$K%{}qo8AJ7jSkdMZxR+{RquLIepyJhgR zEs;Vm?0|u=fu`093_Gf~m7oX~n)$ClQEkiZTy;wn_bgt7y{losku5JyK?xoJR4M7cqMswJg|4m6n`6%rzzWOuy3U-nV8n|T%zt?J>=IWZ PVk4DSYs6-CN9=z90}Jj{ delta 638 zcmaDbo$<;v#tq6E3KO(S804R7DrT0X<`ydk_!wpcyE^*@nWZ_JdU%#II&OB>*v!ae zWVHE*W+Hn%ib--NbuGbAfT@-PHTT@@7jB%qK|T9A{OoLG`-Ce9#`oL`h0 zrl`i(#H*lWXryOsY@nng)g~;oiiaUZXdjQDu%r%;v7WJ>&{qzTqEw)!6tRn(CWhul z#wNywre;Q_7N$CU3%EHl(=x4O8AQwsEe*|$`HXqgd5TMX^Enk6ocKNn*c9alxm1?B z7+MyT8iiHlIP=MJ@}%YGr0{K->}w=$E3}ZuZnFsEYL5J(5}^(*h5Yio)S}{y%mTi3 zTypn$`4~8zvKe%&jB9HdfPfK%xh}X$Ueg8!$m+=pj3gNyHt#Z;5B7YtNev^bh?0&{ z@#I^kj;su|j3ok_70tZa>KR}GvXPsiSV&YvD47@N$8uf<9bRFEFhN5BC6GtO)^o5F zrAms4Ktki74b0n%fZjH 19424 bytes +2024/09/21-21:27:43.291 1147c compacted to: files[ 0 0 1 0 0 0 0 ] +2024/09/21-21:27:43.292 1147c Delete type=2 #1070 +2024/09/21-21:27:43.292 1147c Delete type=2 #1324 +2024/09/21-21:27:43.298 1147c Manual compaction at level-1 from '!items!y6y7B3DSHbduxFDF' @ 68 : 1 .. '!items.effects!G2IDv711EWrOF7ef.kE7T0D7E6CnMvjvr' @ 0 : 0; will stop at (end) diff --git a/packs/gps-3rd-party-features/LOG.old b/packs/gps-3rd-party-features/LOG.old index a7a27c7c..8e497bb9 100644 --- a/packs/gps-3rd-party-features/LOG.old +++ b/packs/gps-3rd-party-features/LOG.old @@ -1,3 +1,8 @@ -2024/09/17-10:53:01.661 19cc Recovering log #1297 -2024/09/17-10:53:01.666 19cc Delete type=0 #1297 -2024/09/17-10:53:01.666 19cc Delete type=3 #1295 +2024/09/21-16:06:48.807 1304c Recovering log #1315 +2024/09/21-16:06:48.811 1304c Delete type=0 #1315 +2024/09/21-16:06:48.811 1304c Delete type=3 #1313 +2024/09/21-16:14:51.133 1147c Level-0 table #1320: started +2024/09/21-16:14:51.133 1147c Level-0 table #1320: 0 bytes OK +2024/09/21-16:14:51.135 1147c Delete type=0 #1318 +2024/09/21-16:14:51.140 1147c Manual compaction at level-0 from '!folders!4Ecsdk7k1FvMs9OF' @ 72057594037927935 : 1 .. '!items.effects!G2IDv711EWrOF7ef.kE7T0D7E6CnMvjvr' @ 0 : 0; will stop at (end) +2024/09/21-16:14:51.140 1147c Manual compaction at level-1 from '!folders!4Ecsdk7k1FvMs9OF' @ 72057594037927935 : 1 .. '!items.effects!G2IDv711EWrOF7ef.kE7T0D7E6CnMvjvr' @ 0 : 0; will stop at (end) diff --git a/packs/gps-3rd-party-features/MANIFEST-001301 b/packs/gps-3rd-party-features/MANIFEST-001301 deleted file mode 100644 index 0e924f638ac37d483a8e9b424b53b36747273a00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 226 zcmdn?fJ=HO10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei199g<@t&YHqP!YFb)q za!IkGn@M<%Q%;eOVWLNBaYm|-UW#RkQ-*PBZh(b{PkNDWHlscR7_c*~d~gG`(zB^AH0U wb5}FxJm0dcvLZ%#h{pMIYL;^`FfvW!;$&c+&c)(5LF4dSkic}1z)YY301)v&e*gdg diff --git a/packs/gps-3rd-party-features/MANIFEST-001321 b/packs/gps-3rd-party-features/MANIFEST-001321 new file mode 100644 index 0000000000000000000000000000000000000000..88f76a7f9256510bb28a08fa36d79c32573a182a GIT binary patch literal 453 zcmdn?fJ=HO10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei199g<@t&YHqP!YFb)q za!IkGn@M<%Q%;eOVWLNBaYm|-UW#RkQ-*PBZh(b{PkNDWHlscR7_c*~d~gG`(zB^AH0U zb5}FxJm0dcvLZ%#h{lEdJ6gCH7@1aaaWXKk=3;R)?lJQW01B)I39RK}ab;&*!?i42 z9^wVX03XAQU{`0~AhR?_QxDH_MrVjQF!@TeN^>V;mtc>il+p?}7dJ*1hA2|wfogE1>vtH;Vxkb{jMJZ$r_X#pE|C9UiQ>w#9b zF;sCx6CQ?43^&CMNyCT^O^j^U_1UGu66Cc!d- zKQ8qMaVZjJJiEAO+L)-^z-$xC_#<+h@oITiy zE;LZirkDIvcbKBl!00@fjZTd=68k|^MFTPUHp0frR10edg)+3=Iu|vK9mq)S*3hq= zN4LgA_%~F0Y9kcTu~V&?IqO6@9+QSsl_=u_Pyg~nLiv*pA>>oUnWHf=Bm{`5oQ|m6 z(k&IM27MK7hnwT9=3v0)G&=&k%PjEDpqcXp{Puv=?z8hE1MAi8a$KmojqhS)ssJxp zCRG<&arFitVMyIqwxZB&c>fo3T+=-_y_&Eay}ZFU#$ zVv~8e6qIrc8eBHs&GYUGC+~K!OqU?X8zV$9s7~Em5{s;>>FcfG+|h2^h8J4y}LGIDFF-=#F+tejzSe@_=5E7>slUs+x!epuL2y+)uze`baF!tn#?55SFq` zq&KV-+bKnhliUB1DylvN0v>xJF-L#AORR4R?%2M)*S)i0WBtypPMGxEAn@g)kor}Q zslKZ(+ByBsXRX0Mq59LN{%ZtgT5J5Az*y6MwcgYy_+t^v>?rX)4v!MRDvSxAfgUDK zm_Ju{M!I9QsW09m)N)kx!&d4p{=4V9-y?u?)B6MnP9N92l@k*bVKUiB7#+lkJs?px zOi1&aMwBOFR}lVuc8nMpBSm7QoX4ik8%D3J3sbUO~J7i`97FA)k3Um}3L z>=JTcX=mAA)L1|$&cc{b>P~UHu}fPym{Ipb?crp`>;9@AgJ@F5Wq*YF zKucSQ6Itp|NC=Y$@lq*RD#SYE&DJ)H>h;n!!V9u&@_N0dR;I8AImXN23~C<_K_B|< zcmezwdN^K`#_5oHBA%vGqumo+-W!zO5)=I5>KM$`v~vaO@^aHEvISk6*!05J+3Hrt zW2&8@rcwD>mh-7$1GNC>3xQFhU|~TDLcEoUkwP|*;atEOj)H`3DWKlYf=sm+&^OS* zv*j7@=8!LH)Du_EmcTSB7v2AG9!w(5WKnr48#8%xU&SnOayAzR7Nl-hE?aSXf~6rxEiCdFIVAvAYM&G9km;($=W=bpwh1*{SYG6L5m)Bt z3TyrzPP{5oOE)hf#ZofesSfusEKdWl zf*vdd>&c_#)GIE!k0)HVcbqR@aIP4qZ#wDklz~9~aX$Z;r)vy&l|RmWV>LTg{@Y2g zU>UFFOTyGv8)%{*FR6V;c#JFdlGe`&mW`#1@=(VF9T?4SEy` z8ntgH56twz#lTGd-BopMMFo~%jrX0vLpsa#F|k8gBxb6HqfS;}yBIUoUgNiTn; zlFtXqf&b(2cOMo`+_~u40rw6S@~{L;|N7Xzp?W2vK6!xMN&9~yI9k>;KJ+pVzcl`N z5zy%_V!^e#4(-)%)1K!Q7=TY_(0=;nP}BwI_CFj+|3kjvW6+^{N&Csw^l$SFdJxj- z)t}x@f9kCR5uILt`BiL+0(wm<-y#NsqCYOXf3N+|5o|cG&ZP81w^ToJ3QLl}P`MNs z?rYCnz%Fa+szB~rrl-Hb_UZtkVsz`YyKiC_)y4mM@`F63N{hl;g{?!G6|f=GwQcjZ Q(MOo=&ZD6pRlu_U0wsTGssI20 delta 1749 zcmX|BeNYtV8Gqkn4|nx$xm{rIg9G+f!~^e+`{3^21i~Sp*q|dKDT?CW?H(-Nm$!F( z)KWuCjDvAXeG^eT8FS7!DHAY!s4=2O+8HuUoHTZl)J|-bkW6ZmY3nqTq$Z)g{*z~Z z&oj>-zh{0k&(}X6VWW?*>Anf}lf#3c_&>BsN{SKL6cn5T9dc}^Jst=}0|_@AoI5^o z48mzN|E^{HuUSy-8?}CoB}AyjVo|u+9+Q)t&tc($v8W&sX5}tiNG0;Upx?S+l;f(D zEXpQIZ6(g(5q{9*#4TK0KbO%~{uT_W^`0c)b3lr3L`9PYxh2CEjt@v-DLF(Hm8C$t z^fNSC;YB!2qF+v~RnTK-`{(&+yO@jaO_mVHKwQZHapWu_rplG2O=El+I%qFIJEx9k z^WUhM=dPhor$o4fwqESS_TOp|#&4FwVzhYCw?@|{%E^QjoO;27R=@6RD;dt1h3l4+ zy#FkIh?772Ncls{_m3W`I>dy$(5UlqE}PTl7l^$ZWhge!XB@)W=3)zMsf%l3$X}YIk^f+iJ z&Bs>;i40B-62MhHNZ@>+k355K8$^3%Eam5k$LEQTIH8kc5k4se3zu+iuf=*f9Y6IR z5ttzsUcxvZd5qXipqZI+?ANOq3EiJDK`nx_d8?K_U(w<=Eh?NXaKEU+1m2W`agp@0 zsoStlQ#Y2~OleMzWS zP%LEH_C^KlnrnT7go=M@(cY`i>(3VEg@;&P5V!>b3-Dw#H*@$V4O5GLxN62X8L(J_ zzEzB@Z`z?ex9`n*2oIoh*DRTjar>IS!d@dt{cJGI%W`cOM{*@VP)-6XY%=mvR7`Yn zbw`^4g!{GvAT!@?KzZ{Hm_W_*b&9tf=;-{_%p{(;UR~DWX?W4T@0K07$iF#A=%CjZ z`wR{SI)I&SaDyK5aV4~__2{h0jmUt#SOrsw22TQws z*2=Ay-Gl{f^1S0-7p420U>ozBnx-$v^={^y4PdWHqhuZAN|X0T7@E8q3nvMQ(mpRH zNQElUpK)HT3RHT4m3d(Uu##!7zxkb(Ds0$dc<2T`{wrNV?2%$oE8Xazg(~b2N2oxX zQjfRC+70(SRAj}BoiTURdRUjo>#%#>m9CXqPX-25cC!GhS?+mdZp%&IARHS%;(_Zh z&Bbct_+%!d??1$r6(D2q|KaJ8lQ+kgJ@D?~ugrj=ZeXDuRF7u)JH@x!LOlpjdd&lr zmDcJz8$&}*M{1yN`;Mvsc~j$055j(;Q*-pStPhO(w?Gf|gy#O+S>J2*IuN0Bst5P8 zzOHQsF-oWV_y~5D20C@xXcI#rF_@IA|EM{A3Y*Y2vjDVE^}59=Y=krceO*1!Kh)fw z$8Kqw{UHAg`>Wg7^AsSI9Mz_I`7h&ps^EV0j+Q^D-u@DEu6&98DQo;r6=cRARKZoN P0eI@Wr;nGUHh=s-mP#xH diff --git a/packs/gps-3rd-party-spells/CURRENT b/packs/gps-3rd-party-spells/CURRENT index 4d7a8d6f..12770e7e 100644 --- a/packs/gps-3rd-party-spells/CURRENT +++ b/packs/gps-3rd-party-spells/CURRENT @@ -1 +1 @@ -MANIFEST-001320 +MANIFEST-001340 diff --git a/packs/gps-3rd-party-spells/LOG b/packs/gps-3rd-party-spells/LOG index d06b9362..f5b039c6 100644 --- a/packs/gps-3rd-party-spells/LOG +++ b/packs/gps-3rd-party-spells/LOG @@ -1,8 +1,15 @@ -2024/09/17-11:31:04.191 13054 Recovering log #1319 -2024/09/17-11:31:04.195 13054 Delete type=0 #1319 -2024/09/17-11:31:04.195 13054 Delete type=3 #1318 -2024/09/19-01:12:07.723 1147c Level-0 table #1323: started -2024/09/19-01:12:07.723 1147c Level-0 table #1323: 0 bytes OK -2024/09/19-01:12:07.725 1147c Delete type=0 #1321 -2024/09/19-01:12:07.728 1147c Manual compaction at level-0 from '!items!2YNbYocBRdEDgO4Q' @ 72057594037927935 : 1 .. '!items.effects!qBnx0VU4WBSLrGeK.zhzkM83QyjS4pBGp' @ 0 : 0; will stop at (end) -2024/09/19-01:12:07.730 1147c Manual compaction at level-1 from '!items!2YNbYocBRdEDgO4Q' @ 72057594037927935 : 1 .. '!items.effects!qBnx0VU4WBSLrGeK.zhzkM83QyjS4pBGp' @ 0 : 0; will stop at (end) +2024/09/21-16:17:33.040 13054 Recovering log #1338 +2024/09/21-16:17:33.045 13054 Delete type=0 #1338 +2024/09/21-16:17:33.045 13054 Delete type=3 #1336 +2024/09/21-21:27:43.311 1147c Level-0 table #1343: started +2024/09/21-21:27:43.312 1147c Level-0 table #1343: 2084 bytes OK +2024/09/21-21:27:43.313 1147c Delete type=0 #1341 +2024/09/21-21:27:43.317 1147c Manual compaction at level-0 from '!items!2YNbYocBRdEDgO4Q' @ 72057594037927935 : 1 .. '!items.effects!qBnx0VU4WBSLrGeK.zhzkM83QyjS4pBGp' @ 0 : 0; will stop at (end) +2024/09/21-21:27:43.317 1147c Manual compaction at level-1 from '!items!2YNbYocBRdEDgO4Q' @ 72057594037927935 : 1 .. '!items.effects!qBnx0VU4WBSLrGeK.zhzkM83QyjS4pBGp' @ 0 : 0; will stop at '!items!cd2wVsoS0pbfnbr5' @ 420 : 1 +2024/09/21-21:27:43.317 1147c Compacting 1@1 + 1@2 files +2024/09/21-21:27:43.320 1147c Generated table #1344@1: 34 keys, 80111 bytes +2024/09/21-21:27:43.320 1147c Compacted 1@1 + 1@2 files => 80111 bytes +2024/09/21-21:27:43.321 1147c compacted to: files[ 0 0 1 0 0 0 0 ] +2024/09/21-21:27:43.321 1147c Delete type=2 #1295 +2024/09/21-21:27:43.321 1147c Delete type=2 #1343 +2024/09/21-21:27:43.324 1147c Manual compaction at level-1 from '!items!cd2wVsoS0pbfnbr5' @ 420 : 1 .. '!items.effects!qBnx0VU4WBSLrGeK.zhzkM83QyjS4pBGp' @ 0 : 0; will stop at (end) diff --git a/packs/gps-3rd-party-spells/LOG.old b/packs/gps-3rd-party-spells/LOG.old index 78c360df..a90ed7c8 100644 --- a/packs/gps-3rd-party-spells/LOG.old +++ b/packs/gps-3rd-party-spells/LOG.old @@ -1,3 +1,8 @@ -2024/09/17-10:53:01.742 19cc Recovering log #1316 -2024/09/17-10:53:01.751 19cc Delete type=0 #1316 -2024/09/17-10:53:01.752 19cc Delete type=3 #1314 +2024/09/21-16:06:48.854 1304c Recovering log #1334 +2024/09/21-16:06:48.858 1304c Delete type=0 #1334 +2024/09/21-16:06:48.858 1304c Delete type=3 #1332 +2024/09/21-16:14:51.153 1147c Level-0 table #1339: started +2024/09/21-16:14:51.153 1147c Level-0 table #1339: 0 bytes OK +2024/09/21-16:14:51.156 1147c Delete type=0 #1337 +2024/09/21-16:14:51.163 1147c Manual compaction at level-0 from '!items!2YNbYocBRdEDgO4Q' @ 72057594037927935 : 1 .. '!items.effects!qBnx0VU4WBSLrGeK.zhzkM83QyjS4pBGp' @ 0 : 0; will stop at (end) +2024/09/21-16:14:51.163 1147c Manual compaction at level-1 from '!items!2YNbYocBRdEDgO4Q' @ 72057594037927935 : 1 .. '!items.effects!qBnx0VU4WBSLrGeK.zhzkM83QyjS4pBGp' @ 0 : 0; will stop at (end) diff --git a/packs/gps-3rd-party-spells/MANIFEST-001320 b/packs/gps-3rd-party-spells/MANIFEST-001320 deleted file mode 100644 index e800e752a773440a4951c29df2a3c36b779589ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmaFi{mbqE10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei18!ykcfaYHqP&agdRx zqpz`Npktv~u1Q5GV;%z-urk6_xJQ_KnwuN=nT5KPgqwwCFwSQLt6*p9=j!^%0#jxb z>6a9lpX?Nr;_8y_ZxYB@2T^7Lu}Cj9EiE;oflU|z+=vY2^$yMZ}KWEDtc4M+q4@B%?8 diff --git a/packs/gps-3rd-party-spells/MANIFEST-001340 b/packs/gps-3rd-party-spells/MANIFEST-001340 new file mode 100644 index 0000000000000000000000000000000000000000..f62d5478cb7c4dd4503eb6b38b4ab05ba73b07fb GIT binary patch literal 461 zcmaFi{mbqE10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei18!ykcfaYHqP&agdRx zqpz`Npktv~u1Q5GV;%z-urk6_xJQ_KnwuN=nT5KPgqwwCFwSQLt6*p9=j!^%0#jxb z>6a9lpX?Nr;_8y_ZxYB@2T^7Lu}Cj9EiE; z{ai}~U`|L*F)9x$&JQ*yNJ`5~Dl%nU3ULBX`6UqfnB048Q(@*F1euHQJ%*W3J#0Xm Q*?=Ly&UAq5Jq<$v0GG{yPXGV_ literal 0 HcmV?d00001 diff --git a/packs/gps-actors/001771.log b/packs/gps-actors/001791.log similarity index 100% rename from packs/gps-actors/001771.log rename to packs/gps-actors/001791.log diff --git a/packs/gps-actors/CURRENT b/packs/gps-actors/CURRENT index fefc654e..8bed4cfd 100644 --- a/packs/gps-actors/CURRENT +++ b/packs/gps-actors/CURRENT @@ -1 +1 @@ -MANIFEST-001769 +MANIFEST-001789 diff --git a/packs/gps-actors/LOG b/packs/gps-actors/LOG index 76f2d812..ffdba5f5 100644 --- a/packs/gps-actors/LOG +++ b/packs/gps-actors/LOG @@ -1,8 +1,8 @@ -2024/09/17-11:31:04.178 1304c Recovering log #1768 -2024/09/17-11:31:04.183 1304c Delete type=0 #1768 -2024/09/17-11:31:04.183 1304c Delete type=3 #1767 -2024/09/19-01:12:07.705 1147c Level-0 table #1772: started -2024/09/19-01:12:07.705 1147c Level-0 table #1772: 0 bytes OK -2024/09/19-01:12:07.707 1147c Delete type=0 #1770 -2024/09/19-01:12:07.714 1147c Manual compaction at level-0 from '!actors!2Q055cZ4Q4eMWCQT' @ 72057594037927935 : 1 .. '!actors.items.effects!2Q055cZ4Q4eMWCQT.icorevoMIkBVXL37.jFKhp34XZd32ryYT' @ 0 : 0; will stop at (end) -2024/09/19-01:12:07.714 1147c Manual compaction at level-1 from '!actors!2Q055cZ4Q4eMWCQT' @ 72057594037927935 : 1 .. '!actors.items.effects!2Q055cZ4Q4eMWCQT.icorevoMIkBVXL37.jFKhp34XZd32ryYT' @ 0 : 0; will stop at (end) +2024/09/21-16:17:33.027 13050 Recovering log #1787 +2024/09/21-16:17:33.030 13050 Delete type=0 #1787 +2024/09/21-16:17:33.030 13050 Delete type=3 #1785 +2024/09/21-21:27:43.308 1147c Level-0 table #1792: started +2024/09/21-21:27:43.308 1147c Level-0 table #1792: 0 bytes OK +2024/09/21-21:27:43.311 1147c Delete type=0 #1790 +2024/09/21-21:27:43.317 1147c Manual compaction at level-0 from '!actors!2Q055cZ4Q4eMWCQT' @ 72057594037927935 : 1 .. '!actors.items.effects!2Q055cZ4Q4eMWCQT.icorevoMIkBVXL37.jFKhp34XZd32ryYT' @ 0 : 0; will stop at (end) +2024/09/21-21:27:43.317 1147c Manual compaction at level-1 from '!actors!2Q055cZ4Q4eMWCQT' @ 72057594037927935 : 1 .. '!actors.items.effects!2Q055cZ4Q4eMWCQT.icorevoMIkBVXL37.jFKhp34XZd32ryYT' @ 0 : 0; will stop at (end) diff --git a/packs/gps-actors/LOG.old b/packs/gps-actors/LOG.old index 41071eaa..1f417550 100644 --- a/packs/gps-actors/LOG.old +++ b/packs/gps-actors/LOG.old @@ -1,3 +1,8 @@ -2024/09/17-10:53:01.711 2468 Recovering log #1765 -2024/09/17-10:53:01.715 2468 Delete type=0 #1765 -2024/09/17-10:53:01.715 2468 Delete type=3 #1763 +2024/09/21-16:06:48.843 13054 Recovering log #1783 +2024/09/21-16:06:48.847 13054 Delete type=0 #1783 +2024/09/21-16:06:48.847 13054 Delete type=3 #1781 +2024/09/21-16:14:51.148 1147c Level-0 table #1788: started +2024/09/21-16:14:51.148 1147c Level-0 table #1788: 0 bytes OK +2024/09/21-16:14:51.150 1147c Delete type=0 #1786 +2024/09/21-16:14:51.151 1147c Manual compaction at level-0 from '!actors!2Q055cZ4Q4eMWCQT' @ 72057594037927935 : 1 .. '!actors.items.effects!2Q055cZ4Q4eMWCQT.icorevoMIkBVXL37.jFKhp34XZd32ryYT' @ 0 : 0; will stop at (end) +2024/09/21-16:14:51.151 1147c Manual compaction at level-1 from '!actors!2Q055cZ4Q4eMWCQT' @ 72057594037927935 : 1 .. '!actors.items.effects!2Q055cZ4Q4eMWCQT.icorevoMIkBVXL37.jFKhp34XZd32ryYT' @ 0 : 0; will stop at (end) diff --git a/packs/gps-actors/MANIFEST-001769 b/packs/gps-actors/MANIFEST-001789 similarity index 70% rename from packs/gps-actors/MANIFEST-001769 rename to packs/gps-actors/MANIFEST-001789 index b7ab0bd8b6b7b61ac8fcb35a25018853cb9ff514..8142ebfd8e7fc1eeb1b20d8be27170cce9d06332 100644 GIT binary patch delta 41 tcmbQhG=XWtJEg=0ldfz6pplP73;-923sL|8 delta 41 scmbQhG=XWtJEfG3=Zv@*7@1!2axyT#=4BBJo_J^%NZ>U{;4M%901zDufdBvi diff --git a/packs/gps-class-features/002982.log b/packs/gps-class-features/003002.log similarity index 100% rename from packs/gps-class-features/002982.log rename to packs/gps-class-features/003002.log diff --git a/packs/gps-class-features/002973.ldb b/packs/gps-class-features/003004.ldb similarity index 60% rename from packs/gps-class-features/002973.ldb rename to packs/gps-class-features/003004.ldb index f535487dc7630cf54471ea39a29e87d794b70b95..a55495afc7cc677117ead994cf46abe2b0f198d0 100644 GIT binary patch delta 18076 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 z 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 diff --git a/packs/gps-class-features/CURRENT b/packs/gps-class-features/CURRENT index f7a41738..691c9508 100644 --- a/packs/gps-class-features/CURRENT +++ b/packs/gps-class-features/CURRENT @@ -1 +1 @@ -MANIFEST-002980 +MANIFEST-003000 diff --git a/packs/gps-class-features/LOG b/packs/gps-class-features/LOG index e1750e1b..75330424 100644 --- a/packs/gps-class-features/LOG +++ b/packs/gps-class-features/LOG @@ -1,8 +1,15 @@ -2024/09/17-11:31:04.128 13050 Recovering log #2979 -2024/09/17-11:31:04.133 13050 Delete type=0 #2979 -2024/09/17-11:31:04.133 13050 Delete type=3 #2978 -2024/09/19-01:12:07.686 1147c Level-0 table #2983: started -2024/09/19-01:12:07.687 1147c Level-0 table #2983: 0 bytes OK -2024/09/19-01:12:07.688 1147c Delete type=0 #2981 -2024/09/19-01:12:07.688 1147c Manual compaction at level-0 from '!folders!89rvrtGjpBsZz1Tr' @ 72057594037927935 : 1 .. '!items.effects!ugNmjDFbPNnpG0CG.Z6aK5JHacSpklffP' @ 0 : 0; will stop at (end) -2024/09/19-01:12:07.689 1147c Manual compaction at level-1 from '!folders!89rvrtGjpBsZz1Tr' @ 72057594037927935 : 1 .. '!items.effects!ugNmjDFbPNnpG0CG.Z6aK5JHacSpklffP' @ 0 : 0; will stop at (end) +2024/09/21-16:17:32.981 13050 Recovering log #2998 +2024/09/21-16:17:32.985 13050 Delete type=0 #2998 +2024/09/21-16:17:32.985 13050 Delete type=3 #2996 +2024/09/21-21:27:43.271 1147c Level-0 table #3003: started +2024/09/21-21:27:43.273 1147c Level-0 table #3003: 30022 bytes OK +2024/09/21-21:27:43.275 1147c Delete type=0 #3001 +2024/09/21-21:27:43.281 1147c Manual compaction at level-0 from '!folders!89rvrtGjpBsZz1Tr' @ 72057594037927935 : 1 .. '!items.effects!ugNmjDFbPNnpG0CG.Z6aK5JHacSpklffP' @ 0 : 0; will stop at (end) +2024/09/21-21:27:43.281 1147c Manual compaction at level-1 from '!folders!89rvrtGjpBsZz1Tr' @ 72057594037927935 : 1 .. '!items.effects!ugNmjDFbPNnpG0CG.Z6aK5JHacSpklffP' @ 0 : 0; will stop at '!items!ncM5DuaY4k9S3pII' @ 983 : 1 +2024/09/21-21:27:43.281 1147c Compacting 1@1 + 1@2 files +2024/09/21-21:27:43.286 1147c Generated table #3004@1: 69 keys, 112294 bytes +2024/09/21-21:27:43.286 1147c Compacted 1@1 + 1@2 files => 112294 bytes +2024/09/21-21:27:43.287 1147c compacted to: files[ 0 0 1 0 0 0 0 ] +2024/09/21-21:27:43.287 1147c Delete type=2 #2973 +2024/09/21-21:27:43.287 1147c Delete type=2 #3003 +2024/09/21-21:27:43.294 1147c Manual compaction at level-1 from '!items!ncM5DuaY4k9S3pII' @ 983 : 1 .. '!items.effects!ugNmjDFbPNnpG0CG.Z6aK5JHacSpklffP' @ 0 : 0; will stop at (end) diff --git a/packs/gps-class-features/LOG.old b/packs/gps-class-features/LOG.old index 66da3f3d..8798a756 100644 --- a/packs/gps-class-features/LOG.old +++ b/packs/gps-class-features/LOG.old @@ -1,3 +1,8 @@ -2024/09/17-10:53:01.645 2468 Recovering log #2976 -2024/09/17-10:53:01.650 2468 Delete type=0 #2976 -2024/09/17-10:53:01.650 2468 Delete type=3 #2974 +2024/09/21-16:06:48.791 13054 Recovering log #2994 +2024/09/21-16:06:48.798 13054 Delete type=0 #2994 +2024/09/21-16:06:48.798 13054 Delete type=3 #2992 +2024/09/21-16:14:51.122 1147c Level-0 table #2999: started +2024/09/21-16:14:51.123 1147c Level-0 table #2999: 0 bytes OK +2024/09/21-16:14:51.124 1147c Delete type=0 #2997 +2024/09/21-16:14:51.128 1147c Manual compaction at level-0 from '!folders!89rvrtGjpBsZz1Tr' @ 72057594037927935 : 1 .. '!items.effects!ugNmjDFbPNnpG0CG.Z6aK5JHacSpklffP' @ 0 : 0; will stop at (end) +2024/09/21-16:14:51.129 1147c Manual compaction at level-1 from '!folders!89rvrtGjpBsZz1Tr' @ 72057594037927935 : 1 .. '!items.effects!ugNmjDFbPNnpG0CG.Z6aK5JHacSpklffP' @ 0 : 0; will stop at (end) diff --git a/packs/gps-class-features/MANIFEST-002980 b/packs/gps-class-features/MANIFEST-002980 deleted file mode 100644 index 702d43d1fa2febd1f7de4ccff281d4f2e3238058..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262 zcmeC?F|54Jz{n_-lUkOVlai$8R9TW*o>`pgoS$2eSd>_jU&P8_p_o~cnp>=wnwFND zTvDu<;&0&MlWSpMVp(9~l4|Uv=Ui%RmTH(57L}1(WNKDe!8nhZ0R&hXkyf993l)Qp8va zHVMNGrRjdTSuSo#0e*P}?gq~8dQoPH-lkq2iOInQ**R%x0gOwSz&fAavexEiU}Rb< Z&dI>MOq}H)`;RL>y+9(%Kq4zZA^-%IO)vle diff --git a/packs/gps-class-features/MANIFEST-003000 b/packs/gps-class-features/MANIFEST-003000 new file mode 100644 index 0000000000000000000000000000000000000000..a0c3ac61c49e300befeb791dfbda00aa7c0d2d2b GIT binary patch literal 491 zcmeC?F|54Jz{n_-lUkOVlai$8R9TW*o>`pgoS$2eSd>_jU&P8_p_o~cnp>=wnwFND zTvDu<;&0&MlWSpMVp(9~l4|Uv=Ui%RmTH(57L}1(WNKDe!8nhZ0R&hXkyf993l)Qp8va zHVMNGrRjdTSuSo#0e*P}?gq~8dQoPH-lkq2iOInQ**R%x0gOwSz&anq{S4w}U}V}U z&dI>MOPu8(`>EMe*9HMac7a6ph_l>aXJ_0ke(V+8u|~yau5OvRIh8Is$tfv$mW&r6 zj)i$9FWJ}Br8F_pB-=9BxWLns@j68Qb&tf<=`e%$f(%9k04_ajK&#n+fxynRM|{~^ HS_T9FB@K?) literal 0 HcmV?d00001 diff --git a/packs/gps-generic-features/003034.log b/packs/gps-generic-features/003054.log similarity index 100% rename from packs/gps-generic-features/003034.log rename to packs/gps-generic-features/003054.log diff --git a/packs/gps-generic-features/003025.ldb b/packs/gps-generic-features/003056.ldb similarity index 85% rename from packs/gps-generic-features/003025.ldb rename to packs/gps-generic-features/003056.ldb index be1ea62aba04d24c71976c4b3c953b0ba4262a96..056f569c4cebf65c219d021eccfbc1ca9cbd2095 100644 GIT binary patch delta 1107 zcmZ`&e@q*76#pK!aQ$*U+M~1uwop$%B(%HhwbyIIh%gvG3vX<14j5oK48 z(W7Z)FcTB$03Gp#nUE0XorvR+(-U#~odOcWPOe}PgTk!9hiUYYE|zG02*j4Z27C0E zwOP}{Z6^)4bqf7vlsKfQ2qVC;s<=VQo5ZB(mFQ^$J|xL6sW|6izehS*sfP4)D!JT$J<$dI^!Oii0{*@ zi%Vdjsv5sM;Se+Fcr1)m$z=n}2k=x}oc+pB4-VBm)iMXM@9ZgAr2`%Y!y20C)Ob>o zm1r!DPCve`3ox^hz#+~j15{f;H5J#VIZuEU1@R9r%G!qJPA<*T#}Uw#Ced36Jt zhEwukg<3ICyg}EOUUTR&Nm7AxdAp-EqoxvwyoJk`AYBWMK7dZ1(>Bc9zB>jQKpk>? zeAnEsQ&T(!Hywsi@^=G~N~cq67YK)x6v-KgS*q$Fp+=EP4nUyjD@+PXNRA&j$#=97 zss;;c6IA`Qu@sl$B6%G4`~iq`?64Fm!mLzj$K4wQeX&%BlKKrGJ6|{E>6KD^JStIB zg#Bn?f-1?_oON$0h<^DelpN%5u=`ei8{Utz+pz8kh~{(feoW<{juZaQtmG`PIoT8S zj-(jxNcaA+p@UtI)#o&}-0jT4`9kGn6LlWuul+Bq*LG^$+I+c>bub>5V;R5SmtTPA z7hua?2xxMfA{QX=l4s!h0^9`(g6-(J)1k`jujOZ`qFEt(qP`usT-hDV40aCi?)1|K z+cGJ3kiizU>#k3+4(+WyM~XZ`wuWhZfN(_!tBwGPsvJ3`^>Y05e>q^iScVrU(5k(> z!+c7x zWlwIAAQpIqL{g#a`c3lR)!ztaPGmQ^s}}R6MJ)QyMZk@%##!yNF1qEX@=6;RHrt2~ z8|Lc@?wHwTxzf8*4eZ7ayGx2hq_Da>OgtC+ynKHRsA$>s?K8g^fk9834=j8!uQhhp i8b>;DInIo+Q+*hM-(Edwq>xftkdv95SdywI&ajY!BR?mlaU!RhNPK3Bl9iI3 z^W@orQXFo9H7r&JjS7?Z3d(y<UUP=T)|km^LdMSPIF)vB zvLq@T-7FZuQj%}BoAcx?&UC(woILpj1^EYacob6eQuwU67)7M+bMlmAB$n{;axoOM ziV74b=B6sVUCft0d5(}gBj4mbLTdHLxj0gDQuu7Sy#6ro6l7+nrZF*!o#Ar*dGMH0 z9yd#39_u59BHhKj|C9>2Im$Cqg)Dd^DuFhXq!uxDihbu|$hfwhD^-DSJ(uUZf19|F z(X>rms$~or|2A+Tqq+@TEXEcPk!>3$CkhKQZkSvuY^1({s|zSqt0R=c^=}GJ6g2sY zu(^?nfr+89p@F5Px#hnJT+1eK+1YY2DDiC);+w$5V9M9eb!Y;Y3I;GA2Xw&1nW& z%q)CQIIm5fV{BHhsQD>?Z6%A)GCmteqmaDP@~p53*AR~Y!yXKX z&tza|Ze(O=X<=?+W@%{bb(K#AoWv~5j1A5DuJT1K<73FQ3g%0c2O4!~As@n(8}45> znWPF#{I7)+GfPr)ixrE@yc2`c{7U>Id^gWG*)Afud;((z%vTJ%4zfy5PWM!@TP7?i z&JZpr&huHlOBKk>5)>C{@_i)5Ai?V@p_iJLmYQ55o6Pev{fe-gJcFp6%%SR!ybPSI xN`ih9c63fY?y17NZT|B~QzkMRo|?$m%s83ROKh@$7dsaNL-_B8Zk1B^+W-d!E8YMA diff --git a/packs/gps-generic-features/CURRENT b/packs/gps-generic-features/CURRENT index dc420445..20fde705 100644 --- a/packs/gps-generic-features/CURRENT +++ b/packs/gps-generic-features/CURRENT @@ -1 +1 @@ -MANIFEST-003032 +MANIFEST-003052 diff --git a/packs/gps-generic-features/LOG b/packs/gps-generic-features/LOG index 6263508a..58b0b150 100644 --- a/packs/gps-generic-features/LOG +++ b/packs/gps-generic-features/LOG @@ -1,8 +1,15 @@ -2024/09/17-11:31:04.154 13058 Recovering log #3031 -2024/09/17-11:31:04.159 13058 Delete type=0 #3031 -2024/09/17-11:31:04.159 13058 Delete type=3 #3030 -2024/09/19-01:12:07.692 1147c Level-0 table #3035: started -2024/09/19-01:12:07.693 1147c Level-0 table #3035: 0 bytes OK -2024/09/19-01:12:07.694 1147c Delete type=0 #3033 -2024/09/19-01:12:07.699 1147c Manual compaction at level-0 from '!items!0XoQ7lGPSwjM8Gw4' @ 72057594037927935 : 1 .. '!items.effects!svKaRfNtOXMOXoW6.NcYMpQ7B3RwBuLC7' @ 0 : 0; will stop at (end) -2024/09/19-01:12:07.699 1147c Manual compaction at level-1 from '!items!0XoQ7lGPSwjM8Gw4' @ 72057594037927935 : 1 .. '!items.effects!svKaRfNtOXMOXoW6.NcYMpQ7B3RwBuLC7' @ 0 : 0; will stop at (end) +2024/09/21-16:17:33.005 1304c Recovering log #3050 +2024/09/21-16:17:33.009 1304c Delete type=0 #3050 +2024/09/21-16:17:33.009 1304c Delete type=3 #3048 +2024/09/21-21:27:43.294 1147c Level-0 table #3055: started +2024/09/21-21:27:43.296 1147c Level-0 table #3055: 5912 bytes OK +2024/09/21-21:27:43.298 1147c Delete type=0 #3053 +2024/09/21-21:27:43.300 1147c Manual compaction at level-0 from '!items!0XoQ7lGPSwjM8Gw4' @ 72057594037927935 : 1 .. '!items.effects!svKaRfNtOXMOXoW6.NcYMpQ7B3RwBuLC7' @ 0 : 0; will stop at (end) +2024/09/21-21:27:43.302 1147c Manual compaction at level-1 from '!items!0XoQ7lGPSwjM8Gw4' @ 72057594037927935 : 1 .. '!items.effects!svKaRfNtOXMOXoW6.NcYMpQ7B3RwBuLC7' @ 0 : 0; will stop at '!items!iuUGS62pqYBuo1U0' @ 656 : 1 +2024/09/21-21:27:43.302 1147c Compacting 1@1 + 1@2 files +2024/09/21-21:27:43.304 1147c Generated table #3056@1: 14 keys, 18975 bytes +2024/09/21-21:27:43.304 1147c Compacted 1@1 + 1@2 files => 18975 bytes +2024/09/21-21:27:43.306 1147c compacted to: files[ 0 0 1 0 0 0 0 ] +2024/09/21-21:27:43.306 1147c Delete type=2 #3025 +2024/09/21-21:27:43.306 1147c Delete type=2 #3055 +2024/09/21-21:27:43.307 1147c Manual compaction at level-1 from '!items!iuUGS62pqYBuo1U0' @ 656 : 1 .. '!items.effects!svKaRfNtOXMOXoW6.NcYMpQ7B3RwBuLC7' @ 0 : 0; will stop at (end) diff --git a/packs/gps-generic-features/LOG.old b/packs/gps-generic-features/LOG.old index b55e0230..d1f2855f 100644 --- a/packs/gps-generic-features/LOG.old +++ b/packs/gps-generic-features/LOG.old @@ -1,3 +1,8 @@ -2024/09/17-10:53:01.677 60f8 Recovering log #3028 -2024/09/17-10:53:01.682 60f8 Delete type=0 #3028 -2024/09/17-10:53:01.682 60f8 Delete type=3 #3026 +2024/09/21-16:06:48.819 13050 Recovering log #3046 +2024/09/21-16:06:48.823 13050 Delete type=0 #3046 +2024/09/21-16:06:48.823 13050 Delete type=3 #3044 +2024/09/21-16:14:51.137 1147c Level-0 table #3051: started +2024/09/21-16:14:51.137 1147c Level-0 table #3051: 0 bytes OK +2024/09/21-16:14:51.139 1147c Delete type=0 #3049 +2024/09/21-16:14:51.140 1147c Manual compaction at level-0 from '!items!0XoQ7lGPSwjM8Gw4' @ 72057594037927935 : 1 .. '!items.effects!svKaRfNtOXMOXoW6.NcYMpQ7B3RwBuLC7' @ 0 : 0; will stop at (end) +2024/09/21-16:14:51.140 1147c Manual compaction at level-1 from '!items!0XoQ7lGPSwjM8Gw4' @ 72057594037927935 : 1 .. '!items.effects!svKaRfNtOXMOXoW6.NcYMpQ7B3RwBuLC7' @ 0 : 0; will stop at (end) diff --git a/packs/gps-generic-features/MANIFEST-003032 b/packs/gps-generic-features/MANIFEST-003032 deleted file mode 100644 index 0ba14ea385af0f966ccec52aafdee9521778fe39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmaEm`{w=u21Z7yoYb<^oRlOzr^=Gl^338?=ltA)#G=HK{32EcdBx0<)ZAjlln}RM zACI77pNevmAoGAgMq4HZ5MX75sR)Zm3Gxf_@r?@0@~U)nt77bfs9`$1roUf5&-}y%0ol| diff --git a/packs/gps-generic-features/MANIFEST-003052 b/packs/gps-generic-features/MANIFEST-003052 new file mode 100644 index 0000000000000000000000000000000000000000..7084d16cf700332f8180b109099f7ea20feab77d GIT binary patch literal 461 zcmaEm`{w=u21Z7yoYb<^oRlOzr^=Gl^338?=ltA)#G=HK{32EcdBx0<)ZAjlln}RM zACI77pNevmAoGAgMq4HZ5MX75sR)Zm3Gxf_@r?@0@~U)nt77bfs9 42455 bytes -2024/09/19-01:12:07.719 1147c compacted to: files[ 0 0 1 0 0 0 0 ] -2024/09/19-01:12:07.719 1147c Delete type=2 #2921 -2024/09/19-01:12:07.720 1147c Delete type=2 #2945 -2024/09/19-01:12:07.725 1147c Manual compaction at level-1 from '!items.effects!CoYpAaVmu8WymKah.fRzfKB7OFT8zJ2aH' @ 513 : 1 .. '!items.effects!zEXJxqsAmVM7Pohu.v3j3orDGcbQyk7ZI' @ 0 : 0; will stop at (end) +2024/09/21-16:17:33.016 13058 Recovering log #2961 +2024/09/21-16:17:33.020 13058 Delete type=0 #2961 +2024/09/21-16:17:33.020 13058 Delete type=3 #2959 +2024/09/21-21:27:43.300 1147c Level-0 table #2966: started +2024/09/21-21:27:43.300 1147c Level-0 table #2966: 0 bytes OK +2024/09/21-21:27:43.302 1147c Delete type=0 #2964 +2024/09/21-21:27:43.307 1147c Manual compaction at level-0 from '!items!1WSJjnpLJhilXEgO' @ 72057594037927935 : 1 .. '!items.effects!zEXJxqsAmVM7Pohu.v3j3orDGcbQyk7ZI' @ 0 : 0; will stop at (end) +2024/09/21-21:27:43.307 1147c Manual compaction at level-1 from '!items!1WSJjnpLJhilXEgO' @ 72057594037927935 : 1 .. '!items.effects!zEXJxqsAmVM7Pohu.v3j3orDGcbQyk7ZI' @ 0 : 0; will stop at (end) diff --git a/packs/gps-homebrew-items/LOG.old b/packs/gps-homebrew-items/LOG.old index 4dea24af..a8037b14 100644 --- a/packs/gps-homebrew-items/LOG.old +++ b/packs/gps-homebrew-items/LOG.old @@ -1,3 +1,8 @@ -2024/09/17-10:53:01.693 1df4 Recovering log #2938 -2024/09/17-10:53:01.698 1df4 Delete type=0 #2938 -2024/09/17-10:53:01.698 1df4 Delete type=3 #2936 +2024/09/21-16:06:48.830 13058 Recovering log #2957 +2024/09/21-16:06:48.834 13058 Delete type=0 #2957 +2024/09/21-16:06:48.834 13058 Delete type=3 #2955 +2024/09/21-16:14:51.141 1147c Level-0 table #2962: started +2024/09/21-16:14:51.141 1147c Level-0 table #2962: 0 bytes OK +2024/09/21-16:14:51.143 1147c Delete type=0 #2960 +2024/09/21-16:14:51.151 1147c Manual compaction at level-0 from '!items!1WSJjnpLJhilXEgO' @ 72057594037927935 : 1 .. '!items.effects!zEXJxqsAmVM7Pohu.v3j3orDGcbQyk7ZI' @ 0 : 0; will stop at (end) +2024/09/21-16:14:51.151 1147c Manual compaction at level-1 from '!items!1WSJjnpLJhilXEgO' @ 72057594037927935 : 1 .. '!items.effects!zEXJxqsAmVM7Pohu.v3j3orDGcbQyk7ZI' @ 0 : 0; will stop at (end) diff --git a/packs/gps-homebrew-items/MANIFEST-002942 b/packs/gps-homebrew-items/MANIFEST-002942 deleted file mode 100644 index e42c04d04e46d8c694943eb90ebf7420b6c30250..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 511 zcmXT-@%KK!z{n_-lUkOVlai$8R9TW*o>`pgoS$2eSd>_jU&P8Fub5eqnp>=BX_9Ih zP#PZQTAr9#kRBe%sKCeo0<4U16=8WUt3Phug>ZUYq21cg;Vw?=j4dN^fEcf>tm1hA(8pMGjP2w!AEbNSp z;%if3PH@hTEO1N=%PqACugvvM%wS|?0{aEs3Fzwd(t@heyq(Pb-9jv?yo?e(7#SfN j*9mUjwhm@tGsr?#MzRfK1G<$B7-sBDP2$&2(=OZqmO+vc diff --git a/packs/gps-homebrew-items/MANIFEST-002963 b/packs/gps-homebrew-items/MANIFEST-002963 new file mode 100644 index 0000000000000000000000000000000000000000..467c0fb01fcd33c47ceec7bc661c8ed47013b4c9 GIT binary patch literal 260 zcmX>)?Y7@d21Z7yoYb<^oRlOzr^=Gl^338?=ltA)#G=HK{32EcdBx0<)ZAi4OOsU7 zfYR_V*Yd=~g7ol6Mg>L&5MX7rfT++*O-oBnE-6-Y&W|i`Obp8{wFs}w^-j#tOAD$> z^L8@#cMGwo@-j;FU}R(hYh`C@62E?$31)*~c(7MiUV)ESMrKZgYq~#UHpB*W^Q&AV zyebNd9dpBc%>(i?O7+T&vyAhLT-=kB0xPr4qdXa}K%KTcc_lXkBhwUdP6pghJUX`24dZ)M<7?}=;a569-6k*xUc;MG10g%W+kjP<>2mnN-4F>=K delta 43 tcmaFJ_>ghJUX=wGowjf@Ffy$X;bdT5E5fp!@n_ZXUm%gSAd&ST5dcoz4T1mw diff --git a/packs/gps-items/002943.log b/packs/gps-items/002963.log similarity index 100% rename from packs/gps-items/002943.log rename to packs/gps-items/002963.log diff --git a/packs/gps-items/CURRENT b/packs/gps-items/CURRENT index 6cf77b28..788ee915 100644 --- a/packs/gps-items/CURRENT +++ b/packs/gps-items/CURRENT @@ -1 +1 @@ -MANIFEST-002941 +MANIFEST-002961 diff --git a/packs/gps-items/LOG b/packs/gps-items/LOG index bf506110..5a3568ae 100644 --- a/packs/gps-items/LOG +++ b/packs/gps-items/LOG @@ -1,8 +1,8 @@ -2024/09/17-11:31:04.136 13058 Recovering log #2940 -2024/09/17-11:31:04.140 13058 Delete type=0 #2940 -2024/09/17-11:31:04.140 13058 Delete type=3 #2939 -2024/09/19-01:12:07.690 1147c Level-0 table #2944: started -2024/09/19-01:12:07.690 1147c Level-0 table #2944: 0 bytes OK -2024/09/19-01:12:07.692 1147c Delete type=0 #2942 -2024/09/19-01:12:07.699 1147c Manual compaction at level-0 from '!items!0qTQDQ2Cipf15JGW' @ 72057594037927935 : 1 .. '!items.effects!wds22ulA8PSTvYWP.ZrTNMwai89gqFKJo' @ 0 : 0; will stop at (end) -2024/09/19-01:12:07.699 1147c Manual compaction at level-1 from '!items!0qTQDQ2Cipf15JGW' @ 72057594037927935 : 1 .. '!items.effects!wds22ulA8PSTvYWP.ZrTNMwai89gqFKJo' @ 0 : 0; will stop at (end) +2024/09/21-16:17:32.988 13058 Recovering log #2959 +2024/09/21-16:17:32.992 13058 Delete type=0 #2959 +2024/09/21-16:17:32.992 13058 Delete type=3 #2957 +2024/09/21-21:27:43.275 1147c Level-0 table #2964: started +2024/09/21-21:27:43.275 1147c Level-0 table #2964: 0 bytes OK +2024/09/21-21:27:43.277 1147c Delete type=0 #2962 +2024/09/21-21:27:43.281 1147c Manual compaction at level-0 from '!items!0qTQDQ2Cipf15JGW' @ 72057594037927935 : 1 .. '!items.effects!wds22ulA8PSTvYWP.ZrTNMwai89gqFKJo' @ 0 : 0; will stop at (end) +2024/09/21-21:27:43.287 1147c Manual compaction at level-1 from '!items!0qTQDQ2Cipf15JGW' @ 72057594037927935 : 1 .. '!items.effects!wds22ulA8PSTvYWP.ZrTNMwai89gqFKJo' @ 0 : 0; will stop at (end) diff --git a/packs/gps-items/LOG.old b/packs/gps-items/LOG.old index 2e2fd15d..4f29c959 100644 --- a/packs/gps-items/LOG.old +++ b/packs/gps-items/LOG.old @@ -1,3 +1,8 @@ -2024/09/17-10:53:01.653 60f8 Recovering log #2937 -2024/09/17-10:53:01.658 60f8 Delete type=0 #2937 -2024/09/17-10:53:01.658 60f8 Delete type=3 #2935 +2024/09/21-16:06:48.802 13058 Recovering log #2955 +2024/09/21-16:06:48.805 13058 Delete type=0 #2955 +2024/09/21-16:06:48.806 13058 Delete type=3 #2953 +2024/09/21-16:14:51.130 1147c Level-0 table #2960: started +2024/09/21-16:14:51.130 1147c Level-0 table #2960: 0 bytes OK +2024/09/21-16:14:51.133 1147c Delete type=0 #2958 +2024/09/21-16:14:51.140 1147c Manual compaction at level-0 from '!items!0qTQDQ2Cipf15JGW' @ 72057594037927935 : 1 .. '!items.effects!wds22ulA8PSTvYWP.ZrTNMwai89gqFKJo' @ 0 : 0; will stop at (end) +2024/09/21-16:14:51.140 1147c Manual compaction at level-1 from '!items!0qTQDQ2Cipf15JGW' @ 72057594037927935 : 1 .. '!items.effects!wds22ulA8PSTvYWP.ZrTNMwai89gqFKJo' @ 0 : 0; will stop at (end) diff --git a/packs/gps-items/MANIFEST-002941 b/packs/gps-items/MANIFEST-002961 similarity index 63% rename from packs/gps-items/MANIFEST-002941 rename to packs/gps-items/MANIFEST-002961 index 64080efa8b08e4fc5ac677b0f67ffed554fad7cf..f197d23e74ec3e460e7212e3ebe4e17e0028891c 100644 GIT binary patch delta 43 tcmX@fc#?6#QkCAg2Zh`Wj7*cnIT@HIi?iHhUcbR>9!O*|NMtHV1OO|k3=RMQ delta 43 ucmX@fc#?6#QkA5YI*Yj(7@7WwaWXLf7h}1}{3&z$8j#3;kVvCAPy_%!Ck;>l diff --git a/packs/gps-monster-features/002937.log b/packs/gps-monster-features/002957.log similarity index 100% rename from packs/gps-monster-features/002937.log rename to packs/gps-monster-features/002957.log diff --git a/packs/gps-monster-features/CURRENT b/packs/gps-monster-features/CURRENT index 8c0950dc..449eea24 100644 --- a/packs/gps-monster-features/CURRENT +++ b/packs/gps-monster-features/CURRENT @@ -1 +1 @@ -MANIFEST-002935 +MANIFEST-002955 diff --git a/packs/gps-monster-features/LOG b/packs/gps-monster-features/LOG index 792b47cd..0de0aa8e 100644 --- a/packs/gps-monster-features/LOG +++ b/packs/gps-monster-features/LOG @@ -1,8 +1,8 @@ -2024/09/17-11:31:04.149 13050 Recovering log #2934 -2024/09/17-11:31:04.152 13050 Delete type=0 #2934 -2024/09/17-11:31:04.152 13050 Delete type=3 #2933 -2024/09/19-01:12:07.697 1147c Level-0 table #2938: started -2024/09/19-01:12:07.697 1147c Level-0 table #2938: 0 bytes OK -2024/09/19-01:12:07.699 1147c Delete type=0 #2936 -2024/09/19-01:12:07.699 1147c Manual compaction at level-0 from '!folders!44lJ4L7xySVYZzED' @ 72057594037927935 : 1 .. '!items.effects!yp0IIuvsEkJd6KKW.WlySPDKKWMIOowHi' @ 0 : 0; will stop at (end) -2024/09/19-01:12:07.699 1147c Manual compaction at level-1 from '!folders!44lJ4L7xySVYZzED' @ 72057594037927935 : 1 .. '!items.effects!yp0IIuvsEkJd6KKW.WlySPDKKWMIOowHi' @ 0 : 0; will stop at (end) +2024/09/21-16:17:33.000 13050 Recovering log #2953 +2024/09/21-16:17:33.003 13050 Delete type=0 #2953 +2024/09/21-16:17:33.003 13050 Delete type=3 #2951 +2024/09/21-21:27:43.292 1147c Level-0 table #2958: started +2024/09/21-21:27:43.292 1147c Level-0 table #2958: 0 bytes OK +2024/09/21-21:27:43.293 1147c Delete type=0 #2956 +2024/09/21-21:27:43.298 1147c Manual compaction at level-0 from '!folders!44lJ4L7xySVYZzED' @ 72057594037927935 : 1 .. '!items.effects!yp0IIuvsEkJd6KKW.WlySPDKKWMIOowHi' @ 0 : 0; will stop at (end) +2024/09/21-21:27:43.300 1147c Manual compaction at level-1 from '!folders!44lJ4L7xySVYZzED' @ 72057594037927935 : 1 .. '!items.effects!yp0IIuvsEkJd6KKW.WlySPDKKWMIOowHi' @ 0 : 0; will stop at (end) diff --git a/packs/gps-monster-features/LOG.old b/packs/gps-monster-features/LOG.old index d94c69a1..c2e3f5ea 100644 --- a/packs/gps-monster-features/LOG.old +++ b/packs/gps-monster-features/LOG.old @@ -1,3 +1,8 @@ -2024/09/17-10:53:01.668 1df4 Recovering log #2931 -2024/09/17-10:53:01.674 1df4 Delete type=0 #2931 -2024/09/17-10:53:01.674 1df4 Delete type=3 #2929 +2024/09/21-16:06:48.813 13054 Recovering log #2949 +2024/09/21-16:06:48.817 13054 Delete type=0 #2949 +2024/09/21-16:06:48.817 13054 Delete type=3 #2947 +2024/09/21-16:14:51.135 1147c Level-0 table #2954: started +2024/09/21-16:14:51.135 1147c Level-0 table #2954: 0 bytes OK +2024/09/21-16:14:51.137 1147c Delete type=0 #2952 +2024/09/21-16:14:51.140 1147c Manual compaction at level-0 from '!folders!44lJ4L7xySVYZzED' @ 72057594037927935 : 1 .. '!items.effects!yp0IIuvsEkJd6KKW.WlySPDKKWMIOowHi' @ 0 : 0; will stop at (end) +2024/09/21-16:14:51.140 1147c Manual compaction at level-1 from '!folders!44lJ4L7xySVYZzED' @ 72057594037927935 : 1 .. '!items.effects!yp0IIuvsEkJd6KKW.WlySPDKKWMIOowHi' @ 0 : 0; will stop at (end) diff --git a/packs/gps-monster-features/MANIFEST-002935 b/packs/gps-monster-features/MANIFEST-002955 similarity index 66% rename from packs/gps-monster-features/MANIFEST-002935 rename to packs/gps-monster-features/MANIFEST-002955 index ec23af0d46dfa203207ab4d364a612a3ffc38e35..8c9da18a400f8f487a8f6739205321110c2c1a8a 100644 GIT binary patch delta 43 tcmbQwG@oh0ZghJex;e`w(4;)FfvVHghJex*6pKQC}GFfui;axySCva-nee@x2&2{eKPnt=iU9a{>s diff --git a/packs/gps-spells/003026.log b/packs/gps-spells/003047.log similarity index 100% rename from packs/gps-spells/003026.log rename to packs/gps-spells/003047.log diff --git a/packs/gps-spells/003003.ldb b/packs/gps-spells/003049.ldb similarity index 91% rename from packs/gps-spells/003003.ldb rename to packs/gps-spells/003049.ldb index 6bcd0499d278ce65c64ad79d087314a44862625c..895044ff1644b4eb9ea9063853e7d24859d5baca 100644 GIT binary patch delta 6734 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 154092 bytes +2024/09/21-21:27:43.271 1147c compacted to: files[ 0 0 1 0 0 0 0 ] +2024/09/21-21:27:43.271 1147c Delete type=2 #3036 +2024/09/21-21:27:43.271 1147c Delete type=2 #3048 +2024/09/21-21:27:43.281 1147c Manual compaction at level-1 from '!items!U9ZIV2vqOstvPzUo' @ 1750 : 1 .. '!items.effects!zb0bHX95fRFILazJ.2TVoFB98ZtniR8Z7' @ 0 : 0; will stop at (end) diff --git a/packs/gps-spells/LOG.old b/packs/gps-spells/LOG.old index 423777a9..91ebc99b 100644 --- a/packs/gps-spells/LOG.old +++ b/packs/gps-spells/LOG.old @@ -1,3 +1,8 @@ -2024/09/17-10:53:01.635 19cc Recovering log #3020 -2024/09/17-10:53:01.640 19cc Delete type=0 #3020 -2024/09/17-10:53:01.640 19cc Delete type=3 #3018 +2024/09/21-16:06:48.780 13050 Recovering log #3039 +2024/09/21-16:06:48.785 13050 Delete type=0 #3039 +2024/09/21-16:06:48.785 13050 Delete type=3 #3037 +2024/09/21-16:14:51.124 1147c Level-0 table #3044: started +2024/09/21-16:14:51.124 1147c Level-0 table #3044: 0 bytes OK +2024/09/21-16:14:51.126 1147c Delete type=0 #3042 +2024/09/21-16:14:51.128 1147c Manual compaction at level-0 from '!items!0gEfNrgZuAxvnL5H' @ 72057594037927935 : 1 .. '!items.effects!zb0bHX95fRFILazJ.2TVoFB98ZtniR8Z7' @ 0 : 0; will stop at (end) +2024/09/21-16:14:51.129 1147c Manual compaction at level-1 from '!items!0gEfNrgZuAxvnL5H' @ 72057594037927935 : 1 .. '!items.effects!zb0bHX95fRFILazJ.2TVoFB98ZtniR8Z7' @ 0 : 0; will stop at (end) diff --git a/packs/gps-spells/MANIFEST-003024 b/packs/gps-spells/MANIFEST-003024 deleted file mode 100644 index 174219dab657c91fcaa81171a5116cba9a8804c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmbRGq(Sfi10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei18!ykcfaYHqP&VVS>2 zo}YP8aBh-Upjl=h<5D&T5MX7*sp29;1v}Gj@e`XkVag2BUDN!E(xXZpE6VbGOg$JQ zSiuHaKrGTrO-oBnE-6;5N-{|Dh_EzG3v%=HNv!hHGYSdIcXP6|h$_j;46=waXPnFe l*7#!Dg(=(&j7%5BIT@HQiL+edJ*}>s0TQ_c61f5r0RRGPL{9(! diff --git a/packs/gps-spells/MANIFEST-003045 b/packs/gps-spells/MANIFEST-003045 new file mode 100644 index 0000000000000000000000000000000000000000..6905531d229dffc437661afb8d4b1490f5a876c7 GIT binary patch literal 461 zcmdPBI#u@o10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei18!ykcfaYHqP&VVS>2 zo}YP8aBh-Upjl=h<5D&T5MX75sW478F)+*x^-JlS_&ftC9?oJR&Sj(}LVQeG;p@^o&Bn z^4**)Euu>DGJ`Cl%o!)MfHm&<^MRk6fsyH%I41-1b8(idy!R6>WCQ|5o`XbQinHA0 zWoLXLzCju01QUy_bYGWJzm%`*jEu%ccjLHiAi%ZG^szUP_uR-Kh ig0t$T!pwaIG8f@{Tzc4mHnRakfSu{3_?ykN3k3kJd4)Fs literal 0 HcmV?d00001 diff --git a/scripts/helpers.js b/scripts/helpers.js index f5434542..64ec8ba6 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -174,12 +174,14 @@ export function convertFromFeet({ range }) { return range * conversionFactor; } -export async function handleDialogPromises(userDialogArgs, gmDialogArgs) { +export async function handleDialogPromises({userDialogArgs, gmDialogArgs}) { if(!userDialogArgs || !gmDialogArgs) return; + console.log(userDialogArgs) + console.log(gmDialogArgs) const module = await import('./module.js'); const socket = module.socket; let userDialogPromise = socket.executeAsUser("process3rdPartyReactionDialog", userDialogArgs.browserUser, userDialogArgs); - let gmDialogPromise = process3rdPartyReactionDialog(gmDialogArgs); + let gmDialogPromise = socket.executeAsUser("process3rdPartyReactionDialog", getPrimaryGM(), gmDialogArgs); return new Promise((resolve, reject) => { let userResolved = false; @@ -232,7 +234,7 @@ export function findValidTokens({initiatingToken, targetedToken, itemName, itemT } let checkItem; if(gpsUuid) checkItem = t?.actor?.items?.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); - else checkItem = t?.actor?.items?.find(i => i.name.toLowerCase() === itemName); + else checkItem = t?.actor?.items?.find(i => i.name.toLowerCase() === itemName.toLowerCase()); const effectNamesOrigin = ["Confusion", "Arms of Hadar", "Shocking Grasp", "Slow", "Staggering Smite"]; let hasEffectOrigin = t?.actor?.appliedEffects.some(effect => effectNamesOrigin.includes(effect.name)); let measuredDistance = (dispositionCheckType === "ally" || dispositionCheckType === "enemyAlly") ? MidiQOL.computeDistance(targetedToken,t,true) : MidiQOL.computeDistance(initiatingToken,t,true); @@ -352,12 +354,13 @@ export function findValidTokens({initiatingToken, targetedToken, itemName, itemT return validTokens; } -export async function process3rdPartyReactionDialog({ dialogTitle, dialogContent, dialogId, initialTimeLeft, validTokenPrimaryUuid, source, type }) { +export async function process3rdPartyReactionDialog({ dialogTitle, dialogContent, dialogId, initialTimeLeft, validTokenPrimaryUuid, source, type, notificationId }) { + console.log("made it to 3rd party dialog") const module = await import('./module.js'); const socket = module.socket; let validTokenPrimary = await fromUuid(validTokenPrimaryUuid); - let browserUser = MidiQOL.playerForActor(validTokenPrimary?.actor); - if (!browserUser.active) browserUser = game.users?.activeGM; + let browserUser = getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); + console.log(browserUser, "3rd party dialog browseruser") let dialogState = { interacted: false, decision: null, programmaticallyClosed: false, dialogId: dialogId }; let result = null; @@ -396,9 +399,9 @@ export async function process3rdPartyReactionDialog({ dialogTitle, dialogContent const pauseState = { dialogId: dialogId, timeLeft: dialog.timeLeft, isPaused: dialog.isPaused }; if (source === "user" && type === "multiDialog") { - socket.executeAsGM("pauseDialogById", pauseState); + socket.executeAsUser("pauseDialogById", getPrimaryGM(), pauseState); } else if (source === "gm" && type === "multiDialog") { - socket.executeAsUser("pauseDialogById", browserUser.id, pauseState); + socket.executeAsUser("pauseDialogById", browserUser, pauseState); } } @@ -495,10 +498,11 @@ export async function process3rdPartyReactionDialog({ dialogTitle, dialogContent action: "yes", label: "Yes", callback: async (event, button, dialog) => { + await socket.executeAsUser("deleteChatMessage", getPrimaryGM(), {chatId: notificationId}); dialogState.interacted = true; dialogState.decision = "yes"; - if (source && source === "user" && type === "multiDialog") await socket.executeAsGM("closeDialogById", { dialogId: dialogId }); - else if (source && source === "gm" && type === "multiDialog") await socket.executeAsUser("closeDialogById", browserUser.id, { dialogId: dialogId }); + if (source && source === "user" && type === "multiDialog") await socket.executeAsUser("closeDialogById", getPrimaryGM(), { dialogId: dialogId }); + else if (source && source === "gm" && type === "multiDialog") await socket.executeAsUser("closeDialogById", browserUser, { dialogId: dialogId }); let enemyTokenUuid = button.form?.elements["enemy-token"]?.value ?? false; let allyTokenUuid = button.form?.elements["ally-token"]?.value ?? false; @@ -529,10 +533,11 @@ export async function process3rdPartyReactionDialog({ dialogTitle, dialogContent label: `No`, default: true, callback: async (event, button, dialog) => { + await socket.executeAsUser("deleteChatMessage", getPrimaryGM(), {chatId: notificationId}); dialogState.interacted = true; dialogState.decision = "no"; - if(source && source === "user" && type === "multiDialog") await socket.executeAsGM("closeDialogById", { dialogId: dialogId }); - else if(source && source === "gm" && type === "multiDialog") await socket.executeAsUser("closeDialogById", browserUser.id, { dialogId: dialogId }); + if(source && source === "user" && type === "multiDialog") await socket.executeAsUser("closeDialogById", getPrimaryGM(), { dialogId: dialogId }); + else if(source && source === "gm" && type === "multiDialog") await socket.executeAsUser("closeDialogById", browserUser, { dialogId: dialogId }); let enemyTokenUuid = button.form?.elements["enemy-token"]?.value ?? false; @@ -626,8 +631,8 @@ export async function process3rdPartyReactionDialog({ dialogTitle, dialogContent if (dialog.dialogState.programmaticallyClosed) result = ({ userDecision: false, programmaticallyClosed: true, source, type }); else if (!dialog.dialogState.interacted) result = ({ userDecision: false, programmaticallyClosed: false, source, type }); - if(source && source === "user" && type === "multiDialog" && !dialog.dialogState.programmaticallyClosed) await socket.executeAsGM("closeDialogById", { dialogId: dialogId }); - else if(source && source === "gm" && type === "multiDialog" && !dialog.dialogState.programmaticallyClosed) await socket.executeAsUser("closeDialogById", browserUser.id, { dialogId: dialogId }); + if(source && source === "user" && type === "multiDialog" && !dialog.dialogState.programmaticallyClosed) await socket.executeAsUser("closeDialogById", getPrimaryGM(), { dialogId: dialogId }); + else if(source && source === "gm" && type === "multiDialog" && !dialog.dialogState.programmaticallyClosed) await socket.executeAsUser("closeDialogById", browserUser, { dialogId: dialogId }); }, rejectClose:false }); return result; @@ -774,6 +779,9 @@ export async function moveTokenByCardinal({ targetUuid, distance, direction }) { let moveX = 0; let moveY = 0; + const initialX = target.x; + const initialY = target.y; + switch (direction) { case "North": moveY = -moveDistancePixels; @@ -841,20 +849,20 @@ export async function moveTokenByCardinal({ targetUuid, distance, direction }) { break; } - let newX = target.x + moveX; - let newY = target.y + moveY; + let finalX = target.x + moveX; + let finalY = target.y + moveY; if (canvas.scene.grid.type === 1) { - const snapped = canvas.scene.grid.getSnappedPoint({ x: newX, y: newY }, { mode: 0xFF0, resolution: 1 }); - newX = snapped.x; - newY = snapped.y; + const snapped = canvas.scene.grid.getSnappedPoint({ x: finalX, y: finalY }, { mode: 0xFF0, resolution: 1 }); + finalX = snapped.x; + finalY = snapped.y; } - let endPoint = new PIXI.Point(newX, newY); + let endPoint = new PIXI.Point(finalX, finalY); let collisionDetected = CONFIG.Canvas.polygonBackends.move.testCollision(target.center, endPoint, { type: "move", mode: "any" }); if (!collisionDetected) { - await target.document.update({ x: newX, y: newY }); + await target.document.update({ x: finalX, y: finalY }); } else { let directionVector = { x: moveX, y: moveY }; let magnitude = Math.hypot(directionVector.x, directionVector.y); @@ -882,8 +890,8 @@ export async function moveTokenByCardinal({ targetUuid, distance, direction }) { stepCounter = step; } - let finalX = target.x + directionVector.x * (canvas.scene.grid.size / 10) * stepCounter; - let finalY = target.y + directionVector.y * (canvas.scene.grid.size / 10) * stepCounter; + finalX = target.x + directionVector.x * (canvas.scene.grid.size / 10) * stepCounter; + finalY = target.y + directionVector.y * (canvas.scene.grid.size / 10) * stepCounter; if (stepCounter > 0) { if (canvas.scene.grid.type === 1) { @@ -894,6 +902,38 @@ export async function moveTokenByCardinal({ targetUuid, distance, direction }) { await target.document.update({ x: finalX, y: finalY }); } } + + let totalDistanceMoved; + + const dx = Math.abs(finalX - initialX) / canvas.grid.size; + const dy = Math.abs(finalY - initialY) / canvas.grid.size; + const diagonalSteps = Math.min(dx, dy); + const straightSteps = Math.abs(dx - dy); + + switch (gridDiagonals) { + case 0: // Equidistant + totalDistanceMoved = (diagonalSteps + straightSteps) * gridDistance; + break; + case 1: // Exact + totalDistanceMoved = Math.hypot(finalX - initialX, finalY - initialY) / pixelsPerFoot; + break; + case 2: // 1.5x cost for diagonals + totalDistanceMoved = (diagonalSteps * 1.5 + straightSteps) * gridDistance; + break; + case 3: // 2x cost for diagonals + totalDistanceMoved = (diagonalSteps * 2 + straightSteps) * gridDistance; + break; + case 4: // Alternating (1/2/1) + totalDistanceMoved = ((diagonalSteps % 2 === 0 ? diagonalSteps * 1 : diagonalSteps * 2) + straightSteps) * gridDistance; + break; + case 5: // Alternating (2/1/2) + totalDistanceMoved = ((diagonalSteps % 2 === 0 ? diagonalSteps * 2 : diagonalSteps * 1) + straightSteps) * gridDistance; + break; + default: + totalDistanceMoved = (diagonalSteps + straightSteps) * gridDistance; + } + + return totalDistanceMoved; } export async function replaceChatCard({ actorUuid, itemUuid, chatContent, rollData }) { @@ -1045,11 +1085,11 @@ export async function ritualSpellUse({ workflowUuid }) { let content = ` ${workflow.actor.name} cast ${workflow.item.name} ritually.` let chatData = { - user: game.users.find(u => u.isGM).id, + user: getPrimaryGM(), content: content, - whisper: game.users.find(u => u.isGM).id + whisper: getPrimaryGM() }; - await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + await MidiQOL.socket().executeAsUser("createChatMessage", getPrimaryGM(), { chatData }); return; } }, @@ -1062,4 +1102,34 @@ export async function ritualSpellUse({ workflowUuid }) { return; }, rejectClose:false }); -} \ No newline at end of file +} + +export function getBrowserUser({ actorUuid }) { + if(!actorUuid) return; + + let actor = fromUuidSync(actorUuid); + let player = MidiQOL.playerForActor(actor); + let playerId; + + if(!player.active) playerId = getPrimaryGM(); + else playerId = player.id; + return playerId; +} + +export function getPrimaryGM() { + const primaryGMId = game.settings.get("gambits-premades", "primaryGM"); + const primaryGM = game.users.find(user => user.id === primaryGMId && user.active && user.isGM); + + if (!primaryGM) { + const activeGM = game.users.activeGM; + + if (!activeGM) { + console.warn("No active GM found."); + return false; + } + + return activeGM.id; + } + + return primaryGMId; + } \ No newline at end of file diff --git a/scripts/macros/ballBearings.js b/scripts/macros/ballBearings.js index 4aaf5ec1..30bc37b6 100644 --- a/scripts/macros/ballBearings.js +++ b/scripts/macros/ballBearings.js @@ -4,6 +4,7 @@ export async function ballBearings({tokenUuid, regionUuid, regionScenario, origi const socket = module.socket; const helpers = await import('../helpers.js'); let region = await fromUuid(regionUuid); + let gmUser = helpers.getPrimaryGM(); let tokenDocument = await fromUuid(tokenUuid); let token = tokenDocument?.object; @@ -20,10 +21,6 @@ export async function ballBearings({tokenUuid, regionUuid, regionScenario, origi let itemProperName = chosenItem.name; let dialogId = "ballbearings"; let dialogTitlePrimary = `${token.actor.name} | ${itemProperName}`; - let browserUser = MidiQOL.playerForActor(token.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } const effectOriginActor = await fromUuid(region.flags["region-attacher"].actorUuid); @@ -49,7 +46,7 @@ export async function ballBearings({tokenUuid, regionUuid, regionScenario, origi `; - let result = await socket.executeAsGM("process3rdPartyReactionDialog", {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source: "gm",type: "singleDialog"}); + let result = await socket.executeAsUser("process3rdPartyReactionDialog", gmUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source: "gm",type: "singleDialog"}); const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, abilityCheck, source, type } = result; @@ -95,7 +92,7 @@ export async function ballBearings({tokenUuid, regionUuid, regionScenario, origi const hasEffectApplied = tokenDocument.hasStatusEffect("prone"); if (!hasEffectApplied) { - await game.gps.socket.executeAsGM("gmToggleStatus", {tokenUuid: `${token.document.uuid}`, status: "prone", active: true }); + await game.gps.socket.executeAsUser("gmToggleStatus", gmUser, {tokenUuid: `${token.document.uuid}`, status: "prone", active: true }); } } } diff --git a/scripts/macros/biohazard.js b/scripts/macros/biohazard.js index 2ffbe76e..a2f0a5c4 100644 --- a/scripts/macros/biohazard.js +++ b/scripts/macros/biohazard.js @@ -1,6 +1,7 @@ export async function biohazard({tokenUuid, regionUuid, regionScenario, regionStatus}) { const helpers = await import('../helpers.js'); let region = await fromUuid(regionUuid); + let gmUser = helpers.getPrimaryGM(); let template; if(region?.flags["region-attacher"]?.attachedTemplate) { @@ -21,11 +22,6 @@ export async function biohazard({tokenUuid, regionUuid, regionScenario, regionSt let chosenItem = await fromUuid(region.flags["region-attacher"].itemUuid); let itemProperName = chosenItem?.name; - - let browserUser = MidiQOL.playerForActor(token.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } const effectOriginActor = await fromUuid(region.flags["region-attacher"].actorUuid); @@ -89,7 +85,7 @@ export async function biohazard({tokenUuid, regionUuid, regionScenario, regionSt } }]; - await MidiQOL.socket().executeAsGM("createEffects", { actorUuid: token.actor.uuid, effects: effectData }); + await MidiQOL.socket().executeAsUser("createEffects", gmUser, { actorUuid: token.actor.uuid, effects: effectData }); } if(saveResult) { diff --git a/scripts/macros/blackTentacles.js b/scripts/macros/blackTentacles.js index 35dfbcf2..b6ad8cad 100644 --- a/scripts/macros/blackTentacles.js +++ b/scripts/macros/blackTentacles.js @@ -3,6 +3,7 @@ export async function blackTentacles({tokenUuid, regionUuid, regionScenario, ori const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); + let gmUser = helpers.getPrimaryGM(); let region = await fromUuid(regionUuid); let tokenDocument = await fromUuid(tokenUuid); @@ -27,10 +28,7 @@ export async function blackTentacles({tokenUuid, regionUuid, regionScenario, ori let dialogId = "blacktentacles"; let dialogTitlePrimary = `${token.actor.name} | ${itemProperName}`; - let browserUser = MidiQOL.playerForActor(token.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + let browserUser = helpers.getBrowserUser({ actorUuid: token.actor.uuid }); const effectOriginActor = await fromUuid(region.flags["region-attacher"].actorUuid); @@ -97,7 +95,7 @@ export async function blackTentacles({tokenUuid, regionUuid, regionScenario, ori `; - let result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + let result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog"}); const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, abilityCheck, source, type } = result; @@ -109,7 +107,7 @@ export async function blackTentacles({tokenUuid, regionUuid, regionScenario, ori if (abilityCheck) { const skillCheck = await token.actor.rollAbilityTest(abilityCheck); if (skillCheck.total >= spellDC) { - await game.gps.socket.executeAsGM("gmToggleStatus", {tokenUuid: `${token.document.uuid}`, status: "restrained", active: false }); + await game.gps.socket.executeAsUser("gmToggleStatus", gmUser, {tokenUuid: `${token.document.uuid}`, status: "restrained", active: false }); let chatData = { user: browserUser.id, speaker: ChatMessage.getSpeaker({ token: token }), @@ -167,7 +165,7 @@ export async function blackTentacles({tokenUuid, regionUuid, regionScenario, ori const hasEffectApplied = token.document.hasStatusEffect("restrained"); if (!hasEffectApplied) { - await game.gps.socket.executeAsGM("gmToggleStatus", {tokenUuid: `${token.document.uuid}`, status: "restrained", active: true }); + await game.gps.socket.executeAsUser("gmToggleStatus", gmUser, {tokenUuid: `${token.document.uuid}`, status: "restrained", active: true }); } let dialogContent = ` @@ -193,7 +191,7 @@ export async function blackTentacles({tokenUuid, regionUuid, regionScenario, ori `; - let result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + let result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog"}); const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, abilityCheck, source, type } = result; @@ -210,7 +208,7 @@ export async function blackTentacles({tokenUuid, regionUuid, regionScenario, ori if (abilityCheck) { const skillCheck = await token.actor.rollAbilityTest(abilityCheck); if (skillCheck.total >= spellDC) { - await game.gps.socket.executeAsGM("gmToggleStatus", {tokenUuid: `${token.document.uuid}`, status: "restrained", active: false }); + await game.gps.socket.executeAsUser("gmToggleStatus", gmUser, {tokenUuid: `${token.document.uuid}`, status: "restrained", active: false }); let chatData = { user: browserUser.id, speaker: ChatMessage.getSpeaker({ token: token }), diff --git a/scripts/macros/caltrops.js b/scripts/macros/caltrops.js index ea4a167a..03057769 100644 --- a/scripts/macros/caltrops.js +++ b/scripts/macros/caltrops.js @@ -2,6 +2,7 @@ export async function caltrops({tokenUuid, regionUuid, regionScenario, originX, const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); + let gmUser = helpers.getPrimaryGM(); let region = await fromUuid(regionUuid); let tokenDocument = await fromUuid(tokenUuid); @@ -19,10 +20,6 @@ export async function caltrops({tokenUuid, regionUuid, regionScenario, originX, let itemProperName = chosenItem.name; let dialogId = "caltrops"; let dialogTitlePrimary = `${token.actor.name} | ${itemProperName}`; - let browserUser = MidiQOL.playerForActor(token.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } const effectOriginActor = await fromUuid(region.flags["region-attacher"].actorUuid); @@ -48,7 +45,7 @@ export async function caltrops({tokenUuid, regionUuid, regionScenario, originX, `; - let result = await socket.executeAsGM("process3rdPartyReactionDialog", {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source: "gm",type: "singleDialog"}); + let result = await socket.executeAsUser("process3rdPartyReactionDialog", gmUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source: "gm",type: "singleDialog"}); const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, abilityCheck, source, type } = result; @@ -117,7 +114,7 @@ export async function caltrops({tokenUuid, regionUuid, regionScenario, originX, } ]; - await MidiQOL.socket().executeAsGM("createEffects", { actorUuid: token.actor.uuid, effects: effectData }); + await MidiQOL.socket().executeAsUser("createEffects", gmUser, { actorUuid: token.actor.uuid, effects: effectData }); let actorPlayer = MidiQOL.playerForActor(token.actor); let chatData = { diff --git a/scripts/macros/caltropsFeyGlass.js b/scripts/macros/caltropsFeyGlass.js index 9771a265..c415f141 100644 --- a/scripts/macros/caltropsFeyGlass.js +++ b/scripts/macros/caltropsFeyGlass.js @@ -2,6 +2,7 @@ export async function caltropsFeyGlass({tokenUuid, regionUuid, regionScenario, o const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); + let gmUser = helpers.getPrimaryGM(); let region = await fromUuid(regionUuid); let tokenDocument = await fromUuid(tokenUuid); @@ -19,10 +20,6 @@ export async function caltropsFeyGlass({tokenUuid, regionUuid, regionScenario, o let itemProperName = chosenItem.name; let dialogId = "feyglasscaltrops"; let dialogTitlePrimary = `${token.actor.name} | ${itemProperName}`; - let browserUser = MidiQOL.playerForActor(token.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } const effectOriginActor = await fromUuid(region.flags["region-attacher"].actorUuid); @@ -48,7 +45,7 @@ export async function caltropsFeyGlass({tokenUuid, regionUuid, regionScenario, o `; - let result = await socket.executeAsGM("process3rdPartyReactionDialog", {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source: "gm",type: "singleDialog"}); + let result = await socket.executeAsUser("process3rdPartyReactionDialog", gmUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft: 30,validTokenPrimaryUuid: token.document.uuid,source: "gm",type: "singleDialog"}); const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, abilityCheck, source, type } = result; @@ -117,7 +114,7 @@ export async function caltropsFeyGlass({tokenUuid, regionUuid, regionScenario, o } ]; - await MidiQOL.socket().executeAsGM("createEffects", { actorUuid: token.actor.uuid, effects: effectData }); + await MidiQOL.socket().executeAsUser("createEffects", gmUser, { actorUuid: token.actor.uuid, effects: effectData }); let actorPlayer = MidiQOL.playerForActor(token.actor); let chatData = { diff --git a/scripts/macros/cloudRune.js b/scripts/macros/cloudRune.js index cb062844..585dfe76 100644 --- a/scripts/macros/cloudRune.js +++ b/scripts/macros/cloudRune.js @@ -2,27 +2,27 @@ export async function cloudRune({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const helpers = await import('../helpers.js'); const socket = module.socket; - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "cloud rune"; - let itemProperName = "Cloud Rune"; - let dialogId = "cloudrune"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - - if(workflow.item.name.toLowerCase() === itemName) return; + const gpsUuid = "8b8a1e0a-54b8-4b11-9247-5e16e4d92b4b"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Cloud Rune"; + let dialogId = gpsUuid; let target = workflow.targets.first(); + let gmUser = helpers.getPrimaryGM(); if(workflow.attackTotal < target.actor.system.attributes.ac.value) return; if(workflow.targets.size > 1) return; - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "feature", itemChecked: [itemName], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 30, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "feature", itemChecked: [itemName], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 30, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; for (const validTokenPrimary of findValidTokens) { const nearbyTokens = MidiQOL.findNearby(null, validTokenPrimary, 30, { includeToken: false }); let targets = nearbyTokens.filter(token => token.document.disposition !== validTokenPrimary.document.disposition && MidiQOL.canSee(validTokenPrimary.document.uuid,token.document.uuid) && token.document.uuid !== workflow.token.document.uuid); - + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const targetUuids = targets.map(t => t.document.uuid); const targetNames = targets.map(t => t.actor.name); if(targetUuids.length === 0) continue; @@ -33,120 +33,116 @@ export async function cloudRune({workflowData,workflowType,workflowCombat}) { const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } - - if(workflowType === "attack") { - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); - let chosenItem = await validTokenPrimary.actor.items.find(i => i.name === itemProperName); - - const optionBackground = (document.body.classList.contains("theme-dark")) ? 'black' : 'var(--color-bg)'; - - let dialogContent = ` -
-
-
-

Would you like to use your reaction to initiate ${itemProperName} and re-direct this attack?

-
-
- - ${targetNames.length >= 1 ? - `` : '
No valid enemies in range.
' - } -
- -
+ browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); + + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); + + const optionBackground = (document.body.classList.contains("theme-dark")) ? 'black' : 'var(--color-bg)'; + + let dialogContent = ` +
+
+
+

Would you like to use your reaction to initiate ${itemProperName} and re-direct this attack?

+
+
+ + ${targetNames.length >= 1 ? + `` : '
No valid enemies in range.
' + } +
+
-
- -
- `; +
+ +
+
+ `; - let result; + let content = ` ${validTokenPrimary.actor.name} has an option available for an attack triggering ${itemProperName}.` + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; - - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let result; + + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); - } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); - } - - const { userDecision, enemyTokenUuid, source, type } = result; - - if (!userDecision) { - if(source && source === "user" && type === "multiDialog") await socket.executeAsGM("closeDialogById", { dialogId: dialogId }); - if(source && source === "gm" && type === "multiDialog") await socket.executeAsUser("closeDialogById", browserUser.id, { dialogId: dialogId }); - continue; - } - else if (userDecision) { - chosenItem.prepareData(); - chosenItem.prepareFinalAttributes(); - chosenItem.applyActiveEffects(); - - const optionsChosenItem = { - showFullCard: false, - createWorkflow: true, - versatile: false, - configureDialog: true, - targetUuids: [validTokenPrimary.document.uuid] - }; - - let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: optionsChosenItem }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: optionsChosenItem }); - if(itemRoll.aborted === true) continue; - - await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; + + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); + } else { + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); + } - let rerollNew = await new Roll(`${workflow.attackRoll.result}`).evaluate(); - let newItemData = workflow.item; - - newItemData = newItemData.clone({ - system: { - "range": { - "value": null, - "long": null, - "units": "" - } + const { userDecision, enemyTokenUuid, source, type } = result; + + if (!userDecision) { + continue; + } + else if (userDecision) { + chosenItem.prepareData(); + chosenItem.prepareFinalAttributes(); + chosenItem.applyActiveEffects(); + + const optionsChosenItem = { + showFullCard: false, + createWorkflow: true, + versatile: false, + configureDialog: true, + targetUuids: [validTokenPrimary.document.uuid] + }; + + let itemRoll; + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: optionsChosenItem }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: optionsChosenItem }); + if(itemRoll.aborted === true) continue; + + await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); + + let rerollNew = await new Roll(`${workflow.attackRoll.result}`).evaluate(); + let newItemData = workflow.item; + + newItemData = newItemData.clone({ + system: { + "range": { + "value": null, + "long": null, + "units": "" } - }, { keepId: true }); + } + }, { keepId: true }); - newItemData.prepareData(); - newItemData.prepareFinalAttributes(); - newItemData.applyActiveEffects(); - - const options = { - showFullCard: false, - createWorkflow: true, - versatile: false, - configureDialog: true, - targetUuids: [enemyTokenUuid], - workflowOptions: {autoFastForward: "on", autoRollAttack: true, attackRollDSN: false} - }; - - workflow.aborted = true; - - const hookid = Hooks.once("midi-qol.preAttackRollComplete", async (workflow) => { - await workflow.setAttackRoll(rerollNew); - }); - - await MidiQOL.completeItemUse(newItemData, {}, options); - - Hooks.off('', hookid); - } + newItemData.prepareData(); + newItemData.prepareFinalAttributes(); + newItemData.applyActiveEffects(); + + const options = { + showFullCard: false, + createWorkflow: true, + versatile: false, + configureDialog: true, + targetUuids: [enemyTokenUuid], + workflowOptions: {autoFastForward: "on", autoRollAttack: true, attackRollDSN: false} + }; + + workflow.aborted = true; + + const hookid = Hooks.once("midi-qol.preAttackRollComplete", async (workflow) => { + await workflow.setAttackRoll(rerollNew); + }); + + await MidiQOL.completeItemUse(newItemData, {}, options); + + Hooks.off('', hookid); } } } \ No newline at end of file diff --git a/scripts/macros/counterspell.js b/scripts/macros/counterspell.js index ddd8f4ca..10525a26 100644 --- a/scripts/macros/counterspell.js +++ b/scripts/macros/counterspell.js @@ -2,15 +2,14 @@ export async function counterspell({ workflowData,workflowType,workflowCombat }) const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(`${workflowUuid}`); - let itemName = "counterspell"; - let itemProperName = "Counterspell"; - let dialogId = "counterspell"; + const workflow = await MidiQOL.Workflow.getWorkflow(`${workflowData}`); if(!workflow) return; - if(workflow.item.type !== "spell" || workflow.item.name === itemProperName) return; + const gpsUuid = "a3992a10-f36a-4416-a995-f83d444c3c0a"; + if(workflow.item.type !== "spell" || workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Counterspell"; + let dialogId = gpsUuid; const lastMessage = game.messages.contents[game.messages.contents.length - 1]; // Use to hide initial spell message - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + let gmUser = helpers.getPrimaryGM(); const castProperties = ["vocal", "somatic", "material"]; let hasVSMProperty = castProperties.some(prop => workflow.item.system.properties.has(prop)); @@ -18,6 +17,7 @@ export async function counterspell({ workflowData,workflowType,workflowCombat }) let hasDeafenedStatus; if (!hasVSMProperty) return; + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); let selectedToken = workflow.token; let castLevel = false; let browserUser; @@ -26,26 +26,23 @@ export async function counterspell({ workflowData,workflowType,workflowCombat }) async function initialCounterspellProcess(workflow, lastMessage, castLevel, selectedToken) { - let findValidTokens = helpers.findValidTokens({initiatingToken: selectedToken, targetedToken: null, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: selectedToken, targetedToken: null, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); if(findValidTokens.length === 0 || !findValidTokens) return; for (const validTokenPrimary of findValidTokens) { - if(lastMessage && validTokenPrimary.actor.type === "character") lastMessage.update({ whisper: [game.users.find((u) => u.isGM && u.active).id] }); - let workflowStatus = workflow.aborted; - if(workflowStatus === true) return; + if(lastMessage && validTokenPrimary.actor.type === "character") lastMessage.update({ whisper: gmUser }); + if(workflow.aborted === true) return; if(!castLevel) { hasDeafenedStatus = validTokenPrimary.document.hasStatusEffect("deafened"); if (isVocalOnly && hasDeafenedStatus) continue; } + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); castLevel = !castLevel ? workflow.castData.castLevel : castLevel; - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); const currentIndex = findValidTokens.indexOf(validTokenPrimary); const isLastToken = currentIndex === findValidTokens.length - 1; @@ -72,42 +69,34 @@ export async function counterspell({ workflowData,workflowType,workflowCombat })
`; - let content = ` ${validTokenPrimary.actor.name} has a reaction available for a spell triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - roll: false, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let content = ` ${validTokenPrimary.actor.name} has a reaction available for a spell triggering ${itemProperName}.`; + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision && isLastToken) { if(lastMessage && validTokenPrimary.actor.type === "character") lastMessage.update({ whisper: [] }); - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); return workflow.aborted = false; } else if (!userDecision) { if(lastMessage && validTokenPrimary.actor.type === "character") lastMessage.update({ whisper: [] }); - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { if(lastMessage && validTokenPrimary.actor.type === "character") lastMessage.update({ whisper: [] }); - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); let chosenSpell = validTokenPrimary.actor.items.find(i => i.name === itemProperName); @@ -131,8 +120,8 @@ export async function counterspell({ workflowData,workflowType,workflowCombat }) }); let itemRoll = false; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenSpell, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenSpell, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenSpell, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenSpell, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(!itemRoll) continue; @@ -196,18 +185,16 @@ export async function counterspell({ workflowData,workflowType,workflowCombat }) async function secondaryCounterspellProcess(workflow, lastMessage, castLevel, validTokenPrimary) { - let findValidTokens = helpers.findValidTokens({initiatingToken: validTokenPrimary, targetedToken: null, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: validTokenPrimary, targetedToken: null, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); if(findValidTokens.length === 0 || !findValidTokens) return workflow.aborted = true; for (const validTokenSecondary of findValidTokens) { + let chosenItem = validTokenSecondary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenSecondary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenSecondary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenSecondary.actor.items.find(i => i.name === itemProperName); - browserUser = MidiQOL.playerForActor(validTokenSecondary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + browserUser = helpers.getBrowserUser({ actorUuid: validTokenSecondary.actor.uuid }); const currentIndex = findValidTokens.indexOf(validTokenSecondary); const isLastToken = currentIndex === findValidTokens.length - 1; @@ -234,42 +221,34 @@ export async function counterspell({ workflowData,workflowType,workflowCombat })
`; - let content = ` ${validTokenSecondary.actor.name} has a reaction available for a spell triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - roll: false, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessageSecondary = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let content = ` ${validTokenSecondary.actor.name} has a reaction available for a spell triggering ${itemProperName}.`; + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessageSecondary = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenSecondary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenSecondary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessageSecondary._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenSecondary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenSecondary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessageSecondary._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenSecondary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenSecondary.document.uuid,source:gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessageSecondary._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision && isLastToken) { if(lastMessage && validTokenPrimary.actor.type === "character") lastMessage.update({ whisper: [] }); - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessageSecondary._id }); return workflow.aborted = true; } else if (!userDecision) { if(lastMessage) lastMessage.update({ whisper: [] }); - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessageSecondary._id }); continue; } else if (userDecision) { if(lastMessage && validTokenPrimary.actor.type === "character") lastMessage.update({ whisper: [] }); - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessageSecondary._id }); let chosenSpell = validTokenSecondary.actor.items.find(i => i.name === itemProperName); @@ -293,8 +272,8 @@ export async function counterspell({ workflowData,workflowType,workflowCombat }) }); let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenSpell, actorUuid: validTokenSecondary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenSpell, actorUuid: validTokenSecondary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenSpell, actorUuid: validTokenSecondary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenSpell, actorUuid: validTokenSecondary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; diff --git a/scripts/macros/cuttingWords.js b/scripts/macros/cuttingWords.js index 3a254ad5..aaee4464 100644 --- a/scripts/macros/cuttingWords.js +++ b/scripts/macros/cuttingWords.js @@ -2,35 +2,33 @@ export async function cuttingWords({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "cutting words"; - let itemProperName = "Cutting Words"; - let dialogId = "cuttingwords"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name === itemProperName) return; + const gpsUuid = "b352241e-5042-44a4-b632-3168ded51946"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Cutting Words"; + let dialogId = gpsUuid; + let gmUser = helpers.getPrimaryGM(); - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "feature", itemChecked: ["bardic inspiration"], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "feature", itemChecked: ["bardic inspiration"], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; for (const validTokenPrimary of findValidTokens) { + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); let bardicDie = validTokenPrimary.actor.system.scale?.bard["bardic-inspiration"]?.die; if(!bardicDie) { ui.notifications.error("You must have a Bard scale for this actor named 'bardic-inspiration'") continue; } - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); let dialogContent; const rollDetailSetting = MidiQOL.safeGetGameSetting('midi-qol', 'ConfigSettings').hideRollDetails; - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); if(workflowType === "damage") { if (workflow.token.document.disposition === validTokenPrimary.document.disposition) continue; @@ -95,36 +93,28 @@ export async function cuttingWords({workflowData,workflowType,workflowCombat}) { `; } - let content = ` ${validTokenPrimary.actor.name} has a reaction available for a save triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - roll: false, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let content = ` ${validTokenPrimary.actor.name} has a reaction available for a save triggering ${itemProperName}.`; + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } - else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - + else if (userDecision) { chosenItem.prepareData(); chosenItem.prepareFinalAttributes(); chosenItem.applyActiveEffects(); @@ -138,8 +128,8 @@ export async function cuttingWords({workflowData,workflowType,workflowCombat}) { }; let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; let chatContent; @@ -167,8 +157,8 @@ export async function cuttingWords({workflowData,workflowType,workflowCombat}) { const saveSetting = workflow.options.noOnUseMacro; workflow.options.noOnUseMacro = true; let reroll; - if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser.id, { rollParams: `1${bardicDie}`, type: workflowType }); - if(source && source === "gm") reroll = await socket.executeAsGM("rollAsUser", { rollParams: `1${bardicDie}`, type: workflowType }); + if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser, { rollParams: `1${bardicDie}`, type: workflowType }); + if(source && source === "gm") reroll = await socket.executeAsUser("rollAsUser", gmUser, { rollParams: `1${bardicDie}`, type: workflowType }); let remainingReduction = reroll.total; let updatedRolls = []; @@ -217,8 +207,8 @@ export async function cuttingWords({workflowData,workflowType,workflowCombat}) { const saveSetting = workflow.options.noOnUseMacro; workflow.options.noOnUseMacro = true; let reroll; - if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser.id, { rollParams: `1${bardicDie}`, type: workflowType }); - if(source && source === "gm") reroll = await socket.executeAsGM("rollAsUser", { rollParams: `1${bardicDie}`, type: workflowType }); + if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser, { rollParams: `1${bardicDie}`, type: workflowType }); + if(source && source === "gm") reroll = await socket.executeAsUser("rollAsUser", gmUser, { rollParams: `1${bardicDie}`, type: workflowType }); let rerollNew = await new Roll(`${workflow.attackRoll.result} - ${reroll.total}`).evaluate(); await workflow.setAttackRoll(rerollNew); diff --git a/scripts/macros/indomitable.js b/scripts/macros/indomitable.js index 375c209a..95c77469 100644 --- a/scripts/macros/indomitable.js +++ b/scripts/macros/indomitable.js @@ -2,32 +2,31 @@ export async function indomitable({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "indomitable"; - let itemProperName = "Indomitable"; - let dialogId = "indomitable"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name === itemProperName) return; + const gpsUuid = "75e0633f-3973-4ea7-9246-da3e6d0da457"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Indomitable"; + let dialogId = gpsUuid; + let gmUser = helpers.getPrimaryGM(); // Check if there is a save success if(workflowType === "save" && workflow.failedSaves.size === 0) return; - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "feature", itemChecked: ["indomitable"], reactionCheck: false, sightCheck: false, rangeCheck: false, rangeTotal: null, dispositionCheck: false, dispositionCheckType: null, workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "feature", itemChecked: ["indomitable"], reactionCheck: false, sightCheck: false, rangeCheck: false, rangeTotal: null, dispositionCheck: false, dispositionCheckType: null, workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; for (const validTokenPrimary of findValidTokens) { let targetUuids = Array.from(workflow.failedSaves).filter(t => t.document.uuid === validTokenPrimary.document.uuid).map(t => t.document.uuid); if(targetUuids.length === 0) continue; - + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) browserUser = game.users?.activeGM; + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); let indomitableHomebrew = MidiQOL.safeGetGameSetting('gambits-premades', 'enableAutoSucceedIndomitable'); let contentQuestion; @@ -58,32 +57,25 @@ export async function indomitable({workflowData,workflowType,workflowCombat}) { let result; let content = ` ${validTokenPrimary.actor.name} has an option available for a save triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); - - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); + + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - chosenItem.prepareData(); chosenItem.prepareFinalAttributes(); chosenItem.applyActiveEffects(); @@ -97,8 +89,8 @@ export async function indomitable({workflowData,workflowType,workflowCombat}) { }; let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; let chatContent; @@ -107,8 +99,8 @@ export async function indomitable({workflowData,workflowType,workflowCombat}) { let saveAbility = workflow.saveItem.system.save.ability; let targetSaveBonus = validTokenPrimary.actor.system.abilities[`${saveAbility}`].save + validTokenPrimary.actor.system.abilities[`${saveAbility}`].saveBonus; let reroll; - if(source && source === "user" && !indomitableHomebrew) reroll = await socket.executeAsUser("rollAsUser", browserUser.id, { rollParams: `1d20 + ${targetSaveBonus}` }); - if(source && source === "gm" && !indomitableHomebrew) reroll = await socket.executeAsGM("rollAsUser", { rollParams: `1d20 + ${targetSaveBonus}` }); + if(source && source === "user" && !indomitableHomebrew) reroll = await socket.executeAsUser("rollAsUser", browserUser, { rollParams: `1d20 + ${targetSaveBonus}` }); + if(source && source === "gm" && !indomitableHomebrew) reroll = await socket.executeAsUser("rollAsUser", gmUser, { rollParams: `1d20 + ${targetSaveBonus}` }); if((reroll?.total >= saveDC) || indomitableHomebrew) { workflow.saves.add(validTokenPrimary); diff --git a/scripts/macros/instinctiveCharm.js b/scripts/macros/instinctiveCharm.js index e3881731..8732b054 100644 --- a/scripts/macros/instinctiveCharm.js +++ b/scripts/macros/instinctiveCharm.js @@ -2,18 +2,17 @@ export async function instinctiveCharm({workflowData,workflowType,workflowCombat const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "instinctive charm"; - let itemProperName = "Instinctive Charm"; - let dialogId = "instinctivecharm"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name === itemProperName) return; + const gpsUuid = "b9a797f2-3262-4a89-9b32-d8482a0c5f29"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Instinctive Charm"; + let dialogId = gpsUuid; let target = workflow.token; - if(target.actor.appliedEffects.some(e => e.name === `${itemProperName} - Immunity`)) return; let debugEnabled = MidiQOL.safeGetGameSetting('gambits-premades', 'debugEnabled'); + let gmUser = helpers.getPrimaryGM(); - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: null, itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 30, dispositionCheck: false, dispositionCheckType: null, workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: null, itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 30, dispositionCheck: false, dispositionCheckType: null, workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; @@ -32,14 +31,15 @@ export async function instinctiveCharm({workflowData,workflowType,workflowCombat `` ).join(''); + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; + if(target.actor.appliedEffects.some(e => e.name === `${itemProperName} - Immunity`)) return; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) browserUser = game.users?.activeGM; + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); const optionBackground = (document.body.classList.contains("theme-dark")) ? 'black' : 'var(--color-bg)'; - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); let dialogContent = `
@@ -63,33 +63,28 @@ export async function instinctiveCharm({workflowData,workflowType,workflowCombat
`; - let result; let content = ` ${validTokenPrimary.actor.name} has an option available for an attack triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); - - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); + + let result; + + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); chosenItem.prepareData(); chosenItem.prepareFinalAttributes(); chosenItem.applyActiveEffects(); @@ -103,16 +98,15 @@ export async function instinctiveCharm({workflowData,workflowType,workflowCombat }; let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); let dialogIdTarget = "instinctivecharmtarget"; - let browserUserTarget = MidiQOL.playerForActor(target.actor); - if (!browserUserTarget.active) browserUserTarget = game.users?.activeGM; + let browserUserTarget = helpers.getBrowserUser({ actorUuid: target.actor.uuid }); const spellDC = validTokenPrimary.actor.system.attributes.spelldc; let saveAbility = "wis"; @@ -179,14 +173,14 @@ export async function instinctiveCharm({workflowData,workflowType,workflowCombat let resultTarget; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUserTarget.id !== game.users?.activeGM.id) { - let userDialogPromise = socket.executeAsUser("process3rdPartyReactionDialog", browserUserTarget.id, {dialogTitle:dialogTitlePrimary,dialogContent: dialogContentTarget,dialogId: dialogIdTarget,initialTimeLeft,validTokenPrimaryUuid: target.document.uuid,source: "user",type: "multiDialog"}); + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUserTarget !== gmUser) { + let userDialogArgsTarget = { dialogTitle:dialogTitlePrimary,dialogContent: dialogContentTarget,dialogId: dialogIdTarget,initialTimeLeft,validTokenPrimaryUuid: target.document.uuid,source: "user",type: "multiDialog", browserUser: browserUserTarget, notificationId: notificationMessage._id }; - let gmDialogPromise = socket.executeAsGM("process3rdPartyReactionDialog", {dialogTitle:dialogTitleGM,dialogContent: dialogContentTarget,dialogId: dialogIdTarget,initialTimeLeft,validTokenPrimaryUuid: target.document.uuid,source: "gm",type: "multiDialog"}); + let gmDialogArgsTarget = { dialogTitle:dialogTitleGM,dialogContent: dialogContentTarget,dialogId: dialogIdTarget,initialTimeLeft,validTokenPrimaryUuid: target.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - resultTarget = await socket.executeAsGM("handleDialogPromises", userDialogPromise, gmDialogPromise); + resultTarget = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgsTarget, gmDialogArgsTarget}); } else { - resultTarget = await socket.executeAsUser("process3rdPartyReactionDialog", browserUserTarget.id, {dialogTitle:dialogTitlePrimary,dialogContent: dialogContentTarget,dialogId: dialogIdTarget,initialTimeLeft,validTokenPrimaryUuid: target.document.uuid,source:browserUserTarget.isGM ? "gm" : "user",type:"singleDialog"}); + resultTarget = await socket.executeAsUser("process3rdPartyReactionDialog", browserUserTarget.id, {dialogTitle:dialogTitlePrimary,dialogContent: dialogContentTarget,dialogId: dialogIdTarget,initialTimeLeft,validTokenPrimaryUuid: target.document.uuid,source: gmUser === browserUserTarget ? "gm" : "user",type:"singleDialog"}); } const { enemyTokenUuid } = resultTarget; @@ -214,7 +208,7 @@ export async function instinctiveCharm({workflowData,workflowType,workflowCombat } } ]; - await MidiQOL.socket().executeAsGM("createEffects", { actorUuid: target.actor.uuid, effects: effectData }); + await MidiQOL.socket().executeAsUser("createEffects", gmUser, { actorUuid: target.actor.uuid, effects: effectData }); continue; } diff --git a/scripts/macros/interception.js b/scripts/macros/interception.js index 5d95cded..5eeca5e8 100644 --- a/scripts/macros/interception.js +++ b/scripts/macros/interception.js @@ -2,44 +2,38 @@ export async function interception({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const helpers = await import('../helpers.js'); const socket = module.socket; - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "fighting style: interception"; - let itemProperName = "Interception"; - let dialogId = "interception"; - let target = workflow.hitTargets.first(); + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name.toLowerCase() === itemName) return; + const gpsUuid = "411b0d88-a483-4d85-97d9-2bd8dbd4ef70"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Fighting Style: Interception"; + let dialogId = gpsUuid; + let target = workflow.hitTargets.first(); const actionTypes = ["mwak", "rwak", "msak", "rsak"]; if (!actionTypes.some(type => workflow.item.system.actionType?.includes(type))) return; + let gmUser = helpers.getPrimaryGM(); - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "item", itemChecked: ["mwak", "shield"], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 5, dispositionCheck: true, dispositionCheckType: "enemyAlly", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "item", itemChecked: ["mwak", "shield"], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 5, dispositionCheck: true, dispositionCheckType: "enemyAlly", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; for (const validTokenPrimary of findValidTokens) { if (target.document.uuid === validTokenPrimary.document.uuid) continue; + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name.toLowerCase() === itemName); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); let damageTypes = workflow.damageRolls.map(roll => roll.options.type); let hasHealing = damageTypes.some(type => type === "healing"); if (hasHealing) return; let damageTotals = workflow.damageRolls.map(roll => roll.total); - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `Interception Timeout`)); let content = ` ${validTokenPrimary.actor.name} has a reaction available for a roll triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); const rollDetailSetting = MidiQOL.safeGetGameSetting('midi-qol', 'ConfigSettings').hideRollDetails; @@ -74,25 +68,22 @@ export async function interception({workflowData,workflowType,workflowCombat}) { let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); let primaryFile = "jb2a.spiritual_weapon.sword.spectral.orange"; @@ -123,8 +114,8 @@ export async function interception({workflowData,workflowType,workflowCombat}) { numDice = `${dieNumber}d${dieFace}`; } - if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser.id, { rollParams: `${numDice} + ${actorProf}`, type: workflowType }); - if(source && source === "gm") reroll = await socket.executeAsGM("rollAsUser", { rollParams: `${numDice} + ${actorProf}`, type: workflowType }); + if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser, { rollParams: `${numDice} + ${actorProf}`, type: workflowType }); + if(source && source === "gm") reroll = await socket.executeAsUser("rollAsUser", gmUser, { rollParams: `${numDice} + ${actorProf}`, type: workflowType }); let remainingReduction = reroll.total; let updatedRolls = []; diff --git a/scripts/macros/mageSlayer.js b/scripts/macros/mageSlayer.js index 2f5fa1d8..5762f5d5 100644 --- a/scripts/macros/mageSlayer.js +++ b/scripts/macros/mageSlayer.js @@ -2,18 +2,19 @@ export async function mageSlayer({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const helpers = await import('../helpers.js'); const socket = module.socket; - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "mage slayer"; - let itemProperName = "Mage Slayer"; - let dialogId = "mageslayer"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name.toLowerCase() === itemName) return; + const gpsUuid = "fc0e0473-038b-4e68-abd5-538b8fbbb4a5"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Mage Slayer"; + let dialogId = gpsUuid; + let gmUser = helpers.getPrimaryGM(); - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: workflow.token, itemName: itemName, itemType: null, itemChecked: null, reactionCheck: true, sightCheck: false, rangeCheck: true, rangeTotal: 5, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: workflow.token, itemName: itemName, itemType: null, itemChecked: null, reactionCheck: true, sightCheck: false, rangeCheck: true, rangeTotal: 5, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); for (const validTokenPrimary of findValidTokens) { - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; if(workflowType === "save") { let target = Array.from(workflow.targets).filter(t => t.document.uuid === validTokenPrimary.document.uuid); @@ -43,20 +44,17 @@ export async function mageSlayer({workflowData,workflowType,workflowCombat}) { } }]; - await MidiQOL.socket().executeAsGM("createEffects", { actorUuid: validTokenPrimary.actor.uuid, effects: effectData }); + await MidiQOL.socket().executeAsUser("createEffects", gmUser, { actorUuid: validTokenPrimary.actor.uuid, effects: effectData }); continue; } } else { const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + let browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); const optionBackground = (document.body.classList.contains("theme-dark")) ? 'black' : 'var(--color-bg)'; - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); // Check valid weapons let validWeapons = validTokenPrimary.actor.items.filter(item => { @@ -142,34 +140,27 @@ export async function mageSlayer({workflowData,workflowType,workflowCombat}) { `; let content = ` ${validTokenPrimary.actor.name} has a reaction available for an attack triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, selectedItemUuid, favoriteCheck, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - if (!selectedItemUuid) { console.log("No weapon selected"); continue; @@ -221,8 +212,8 @@ export async function mageSlayer({workflowData,workflowType,workflowCombat}) { }); let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); diff --git a/scripts/macros/opportunityAttack.js b/scripts/macros/opportunityAttack.js index 85e3257a..1814a86c 100644 --- a/scripts/macros/opportunityAttack.js +++ b/scripts/macros/opportunityAttack.js @@ -1,9 +1,10 @@ const regionTokenStates = new Map(); export async function opportunityAttackScenarios({tokenUuid, regionUuid, regionScenario, originX, originY, isTeleport}) { - if(!game.user.isGM) return; - const module = await import('../module.js'); const helpers = await import('../helpers.js'); + let gmUser = helpers.getPrimaryGM(); + if(game.user.id !== gmUser) return; + const module = await import('../module.js'); const socket = module.socket; //async function wait(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } let region = await fromUuid(regionUuid); @@ -33,10 +34,7 @@ export async function opportunityAttackScenarios({tokenUuid, regionUuid, regionS let hasPolearmReaction = effectOriginActor.items.find(i => i.name.toLowerCase() === "polearm master"); let hasDeadlyReachReaction = effectOriginActor.items.find(i => i.name.toLowerCase() === "deadly reach"); - let browserUser = MidiQOL.playerForActor(effectOriginActor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + let browserUser = helpers.getBrowserUser({ actorUuid: effectOriginActor.uuid }); let result; let dialogTitle; @@ -311,34 +309,27 @@ export async function opportunityAttackScenarios({tokenUuid, regionUuid, regionS let dialogTitleGM = `Waiting for ${effectOriginActor.name}'s selection | ${dialogTitle}`; let content = ` ${effectOriginToken.actor.name} has a reaction available for an Opportunity Attack.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); - - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: effectOriginToken.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); + + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: effectOriginToken.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: effectOriginToken.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: effectOriginToken.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: effectOriginToken.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: effectOriginToken.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, selectedItemUuid, favoriteCheck, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); await effectOriginActor.unsetFlag("gambits-premades", "dragonTurtleShieldOA"); //if(hasSentinel) await effectOriginActor.setFlag("gambits-premades", "sentinelDeclined", true); return; } else if (userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - if (braceItemUuid) { let braceItem = await fromUuid(braceItemUuid); const braceRoll = await braceItem.use(); @@ -380,8 +371,8 @@ export async function opportunityAttackScenarios({tokenUuid, regionUuid, regionS chosenWeapon.applyActiveEffects(); let userSelect = undefined; - if(source && source === "user") userSelect = browserUser.id; - else if(source && source === "gm") userSelect = game.users?.activeGM.id; + if(source && source === "user") userSelect = browserUser; + else if(source && source === "gm") userSelect = gmUser; const options = { showFullCard: false, @@ -405,8 +396,8 @@ export async function opportunityAttackScenarios({tokenUuid, regionUuid, regionS }); let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenWeapon, actorUuid: effectOriginActor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenWeapon, actorUuid: effectOriginActor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenWeapon, actorUuid: effectOriginActor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenWeapon, actorUuid: effectOriginActor.uuid, options: options }); await effectOriginActor.unsetFlag("gambits-premades", "dragonTurtleShieldOA"); @@ -438,7 +429,7 @@ export async function opportunityAttackScenarios({tokenUuid, regionUuid, regionS } ]; - await MidiQOL.socket().executeAsGM("createEffects", { actorUuid: token.actor.uuid, effects: effectData }); + await MidiQOL.socket().executeAsUser("createEffects", gmUser, { actorUuid: token.actor.uuid, effects: effectData }); } //else if(hasSentinel && !checkHits) await effectOriginActor.setFlag("gambits-premades", "sentinelDeclined", true); } @@ -586,7 +577,7 @@ export async function enableOpportunityAttack(combat, combatEvent) { disabled: false, system: { source: ` - if(!game.user.isGM) return; + if(game.user.id !== game.gps.getPrimaryGM()) return; if(event.data.token.uuid !== region.flags["gambits-premades"].tokenUuid) return; let token = await fromUuid(region.flags["gambits-premades"].tokenUuid); let actor = await fromUuid(region.flags["gambits-premades"].actorUuid); @@ -758,14 +749,24 @@ export async function enableOpportunityAttack(combat, combatEvent) { } if(combatEvent === "startCombat") { + let levelsUI = CONFIG.Levels?.UI?.stairEnabled; + if(levelsUI) CONFIG.Levels.UI.stairEnabled = false; + for (let combatant of combat.combatants.values()) { await processCombatant(combatant); } + + if(levelsUI) CONFIG.Levels.UI.stairEnabled = true; } if(combatEvent === "enterCombat") { + let levelsUI = CONFIG.Levels?.UI?.stairEnabled; + if(levelsUI) CONFIG.Levels.UI.stairEnabled = false; + let combatant = combat; await processCombatant(combatant); + + if(levelsUI) CONFIG.Levels.UI.stairEnabled = true; } }; diff --git a/scripts/macros/poetryInMisery.js b/scripts/macros/poetryInMisery.js index 452b1289..63267a61 100644 --- a/scripts/macros/poetryInMisery.js +++ b/scripts/macros/poetryInMisery.js @@ -2,17 +2,17 @@ export async function poetryInMisery({workflowData,workflowType,workflowCombat}) const module = await import('../module.js'); const helpers = await import('../helpers.js'); const socket = module.socket; - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid) ?? null; - let itemName = "poetry in misery"; - let itemProperName = "Poetry in Misery"; - let dialogId = "poetryinmisery"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData) ?? null; if(!workflow && workflowCombat === true) return; - if(workflow?.item?.name.toLowerCase() === itemName) return; + const gpsUuid = "f4b6923a-eda4-4c29-a6fb-a1728f6e71e3"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Poetry in Misery"; + let dialogId = gpsUuid; let initiatingToken; (workflow) ? initiatingToken = workflow.token : initiatingToken = await MidiQOL.tokenForActor(workflowData.actor.uuid); + let gmUser = helpers.getPrimaryGM(); - let findValidTokens = helpers.findValidTokens({initiatingToken: initiatingToken, targetedToken: initiatingToken, itemName: itemName, itemType: null, itemChecked: null, reactionCheck: true, sightCheck: false, rangeCheck: true, rangeTotal: 30, dispositionCheck: true, dispositionCheckType: "ally", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: initiatingToken, targetedToken: initiatingToken, itemName: itemName, itemType: null, itemChecked: null, reactionCheck: true, sightCheck: false, rangeCheck: true, rangeTotal: 30, dispositionCheck: true, dispositionCheckType: "ally", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; @@ -32,15 +32,13 @@ export async function poetryInMisery({workflowData,workflowType,workflowCombat}) } else continue; + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); let chatActor; - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); if (workflowType === "attack") { if(initiatingToken.document.disposition !== validTokenPrimary.document.disposition) continue; @@ -88,32 +86,25 @@ export async function poetryInMisery({workflowData,workflowType,workflowCombat}) let result; let content = ` ${validTokenPrimary.actor.name} has a reaction available for a roll triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); if (resourceKey) { diff --git a/scripts/macros/powerWordRebound.js b/scripts/macros/powerWordRebound.js index bab70306..14071d73 100644 --- a/scripts/macros/powerWordRebound.js +++ b/scripts/macros/powerWordRebound.js @@ -2,34 +2,31 @@ export async function powerWordRebound({workflowData,workflowType,workflowCombat const module = await import('../module.js'); const helpers = await import('../helpers.js'); const socket = module.socket; - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "power word rebound"; - let itemProperName = "Power Word Rebound"; - let dialogId = "powerwordrebound"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name.toLowerCase() === itemName) return; + const gpsUuid = "b8949110-fd25-4d67-a65f-1bdc3d03b36e"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Power Word Rebound"; + let dialogId = gpsUuid; let target = workflow.targets.first(); + let gmUser = helpers.getPrimaryGM(); if(target.actor.system.attributes.hp.value >= Math.floor(target.actor.system.attributes.hp.max / 2)) return; if(workflow.attackTotal < target.actor.system.attributes.ac.value) return; if(workflow.targets.size > 1) return; - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; for (const validTokenPrimary of findValidTokens) { + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } - + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); let dialogContent = `
@@ -56,32 +53,25 @@ export async function powerWordRebound({workflowData,workflowType,workflowCombat let result; let content = ` ${validTokenPrimary.actor.name} has a reaction available for a roll triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); - - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); + + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - chosenItem.prepareData(); chosenItem.prepareFinalAttributes(); chosenItem.applyActiveEffects(); @@ -95,8 +85,8 @@ export async function powerWordRebound({workflowData,workflowType,workflowCombat }; let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); diff --git a/scripts/macros/protection.js b/scripts/macros/protection.js index 512f4117..f9acab49 100644 --- a/scripts/macros/protection.js +++ b/scripts/macros/protection.js @@ -2,33 +2,33 @@ export async function protection({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "fighting style: protection"; - let itemProperName = "Protection"; - let dialogId = "protection"; - let target = workflow.targets.first(); + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name.toLowerCase() === itemName) return; + const gpsUuid = "82548541-757a-4d56-961a-3f86bb8a14e6"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Fighting Style: Protection"; + let dialogId = gpsUuid; + let target = workflow.targets.first(); let enableProtectionOnSuccess = MidiQOL.safeGetGameSetting('gambits-premades', 'enableProtectionOnSuccess'); if ((enableProtectionOnSuccess && workflow.attackRoll.formula.includes("kl")) || (!enableProtectionOnSuccess && workflow.disadvantage === true)) return; + let gmUser = helpers.getPrimaryGM(); if(enableProtectionOnSuccess && (workflow.attackTotal < target.actor.system.attributes.ac.value)) return; - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "item", itemChecked: ["shield"], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 5, dispositionCheck: true, dispositionCheckType: "enemyAlly", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "item", itemChecked: ["shield"], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 5, dispositionCheck: true, dispositionCheckType: "enemyAlly", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; for (const validTokenPrimary of findValidTokens) { + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name.toLowerCase() === itemName); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) browserUser = game.users?.activeGM; + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); if (target.document.uuid === validTokenPrimary.document.uuid) continue; - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `Protection Timeout`)); let dialogContent = `
@@ -53,33 +53,26 @@ export async function protection({workflowData,workflowType,workflowCombat}) { `; let content = ` ${validTokenPrimary.actor.name} has a reaction available for an attack triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); let primaryFile = "jaamod.condition.magic_shield"; diff --git a/scripts/macros/rainOfCinders.js b/scripts/macros/rainOfCinders.js index 6a9894ba..20d54a05 100644 --- a/scripts/macros/rainOfCinders.js +++ b/scripts/macros/rainOfCinders.js @@ -2,19 +2,19 @@ export async function rainOfCinders({workflowData,workflowType,workflowCombat}) const module = await import('../module.js'); const helpers = await import('../helpers.js'); const socket = module.socket; - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "rain of cinders"; - let itemProperName = "Rain of Cinders"; - let dialogId = "rainofcinders"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name.toLowerCase() === itemName) return; + const gspUuid = "a95f3926-ba77-45ab-90d9-c0cf3cca10aa"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Rain of Cinders"; + let dialogId = gspUuid; let target = workflow.targets.first(); let debugEnabled = MidiQOL.safeGetGameSetting('gambits-premades', 'debugEnabled'); + let gmUser = helpers.getPrimaryGM(); if(workflow.targets.size > 1) return; - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "feature", itemChecked: ["drawing the hearth"], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "feature", itemChecked: ["drawing the hearth"], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; @@ -23,16 +23,14 @@ export async function rainOfCinders({workflowData,workflowType,workflowCombat}) if(debugEnabled) console.error(`${itemName} for ${validTokenPrimary.actor.name} failed at parent effect active`); continue; } + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); let baseItem = validTokenPrimary.actor.items.find(i => i.name === "Drawing the Hearth"); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); let dialogContent = `
@@ -59,32 +57,25 @@ export async function rainOfCinders({workflowData,workflowType,workflowCombat}) let result; let content = ` ${validTokenPrimary.actor.name} has a reaction available for an attack triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); - - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); + + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - chosenItem.prepareData(); chosenItem.prepareFinalAttributes(); chosenItem.applyActiveEffects(); @@ -98,8 +89,8 @@ export async function rainOfCinders({workflowData,workflowType,workflowCombat}) }; let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); diff --git a/scripts/macros/riposte.js b/scripts/macros/riposte.js index 79bbaa7c..63917cc6 100644 --- a/scripts/macros/riposte.js +++ b/scripts/macros/riposte.js @@ -1,42 +1,38 @@ -//done export async function riposte({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const helpers = await import('../helpers.js'); const socket = module.socket; - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "maneuvers: riposte"; - let itemProperName = "Riposte"; - let dialogId = "riposte"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name.toLowerCase() === itemName) return; + const gpsUuid = "73ae66c4-4bd4-41cd-b75a-0056ef8b670c"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Maneuvers: Riposte"; + let dialogId = gpsUuid; const actionTypes = ["mwak"]; if (!actionTypes.some(type => workflow.item.system.actionType?.includes(type))) { return; } let target = workflow.targets.first(); + let gmUser = helpers.getPrimaryGM(); let targetAC = target.actor.system.attributes.ac.value; let attackTotal = workflow.attackTotal; if (attackTotal >= targetAC) return; - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "feature", itemChecked: ["superiority dice", "superiority die"], reactionCheck: true, sightCheck: false, rangeCheck: false, rangeTotal: null, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "feature", itemChecked: ["superiority dice", "superiority die"], reactionCheck: true, sightCheck: false, rangeCheck: false, rangeTotal: null, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; for (const validTokenPrimary of findValidTokens) { if(validTokenPrimary.id !== target.id) continue; - + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === "Maneuvers: Riposte"); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); const optionBackground = (document.body.classList.contains("theme-dark")) ? 'black' : 'var(--color-bg)'; - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `Riposte Timeout`)); // Check valid weapons let validWeapons = validTokenPrimary.actor.items.filter(item => { @@ -122,33 +118,26 @@ export async function riposte({workflowData,workflowType,workflowCombat}) { `; let content = ` ${validTokenPrimary.actor.name} has a reaction available for an attack triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, selectedItemUuid, favoriteCheck, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - const riposteOptions = { showFullCard: false, createWorkflow: true, @@ -158,8 +147,8 @@ export async function riposte({workflowData,workflowType,workflowCombat}) { }; let riposteRoll; - if(source && source === "user") riposteRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: riposteOptions }); - else if(source && source === "gm") riposteRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: riposteOptions }); + if(source && source === "user") riposteRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: riposteOptions }); + else if(source && source === "gm") riposteRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: riposteOptions }); if(riposteRoll.aborted === true) continue; if (!selectedItemUuid) { @@ -210,8 +199,8 @@ export async function riposte({workflowData,workflowType,workflowCombat}) { }; let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; const hasEffectAppliedReaction = MidiQOL.hasUsedReaction(validTokenPrimary.actor); diff --git a/scripts/macros/runicShield.js b/scripts/macros/runicShield.js index 4da4e926..f1a2adec 100644 --- a/scripts/macros/runicShield.js +++ b/scripts/macros/runicShield.js @@ -2,35 +2,33 @@ export async function runicShield({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "runic shield"; - let itemProperName = "Runic Shield"; - let dialogId = "runicshield"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name === itemProperName) return; + const gpsUuid = "088a34cd-f8c0-42d0-be77-ccaac97ba913"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Runic Shield"; + let dialogId = gpsUuid; + let gmUser = helpers.getPrimaryGM(); let target = workflow.targets.first(); if(workflow.attackTotal < target.actor.system.attributes.ac.value) return; - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "feature", itemChecked: ["runic shield"], reactionCheck: true, sightCheck: true, sightCheckType: "ally", rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemyAlly", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: "feature", itemChecked: ["runic shield"], reactionCheck: true, sightCheck: true, sightCheckType: "ally", rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemyAlly", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); let browserUser; let browserUserEnemy; for (const validTokenPrimary of findValidTokens) { if(validTokenPrimary.id === target.id) continue; - + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) browserUser = game.users?.activeGM; - browserUserEnemy = MidiQOL.playerForActor(workflow.token.actor); - if (!browserUserEnemy.active) browserUserEnemy = game.users?.activeGM; + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); + browserUserEnemy = helpers.getBrowserUser({ actorUuid: workflow.token.actor.uuid }); - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); let dialogContent = `
@@ -56,32 +54,25 @@ export async function runicShield({workflowData,workflowType,workflowCombat}) { let result; let content = ` ${validTokenPrimary.actor.name} has a reaction available for an attack triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); - - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); + + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - chosenItem.prepareData(); chosenItem.prepareFinalAttributes(); chosenItem.applyActiveEffects(); @@ -95,8 +86,8 @@ export async function runicShield({workflowData,workflowType,workflowCombat}) { }; let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; @@ -118,7 +109,7 @@ export async function runicShield({workflowData,workflowType,workflowCombat}) { newItemData.prepareFinalAttributes(); newItemData.applyActiveEffects(); - await MidiQOL.socket().executeAsUser("completeItemUse", browserUserEnemy?.id, { itemData: newItemData, actorUuid: workflow.token.actor.uuid, options: optionsEnemy }); + await MidiQOL.socket().executeAsUser("completeItemUse", browserUserEnemy, { itemData: newItemData, actorUuid: workflow.token.actor.uuid, options: optionsEnemy }); } } } \ No newline at end of file diff --git a/scripts/macros/sentinel.js b/scripts/macros/sentinel.js index 216a65cb..b6501beb 100644 --- a/scripts/macros/sentinel.js +++ b/scripts/macros/sentinel.js @@ -3,16 +3,16 @@ export async function sentinel({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const helpers = await import('../helpers.js'); const socket = module.socket; - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "sentinel"; - let itemProperName = "Sentinel"; - let dialogId = "sentinel"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name.toLowerCase() === itemName) return; + const gpsUuid = "f7c0b8c6-a36a-4f29-8adc-38ada0ac186c"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Sentinel"; + let dialogId = gpsUuid; let target = workflow.hitTargets.first(); + let gmUser = helpers.getPrimaryGM(); - let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: null, itemChecked: null, reactionCheck: true, sightCheck: false, rangeCheck: true, rangeTotal: 5, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + let findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: target, itemName: itemName, itemType: null, itemChecked: null, reactionCheck: true, sightCheck: false, rangeCheck: true, rangeTotal: 5, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); for (const validTokenPrimary of findValidTokens) { if (target.document.uuid === validTokenPrimary.document.uuid || workflow.token.document.disposition === target.document.disposition) continue; @@ -21,16 +21,14 @@ export async function sentinel({workflowData,workflowType,workflowCombat}) { if(target.actor.items.find(i => i.name === itemProperName)) return; + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); - let browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + let browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); const optionBackground = (document.body.classList.contains("theme-dark")) ? 'black' : 'var(--color-bg)'; - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); // Check valid weapons let validWeapons = validTokenPrimary.actor.items.filter(item => { @@ -116,34 +114,27 @@ export async function sentinel({workflowData,workflowType,workflowCombat}) { `; let content = ` ${validTokenPrimary.actor.name} has a reaction available for an attack triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog",browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog",browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, selectedItemUuid, favoriteCheck, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - if (!selectedItemUuid) { console.log("No weapon selected"); continue; @@ -196,8 +187,8 @@ export async function sentinel({workflowData,workflowType,workflowCombat}) { }); let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenWeapon, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; if(checkHits) { @@ -222,7 +213,7 @@ export async function sentinel({workflowData,workflowType,workflowCombat}) { } ]; - await MidiQOL.socket().executeAsGM("createEffects", { actorUuid: target.actor.uuid, effects: effectData }); + await MidiQOL.socket().executeAsUser("createEffects", gmUser, { actorUuid: target.actor.uuid, effects: effectData }); } await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); diff --git a/scripts/macros/silveryBarbs.js b/scripts/macros/silveryBarbs.js index 1c3eedf9..834e612d 100644 --- a/scripts/macros/silveryBarbs.js +++ b/scripts/macros/silveryBarbs.js @@ -3,13 +3,13 @@ export async function silveryBarbs({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "silvery barbs"; - let itemProperName = "Silvery Barbs"; - let dialogId = "silverybarbs"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name === itemProperName) return; + const gpsUuid = "548b5cab-f870-47b6-828a-8de7549debeb"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Silvery Barbs"; + let dialogId = gpsUuid; + let gmUser = helpers.getPrimaryGM(); // Check if attack hits if(workflowType === "attack" && workflow.attackTotal < workflow.targets.first().actor.system.attributes.ac.value) return; @@ -19,22 +19,22 @@ export async function silveryBarbs({workflowData,workflowType,workflowCombat}) { let findValidTokens; if(workflowType === "attack") { - findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); } else if(workflowType === "save") { - findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: false, rangeCheck: false, rangeTotal: null, dispositionCheck: true, dispositionCheckType: "ally", workflowType: workflowType, workflowCombat: workflowCombat}); + findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "spell", itemChecked: null, reactionCheck: true, sightCheck: false, rangeCheck: false, rangeTotal: null, dispositionCheck: true, dispositionCheckType: "ally", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); } let browserUser; for (const validTokenPrimary of findValidTokens) { - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; - const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; + const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemName}`; + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) browserUser = game.users?.activeGM; + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); let dialogContent; const rollDetailSetting = MidiQOL.safeGetGameSetting('midi-qol', 'ConfigSettings').hideRollDetails; @@ -124,33 +124,27 @@ export async function silveryBarbs({workflowData,workflowType,workflowCombat}) { } let content = ` ${validTokenPrimary.actor.name} has a reaction available for a save triggering ${itemProperName}.` - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle: dialogTitlePrimary, dialogContent, dialogId, initialTimeLeft, validTokenPrimaryUuid: validTokenPrimary.document.uuid, source: "user", type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle: dialogTitlePrimary, dialogContent, dialogId, initialTimeLeft, validTokenPrimaryUuid: validTokenPrimary.document.uuid, source: "user", type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle: dialogTitleGM, dialogContent, dialogId, initialTimeLeft, validTokenPrimaryUuid: validTokenPrimary.document.uuid, source: "gm", type: "multiDialog" }; + let gmDialogArgs = { dialogTitle: dialogTitleGM, dialogContent, dialogId, initialTimeLeft, validTokenPrimaryUuid: validTokenPrimary.document.uuid, source: "gm", type: "multiDialog", notificationId: notificationMessage._id }; - result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); + result = await socket.executeAsUser("handleDialogPromises", gmUser, {userDialogArgs, gmDialogArgs}); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); let advantageToken = await fromUuid(allyTokenUuid); let chatContent; @@ -167,8 +161,8 @@ export async function silveryBarbs({workflowData,workflowType,workflowCombat}) { }; let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; @@ -216,18 +210,17 @@ export async function silveryBarbs({workflowData,workflowType,workflowCombat}) { } } ]; - if(advantageToken) await MidiQOL.socket().executeAsGM("createEffects", { actorUuid: advantageToken.actor.uuid, effects: effectData }); + if(advantageToken) await MidiQOL.socket().executeAsUser("createEffects", gmUser, { actorUuid: advantageToken.actor.uuid, effects: effectData }); if(workflowType === "save") { let saveDC = workflow.saveItem.system.save.dc; let saveAbility = workflow.saveItem.system.save.ability; let workflowTarget = Array.from(workflow.saves).find(t => t.document.uuid === enemyTokenUuid); - let targetUser = MidiQOL.playerForActor(workflowTarget.actor); - if (!targetUser.active) targetUser = game.users?.activeGM; + let browserUserTarget = helpers.getBrowserUser({ actorUuid: workflowTarget.actor.uuid }); let targetSaveBonus = workflowTarget.actor.system.abilities[`${saveAbility}`].save + workflowTarget.actor.system.abilities[`${saveAbility}`].saveBonus; let reroll; - if(workflowTarget.actor.type !== "npc") reroll = await socket.executeAsUser("rollAsUser", targetUser.id, { rollParams: `1d20 + ${targetSaveBonus}` }); - else reroll = await socket.executeAsGM("rollAsUser", { rollParams: `1d20 + ${targetSaveBonus}` }); + if(workflowTarget.actor.type !== "npc") reroll = await socket.executeAsUser("rollAsUser", browserUserTarget, { rollParams: `1d20 + ${targetSaveBonus}` }); + else reroll = await socket.executeAsUser("rollAsUser", gmUser, { rollParams: `1d20 + ${targetSaveBonus}` }); if(reroll.total < saveDC) { workflow.saves.delete(workflowTarget); @@ -250,8 +243,8 @@ export async function silveryBarbs({workflowData,workflowType,workflowCombat}) { const saveSetting = workflow.options.noOnUseMacro; workflow.options.noOnUseMacro = true; let reroll; - if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser.id, { rollParams: `1d20 + ${rerollAddition}` }); - if(source && source === "gm") reroll = await socket.executeAsGM("rollAsUser", { rollParams: `1d20 + ${rerollAddition}` }); + if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser, { rollParams: `1d20 + ${rerollAddition}` }); + if(source && source === "gm") reroll = await socket.executeAsUser("rollAsUser", gmUser, { rollParams: `1d20 + ${rerollAddition}` }); if(reroll.total < workflow.attackTotal) await workflow.setAttackRoll(reroll); workflow.options.noOnUseMacro = saveSetting; diff --git a/scripts/macros/witchesHex.js b/scripts/macros/witchesHex.js index 8b1588bf..3c83515e 100644 --- a/scripts/macros/witchesHex.js +++ b/scripts/macros/witchesHex.js @@ -3,13 +3,13 @@ export async function witchesHex({workflowData,workflowType,workflowCombat}) { const module = await import('../module.js'); const socket = module.socket; const helpers = await import('../helpers.js'); - const workflowUuid = workflowData; - const workflow = await MidiQOL.Workflow.getWorkflow(workflowUuid); - let itemName = "witches hex"; - let itemProperName = "Witches Hex"; - let dialogId = "witcheshex"; + const workflow = await MidiQOL.Workflow.getWorkflow(workflowData); if(!workflow) return; - if(workflow.item.name === itemProperName) return; + const gpsUuid = "02fc5000-7f5d-462e-94ac-42a27f453a8f"; + if(workflow.item.flags["gambits-premades"]?.gpsUuid === gpsUuid) return; + let itemName = "Witches Hex"; + let dialogId = gpsUuid; + let gmUser = helpers.getPrimaryGM(); if(workflowType === "save" && workflow.saveResults.length === 0) return; if(workflowType === "attack" && (workflow.isCritical === true || workflow.isFumble === true)) return; @@ -17,28 +17,26 @@ export async function witchesHex({workflowData,workflowType,workflowCombat}) { let findValidTokens; if(workflowType === "attack") { - findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "feature", itemChecked: [itemName], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat}); + findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "feature", itemChecked: [itemName], reactionCheck: true, sightCheck: true, rangeCheck: true, rangeTotal: 60, dispositionCheck: true, dispositionCheckType: "enemy", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); } else if(workflowType === "save") { - findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "feature", itemChecked: [itemName], reactionCheck: true, sightCheck: false, rangeCheck: false, rangeTotal: null, dispositionCheck: true, dispositionCheckType: "ally", workflowType: workflowType, workflowCombat: workflowCombat}); + findValidTokens = helpers.findValidTokens({initiatingToken: workflow.token, targetedToken: null, itemName: itemName, itemType: "feature", itemChecked: [itemName], reactionCheck: true, sightCheck: false, rangeCheck: false, rangeTotal: null, dispositionCheck: true, dispositionCheckType: "ally", workflowType: workflowType, workflowCombat: workflowCombat, gpsUuid: gpsUuid}); } let browserUser; for (const validTokenPrimary of findValidTokens) { - const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemProperName} Timeout`)); + let chosenItem = validTokenPrimary.actor.items.find(i => i.flags["gambits-premades"]?.gpsUuid === gpsUuid); + let itemProperName = chosenItem?.name; const dialogTitlePrimary = `${validTokenPrimary.actor.name} | ${itemProperName}`; const dialogTitleGM = `Waiting for ${validTokenPrimary.actor.name}'s selection | ${itemProperName}`; + const initialTimeLeft = Number(MidiQOL.safeGetGameSetting('gambits-premades', `${itemName} Timeout`)); let hexDie = validTokenPrimary.actor.system.scale["kp-witch"]["hex-die"]?.die; if(!hexDie) { ui.notifications.error("You must have a Witch scale for this actor named 'kp-witch'") continue; } - let chosenItem = validTokenPrimary.actor.items.find(i => i.name === itemProperName); - browserUser = MidiQOL.playerForActor(validTokenPrimary.actor); - if (!browserUser.active) { - browserUser = game.users?.activeGM; - } + browserUser = helpers.getBrowserUser({ actorUuid: validTokenPrimary.actor.uuid }); let content; let dialogContent; const optionBackground = (document.body.classList.contains("theme-dark")) ? 'black' : 'var(--color-bg)'; @@ -109,34 +107,27 @@ export async function witchesHex({workflowData,workflowType,workflowCombat}) { content = ` ${validTokenPrimary.actor.name} has a reaction available for an attack triggering ${itemProperName}.` } - let chatData = { - user: game.users.find(u => u.isGM).id, - content: content, - whisper: game.users.find(u => u.isGM).id - }; - let notificationMessage = await MidiQOL.socket().executeAsGM("createChatMessage", { chatData }); + let chatData = { user: gmUser, content: content, roll: false, whisper: gmUser }; + let notificationMessage = await MidiQOL.socket().executeAsUser("createChatMessage", gmUser, { chatData }); let result; - if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser.id !== game.users?.activeGM.id) { - let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser.id }; + if (MidiQOL.safeGetGameSetting('gambits-premades', 'Mirror 3rd Party Dialog for GMs') && browserUser !== gmUser) { + let userDialogArgs = { dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "user",type: "multiDialog", browserUser: browserUser, notificationId: notificationMessage._id }; - let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog" }; + let gmDialogArgs = { dialogTitle:dialogTitleGM,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: "gm",type: "multiDialog", notificationId: notificationMessage._id }; result = await socket.executeAsGM("handleDialogPromises", userDialogArgs, gmDialogArgs); } else { - result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser.id, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source:browserUser.isGM ? "gm" : "user",type:"singleDialog"}); + result = await socket.executeAsUser("process3rdPartyReactionDialog", browserUser, {dialogTitle:dialogTitlePrimary,dialogContent,dialogId,initialTimeLeft,validTokenPrimaryUuid: validTokenPrimary.document.uuid,source: gmUser === browserUser ? "gm" : "user",type:"singleDialog", notificationId: notificationMessage._id}); } const { userDecision, enemyTokenUuid, allyTokenUuid, damageChosen, selectedItemUuid, favoriteCheck, source, type } = result; if (!userDecision) { - if(source === "gm" || type === "singleDialog") await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); continue; } else if (userDecision) { - await socket.executeAsGM("deleteChatMessage", { chatId: notificationMessage._id }); - let target; let targetDocument; if(workflowType === "attack") { @@ -160,8 +151,8 @@ export async function witchesHex({workflowData,workflowType,workflowCombat}) { }; let itemRoll; - if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser?.id, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); - else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsGM("completeItemUse", { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + if(source && source === "user") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", browserUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); + else if(source && source === "gm") itemRoll = await MidiQOL.socket().executeAsUser("completeItemUse", gmUser, { itemData: chosenItem, actorUuid: validTokenPrimary.actor.uuid, options: options }); if(itemRoll.aborted === true) continue; await helpers.addReaction({actorUuid: `${validTokenPrimary.actor.uuid}`}); @@ -263,8 +254,8 @@ export async function witchesHex({workflowData,workflowType,workflowCombat}) { workflow.options.noOnUseMacro = true; let saveDC = workflow.saveItem.system.save.dc; - if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser.id, { rollParams: `1${hexDie}`, type: workflowType }); - if(source && source === "gm") reroll = await socket.executeAsGM("rollAsUser", { rollParams: `1${hexDie}`, type: workflowType }); + if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser, { rollParams: `1${hexDie}`, type: workflowType }); + if(source && source === "gm") reroll = await socket.executeAsUser("rollAsUser", gmUser, { rollParams: `1${hexDie}`, type: workflowType }); let rollFound = workflow.saveRolls.find(roll => roll.data.tokenUuid === returnedTokenUuid); let rollTotal = rollFound.total; let modifiedRoll = await new Roll(`${rollTotal} - ${reroll.total}`).evaluate(); @@ -290,8 +281,8 @@ export async function witchesHex({workflowData,workflowType,workflowCombat}) { const saveSetting = workflow.options.noOnUseMacro; workflow.options.noOnUseMacro = true; let reroll; - if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser.id, { rollParams: `1${hexDie}`, type: workflowType }); - if(source && source === "gm") reroll = await socket.executeAsGM("rollAsUser", { rollParams: `1${hexDie}`, type: workflowType }); + if(source && source === "user") reroll = await socket.executeAsUser("rollAsUser", browserUser, { rollParams: `1${hexDie}`, type: workflowType }); + if(source && source === "gm") reroll = await socket.executeAsUser("rollAsUser", gmUser, { rollParams: `1${hexDie}`, type: workflowType }); let rerollNew = await new Roll(`${workflow.attackRoll.result} - ${reroll.total}`).roll(); await workflow.setAttackRoll(rerollNew); diff --git a/scripts/module.js b/scripts/module.js index 1ddc35b9..8aa769f5 100644 --- a/scripts/module.js +++ b/scripts/module.js @@ -21,7 +21,7 @@ import { instinctiveCharm } from './macros/instinctiveCharm.js'; import { rainOfCinders } from './macros/rainOfCinders.js'; import { biohazard } from './macros/biohazard.js'; import { enableOpportunityAttack, disableOpportunityAttack, opportunityAttackScenarios } from './macros/opportunityAttack.js'; -import { deleteChatMessage, gmIdentifyItem, closeDialogById, handleDialogPromises, rollAsUser, convertFromFeet, gmUpdateTemplateSize, findValidTokens, pauseDialogById, freeSpellUse, process3rdPartyReactionDialog, moveTokenByCardinal, moveTokenByOriginPoint, addReaction, gmUpdateDisposition, gmToggleStatus, replaceChatCard, validateRegionMovement, ritualSpellUse } from './helpers.js'; +import { deleteChatMessage, gmIdentifyItem, closeDialogById, handleDialogPromises, rollAsUser, convertFromFeet, gmUpdateTemplateSize, findValidTokens, pauseDialogById, freeSpellUse, process3rdPartyReactionDialog, moveTokenByCardinal, moveTokenByOriginPoint, addReaction, gmUpdateDisposition, gmToggleStatus, replaceChatCard, validateRegionMovement, ritualSpellUse, getBrowserUser, getPrimaryGM } from './helpers.js'; export let socket; Hooks.once('init', async function() { @@ -29,78 +29,81 @@ Hooks.once('init', async function() { game.gpsSettings = game.gpsSettings || {}; await updateSettings(); - libWrapper.register('gambits-premades', 'Token.prototype.testInsideRegion', function (wrapped, ...args) { - const [region, position] = args; + let wrappingEnabled = game.settings.get("gambits-premades", "enableRegionWrapping"); + if(wrappingEnabled) { + libWrapper.register('gambits-premades', 'Token.prototype.testInsideRegion', function (wrapped, ...args) { + const [region, position] = args; - if (canvas.scene.grid.type >= 2) return wrapped(...args); //Don't wrap hex grid types for now - - if (!this || !this.document) return wrapped(...args); + if (canvas.scene.grid.type >= 2) return wrapped(...args); //Don't wrap hex grid types for now - const pointsToTest = []; - const size = canvas.dimensions.size; - const width = this.document.width; - const height = this.document.height; - const reduction = 5; + if (!this || !this.document) return wrapped(...args); + + const pointsToTest = []; + const size = canvas.dimensions.size; + const width = this.document.width; + const height = this.document.height; + const reduction = 5; + + const points = [ + { x: this.document.x + reduction, y: this.document.y + reduction, elevation: this.document.elevation }, + { x: this.document.x + (width * size) - reduction, y: this.document.y + reduction, elevation: this.document.elevation }, + { x: this.document.x + reduction, y: this.document.y + (height * size) - reduction, elevation: this.document.elevation }, + { x: this.document.x + (width * size) - reduction, y: this.document.y + (height * size) - reduction, elevation: this.document.elevation }, + { x: this.document.x + (width * size / 2), y: this.document.y + reduction, elevation: this.document.elevation }, + { x: this.document.x + (width * size / 2), y: this.document.y + (height * size) - reduction, elevation: this.document.elevation }, + { x: this.document.x + reduction, y: this.document.y + (height * size / 2), elevation: this.document.elevation }, + { x: this.document.x + (width * size) - reduction, y: this.document.y + (height * size / 2), elevation: this.document.elevation }, + { x: this.document.x + (width * size / 2), y: this.document.y + (height * size / 2), elevation: this.document.elevation } + ]; - const points = [ - { x: this.document.x + reduction, y: this.document.y + reduction, elevation: this.document.elevation }, - { x: this.document.x + (width * size) - reduction, y: this.document.y + reduction, elevation: this.document.elevation }, - { x: this.document.x + reduction, y: this.document.y + (height * size) - reduction, elevation: this.document.elevation }, - { x: this.document.x + (width * size) - reduction, y: this.document.y + (height * size) - reduction, elevation: this.document.elevation }, - { x: this.document.x + (width * size / 2), y: this.document.y + reduction, elevation: this.document.elevation }, - { x: this.document.x + (width * size / 2), y: this.document.y + (height * size) - reduction, elevation: this.document.elevation }, - { x: this.document.x + reduction, y: this.document.y + (height * size / 2), elevation: this.document.elevation }, - { x: this.document.x + (width * size) - reduction, y: this.document.y + (height * size / 2), elevation: this.document.elevation }, - { x: this.document.x + (width * size / 2), y: this.document.y + (height * size / 2), elevation: this.document.elevation } - ]; - - points.forEach(point => { - pointsToTest.push(point); - }); - - const testResults = pointsToTest.map(point => { - const result = region.testPoint(point, position?.elevation ?? this.document.elevation); - return result; - }); - - const isInside = testResults.some(x => x); - - return isInside || wrapped(...args); - }, 'MIXED'); - - libWrapper.register('gambits-premades', 'Token.prototype.segmentizeRegionMovement', function (wrapped, ...args) { - const [region, waypoints, options] = args; - - if (!this || !this.document) { - return wrapped(...args); - } + points.forEach(point => { + pointsToTest.push(point); + }); - const { teleport = false } = options || {}; - const samples = []; - const size = canvas.dimensions.size; - const width = this.document.width; - const height = this.document.height; - const reduction = 5; - - const points = [ - { x: reduction, y: reduction, elevation: this.document.elevation }, - { x: width * size - reduction, y: reduction, elevation: this.document.elevation }, - { x: reduction, y: height * size - reduction, elevation: this.document.elevation }, - { x: width * size - reduction, y: height * size - reduction, elevation: this.document.elevation }, - { x: width * size / 2, y: reduction, elevation: this.document.elevation }, - { x: width * size / 2, y: height * size - reduction, elevation: this.document.elevation }, - { x: reduction, y: height * size / 2, elevation: this.document.elevation }, - { x: width * size - reduction, y: height * size / 2, elevation: this.document.elevation } - ]; - - points.forEach(point => { - samples.push(point); - }); + const testResults = pointsToTest.map(point => { + const result = region.testPoint(point, position?.elevation ?? this.document.elevation); + return result; + }); + + const isInside = testResults.some(x => x); + + return isInside || wrapped(...args); + }, 'MIXED'); + + libWrapper.register('gambits-premades', 'Token.prototype.segmentizeRegionMovement', function (wrapped, ...args) { + const [region, waypoints, options] = args; + + if (!this || !this.document) { + return wrapped(...args); + } + + const { teleport = false } = options || {}; + const samples = []; + const size = canvas.dimensions.size; + const width = this.document.width; + const height = this.document.height; + const reduction = 5; - const segments = region.segmentizeMovement(waypoints, samples, { teleport }); + const points = [ + { x: reduction, y: reduction, elevation: this.document.elevation }, + { x: width * size - reduction, y: reduction, elevation: this.document.elevation }, + { x: reduction, y: height * size - reduction, elevation: this.document.elevation }, + { x: width * size - reduction, y: height * size - reduction, elevation: this.document.elevation }, + { x: width * size / 2, y: reduction, elevation: this.document.elevation }, + { x: width * size / 2, y: height * size - reduction, elevation: this.document.elevation }, + { x: reduction, y: height * size / 2, elevation: this.document.elevation }, + { x: width * size - reduction, y: height * size / 2, elevation: this.document.elevation } + ]; - return segments || wrapped(...args); - }, 'MIXED'); + points.forEach(point => { + samples.push(point); + }); + + const segments = region.segmentizeMovement(waypoints, samples, { teleport }); + + return segments || wrapped(...args); + }, 'MIXED'); + } }); Hooks.once('socketlib.ready', async function() { @@ -149,6 +152,7 @@ Hooks.once('socketlib.ready', async function() { socket.register("replaceChatCard", replaceChatCard); socket.register("validateRegionMovement", validateRegionMovement); socket.register("ritualSpellUse", ritualSpellUse); + socket.register("getBrowserUser", getBrowserUser); }) Hooks.once('ready', async function() { @@ -157,6 +161,8 @@ Hooks.once('ready', async function() { }).catch(error => { console.error("Error loading compendium data:", error); }); + + if(!game.gpsSettings.primaryGM) game.settings.set("gambits-premades", "primaryGM", game.users.activeGM.id); game.gps = { gmIdentifyItem, @@ -174,6 +180,7 @@ Hooks.once('ready', async function() { rainOfCinders, biohazard, ritualSpellUse, + getPrimaryGM, socket }; @@ -183,11 +190,7 @@ Hooks.once('ready', async function() { async function executeWorkflow({ workflowItem, workflowData, workflowType, workflowCombat }) { if(!game.gpsSettings.enable3prNoCombat && !game.combat && workflowCombat) return; - if (game.user.isGM) { - await socket.executeAsGM( workflowItem, { workflowData: workflowData, workflowType: workflowType, workflowCombat: workflowCombat }); - } else { - await socket.executeAsUser( workflowItem, game.user.id, { workflowData: workflowData, workflowType: workflowType, workflowCombat: workflowCombat }); - } + await socket.executeAsUser( workflowItem, game.user.id, { workflowData: workflowData, workflowType: workflowType, workflowCombat: workflowCombat }); } Hooks.on("midi-qol.prePreambleComplete", async (workflow) => { @@ -282,14 +285,14 @@ Hooks.once('ready', async function() { }); Hooks.on("preUpdateCombat", (combat, update, options) => { - if(!game.user.isGM) return; + if (game.user.id !== getPrimaryGM()) return; const startedPath = `gambits-premades.started`; const prevStarted = combat.started; foundry.utils.setProperty(options, startedPath, prevStarted); }) Hooks.on("updateCombat", async (combat, update, options) => { - if(!game.user.isGM) return; + if(game.user.id !== getPrimaryGM()) return; const combatStarted = combat.started && !foundry.utils.getProperty(options, `gambits-premades.started`); const hasProcessedStart = await combat.getFlag('gambits-premades', `startProcessed-${combat.id}`); if(combatStarted && !hasProcessedStart && game.gpsSettings.opportunityAttackEnabled) { @@ -299,7 +302,7 @@ Hooks.on("updateCombat", async (combat, update, options) => { }) Hooks.on("createCombatant", async (combatant, options, userId) => { - if(!game.user.isGM) return; + if(game.user.id !== getPrimaryGM()) return; let combat = game.combat; if (combat && combat.started && game.gpsSettings.opportunityAttackEnabled) { await enableOpportunityAttack(combatant, "enterCombat"); @@ -307,12 +310,12 @@ Hooks.on("createCombatant", async (combatant, options, userId) => { }); Hooks.on('deleteCombat', async (combat) => { - if(!game.user.isGM) return; + if(game.user.id !== getPrimaryGM()) return; if(game.gpsSettings.opportunityAttackEnabled) await disableOpportunityAttack(combat, "endCombat"); }); Hooks.on("deleteCombatant", async (combatant, options, userId) => { - if(!game.user.isGM) return; + if(game.user.id !== getPrimaryGM()) return; let combat = game.combat; if (combat && combat.started && game.gpsSettings.opportunityAttackEnabled) { await disableOpportunityAttack(combatant, "exitCombat"); @@ -345,7 +348,8 @@ async function updateSettings(settingKey = null) { 'enableMageSlayer': 'mageSlayerEnabled', 'enableInstinctiveCharm': 'instinctiveCharmEnabled', 'enableRainOfCinders': 'rainOfCindersEnabled', - 'Enable Opportunity Attack': 'opportunityAttackEnabled' + 'Enable Opportunity Attack': 'opportunityAttackEnabled', + 'primaryGM': 'primaryGM' }; if (settingKey === null) { @@ -361,7 +365,7 @@ async function updateSettings(settingKey = null) { } Hooks.on('updateSetting', (setting) => { - if (!game.user.isGM) return; + if (game.user.id !== getPrimaryGM()) return; if (setting.config.namespace === "gambits-premades") { updateSettings(setting.config.key); } @@ -402,7 +406,7 @@ function setupTemplateVisibilityHook() { }); canvas.templates.placeables.forEach(template => { - if(!game.user.isGM) return; + if(game.user.id !== getPrimaryGM()) return; if (game.gpsSettings.hideTemplates || template.document.getFlag('gambits-premades', 'templateHiddenOA')) { hideTemplateElements(template); } @@ -427,7 +431,7 @@ function setupTemplateCreationUpdateHooks() { } async function updateRegionPosition(region, tokenDocument) { - if (!game.user.isGM) return; + if (game.user.id !== getPrimaryGM()) return; if (!region || !tokenDocument) return; let regionDisabled = region.getFlag("gambits-premades", "regionDisabled"); @@ -492,7 +496,7 @@ async function updateRegionPosition(region, tokenDocument) { } Hooks.on('updateToken', async (tokenDocument, updateData, options, userId) => { - if (!game.user.isGM) return; + if (game.user.id !== getPrimaryGM()) return; if(!game.gpsSettings.opportunityAttackEnabled) return; if(!game.combat) return; diff --git a/scripts/settings.js b/scripts/settings.js index bddb25e6..4121ad9d 100644 --- a/scripts/settings.js +++ b/scripts/settings.js @@ -566,6 +566,24 @@ function registerSettings() { } }); + game.settings.register("gambits-premades", "enableRegionWrapping", { + name: "enableRegionWrapping", + scope: "world", + config: false, + type: Boolean, + default: true, + type: Boolean + }); + + game.settings.register('gambits-premades', 'primaryGM', { + name: "primaryGM", + hint: "", + scope: 'world', + config: false, + type: String, + default: "" + }); + game.settings.registerMenu('gambits-premades', 'generalSettings', { name: game.i18n.localize("General Settings"), label: game.i18n.localize("General Settings"), @@ -716,6 +734,7 @@ class BaseSettingsMenu extends FormApplication { const settings = { enableInterceptionCustomDiceNumber: Number(game.settings.get("gambits-premades", "enableInterceptionCustomDiceNumber")), enableInterceptionCustomDiceFace: Number(game.settings.get("gambits-premades", "enableInterceptionCustomDiceFace")), + primaryGM: game.settings.get("gambits-premades", "primaryGM") }; const numberSelect = html.find('#enableInterceptionCustomDiceNumber'); @@ -727,7 +746,7 @@ class BaseSettingsMenu extends FormApplication { option.selected = true; } numberSelect.append(option); - } + }; const faceSelect = html.find('#enableInterceptionCustomDiceFace'); const faces = [4, 6, 8, 10, 12, 20]; @@ -740,6 +759,18 @@ class BaseSettingsMenu extends FormApplication { } faceSelect.append(option); }); + + const primaryGM = html.find('#primaryGM'); + for (const user of game.users.contents) { + if(!user.isGM) continue; + const option = document.createElement('option'); + option.value = user.id; + option.textContent = user.name; + if (user.id === settings.primaryGM) { + option.selected = true; + } + primaryGM.append(option); + }; } } @@ -906,7 +937,9 @@ class generalSettingsMenu extends BaseSettingsMenu { hideTemplates: game.settings.get("gambits-premades", "hideTemplates"), debugEnabled: game.settings.get("gambits-premades", "debugEnabled"), enableIdentifyRestrictions: game.settings.get("gambits-premades", "Enable Identify Restrictions"), - identifyRestrictionMessage: game.settings.get("gambits-premades", "Identify Restriction Message") + identifyRestrictionMessage: game.settings.get("gambits-premades", "Identify Restriction Message"), + enableRegionWrapping: game.settings.get("gambits-premades", "enableRegionWrapping"), + primaryGM: game.settings.get("gambits-premades", "primaryGM") }; } @@ -918,5 +951,7 @@ class generalSettingsMenu extends BaseSettingsMenu { await game.settings.set("gambits-premades", "debugEnabled", formData.debugEnabled); await game.settings.set("gambits-premades", "Enable Identify Restrictions", formData.enableIdentifyRestrictions); await game.settings.set("gambits-premades", "Identify Restriction Message", formData.identifyRestrictionMessage); + await game.settings.set("gambits-premades", "enableRegionWrapping", formData.enableRegionWrapping); + await game.settings.set("gambits-premades", "primaryGM", formData.primaryGM); } } \ No newline at end of file diff --git a/templates/generalSettingsMenu.html b/templates/generalSettingsMenu.html index 102b9fa9..ec53d647 100644 --- a/templates/generalSettingsMenu.html +++ b/templates/generalSettingsMenu.html @@ -118,12 +118,12 @@ -