From a447786b37da9c484879330af716d7b4b37b4337 Mon Sep 17 00:00:00 2001 From: NoxxFlame Date: Tue, 12 Aug 2025 14:40:02 +0100 Subject: [PATCH 001/115] Copied taskmaster progress to current dev branch --- .luacheckrc | 2 + .../materials/vgui/ttt/roles/tsk/icon_tsk.vmt | 7 + .../materials/vgui/ttt/roles/tsk/icon_tsk.vtf | Bin 0 -> 5712 bytes .../vgui/ttt/roles/tsk/score_tsk.png | Bin 0 -> 4640 bytes .../vgui/ttt/roles/tsk/sprite_tsk.vmt | 11 + .../vgui/ttt/roles/tsk/sprite_tsk.vtf | Bin 0 -> 5712 bytes .../vgui/ttt/roles/tsk/sprite_tsk_noz.vmt | 11 + .../materials/vgui/ttt/roles/tsk/tab_tsk.png | Bin 0 -> 2591 bytes .../targeticons/down/sprite_target_task.vmt | 11 + .../targeticons/down/sprite_target_task.vtf | Bin 0 -> 5712 bytes .../down/sprite_target_task_noz.vmt | 11 + .../ttt/targeticons/up/sprite_target_task.vmt | 11 + .../ttt/targeticons/up/sprite_target_task.vtf | Bin 0 -> 5712 bytes .../targeticons/up/sprite_target_task_noz.vmt | 11 + .../roles/taskmaster/cl_taskmaster.lua | 435 ++++++++++++++++++ .../gamemode/roles/taskmaster/shared.lua | 77 ++++ .../gamemode/roles/taskmaster/taskmaster.lua | 247 ++++++++++ gamemodes/terrortown/gamemode/shared.lua | 23 +- 18 files changed, 849 insertions(+), 8 deletions(-) create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/icon_tsk.vmt create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/icon_tsk.vtf create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/score_tsk.png create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk.vmt create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk.vtf create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk_noz.vmt create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/tab_tsk.png create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task.vmt create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task.vtf create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task_noz.vmt create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/targeticons/up/sprite_target_task.vmt create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/targeticons/up/sprite_target_task.vtf create mode 100644 gamemodes/terrortown/content/materials/vgui/ttt/targeticons/up/sprite_target_task_noz.vmt create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua diff --git a/.luacheckrc b/.luacheckrc index 3b71d230b..2dae956eb 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -1142,6 +1142,7 @@ globals = { "ROLE_SPONGE", "ROLE_SPY", "ROLE_SWAPPER", + "ROLE_TASKMASTER", "ROLE_TRACKER", "ROLE_TRICKSTER", "ROLE_TURNCOAT", @@ -1210,6 +1211,7 @@ globals = { "CRHUD", "DEATHRADAR", "SYNC", + "TASKMASTER", -- TTTPAP Namespaces "TTTPAP", diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/icon_tsk.vmt b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/icon_tsk.vmt new file mode 100644 index 000000000..cbf40a7ad --- /dev/null +++ b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/icon_tsk.vmt @@ -0,0 +1,7 @@ +"UnlitGeneric" +{ + "$basetexture" "vgui/ttt/roles/tsk/icon_tsk" + "$vertexcolor" 1 + "$vertexalpha" 1 + "$translucent" 1 +} diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/icon_tsk.vtf b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/icon_tsk.vtf new file mode 100644 index 0000000000000000000000000000000000000000..ccacf7431a54821ba0adc56a5cd832143d5faed3 GIT binary patch literal 5712 zcmc&&4_MP>9{+A*Y^-22;-vDi?QtF=brkkk?NJ%y&KRrUar+4Y%9Ofh{JpYN#5TQr z!n6nEq{|XDN^=;U3eGYQmp(^OcU1R0kWX|Q2}n(m@vre`?7i>1@f$FY)4S*Xyu91^ z?EUk7Ki_}v_qWx$l^_5BKECw$Qqn&u00;l4E$eT4S1>6DSG-jG`xU-#Oz~p;M-Yl{ z5{Y*j*EisOr(fvt^#Hy)@TIHD)k0d@H+E8+Ll_1cT(z0_dAqhUYO%>^H0EUzqQutV z+R_3=ZqqR?tpW64P-oKV=dpT}e1(g#v-fe?VyM@)Sry##BAHK4%diE4@M2F$qrJa#cag~*oa8E{31sOd=HdfVU^0?XABtz|W z4_#G^27oYASQCI}j^|PRF}PyZ^&;>3`59_wJQhIH^321hA)U6lsdE5fS>d z>GnrrG=u<{^nxSgkOlPZRXtK5HNfz%kdzA0$8PJVq+nZcz>;5oz0U(+ zbAe8$^F%zF4hMqN=(4rR+=&tC^Oh}*jf2`KeZJuZ!4Uzqc%9(IUMpA z$;t5OUvO-$;~CPQH^cc+LI}59z79PG_0Mb=Hulfm(mxl#P8MP#l90W$OTny|F26Cl zS;fc3@^8sCE2#dblqMo5AX!<*yIA3U)t^o(d(PqlVI$JCA>MZ&4mOj*PQ3(tU4b|0KLQ%OySLL-Q{I9U~ zzbtP_rH{|1I!l$+=>Cil%wPA;ji{?{EOcW}*+>Wn8xY_96T2~2dn_$2jm6hI7kzGLNSw4y}rN5{y;ZgdVp z1bZ??i8Xy!V;`Vc9f#C4m|q#*VlU=Gu9oI+U|8(S=l?#|c<%%Mdi|t4tM5Ez?ifvN zCd%{MPooiO`Z^Yc`OmL$sMf1W4YTo&4X}TnR-`E@$;u+#H2whZiyu|Ts%t)6^h3&C zF8}sRG(X3S6H`U^?$@_l^4kF`CCq<-*H<~MUucG!hPzli8jOP{^*Gap^L5O`ZHO=P zuE}Wr27Ux@VMWlT@Oik+jP?Hg!l7$&f1kWihav1COYS{Yee1yO{FL#XR{|Q1Bl))7 zwY7f!T8HXd0h!hQ;=GyuPx)t+WQ_>kBI8CfoZa9OCAPLkM2HuhT;6^v6#3d*G+wx+ zNPek)f%ksIt6SDjl~Mj4wLZht0O70eI5WqIDG+Z&dVj9riR+O)AsdqQ9r(E=c-3~q zcEpLl1(^7mQME!T-e+^kgiLW!dGMem^ioCnd)xZxe$PQ72lYkX9Rs*ZGbJYs)aAca zcLV_>2u;|QoS8UJM#_jol^_J}R6L6`W`)VrahbLMmFSuNA9e%(A64#S?h+#N)e8=l zZ+;jg?T}-q3@Cqo*wTWlFBSGsOzUDY2HyIKkOr3t59l`RlG?38IOy6T5$g_v=M5-2 zvoHiMMpFCNFijJ9e^d-%5XohDpMYndesy>_)mDOV-a>j|AYV!u8?A@C7i_Iwaky+4 zz;c?(pT~K!>D6N4tH>6xo~tBFeD#z}*sMZzPm5o(V(SZA{q}DR;D0@Lru`q+HmgS5 z->tnFf3aj~LC;GCe*WLndc-&)p!EuXRq6QzpD#@3@Y{7lFs*;8X>7F2(`1hilA-_V zbPO4%^Ca!ddeGl#`f^iT{`4d^1@a$!FuiOTJHVYsDE|deBzhlvAb)89e`^01);kJW z``?Ve2Ki@whw(pYe|(zo+BeYtk~vEYIUF|xeack~ zL(YTv0SH2Gsg~&V0M!HXk7@mqAguCw_=Guse^*5ite1EzNQMmZaXG-a4ew+f!}Kp< z`9Ji}`D48~-TorYE=BHE8toJW!g!W=Ge|Ik}rPJVU6UbOf z^CiUtw0Z<+r}jsDtM-?HVFv$Qil{hDj~y)kqXF@cPx~|KA4hVjqQpJr|F_D&Y0NnE zn9(Vq_Kd)GZT0bZ={{AI6g?Qt4-=V!B6v0O1M1y8-o+fxdq{5Kmhl}DYJY$O6XZ~r zJX&pYtw+CaWd_DjIiqFxcD4;yaBkiHGx?iUkHtAII~*+koid+2+4?7te~i|kSev!h zHot`Q-%DKaHkUyW5z*Qj5{CER33~rk_0jxuL;Tx(`CszNWc+U!;!*p(whC>G_N#Ok zQ%2Y#8$ZSGFZZbXDcaKF8~^?)3{XtSTWzg$VL<-x_xpc%6_p>dcxT$?oliXiutTE6 z=?_`(@*AhwHwo=ORS%lc{~v#G({n8UBLVh*{RaCR6j{2}C0I{*?=u7XkJJRF5Qk-r zHQK4W`x`0f(z1i(qrnQ9u&vihL=k+m=PC3N$hzW9xbf9-TvCXN zqxRPKU_FS|ygA16|AYD20qcp1M1@T5ucY!O`O@zI-ksj zC-?hi`Z$&R=9&>>u~8hZ_I+yyvN|X`R0Q*lSam&UZ99(gOK!uEU4l ymFwGSJ&5#~x_UGg{(jUMi62;U`mrPc|EuGH^Z!qHM;$)=hUB#e-Q~@H%-;e242Z`7 literal 0 HcmV?d00001 diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/score_tsk.png b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/score_tsk.png new file mode 100644 index 0000000000000000000000000000000000000000..87e26daf69cef5d82b00ee68da4b63b9de16833d GIT binary patch literal 4640 zcmcgw4OmoF8onTlqGq6&l!fD{`Nw7E{?8p9L>UCs0pw@F#Mb*aa2ICoG&8_Jnxt8# zY-T8%N^7Wr;X{_0iMZ&lQJM>86y_2_nV^DLmV%blxiiCPyP`Z>&(8DA+Q#MOd(d03@XI7RH4I^}Fx zp(51~uZWPWf`Sf3U{0+@6%-xHkPL~@WQYP)qqs_qsSp%aQ(9c3MKOi@qXg=#yiuE= zpX*izo^;9#yWOHysd963LvyiE$(pW0Xqr~3Q5A~9KmxYqneB`NHrpojA?O7gXB91W zQ8FuJM23~J?K&ke)#Zc9;(;~W+&lrsR1U_XLPFKDPfkIe^T=7UtyxaxJf{+}1e0L4 z+khcj9t(v<#`xEV3bZmP%VLKQT22L(W=!hQG>*b z#=JgJ6o(NtjB1h)TuV?|Lj8nW3M4Vl*qM9D@toEuSxpQeUo@XDDuEEf!1IM36nI%!WfFPutu$>U;)DgmgRYp zG;)3G^%9pYXPLa-RdKw;0gT&Pd5s2R8H|S+k|SY^1ZXtN(ZEeaL+~tuYETywz?wL# z2#TJ`x)W8liU)`!MzIVH3X(xJJWL}v0W+)-fZ-IwkVYfNsDW2s2Y4!i2UoGUv!`O+tbNr5m1aO6>_4uSWN^?3(!gu1V*^W<3)#%m8us3 zJ2s~wSle<{aXAYC@zRMEB?#{NFKro7-1(?Sf7G#}3 z!L)|MVWWmdQ3}B^lwxP9ED#?8<#`O|d4hCfku<=fG^~K5Y7S?Sfno_H zC2+Dyz%Igt#S#Juvpm8uxIln7-~+~@IF29~1ZD{}4^srr!7NQ7u!bUd3ZpcbVAKp4 zi(_e?04Dtob{R>EL@5j%AeJ)siJ!vRaf{RV$nhNX=f42MzB zkYN_VDVRk`0%nZ_PV*eXaU|WBHGTfvZ9^K6D<~0)pm*+zu2lnZgu8D7+$ZL8T6l7# zf5LddD&CO-ccz)g1cfuX+d_rPgR3yu)?IaCZ}o0BtHMw5Q)p+asTP8#kwu=fptw*dLp^Zo%IJZ~_98Puy4 zyq{EUpAJKiPg9J3c2er<+LR?3fhmE#ZSD2F&mDNB&WsY3(;xROJQeue_$NwVnfHcr z@y4~$f;es`+@tu*>hR#_zFv2Eo$BJMz;*K{J^R_pPxpn4o)j~GP15%0gUxfP6`f^< zcZ=$JjqUX%VHy9f<(tnmHa^&O;>)V`Ww!d=gbJ{22&5hk(9erV} zboS7qSz%!{r__ac^?A>)*%dz}=s2Gc_eMfq1AbgR9NStK8W$UTRw%qY#CKKQgTXT$ z7cYIj+YF6_N|oMKXxhdx+1c9KI`)-`$zBlG83{>VJtM=f#>|@J_iCBn!k?<=RaaL(nANnuGRNWQiB)bG z(s8iMfu6i}?b^r3jvXs*Y;0`XlzwB`lRj?`IznY?r)^p}r}Xtr!`>eq5)$HHAbB0y zTfA-U*oEk3{KuO&+p?GJ*}3}DbMFlm{QLt#(+(_s?kIBt~5>KE?(y8B@+BQvw;a?aCv zzJJ8k6!lSZ@~uMTp;xzVUFRPlpqp1VT@D^>85Hh+WK3dxKJ$K4rFTKIIeq!^sHMHz!0zMG*ymt^8t&-}I?Ne7tEW7y7}w=cjLu7e$ONW{wA@ zPCI($%o#n$om-!nm}vOurN_p;({%Yydpb9lRsA{Hd;ZjyCr(|wWXWUM+SjU~=-~B} zg&^Nq&-~PL5@gZtVj<73plam8$b}!Q8>1q-zN~7f`n2Nb(a##Tl2c3Lr=0)J5#|&B z^!blBJv7_@ZRY6ng>Q8*drr?7e`0UV)tWkE(V-`=%z#SHXAMhYdp^lt!WC8yF0gA& zu^{9J(n1Y^k=E+wt)nB~*=aR2>?$j3n*p`2x$wf|ZaA{_>iH9^dwY8yp6zd@aQvGQ zi)5N5xsasvHpvemTiv&2fx&F>zNykm5Xx+`}&$wv%~efAK$^Iu7$Xe=CfzR zY?nTJv&%6vI7j>1;eZWinwqNpU(}aupK_^|O$?0GJoUByy^4wix~X``7g^+lz@c?L z%W6)SmzQVOZ<}?67`|$o?&<60(G&L$X-$FhPX(0j*l})2axxWGH0?rXXHxf-mK8_Z zzrXd*prZX!OHEXDHDRkB;zK|3OVz(EPHc85tKE+S=OI2XP&m_PFG$4VIsKmyZe$KC)$8(%t~S zmEU?7oQ67UceI2CO!}|_ozi+L^7`n2$Z6wWhjw|z4_^AYPny?o=#he;03l>l&*5(; YpH7cpl9Yi8`9GYP$XNYbbC$0B1%7j&asU7T literal 0 HcmV?d00001 diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk.vmt b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk.vmt new file mode 100644 index 000000000..3df238e0a --- /dev/null +++ b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk.vmt @@ -0,0 +1,11 @@ +"UnlitGeneric" +{ + "$basetexture" "vgui/ttt/roles/tsk/sprite_tsk" + "$nocull" 1 + "$ignorez" 0 + "$nodecal" 1 + "$nolod" 1 + "$vertexcolor" 1 + "$vertexalpha" 1 + "$translucent" 1 +} diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk.vtf b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk.vtf new file mode 100644 index 0000000000000000000000000000000000000000..84d0c09f5648eb00265051db3cf3ea9c3c2094c1 GIT binary patch literal 5712 zcmeHLe^6A{6+Zj+2Mf5eRo1~o+oi5BQcO*1j1VR)OeC|WiL2o)I||cfDQ(mtrKZ1P zL^ivarX6M^1ceb1o@PK7GJ@>7Tq1$w< zsigkV%YE$o_PlrR{m!}PyZ5doI}0KJKuMR4E+hNX1IXx}74N5M>CzSY#*rRFHxU~8 zr`3v&aUp~FpM7DYYYkn4bRoW84h|#T)%kgynRg3xtF-EU>=PnYh;G4aG#Y)v+Qtcp zRU;le^C%>xBW9>oRNMlhj!K*G_KUG=)7BzxE(aZuJzlf}3?R?zbO0rOo@Z@_J`n*_ zDy7n%Z>ls<4fq1SW-8`A+IN$w=K1@5AMhXWvHpYQPd=|$RN}u_<@I(xe*;XFdmh%x z0o;O)=Xu57Jb4|HhkNS$cCAdW*Q(;)dHf2Sw^aZkbHl3!-tFOGs5<+HQ?IbS4$ z%E4ulpY*-^miN7~yifAiPB2v{s7ih-9QW^P@b7AV`^7dPBY%7T*=v}74ePINE=S~z z{0_rqdRcrwgNDdiKVRg2;Y@s{(jfU;7UEAB zk@;J~LM!#h^DDzJaI^l(P*bB@l_KVP*vz5lX+cl-Tt?2zo?{YiM~oc3)to4!HB z$>jjKLp0m@htRX*SivFkzaEq_2TVo{t{CQ2)O&;0YKuK-@f1fddEs2Vk^Dkmt=cG~L>uFVtlajG#5Wu(FRrt%peptM+d%2a z&uIt)m|U=?*a&#$dPSy8P3;%1N{DpA^c$czm9QZ+XrY-0JOFxGik|S%IEd1K;;ruC z1ysLm|1-s)YVt-Uv-}+#ZYiGl)`Q0AbE8j}_~X^lD#gB2M0>o(k>;8WYs!s2MVZ`kl9mPF8&yIZl?Y}&^>D>~)o|;#bb$`q}SB~^Gj)L zh_Q_W2n@G&GKd4XwvkEh1V_QIk*AjU0kX5RE#dJF$J_(!?AvI{viK{NI=)9<_mh4~ zDK?|1IbP9XdZ!3%WdF~w^35Y_IvlLMHd1gSAKu^paY(ON%;xIfoiOu1g?l!iZ{u0L z`*%2`mx~rlc6BtCPd)*f6Ks7`Qh5sYW+q;D%^Uy7 zV_7d;rONd5i};6+&le!7h!Jc*KpwF5)5^%!r{n@rKeEH0zgzrLAZE-=6(CRKugO_@ zxP$6^#s5zHgGXp{^nfzeC&a7OiPhP`1CCcuov5bOQV-_b>Xjc(b#{{jo=PwQd_txw0`3!JrcbX2D)z)l>%$?v=P z;~{Gd)T~Hlv$qMRb2gnSx`kKPo7f81Oy`65f|H2B{dnN5d!v8%UHo6M#_S&4mk_TG z_$a>4z=oOqE3I1+^C%y_XEtwj`=(Cfgp2gALCbMY`|tlwsqoAnRV%u8Q2 z|AmvZ`FYh|z~;9?VW_$yuJ8L30zNSwO_ZNhDhz2uB8Gd81FU`HMZ|s|-IVSgOCNhK z=D^<7itYb9lcA-E zmM{r-t-iOoGpxNoeyu0<@)=B&`g=@v?K_EkN5u2;eDJ69Mg{wQQshtbQv?1g3A6dS kkOlv?{j0zl(ALfEj{~dt`>7az8jo~7Vi`2|d?w+40P;;bIsgCw literal 0 HcmV?d00001 diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk_noz.vmt b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk_noz.vmt new file mode 100644 index 000000000..1c098b498 --- /dev/null +++ b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/sprite_tsk_noz.vmt @@ -0,0 +1,11 @@ +"UnlitGeneric" +{ + "$basetexture" "vgui/ttt/roles/tsk/sprite_tsk" + "$nocull" 1 + "$ignorez" 1 + "$nodecal" 1 + "$nolod" 1 + "$vertexcolor" 1 + "$vertexalpha" 1 + "$translucent" 1 +} diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/tab_tsk.png b/gamemodes/terrortown/content/materials/vgui/ttt/roles/tsk/tab_tsk.png new file mode 100644 index 0000000000000000000000000000000000000000..56f9eb8252878b2e2efab0fe48864718c8fc2d7e GIT binary patch literal 2591 zcmc&$du$X%7(b#Spx_glpiMX1S}U@*kK5bZT{)okfEK;BmTP#l5@vVj+O@Y2cDKE2 ziINnG5~u_&1R^RLB}OXLU_b~2yaF1M2BUu{iJ}-ZN}?751dIaC-m8Taslmic=5}WH zoA38Me&08QW8gu}b&|st(!muDFcxghWCj4(l&Dx2nw|*IxlNB8;)T& z8#hs%|9l+)ifuTY#~9WYP0K^r&a5`%Mm8YBO52fk6Owh%Hd-wi&T2zu7U#UNojN!e z&k<}#;_1z%SYbinzz`Zi9A(f)P(Fg;BD7DWInl>GNz)=lxj3d6HWW45o)={anj#oJ zLbIZu7b#&;Rtix^0S@>lIYkzuhNS`IvZ{e5NSb;Rj^zU>Rv0nELU70?Us`K8ELQ2Z z19TZyg@QP;#;dA|$U>hKkY$#L`T!sVj%5jn=lldC&@_ZlqW%78Zhy#-Tix8c`!hUO z3>oPdL}fTmQY48cqC7_v0Ut{f5>0UgCqMvzKudvWUR#Z&qEZ8~p;}$56r|D5Lm)$e zCm4KMM7Y`g@n(orUY~G=6KOt|@C>$XM4dRWV0jaYT&@k&=IQ}sSg#K&o3HAM z5x1Yn*(Nswy$PcBL*nGkoRJN^4O-5iLng2Q>N?P}gLu?3Gz^$#OqGG_JK3fy*;>wL z3v&!?kUKZUQJ|#`3ENPVyb0KUhc>c z6aD`?Nw;)nWc7E0GsE8%?P|FD^35xcN=rU`Ai3z3 zRN1+A-d~*B(V!I_4jKnGT@sHSJAdWi_x78YUjO;gsW`*+xoV)@x6mYq+dz~*1!A1qSW*QDSy9o$Cj?(w?`W5 z_Y@W1*|S-n`0>iIzox_q@~-bXPTccN!`S4+%lB?wTCh%JC-Ign}>8Fypxm9-q&!g=hWN{a@XnD?w-!VE|U5raG@tK!e{g4FMQcVF&$nP0K& zME%M+YcA9*e&$H`gTF*h_LjE4rc623xZzC6rYX@KEgQFl8+*^E+Ip8StkI-~BcJWq mGok*G;9q3}1%1iVGlALFk(mSa-V^Q>u4-0wXy?;QI{yabK6+vR literal 0 HcmV?d00001 diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task.vmt b/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task.vmt new file mode 100644 index 000000000..d80b4dcfe --- /dev/null +++ b/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task.vmt @@ -0,0 +1,11 @@ +"UnlitGeneric" +{ + "$basetexture" "vgui/ttt/targeticons/down/sprite_target_task" + "$nocull" 1 + "$ignorez" 0 + "$nodecal" 1 + "$nolod" 1 + "$vertexcolor" 1 + "$vertexalpha" 1 + "$translucent" 1 +} diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task.vtf b/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task.vtf new file mode 100644 index 0000000000000000000000000000000000000000..3e8a453d02fee319fe2b4681209eb3252e2d8c96 GIT binary patch literal 5712 zcmeHLeN0nV6hD1XEFYyst#eXmsUV8ZxsMP@Dm+NkRWq%I%Qh!jhcnSg(YeH!B`$?b zH$Mo4fMXj7m~3%G7d4?-*sMgd8TW@XnINVc#c5JEogkoXq2=t{mX~2evN6a43zv6G zfA60Aaen9Ho!7kFH82AJ@HtqzI_p@HBh zzhS1nf_fKqq}E6cvAG?-J-r9O;AWdNn!oOc#$8x`tX^k3>+mEg#C4(=KJM@U=pYwd zsDpJP8?mmm{^DuakubrPGN7HI^)79Lrbu&HF8yr#hzi%&eB04*@hS~57 z7%TQimzxkh7pzvRcuQu~r@mH_!pEbPD%DkpF26(T0iA@&8PnWtP(Oy5S{@M26wi?WVNOx zc<`i`!j^nF zgZzsDv-V~ATQmHvJd(KlSoaH;58vOnp)osZZ^Im|+nw>$EXcg*#5#+-hYoSR5?CWx zeOWaVxqo5rzTKXEyO$ykcItFGlYfQtTp}4dzkBKz-aK3=$%`}|&gV29Up!3n_s{s_{z>jf z&*hN3gy(+1^QC3sFg7WhIIfKeKA#v%5rXn1LH{0Ye%N{@3IE&tI??kNq)7T1+>{nf zu^)20_)dN|P`JwDmfc=cl=(v+y0AbkD{cYYZhhe`(zesnxLG``g!nUOS9LV>tmXNe zv0dh+K|X}v0A9aJ>uE;vW1=?E=O6ESLkpiaL8M65H@IVk2w7mGS615+Px&!hvAEg{ zf&HY#JKtCUwz~QA;;S2EIZ9~~9L56+w8Tf9HDH&OxlD_&`Qp;I+hpWe|D& z$8nq2N8BNP+Rpi8Y^v%1xKMp`(aPe>i7tRVd(;;LE48)=RhP*1Qz})Z)dQrQF-L}& zqyT7S#XgSpMx=P*81HcZQNwUOnLE|=_rAD8c=_5#ZCc8Pd2lMv*xT}x|Ne6UhbLPR z4KebVe8_}{WK$;#n2)*3iFMS@WZ}4~ihDP_h$^I1oQ%(Pe3v>r(-Yvc9>;#C4 z$~*1PjP4TS`-Kx^e^ptju;mff*=O7A-2b`5Z}Fka4%h75KR9mpQm}YK{?8}?CcFO6 zJfe4xLDeExFy9GZqK{k8mVCS^R1b_5KOo%^>muW}1?Q)&x>!8Fqd32V$eEP+|ETPt z?Pp5q{Cxb0pHNM~OeKJXmwjv$U<|mDex7iSSTAx<)w7}Zcdq|*eLvoMWqSUT^~W?H O(|nBlJ@EhT4}SvJ!%zwU literal 0 HcmV?d00001 diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task_noz.vmt b/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task_noz.vmt new file mode 100644 index 000000000..566d39d73 --- /dev/null +++ b/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/down/sprite_target_task_noz.vmt @@ -0,0 +1,11 @@ +"UnlitGeneric" +{ + "$basetexture" "vgui/ttt/targeticons/down/sprite_target_task" + "$nocull" 1 + "$ignorez" 1 + "$nodecal" 1 + "$nolod" 1 + "$vertexcolor" 1 + "$vertexalpha" 1 + "$translucent" 1 +} diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/up/sprite_target_task.vmt b/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/up/sprite_target_task.vmt new file mode 100644 index 000000000..aba37bf74 --- /dev/null +++ b/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/up/sprite_target_task.vmt @@ -0,0 +1,11 @@ +"UnlitGeneric" +{ + "$basetexture" "vgui/ttt/targeticons/up/sprite_target_task" + "$nocull" 1 + "$ignorez" 0 + "$nodecal" 1 + "$nolod" 1 + "$vertexcolor" 1 + "$vertexalpha" 1 + "$translucent" 1 +} diff --git a/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/up/sprite_target_task.vtf b/gamemodes/terrortown/content/materials/vgui/ttt/targeticons/up/sprite_target_task.vtf new file mode 100644 index 0000000000000000000000000000000000000000..32fc5b0d933f8f9153c0493eeb4a8ee8b9deea7c GIT binary patch literal 5712 zcmeHLZ%kWN6hE&}D6rBF0ZD)`kfnfTnSWrKu=IgrTjz&$+SlO3q!L|V1{95pGn*Ft zmqj)zVM+-9bZ+UY6P)r)X4Vkk1H?F|4u)w$o#2`c2MB|8V%ba8UW_m8I?gcDEqx5fD$L0JQJCbG#FepD}k^EOvLMg5SmS|Lw1-w}64Z zLjC+3fAhUJPuG}DwaoR}2wO*`QrA~Qwa|5LWSec9O+6r14ORdC1EOOL(h3uE-xaGI zV%0rqE<`~Pk{HrCl8RUNcEsl27^#TF={U$ssu{^?h+}YJAhwL~%%di$!oYlWItgOU>VTE&f{e zJI^|tgqO)T@m5t+nZxABRM_1~NqNFj^TYisYY)qnXa2WjKLr&owln2&GVnRE^1jIo zv2B`s00&l&Y=726kfTE!PbvMf*S5Zi#^?Hf0&pVFmy|4*|E1xA>T#-eH)07Dt8ce& z%Rs_byZdYtB;+evrgQ<+Jpg0w4|-^gi)OFZ->+@$XX|C-SDOF)R?FrnUu{g8E2lW` zt_(%sAUUl?6>&TEGS~z#&k_Ge{42(P@X~>5*MZykQFxx;k;T#Oel9mPl~5jmi`Wi;L?Pm5w*lV_!J~bh-(}vY`L2%MN`nBwu#E>8XV1 z)uKN?3?UcEvMIY;PXPR&s!i5MTM>&C@j1<=z^e?2`fJLWD1Q>*^Dee>mZ3>>ARi(= z>)jrYSf@74v~CQ@F~UT>POMdw(|uT`o6SCyrCF``(aNcTY9Zxg1}ZoYlx}u%h+>bK z($K&+RdJy1R0XX86w!E@;u$KwF+`?t$Lt^z2$eKf4C}yu`zI&7l%=7%R`C0u>3r*| zejQnBo!Vt+hVI!P8?-n_`1(^~>U!a+o7f>HT7vOBPy|`#L8k~8MZ23}7hu?f9q2&} z=CcNau-5SVUI6%_;^VsuDT4u{80Fsty_|N2b_dZ)r3$@t2VNug1oL%}Xv@Uq^Adeq z|G^m%YYo3A-FhToj;u;`0-Q2}b;o>PT;X@$2igh$(HMw5bm5ATHU~P9{N1Mjuea!A zJTrer+W;o6dpd$7y3cd8Q`Q>(+3Zr~<2kis=SE2VQBg*pc8dk#CwQh!xvJsllWZ$g zKE{nPdmw|~J4!UU1SStgkC5%7w?VRh!C+YJ`1hUmcA&Ql4_-ht8jXereIMPF^f$S8 zfe<}?EaczbuV?=4=c)BGte^QmEBU`sXTq#B{_ylLlR!ZFXOF#O=jm$4KM5I@4~IG^ so&q>c=bK*+d?QM maxWidth then maxWidth = (margin * 3) + checkboxSize + nameWidth end + + height = height + nameHeight + (margin / 2) + + surface.SetFont("UseHint") + surface.SetTextPos(xPos + (margin * 2) + offset, height + offset) + surface.DrawText(desc) + + local descWidth, descHeight = surface.GetTextSize(desc) + if completed then + -- Shifting the strikethrough lines down one pixel makes it look much nicer with lowercase letters + surface.DrawRect(xPos + (margin * 2) + offset, height + (descHeight / 2) + 1 + offset, descWidth, 1) + end + + if (margin * 3) + descWidth > maxWidth then maxWidth = (margin * 3) + descWidth end + + height = height + descHeight + margin + return height +end + +hook.Add("HUDPaintBackground", "Taskmaster_HUDPaintBackground", function() + if GetRoundState() ~= ROUND_ACTIVE then return end + if maxHeight == 0 or maxWidth == 0 then return end + + if not client then + client = LocalPlayer() + end + if not client:IsActiveTaskmaster() then return end + + -- Add 2 to the maxWidth here to account for the text shadows + draw.RoundedBox(8, xOffset:GetInt(), yOffset:GetInt(), maxWidth + 2, maxHeight, Color(0, 0, 10, 200)) + maxWidth, maxHeight = 0, 0 +end) + +hook.Add("HUDPaint", "Taskmaster_HUDPaint", function() + if GetRoundState() ~= ROUND_ACTIVE then return end + + if not client then + client = LocalPlayer() + end + if not client:IsActiveTaskmaster() then return end + + local height = yOffset:GetInt() + margin + + for _, id in ipairs(client.taskmasterKillTasks) do + DrawTask(TASKMASTER.killTasks[id], height, true) + height = DrawTask(TASKMASTER.killTasks[id], height) + end + + for _, id in ipairs(client.taskmasterMiscTasks) do + DrawTask(TASKMASTER.miscTasks[id], height, true) + height = DrawTask(TASKMASTER.miscTasks[id], height) + end + + maxHeight = height - yOffset:GetInt() +end) + +hook.Add("TTTHUDInfoPaint", "Taskmaster_TTTHUDInfoPaint", function(client, label_left, label_top, active_labels) + if client:IsActiveTaskmaster() then + local blockEnd = GetGlobalFloat("taskmaster_block_end", 0) + if blockEnd > 0 then + surface.SetFont("TabLarge") + surface.SetTextColor(255, 255, 255, 230) + + local remaining = math.max(0, blockEnd - CurTime()) + local text = LANG.GetParamTranslation("taskmaster_hud", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local _, h = surface.GetTextSize(text) + + -- Move this up based on how many other labels here are + label_top = label_top + (20 * #active_labels) + + surface.SetTextPos(label_left, ScrH() - label_top - h) + surface.DrawText(text) + + -- Track that the label was added so others can position accurately + table.insert(active_labels, "taskmaster") + end + end +end) + +---------------------- +-- TASK REROLL MENU -- +---------------------- + +local dtasks = {} +local dtasksHeight = 0 + +local scrollBarWidth = 15 +local creditsIconSize = 32 + +local CreateTaskList + +local function CreateTaskReroll(task, dscrollpanel) + if table.HasValue(client.taskmasterCompletedTasks, task.id) then return false end + + local name = task.Name(client) + local desc = task.Description(client) + + local width, _ = dscrollpanel:GetSize() + + local dpanel = vgui.Create("DPanel", dscrollpanel) + dpanel:SetPaintBackground(false) + dpanel:SetWidth(width) + dpanel:SetPos(0, dtasksHeight) + + local buttonWidth, buttonHeight = 80, 45 + + local dname = vgui.Create("DLabel", dpanel) + dname:SetFont("TraitorStateSmall") + dname:SetText(name) + dname:SetPos(margin, margin) + dname:SetWidth(width - (margin * 2) - buttonWidth - scrollBarWidth) + + local _, nameHeight = dname:GetSize() + + local ddesc = vgui.Create("DLabel", dpanel) + ddesc:SetFont("UseHint") + ddesc:SetText(desc) + ddesc:SetPos(margin, (margin * 1.5) + nameHeight) + ddesc:SetWidth(width - (margin * 2) - buttonWidth - scrollBarWidth) + ddesc:SetWrap(true) + ddesc:SetAutoStretchVertical(true) + + local _, descHeight = ddesc:GetSize() + local height = (margin * 2.5) + nameHeight + descHeight + + dpanel:SetHeight(height) + + local dreroll = vgui.Create("DButton", dpanel) + dreroll:SetSize(buttonWidth, buttonHeight) + dreroll:SetPos(width - margin - buttonWidth, (height - buttonHeight) / 2) + dreroll:SetText(" Reroll\n (1 credit)") + + dreroll.DoClick = function() + if client:GetCredits() == 0 then return end + + net.Start("TTT_TaskmasterRerollTask") + net.WriteString(task.id) + net.SendToServer() + end + + dreroll.Think = function() + dreroll:SetDisabled(client:GetCredits() == 0) + end + + dpanel.rerollButton = dreroll + + dtasksHeight = dtasksHeight + height + + local dline = vgui.Create("DPanel", dscrollpanel) + dline:SetSize(width, 1) + dline:SetPos(0, dtasksHeight) + + dtasksHeight = dtasksHeight + 1 + + return dpanel, dline +end + +function CreateTaskList(dscrollpanel) + if not dscrollpanel:IsValid() then return end + + for _, dtask in ipairs(dtasks) do + dtask:Remove() + end + dtasks = {} + dtasksHeight = 0 + + for _, id in ipairs(client.taskmasterKillTasks) do + local dtask, dline = CreateTaskReroll(TASKMASTER.killTasks[id], dscrollpanel) + if dtask then + table.insert(dtasks, dtask) + table.insert(dtasks, dline) + end + end + + for _, id in ipairs(client.taskmasterMiscTasks) do + local dtask, dline = CreateTaskReroll(TASKMASTER.miscTasks[id], dscrollpanel) + if dtask then + table.insert(dtasks, dtask) + table.insert(dtasks, dline) + end + end + + if #dtasks > 0 then + dtasks[#dtasks]:Remove() + + local spacerWidth, _ = dscrollpanel:GetSize() + local spacerHeight = (margin * 2) + creditsIconSize + + local dspacer = vgui.Create("DPanel", dscrollpanel) + dspacer:SetPaintBackground(false) + dspacer:SetSize(spacerWidth, spacerHeight) + dspacer:SetPos(0, dtasksHeight) + + dtasksHeight = dtasksHeight + spacerHeight + end + + if dtasksHeight > dscrollpanel:GetTall() then + for _, dtask in ipairs(dtasks) do + if dtask.rerollButton then + local xPos, yPos = dtask.rerollButton:GetPos() + dtask.rerollButton:SetPos(xPos - scrollBarWidth, yPos) + end + end + end +end + +hook.Add("TTTEquipmentTabs", "Taskmaster_TTTEquipmentTabs", function(dsheet, dframe) + if not client then + client = LocalPlayer() + end + + if client:IsActiveTaskmaster() then + local padding = dsheet:GetPadding() + local tabHeight = 20 + + local dpanel = vgui.Create("DPanel", dsheet) + dpanel:SetBackgroundColor(Color(90, 90, 95)) + dpanel:StretchToParent(padding, padding + tabHeight, padding, padding) + + local _, panelHeight = dpanel:GetSize() + + local dscrollpanel = vgui.Create("DScrollPanel", dpanel) + dscrollpanel:SetPaintBackground(false) + dscrollpanel:StretchToParent(0, 0, 0, 0) + + local dcredits = vgui.Create("Panel", dsheet) + dcredits.Paint = function(panel, w, h) + draw.RoundedBoxEx(8, 0, 0, w, h, Color(151, 155, 159), false, true, false, false) + end + + local dcreditsicon = vgui.Create("DImage", dcredits) + dcreditsicon:SetSize(creditsIconSize, creditsIconSize) + dcreditsicon:SetImage("vgui/ttt/equip/coin.png") + + local dcreditsamount = vgui.Create("DLabel", dcredits) + dcreditsamount:SetFont("DermaLarge") + + dcreditsamount.Think = function() + local credits = client:GetCredits() + local noCreditsColor = Color(220, 60, 60, 255) + + dcreditsamount:SetText(" " .. credits) + dcreditsamount:SetColor(credits == 0 and noCreditsColor or COLOR_WHITE) + dcreditsamount:SizeToContents() + + dcreditsicon:SetImageColor(credits == 0 and noCreditsColor or COLOR_WHITE) + + local creditsAmountWidth, _ = dcreditsamount:GetSize() + + local creditsWidth = padding + margin + creditsAmountWidth + creditsIconSize + local creditsHeight = padding + margin + creditsIconSize + dcredits:SetSize(creditsWidth, creditsHeight) + dcredits:SetPos(padding, panelHeight - creditsHeight + padding + tabHeight) + + dcreditsamount:SetPos(padding + creditsIconSize, margin) + dcreditsicon:SetPos(padding, margin) + + dcredits:MoveToFront() + dcreditsamount:MoveToFront() + dcreditsicon:MoveToFront() + end + + CreateTaskList(dscrollpanel) + + net.Receive("TTT_TaskmasterUpdateTaskList", function(len, ply) + CreateTaskList(dscrollpanel) + end) + + dsheet:AddSheet(LANG.GetTranslation("taskmaster_reroll_name"), dscrollpanel, "icon16/table_edit.png", false, false, LANG.GetTranslation("equip_tooltip_taskmaster_reroll")) + return true + end +end) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua new file mode 100644 index 000000000..73004d14e --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -0,0 +1,77 @@ +AddCSLuaFile() + +ROLE_STARTING_CREDITS[ROLE_TASKMASTER] = 1 +ROLE_HAS_PASSIVE_WIN[ROLE_TASKMASTER] = true +cvars.AddChangeCallback("ttt_taskmaster_is_passive", function(_, _, newValue) + ROLE_HAS_PASSIVE_WIN[ROLE_TASKMASTER] = util.tobool(newValue) +end) + +------------------ +-- ROLE CONVARS -- +------------------ + +CreateConVar("ttt_taskmaster_kill_tasks", "1", FCVAR_REPLICATED, "The number of kill tasks assigned to the Taskmaster", 0, 10) +CreateConVar("ttt_taskmaster_misc_tasks", "2", FCVAR_REPLICATED, "The number of miscellaneous tasks assigned to the Taskmaster", 0, 10) +CreateConVar("ttt_taskmaster_completion_bonus", "1", FCVAR_REPLICATED, "How many credits the Taskmaster should get whenever they complete a task", 0, 10) +CreateConVar("ttt_taskmaster_blocks_team_wins", "1", FCVAR_REPLICATED, "Whether the Taskmaster should block teams (innocent, traitor, monster) from winning if they are alive and haven't finished their tasks.") +CreateConVar("ttt_taskmaster_win_block_length", "60", FCVAR_REPLICATED, "How long (in seconds) the Taskmaster should block teams (innocent, traitor, monster) from winning for (if 'ttt_taskmaster_blocks_team_wins' is enabled). Set to 0 to block until time runs out", 0, 300) +CreateConVar("ttt_taskmaster_wins_with_others", "1", FCVAR_REPLICATED, "If the Taskmaster should be allowed to win alongside other teams/players") +CreateConVar("ttt_taskmaster_is_passive", "1", FCVAR_REPLICATED, "Whether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if 'ttt_taskmaster_wins_with_others' is enabled)") + +ROLE_CONVARS[ROLE_TASKMASTER] = {} + +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_kill_tasks", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_misc_tasks", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +----------------------- +-- TASK REGISTRATION -- +----------------------- + +TASKMASTER = { + killTasks = {}, + miscTasks = {} +} + +function TASKMASTER.RegisterTask(task) + task.id = task.id or task.Id or task.ID + + if TASKMASTER.killTasks[task.id] or TASKMASTER.miscTasks[task.id] then + ErrorNoHalt("ERROR: Attempted to register Taskmaster task '" .. task.id .. "' with duplicate task ID.\n") + return + end + + local cvarName = "ttt_taskmaster_" .. task.id .. "_enabled" + local enabled = CreateConVar(cvarName, 1, FCVAR_REPLICATED) + task.Enabled = function() + return enabled:GetBool() + end + table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = cvarName, + type = ROLE_CONVAR_TYPE_BOOL + }) + + if task.isKillTask then + TASKMASTER.killTasks[task.id] = task + else + TASKMASTER.miscTasks[task.id] = task + end +end + +local function AddTaskFiles(root) + local taskFiles, _ = file.Find(root .. "*.lua", "LUA") + for _, fil in ipairs(taskFiles) do + include(root .. fil) + if SERVER then AddCSLuaFile(root .. fil) end + end +end + +AddTaskFiles("terrortown/gamemode/roles/taskmaster/tasks/") -- Internal tasks +AddTaskFiles("taskmastertasks/") -- External tasks \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua new file mode 100644 index 000000000..dc71bdf62 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -0,0 +1,247 @@ +AddCSLuaFile() + +local plymeta = FindMetaTable("Player") + +util.AddNetworkString("TTT_TaskmasterRerollTask") +util.AddNetworkString("TTT_TaskmasterUpdateTaskList") + +------------- +-- CONVARS -- +------------- + +local taskmaster_kill_tasks = GetConVar("ttt_taskmaster_kill_tasks") +local taskmaster_misc_tasks = GetConVar("ttt_taskmaster_misc_tasks") +local taskmaster_completion_bonus = GetConVar("ttt_taskmaster_completion_bonus") +local taskmaster_blocks_team_wins = GetConVar("ttt_taskmaster_blocks_team_wins") +local taskmaster_win_block_length = GetConVar("ttt_taskmaster_win_block_length") +local taskmaster_wins_with_others = GetConVar("ttt_taskmaster_wins_with_others") + +--------------------- +-- TASK ASSIGNMENT -- +--------------------- + +function plymeta:AssignTask(isKillTask, index) + if not self:IsTaskmaster() then return end + + local taskList = isKillTask and TASKMASTER.killTasks or TASKMASTER.miscTasks + local taskIds = table.GetKeys(taskList) + local activeTasksName = isKillTask and "taskmasterKillTasks" or "taskmasterMiscTasks" + + for _, activeId in ipairs(self[activeTasksName]) do + table.RemoveByValue(taskIds, activeId) + end + for _, rerolledId in ipairs(self.taskmasterRerolledTasks) do + table.RemoveByValue(taskIds, rerolledId) + end + table.Shuffle(taskIds) + + for _, id in ipairs(taskIds) do + if taskList[id].CanAssignTask(self) then + taskList[id].OnTaskAssigned(self) + + if index then + table.insert(self[activeTasksName], index, id) + else + table.insert(self[activeTasksName], id) + end + self:SetProperty(activeTasksName, self[activeTasksName], self) + return taskList[id] + end + end + -- TODO: Handle edge case where there are no valid tasks. Maybe we need to change their role? Or just have a free fallback task? + return false +end + +function plymeta:RemoveTask(taskId) + if not self:IsTaskmaster() then return end + + local isKillTask = TASKMASTER.killTasks[taskId] and true or false + local taskList = isKillTask and TASKMASTER.killTasks or TASKMASTER.miscTasks + local activeTasksName = isKillTask and "taskmasterKillTasks" or "taskmasterMiscTasks" + + taskList[taskId].OnTaskRemoved(self) + + table.RemoveByValue(self[activeTasksName], taskId) + self:SetProperty(activeTasksName, self[activeTasksName], self) +end + +function plymeta:RerollTask(taskId, free) + if not self:IsTaskmaster() then return end + if not free and self:GetCredits() == 0 then return end + + local isKillTask = TASKMASTER.killTasks[taskId] and true or false + local activeTasksName = isKillTask and "taskmasterKillTasks" or "taskmasterMiscTasks" + local index = table.KeyFromValue(self[activeTasksName], taskId) + if not index then return end + + table.insert(self.taskmasterRerolledTasks, taskId) + self:SetProperty("taskmasterRerolledTasks", self.taskmasterRerolledTasks, self) + + self:AssignTask(isKillTask, index) + self:RemoveTask(taskId) + + if not free then + self:SubtractCredits(1) + end + + net.Start("TTT_TaskmasterUpdateTaskList") + net.Send(self) +end + +net.Receive("TTT_TaskmasterRerollTask", function(len, ply) + ply:RerollTask(net.ReadString()) +end) + +function plymeta:CompleteTask(taskId) + if not self:IsActiveTaskmaster() then return end + + local isKillTask = TASKMASTER.killTasks[taskId] and true or false + local taskList = isKillTask and TASKMASTER.killTasks or TASKMASTER.miscTasks + local activeTasksName = isKillTask and "taskmasterKillTasks" or "taskmasterMiscTasks" + if table.HasValue(self[activeTasksName], taskId) then + taskList[taskId].OnTaskComplete(self) + table.insert(self.taskmasterCompletedTasks, taskId) + self:SetProperty("taskmasterCompletedTasks", self.taskmasterCompletedTasks, self) + + local activeTasksList = table.Copy(self.taskmasterKillTasks) + table.Add(activeTasksList, self.taskmasterMiscTasks) + for _, id in ipairs(self.taskmasterCompletedTasks) do + if table.HasValue(activeTasksList, id) then + table.RemoveByValue(activeTasksList, id) + else + break + end + end + if #activeTasksList == 0 then + self:SetProperty("taskmasterShouldWin", true) + -- TODO: Alert the player that they have finished all their tasks + end + + net.Start("TTT_TaskmasterUpdateTaskList") + net.Send(self) + + local bonus = taskmaster_completion_bonus:GetInt() + if bonus > 0 then + self:AddCredits(bonus) + LANG.Msg(self, "taskmaster_credit_bonus", { + role = ROLE_STRINGS[ROLE_TASKMASTER], + num = bonus + }) + end + + return true + end + return false +end + +ROLE_ON_ROLE_ASSIGNED[ROLE_TASKMASTER] = function(ply) + ply:SetProperty("taskmasterKillTasks", {}, ply) + ply:SetProperty("taskmasterMiscTasks", {}, ply) + ply:SetProperty("taskmasterCompletedTasks", {}, ply) + ply:SetProperty("taskmasterRerolledTasks", {}, ply) + for _ = 1, taskmaster_kill_tasks:GetInt() do + ply:AssignTask(true) + end + for _ = 1, taskmaster_misc_tasks:GetInt() do + ply:AssignTask(false) + end +end + +---------------- +-- WIN CHECKS -- +---------------- + +hook.Add("TTTWinCheckBlocks", "Taskmaster_TTTWinCheckBlocks", function(win_blocks) + table.insert(win_blocks, function(win_type) + if win_type == WIN_NONE or win_type == WIN_TASKMASTER then return win_type end + + local taskmaster = player.GetLivingRole(ROLE_TASKMASTER) + if not IsPlayer(taskmaster) then return win_type end + + if taskmaster.taskmasterShouldWin then return win_type end + + if not taskmaster_blocks_team_wins:GetBool() then return win_type end + + if win_type == WIN_TRAITOR or win_type == WIN_INNOCENT or win_type == WIN_MONSTER then + local win_block_length = taskmaster_win_block_length:GetInt() + if win_block_length > 0 then + local winBlockEnd = GetGlobalFloat("taskmaster_block_end", 0) + if winBlockEnd == 0 then + local roundEnd = GetGlobalFloat("ttt_round_end", 0) + local blockEnd = CurTime() + win_block_length + if blockEnd > roundEnd then + win_block_length = roundEnd - CurTime() + end + SetGlobalFloat("taskmaster_block_end", CurTime() + win_block_length) + local teamName + if win_type == WIN_TRAITOR then teamName = "traitor" + elseif win_type == WIN_INNOCENT then teamName = "innocent" + elseif win_type == WIN_MONSTER then teamName = "monster" end + + for _, ply in player.Iterator() do + if ply:IsActiveTaskmaster() then + ply:QueueMessage(MSG_PRINTBOTH, "The " .. teamName .. " team have won! You have " .. math.Round(win_block_length) .. " seconds left to finish your tasks before the round ends!") + end + end + elseif CurTime() > winBlockEnd then + return win_type + end + end + + return WIN_NONE + end + end) +end) + +hook.Add("TTTCheckForWin", "Taskmaster_TTTCheckForWin", function() + local winning_taskmaster_alive = false + local other_alive = false + for _, v in player.Iterator() do + if v:IsActive() then + if v:IsTaskmaster() and v.taskmasterShouldWin then + winning_taskmaster_alive = true + elseif not v:ShouldActLikeJester() and not ROLE_HAS_PASSIVE_WIN[v:GetRole()] then + other_alive = true + end + end + end + + if winning_taskmaster_alive and (not taskmaster_wins_with_others:GetBool() or not other_alive) then + return WIN_TASKMASTER + end +end) + +hook.Add("TTTPrintResultMessage", "Taskmaster_TTTPrintResultMessage", function(type) + if type == WIN_TASKMASTER then + LANG.Msg("win_taskmaster", { role = ROLE_STRINGS[ROLE_TASKMASTER] }) + ServerLog("Result: " .. ROLE_STRINGS[ROLE_TASKMASTER] .. " wins.\n") + return true + end +end) + +------------- +-- CLEANUP -- +------------- + +local function CleanupTasks(ply) + ply:ClearProperty("taskmasterKillTasks", ply) + ply:ClearProperty("taskmasterMiscTasks", ply) + ply:ClearProperty("taskmasterCompletedTasks", ply) + ply:ClearProperty("taskmasterRerolledTasks", ply) + ply:ClearProperty("taskmasterShouldWin") +end + +hook.Add("TTTPrepareRound", "Taskmaster_TTTPrepareRound", function() + SetGlobalFloat("taskmaster_block_end", 0) + for _, ply in player.Iterator() do + CleanupTasks(ply) + end +end) + +hook.Add("TTTPlayerRoleChanged", "Taskmaster_TTTPlayerRoleChanged", function(ply, oldRole, newRole) + if not ply:Alive() or ply:IsSpec() then return end + + if oldRole == ROLE_TASKMASTER and oldRole ~= newRole then + CleanupTasks(ply) + end +end) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/shared.lua b/gamemodes/terrortown/gamemode/shared.lua index ead963f1e..0293a0feb 100644 --- a/gamemodes/terrortown/gamemode/shared.lua +++ b/gamemodes/terrortown/gamemode/shared.lua @@ -184,8 +184,9 @@ ROLE_EVILTWIN = 48 ROLE_PLAGUEMASTER = 49 ROLE_ILLUSIONIST = 50 ROLE_CANNIBAL = 51 +ROLE_TASKMASTER = 52 -ROLE_MAX = 51 +ROLE_MAX = 52 ROLE_EXTERNAL_START = ROLE_MAX + 1 local function AddRoleAssociations(tbl, roles) @@ -222,7 +223,7 @@ JESTER_ROLES = {} AddRoleAssociations(JESTER_ROLES, {ROLE_JESTER, ROLE_SWAPPER, ROLE_CLOWN, ROLE_BEGGAR, ROLE_BODYSNATCHER, ROLE_LOOTGOBLIN, ROLE_CUPID, ROLE_SPONGE, ROLE_GUESSER, ROLE_CANNIBAL}) INDEPENDENT_ROLES = {} -AddRoleAssociations(INDEPENDENT_ROLES, {ROLE_DRUNK, ROLE_OLDMAN, ROLE_KILLER, ROLE_ZOMBIE, ROLE_MADSCIENTIST, ROLE_SHADOW, ROLE_ARSONIST, ROLE_HIVEMIND, ROLE_PLAGUEMASTER}) +AddRoleAssociations(INDEPENDENT_ROLES, {ROLE_DRUNK, ROLE_OLDMAN, ROLE_KILLER, ROLE_ZOMBIE, ROLE_MADSCIENTIST, ROLE_SHADOW, ROLE_ARSONIST, ROLE_HIVEMIND, ROLE_PLAGUEMASTER, ROLE_TASKMASTER}) MONSTER_ROLES = {} AddRoleAssociations(MONSTER_ROLES, {}) @@ -593,7 +594,8 @@ ROLE_STRINGS_RAW = { [ROLE_EVILTWIN] = "eviltwin", [ROLE_PLAGUEMASTER] = "plaguemaster", [ROLE_ILLUSIONIST] = "illusionist", - [ROLE_CANNIBAL] = "cannibal" + [ROLE_CANNIBAL] = "cannibal", + [ROLE_TASKMASTER] = "taskmaster" } ROLE_STRINGS = { @@ -648,7 +650,8 @@ ROLE_STRINGS = { [ROLE_EVILTWIN] = "Evil Twin", [ROLE_PLAGUEMASTER] = "Plaguemaster", [ROLE_ILLUSIONIST] = "Illusionist", - [ROLE_CANNIBAL] = "Cannibal" + [ROLE_CANNIBAL] = "Cannibal", + [ROLE_TASKMASTER] = "Taskmaster" } ROLE_STRINGS_PLURAL = { @@ -703,7 +706,8 @@ ROLE_STRINGS_PLURAL = { [ROLE_EVILTWIN] = "Evil Twins", [ROLE_PLAGUEMASTER] = "Plaguemasters", [ROLE_ILLUSIONIST] = "Illusionists", - [ROLE_CANNIBAL] = "Cannibals" + [ROLE_CANNIBAL] = "Cannibals", + [ROLE_TASKMASTER] = "Taskmasters" } ROLE_STRINGS_EXT = { @@ -759,7 +763,8 @@ ROLE_STRINGS_EXT = { [ROLE_EVILTWIN] = "an Evil Twin", [ROLE_PLAGUEMASTER] = "a Plaguemaster", [ROLE_ILLUSIONIST] = "an Illusionist", - [ROLE_CANNIBAL] = "a Cannibal" + [ROLE_CANNIBAL] = "a Cannibal", + [ROLE_TASKMASTER] = "a Taskmaster" } ROLE_STRINGS_SHORT = { @@ -815,7 +820,8 @@ ROLE_STRINGS_SHORT = { [ROLE_EVILTWIN] = "etw", [ROLE_PLAGUEMASTER] = "plm", [ROLE_ILLUSIONIST] = "ill", - [ROLE_CANNIBAL] = "can" + [ROLE_CANNIBAL] = "can", + [ROLE_TASKMASTER] = "tsk" } function StartsWithVowel(word) @@ -1400,8 +1406,9 @@ WIN_VINDICATOR = 18 WIN_INFECTED = 19 WIN_PLAGUEMASTER = 20 WIN_CANNIBAL = 21 +WIN_TASKMASTER = 22 -WIN_MAX = WIN_MAX or 21 +WIN_MAX = WIN_MAX or 22 WINS_BY_ROLE = WINS_BY_ROLE or {} if SERVER then From c3183fec8565d77f3544d07893336dead0217303 Mon Sep 17 00:00:00 2001 From: NoxxFlame Date: Tue, 12 Aug 2025 16:58:36 +0100 Subject: [PATCH 002/115] Added the ability for tasks that require specific features to block other tasks that require the same features --- .../gamemode/roles/taskmaster/shared.lua | 4 +- .../gamemode/roles/taskmaster/taskmaster.lua | 20 ++++++++++ .../roles/taskmaster/tasks/testkilltask.lua | 38 +++++++++++++++++++ .../roles/taskmaster/tasks/testmisctask.lua | 37 ++++++++++++++++++ 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua index 73004d14e..c8006afdf 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -1,7 +1,7 @@ AddCSLuaFile() ROLE_STARTING_CREDITS[ROLE_TASKMASTER] = 1 -ROLE_HAS_PASSIVE_WIN[ROLE_TASKMASTER] = true +ROLE_HAS_PASSIVE_WIN[ROLE_TASKMASTER] = false cvars.AddChangeCallback("ttt_taskmaster_is_passive", function(_, _, newValue) ROLE_HAS_PASSIVE_WIN[ROLE_TASKMASTER] = util.tobool(newValue) end) @@ -16,7 +16,7 @@ CreateConVar("ttt_taskmaster_completion_bonus", "1", FCVAR_REPLICATED, "How many CreateConVar("ttt_taskmaster_blocks_team_wins", "1", FCVAR_REPLICATED, "Whether the Taskmaster should block teams (innocent, traitor, monster) from winning if they are alive and haven't finished their tasks.") CreateConVar("ttt_taskmaster_win_block_length", "60", FCVAR_REPLICATED, "How long (in seconds) the Taskmaster should block teams (innocent, traitor, monster) from winning for (if 'ttt_taskmaster_blocks_team_wins' is enabled). Set to 0 to block until time runs out", 0, 300) CreateConVar("ttt_taskmaster_wins_with_others", "1", FCVAR_REPLICATED, "If the Taskmaster should be allowed to win alongside other teams/players") -CreateConVar("ttt_taskmaster_is_passive", "1", FCVAR_REPLICATED, "Whether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if 'ttt_taskmaster_wins_with_others' is enabled)") +CreateConVar("ttt_taskmaster_is_passive", "0", FCVAR_REPLICATED, "Whether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if 'ttt_taskmaster_wins_with_others' is enabled)") ROLE_CONVARS[ROLE_TASKMASTER] = {} diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index dc71bdf62..8b74b70d5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -37,6 +37,26 @@ function plymeta:AssignTask(isKillTask, index) for _, id in ipairs(taskIds) do if taskList[id].CanAssignTask(self) then + local blockedByFeature = false + for _, feature in pairs(taskList[id].RequiredFeatures) do + for _, killTaskId in pairs(self.taskmasterKillTasks) do + if table.HasValue(TASKMASTER.killTasks[killTaskId].RequiredFeatures, feature) then + blockedByFeature = true + break + end + end + if blockedByFeature then break end + + for _, miscTaskId in pairs(self.taskmasterMiscTasks) do + if table.HasValue(TASKMASTER.miscTasks[miscTaskId].RequiredFeatures, feature) then + blockedByFeature = true + break + end + end + if blockedByFeature then break end + end + if blockedByFeature then continue end + taskList[id].OnTaskAssigned(self) if index then diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua new file mode 100644 index 000000000..fc1b1c01f --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua @@ -0,0 +1,38 @@ +local TASK = {} + +TASK.id = "testkilltask" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Test Kill Task" +end + +TASK.Description = function(ply) + return "Test Kill Task Description" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return false + end + + TASK.RequiredFeatures = { + --"TargetIDPlayerText", + --"TargetIDPlayerTargetIcon", + --"ProgressBar" + } + + TASK.OnTaskAssigned = function(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Task Assigned: " .. TASK.Name(ply)) + end + + TASK.OnTaskRemoved = function(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Task Removed: " .. TASK.Name(ply)) + end + + TASK.OnTaskComplete = function(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Task Completed: " .. TASK.Name(ply)) + end +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua new file mode 100644 index 000000000..506b0bdf6 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua @@ -0,0 +1,37 @@ +local TASK = {} + +TASK.id = "testmisctask" + +TASK.Name = function(ply) + return "Test Misc Task" +end + +TASK.Description = function(ply) + return "Test Misc Task Description" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return false + end + + TASK.RequiredFeatures = { + --"TargetIDPlayerText", + --"TargetIDPlayerTargetIcon", + --"ProgressBar" + } + + TASK.OnTaskAssigned = function(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Task Assigned: " .. TASK.Name(ply)) + end + + TASK.OnTaskRemoved = function(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Task Removed: " .. TASK.Name(ply)) + end + + TASK.OnTaskComplete = function(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Task Completed: " .. TASK.Name(ply)) + end +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From b84a3a3dbef95dc18d8767347addc07c32ae66bd Mon Sep 17 00:00:00 2001 From: NoxxFlame Date: Wed, 13 Aug 2025 15:33:00 +0100 Subject: [PATCH 003/115] Added 'Kill Nearby Player' and 'Kill Faraway Player' tasks --- .../gamemode/roles/taskmaster/taskmaster.lua | 49 ++++-- .../roles/taskmaster/tasks/killfaraway.lua | 159 ++++++++++++++++++ .../roles/taskmaster/tasks/killnearby.lua | 159 ++++++++++++++++++ 3 files changed, 351 insertions(+), 16 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index 8b74b70d5..3f9907e86 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -40,32 +40,37 @@ function plymeta:AssignTask(isKillTask, index) local blockedByFeature = false for _, feature in pairs(taskList[id].RequiredFeatures) do for _, killTaskId in pairs(self.taskmasterKillTasks) do - if table.HasValue(TASKMASTER.killTasks[killTaskId].RequiredFeatures, feature) then - blockedByFeature = true - break + if not table.HasValue(self.taskmasterCompletedTasks, killTaskId) and not table.HasValue(self.taskmasterRerolledTasks, killTaskId) then + if table.HasValue(TASKMASTER.killTasks[killTaskId].RequiredFeatures, feature) then + blockedByFeature = true + break + end end end if blockedByFeature then break end for _, miscTaskId in pairs(self.taskmasterMiscTasks) do - if table.HasValue(TASKMASTER.miscTasks[miscTaskId].RequiredFeatures, feature) then - blockedByFeature = true - break + if not table.HasValue(self.taskmasterCompletedTasks, miscTaskId) and not table.HasValue(self.taskmasterRerolledTasks, miscTaskId) then + if table.HasValue(TASKMASTER.miscTasks[miscTaskId].RequiredFeatures, feature) then + blockedByFeature = true + break + end end end if blockedByFeature then break end end - if blockedByFeature then continue end - taskList[id].OnTaskAssigned(self) + if not blockedByFeature then + taskList[id].OnTaskAssigned(self) - if index then - table.insert(self[activeTasksName], index, id) - else - table.insert(self[activeTasksName], id) + if index then + table.insert(self[activeTasksName], index, id) + else + table.insert(self[activeTasksName], id) + end + self:SetProperty(activeTasksName, self[activeTasksName], self) + return taskList[id] end - self:SetProperty(activeTasksName, self[activeTasksName], self) - return taskList[id] end end -- TODO: Handle edge case where there are no valid tasks. Maybe we need to change their role? Or just have a free fallback task? @@ -73,8 +78,6 @@ function plymeta:AssignTask(isKillTask, index) end function plymeta:RemoveTask(taskId) - if not self:IsTaskmaster() then return end - local isKillTask = TASKMASTER.killTasks[taskId] and true or false local taskList = isKillTask and TASKMASTER.killTasks or TASKMASTER.miscTasks local activeTasksName = isKillTask and "taskmasterKillTasks" or "taskmasterMiscTasks" @@ -149,6 +152,8 @@ function plymeta:CompleteTask(taskId) }) end + -- TODO: Play a sound and/or send a message when a task is completed + return true end return false @@ -244,6 +249,18 @@ end) ------------- local function CleanupTasks(ply) + if ply.taskmasterKillTasks then + for _, id in pairs(ply.taskmasterKillTasks) do + ply:RemoveTask(id) + end + end + + if ply.taskmasterMiscTasks then + for _, id in pairs(ply.taskmasterMiscTasks) do + ply:RemoveTask(id) + end + end + ply:ClearProperty("taskmasterKillTasks", ply) ply:ClearProperty("taskmasterMiscTasks", ply) ply:ClearProperty("taskmasterCompletedTasks", ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua new file mode 100644 index 000000000..c104e9a38 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua @@ -0,0 +1,159 @@ +local TASK = {} + +TASK.id = "killfaraway" +TASK.isKillTask = true + +local taskmaster_killfaraway_range = CreateConVar("ttt_taskmaster_killfaraway_range", "25", FCVAR_REPLICATED, "The minimum distance (in meters) away a player can be to count for the 'Kill Faraway Player' task", 0, 100) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_killfaraway_range", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + return "Kill Faraway Player" +end + +TASK.Description = function(ply) + local unit + if SERVER then + unit = 1 + else + unit = cvars.Number("ttt_distance_unit", 1) + end + local range = taskmaster_killfaraway_range:GetInt() + local description = "Kill a player from outside " + if unit == 1 then + description = description .. range .. " meter" + if range ~= 1 then + description = description .. "s" + end + elseif unit == 2 then + description = description .. math.ceil(range / UNITS_PER_FOOT) .. " feet" + else + local convertedRange = math.ceil(range * UNITS_PER_METER) + description = description .. convertedRange .. " unit" + if convertedRange ~= 1 then + description = description .. "s" + end + end + return description +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_KillFaraway_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillFaraway_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + "TargetIDPlayerText", + "ParticleRadius" + } + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillFaraway_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + local distanceSqr = victim:GetPos():DistToSqr(attacker:GetPos()) + local range = taskmaster_killfaraway_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + + if (distanceSqr >= rangeSqr) then + ply:CompleteTask(TASK.id) + end + end) + + net.Start("TTT_Taskmaster_KillFaraway_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillFaraway_PlayerDeath_" .. ply:SteamID64()) + net.Start("TTT_Taskmaster_KillFaraway_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillFaraway_PlayerDeath_" .. ply:SteamID64()) + net.Start("TTT_Taskmaster_KillFaraway_Cleanup") + net.Send(ply) + end +end + +if CLIENT then + net.Receive("TTT_Taskmaster_KillFaraway_Assigned", function() + local sid64 = LocalPlayer():SteamID64() + + hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillFaraway_TTTTargetIDPlayerText_" .. sid64, function(ent, cli, text, col, secondaryText) + if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end + + local distanceSqr = ent:GetPos():DistToSqr(cli:GetPos()) + local range = taskmaster_killfaraway_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + + if distanceSqr >= rangeSqr then + return "IN RANGE", ROLE_COLORS_RADAR[ROLE_INNOCENT] + else + return "TOO CLOSE", ROLE_COLORS_RADAR[ROLE_TRAITOR] + end + end) + + hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillFaraway_TTTPlayerAliveClientThink_" .. sid64, function(client, ply) + local shouldDraw = false + if ply == client and client:IsActiveTaskmaster() then + local pos = ply:GetPos() + if not ply.TaskmasterRadiusEmitter then ply.TaskmasterRadiusEmitter = ParticleEmitter(pos) end + if not ply.TaskmasterRadiusNextPart then ply.TaskmasterRadiusNextPart = CurTime() end + if not ply.TaskmasterRadiusDir then ply.TaskmasterRadiusDir = 0 end + if ply.TaskmasterRadiusNextPart < CurTime() then + for _ = 1, 48 do + ply.TaskmasterRadiusEmitter:SetPos(pos) + ply.TaskmasterRadiusNextPart = CurTime() + 0.005 + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + math.pi / 24 + local radius = taskmaster_killfaraway_range:GetInt() * UNITS_PER_METER + local vec = Vector(math.sin(ply.TaskmasterRadiusDir) * radius, math.cos(ply.TaskmasterRadiusDir) * radius, 10) + local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) + particle:SetVelocity(Vector(0, 0, 80)) + particle:SetDieTime(0.5) + particle:SetStartAlpha(200) + particle:SetEndAlpha(0) + particle:SetStartSize(3) + particle:SetEndSize(2) + particle:SetRoll(math.Rand(0, math.pi)) + particle:SetRollDelta(0) + particle:SetColor(255, 255, 255) + end + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + 0.02 + end + shouldDraw = true + end + + if not shouldDraw and ply.TaskmasterRadiusEmitter then + ply.TaskmasterRadiusEmitter:Finish() + ply.TaskmasterRadiusEmitter = nil + ply.TaskmasterRadiusDir = nil + ply.TaskmasterRadiusNextPart = nil + end + end) + end) + + net.Receive("TTT_Taskmaster_KillFaraway_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillFaraway_TTTTargetIDPlayerText_" .. sid64) + hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_KillFaraway_TTTPlayerAliveClientThink_" .. sid64) + + if client.TaskmasterRadiusEmitter then + client.TaskmasterRadiusEmitter:Finish() + client.TaskmasterRadiusEmitter = nil + client.TaskmasterRadiusDir = nil + client.TaskmasterRadiusNextPart = nil + end + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua new file mode 100644 index 000000000..aec39579e --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua @@ -0,0 +1,159 @@ +local TASK = {} + +TASK.id = "killnearby" +TASK.isKillTask = true + +local taskmaster_killnearby_range = CreateConVar("ttt_taskmaster_killnearby_range", "5", FCVAR_REPLICATED, "The maximum distance (in meters) away a player can be to count for the 'Kill Nearby Player' task", 0, 10) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_killnearby_range", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + return "Kill Nearby Player" +end + +TASK.Description = function(ply) + local unit + if SERVER then + unit = 1 + else + unit = cvars.Number("ttt_distance_unit", 1) + end + local range = taskmaster_killnearby_range:GetInt() + local description = "Kill a player from within " + if unit == 1 then + description = description .. range .. " meter" + if range ~= 1 then + description = description .. "s" + end + elseif unit == 2 then + description = description .. math.ceil(range / UNITS_PER_FOOT) .. " feet" + else + local convertedRange = math.ceil(range * UNITS_PER_METER) + description = description .. convertedRange .. " unit" + if convertedRange ~= 1 then + description = description .. "s" + end + end + return description +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_KillNearby_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillNearby_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + "TargetIDPlayerText", + "ParticleRadius" + } + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillNearby_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + local distanceSqr = victim:GetPos():DistToSqr(attacker:GetPos()) + local range = taskmaster_killnearby_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + + if (distanceSqr <= rangeSqr) then + ply:CompleteTask(TASK.id) + end + end) + + net.Start("TTT_Taskmaster_KillNearby_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillNearby_PlayerDeath_" .. ply:SteamID64()) + net.Start("TTT_Taskmaster_KillNearby_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillNearby_PlayerDeath_" .. ply:SteamID64()) + net.Start("TTT_Taskmaster_KillNearby_Cleanup") + net.Send(ply) + end +end + +if CLIENT then + net.Receive("TTT_Taskmaster_KillNearby_Assigned", function() + local sid64 = LocalPlayer():SteamID64() + + hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillNearby_TTTTargetIDPlayerText_" .. sid64, function(ent, cli, text, col, secondaryText) + if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end + + local distanceSqr = ent:GetPos():DistToSqr(cli:GetPos()) + local range = taskmaster_killnearby_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + + if distanceSqr <= rangeSqr then + return "IN RANGE", ROLE_COLORS_RADAR[ROLE_INNOCENT] + else + return "TOO FAR", ROLE_COLORS_RADAR[ROLE_TRAITOR] + end + end) + + hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillNearby_TTTPlayerAliveClientThink_" .. sid64, function(client, ply) + local shouldDraw = false + if ply == client and client:IsActiveTaskmaster() then + local pos = ply:GetPos() + if not ply.TaskmasterRadiusEmitter then ply.TaskmasterRadiusEmitter = ParticleEmitter(pos) end + if not ply.TaskmasterRadiusNextPart then ply.TaskmasterRadiusNextPart = CurTime() end + if not ply.TaskmasterRadiusDir then ply.TaskmasterRadiusDir = 0 end + if ply.TaskmasterRadiusNextPart < CurTime() then + for _ = 1, 24 do + ply.TaskmasterRadiusEmitter:SetPos(pos) + ply.TaskmasterRadiusNextPart = CurTime() + 0.02 + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + math.pi / 12 + local radius = taskmaster_killnearby_range:GetInt() * UNITS_PER_METER + local vec = Vector(math.sin(ply.TaskmasterRadiusDir) * radius, math.cos(ply.TaskmasterRadiusDir) * radius, 10) + local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) + particle:SetVelocity(Vector(0, 0, 40)) + particle:SetDieTime(0.25) + particle:SetStartAlpha(60) + particle:SetEndAlpha(0) + particle:SetStartSize(3) + particle:SetEndSize(2) + particle:SetRoll(math.Rand(0, math.pi)) + particle:SetRollDelta(0) + particle:SetColor(255, 255, 255) + end + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + 0.02 + end + shouldDraw = true + end + + if not shouldDraw and ply.TaskmasterRadiusEmitter then + ply.TaskmasterRadiusEmitter:Finish() + ply.TaskmasterRadiusEmitter = nil + ply.TaskmasterRadiusDir = nil + ply.TaskmasterRadiusNextPart = nil + end + end) + end) + + net.Receive("TTT_Taskmaster_KillNearby_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillNearby_TTTTargetIDPlayerText_" .. sid64) + hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_KillNearby_TTTPlayerAliveClientThink_" .. sid64) + + if client.TaskmasterRadiusEmitter then + client.TaskmasterRadiusEmitter:Finish() + client.TaskmasterRadiusEmitter = nil + client.TaskmasterRadiusDir = nil + client.TaskmasterRadiusNextPart = nil + end + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From d4a31d7611b887e67107a2c5e9ca1548e27c5eb6 Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 13 Aug 2025 18:30:20 -0400 Subject: [PATCH 004/115] Added new conversion constant --- gamemodes/terrortown/gamemode/shared.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gamemodes/terrortown/gamemode/shared.lua b/gamemodes/terrortown/gamemode/shared.lua index 0293a0feb..2fdb8b4d4 100644 --- a/gamemodes/terrortown/gamemode/shared.lua +++ b/gamemodes/terrortown/gamemode/shared.lua @@ -1507,6 +1507,8 @@ UNITS_PER_METER = 39.37 UNITS_PER_FIVE_METERS = UNITS_PER_METER * 5 UNITS_PER_SIX_METERS = UNITS_PER_METER * 6 +FEET_PER_METER = 3.28084 + -- Message queue modes MSG_PRINTBOTH = 1 MSG_PRINTTALK = 3 -- Keep this the same value as HUD_PRINTTALK just in case From 5efb1d2c9c4fc87379d8347ba8bd56fd2b9a2a9b Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 13 Aug 2025 18:30:54 -0400 Subject: [PATCH 005/115] Cleanup --- .../gamemode/roles/shadow/cl_shadow.lua | 7 +-- .../roles/taskmaster/cl_taskmaster.lua | 5 +- .../roles/taskmaster/tasks/killfaraway.lua | 46 ++++++++++++------- .../roles/taskmaster/tasks/killnearby.lua | 46 ++++++++++++------- 4 files changed, 64 insertions(+), 40 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua b/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua index 5f51224ca..ff5decdeb 100644 --- a/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua +++ b/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua @@ -280,11 +280,12 @@ end) -- PARTICLES -- --------------- -local function DrawRadius(ply, ent, r) +local function DrawRadius(ply, ent, radius) if not ent.RadiusEmitter then ent.RadiusEmitter = ParticleEmitter(ent:GetPos()) end if not ent.RadiusNextPart then ent.RadiusNextPart = CurTime() end if not ent.RadiusDir then ent.RadiusDir = 0 end local pos = ent:GetPos() + Vector(0, 0, 30) + local radiusSqr = radius * radius -- Use DistToSqr as it's more efficient and this is called very frequently -- 9000000 = 3000^2 @@ -293,7 +294,7 @@ local function DrawRadius(ply, ent, r) ent.RadiusEmitter:SetPos(pos) ent.RadiusNextPart = CurTime() + 0.02 ent.RadiusDir = ent.RadiusDir + MathPi / 12 - local vec = Vector(MathSin(ent.RadiusDir) * r, MathCos(ent.RadiusDir) * r, 10) + local vec = Vector(MathSin(ent.RadiusDir) * radius, MathCos(ent.RadiusDir) * radius, 10) local particle = ent.RadiusEmitter:Add("particle/wisp.vmt", ent:GetPos() + vec) particle:SetVelocity(Vector(0, 0, 80)) particle:SetDieTime(0.5) @@ -304,7 +305,7 @@ local function DrawRadius(ply, ent, r) particle:SetRoll(MathRand(0, MathPi)) particle:SetRollDelta(0) local color = ROLE_COLORS[ROLE_TRAITOR] - if ply:GetPos():DistToSqr(ent:GetPos()) <= (r * r) then + if ply:GetPos():DistToSqr(ent:GetPos()) <= radiusSqr then color = ROLE_COLORS[ROLE_INNOCENT] end particle:SetColor(color.r, color.g, color.b) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 9bce5e9d2..78c96574b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -40,7 +40,6 @@ hook.Add("TTTSettingsRolesTabSections", "Taskmaster_TTTSettingsRolesTabSections" return true end) - ---------------- -- WIN CHECKS -- ---------------- @@ -217,8 +216,8 @@ hook.Add("HUDPaint", "Taskmaster_HUDPaint", function() maxHeight = height - yOffset:GetInt() end) -hook.Add("TTTHUDInfoPaint", "Taskmaster_TTTHUDInfoPaint", function(client, label_left, label_top, active_labels) - if client:IsActiveTaskmaster() then +hook.Add("TTTHUDInfoPaint", "Taskmaster_TTTHUDInfoPaint", function(cli, label_left, label_top, active_labels) + if cli:IsActiveTaskmaster() then local blockEnd = GetGlobalFloat("taskmaster_block_end", 0) if blockEnd > 0 then surface.SetFont("TabLarge") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua index c104e9a38..405956cc8 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua @@ -1,3 +1,15 @@ +local CurTime = CurTime +local cvars = cvars +local hook = hook +local math = math +local net = net +local table = table + +local MathCos = math.cos +local MathPi = math.pi +local MathRand = math.Rand +local MathSin = math.sin + local TASK = {} TASK.id = "killfaraway" @@ -29,7 +41,13 @@ TASK.Description = function(ply) description = description .. "s" end elseif unit == 2 then - description = description .. math.ceil(range / UNITS_PER_FOOT) .. " feet" + local convertedRange = math.ceil(range * FEET_PER_METER) + description = description .. convertedRange + if convertedRange == 1 then + description = description .. " foot" + else + description = description .. " feet" + end else local convertedRange = math.ceil(range * UNITS_PER_METER) description = description .. convertedRange .. " unit" @@ -62,7 +80,7 @@ if SERVER then local range = taskmaster_killfaraway_range:GetInt() * UNITS_PER_METER local rangeSqr = range * range - if (distanceSqr >= rangeSqr) then + if distanceSqr >= rangeSqr then ply:CompleteTask(TASK.id) end end) @@ -77,24 +95,19 @@ if SERVER then net.Send(ply) end - TASK.OnTaskComplete = function(ply) - hook.Remove("PlayerDeath", "Taskmaster_KillFaraway_PlayerDeath_" .. ply:SteamID64()) - net.Start("TTT_Taskmaster_KillFaraway_Cleanup") - net.Send(ply) - end + TASK.OnTaskComplete = TASK.OnTaskRemoved end if CLIENT then net.Receive("TTT_Taskmaster_KillFaraway_Assigned", function() local sid64 = LocalPlayer():SteamID64() + local range = taskmaster_killfaraway_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillFaraway_TTTTargetIDPlayerText_" .. sid64, function(ent, cli, text, col, secondaryText) if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end local distanceSqr = ent:GetPos():DistToSqr(cli:GetPos()) - local range = taskmaster_killfaraway_range:GetInt() * UNITS_PER_METER - local rangeSqr = range * range - if distanceSqr >= rangeSqr then return "IN RANGE", ROLE_COLORS_RADAR[ROLE_INNOCENT] else @@ -102,9 +115,9 @@ if CLIENT then end end) - hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillFaraway_TTTPlayerAliveClientThink_" .. sid64, function(client, ply) + hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillFaraway_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) local shouldDraw = false - if ply == client and client:IsActiveTaskmaster() then + if ply == cli and cli:IsActiveTaskmaster() then local pos = ply:GetPos() if not ply.TaskmasterRadiusEmitter then ply.TaskmasterRadiusEmitter = ParticleEmitter(pos) end if not ply.TaskmasterRadiusNextPart then ply.TaskmasterRadiusNextPart = CurTime() end @@ -113,9 +126,8 @@ if CLIENT then for _ = 1, 48 do ply.TaskmasterRadiusEmitter:SetPos(pos) ply.TaskmasterRadiusNextPart = CurTime() + 0.005 - ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + math.pi / 24 - local radius = taskmaster_killfaraway_range:GetInt() * UNITS_PER_METER - local vec = Vector(math.sin(ply.TaskmasterRadiusDir) * radius, math.cos(ply.TaskmasterRadiusDir) * radius, 10) + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + MathPi / 24 + local vec = Vector(MathSin(ply.TaskmasterRadiusDir) * range, MathCos(ply.TaskmasterRadiusDir) * range, 10) local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) particle:SetVelocity(Vector(0, 0, 80)) particle:SetDieTime(0.5) @@ -123,7 +135,7 @@ if CLIENT then particle:SetEndAlpha(0) particle:SetStartSize(3) particle:SetEndSize(2) - particle:SetRoll(math.Rand(0, math.pi)) + particle:SetRoll(MathRand(0, MathPi)) particle:SetRollDelta(0) particle:SetColor(255, 255, 255) end @@ -146,7 +158,7 @@ if CLIENT then local sid64 = client:SteamID64() hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillFaraway_TTTTargetIDPlayerText_" .. sid64) hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_KillFaraway_TTTPlayerAliveClientThink_" .. sid64) - + if client.TaskmasterRadiusEmitter then client.TaskmasterRadiusEmitter:Finish() client.TaskmasterRadiusEmitter = nil diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua index aec39579e..5bdfcec15 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua @@ -1,3 +1,15 @@ +local CurTime = CurTime +local cvars = cvars +local hook = hook +local math = math +local net = net +local table = table + +local MathCos = math.cos +local MathPi = math.pi +local MathRand = math.Rand +local MathSin = math.sin + local TASK = {} TASK.id = "killnearby" @@ -29,7 +41,13 @@ TASK.Description = function(ply) description = description .. "s" end elseif unit == 2 then - description = description .. math.ceil(range / UNITS_PER_FOOT) .. " feet" + local convertedRange = math.ceil(range * FEET_PER_METER) + description = description .. convertedRange + if convertedRange == 1 then + description = description .. " foot" + else + description = description .. " feet" + end else local convertedRange = math.ceil(range * UNITS_PER_METER) description = description .. convertedRange .. " unit" @@ -62,7 +80,7 @@ if SERVER then local range = taskmaster_killnearby_range:GetInt() * UNITS_PER_METER local rangeSqr = range * range - if (distanceSqr <= rangeSqr) then + if distanceSqr <= rangeSqr then ply:CompleteTask(TASK.id) end end) @@ -77,24 +95,19 @@ if SERVER then net.Send(ply) end - TASK.OnTaskComplete = function(ply) - hook.Remove("PlayerDeath", "Taskmaster_KillNearby_PlayerDeath_" .. ply:SteamID64()) - net.Start("TTT_Taskmaster_KillNearby_Cleanup") - net.Send(ply) - end + TASK.OnTaskComplete = TASK.OnTaskRemoved end if CLIENT then net.Receive("TTT_Taskmaster_KillNearby_Assigned", function() local sid64 = LocalPlayer():SteamID64() + local range = taskmaster_killnearby_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillNearby_TTTTargetIDPlayerText_" .. sid64, function(ent, cli, text, col, secondaryText) if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end local distanceSqr = ent:GetPos():DistToSqr(cli:GetPos()) - local range = taskmaster_killnearby_range:GetInt() * UNITS_PER_METER - local rangeSqr = range * range - if distanceSqr <= rangeSqr then return "IN RANGE", ROLE_COLORS_RADAR[ROLE_INNOCENT] else @@ -102,9 +115,9 @@ if CLIENT then end end) - hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillNearby_TTTPlayerAliveClientThink_" .. sid64, function(client, ply) + hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillNearby_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) local shouldDraw = false - if ply == client and client:IsActiveTaskmaster() then + if ply == cli and cli:IsActiveTaskmaster() then local pos = ply:GetPos() if not ply.TaskmasterRadiusEmitter then ply.TaskmasterRadiusEmitter = ParticleEmitter(pos) end if not ply.TaskmasterRadiusNextPart then ply.TaskmasterRadiusNextPart = CurTime() end @@ -113,9 +126,8 @@ if CLIENT then for _ = 1, 24 do ply.TaskmasterRadiusEmitter:SetPos(pos) ply.TaskmasterRadiusNextPart = CurTime() + 0.02 - ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + math.pi / 12 - local radius = taskmaster_killnearby_range:GetInt() * UNITS_PER_METER - local vec = Vector(math.sin(ply.TaskmasterRadiusDir) * radius, math.cos(ply.TaskmasterRadiusDir) * radius, 10) + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + MathPi / 12 + local vec = Vector(MathSin(ply.TaskmasterRadiusDir) * range, MathCos(ply.TaskmasterRadiusDir) * range, 10) local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) particle:SetVelocity(Vector(0, 0, 40)) particle:SetDieTime(0.25) @@ -123,7 +135,7 @@ if CLIENT then particle:SetEndAlpha(0) particle:SetStartSize(3) particle:SetEndSize(2) - particle:SetRoll(math.Rand(0, math.pi)) + particle:SetRoll(MathRand(0, MathPi)) particle:SetRollDelta(0) particle:SetColor(255, 255, 255) end @@ -146,7 +158,7 @@ if CLIENT then local sid64 = client:SteamID64() hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillNearby_TTTTargetIDPlayerText_" .. sid64) hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_KillNearby_TTTPlayerAliveClientThink_" .. sid64) - + if client.TaskmasterRadiusEmitter then client.TaskmasterRadiusEmitter:Finish() client.TaskmasterRadiusEmitter = nil From 210773983351cab4e15db76d0d8b97fad03d6987 Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 13 Aug 2025 18:32:59 -0400 Subject: [PATCH 006/115] Luacheck fixes --- .luacheckrc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.luacheckrc b/.luacheckrc index 2dae956eb..19594c979 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -897,6 +897,7 @@ globals = { "EVENT_VINDICATORFAIL", "EVENT_VINDICATORSUCCESS", "EVENT_ZOMBIFIED", + "FEET_PER_METER", "GLITCH_CHAT_NONE", "GLITCH_CHAT_BLOCK_ALWAYS", "GLITCH_CHAT_BLOCK_WHILE_ALIVE", @@ -1078,6 +1079,7 @@ globals = { "WIN_PLAGUEMASTER", "WIN_SHADOW", "WIN_SPONGE", + "WIN_TASKMASTER", "WIN_TIMELIMIT", "WIN_TRAITOR", "WIN_VAMPIRE", From b1fc57cdb487ae3813bdb85a5e6613ed7d9b7337 Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 13 Aug 2025 18:33:46 -0400 Subject: [PATCH 007/115] Added Stay Near Target task (without progress bar) --- .../roles/taskmaster/tasks/stayneartarget.lua | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua new file mode 100644 index 000000000..fc0e7bfd9 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -0,0 +1,223 @@ +local CurTime = CurTime +local cvars = cvars +local hook = hook +local math = math +local net = net +local player = player +local table = table + +local MathCos = math.cos +local MathPi = math.pi +local MathRand = math.Rand +local MathSin = math.sin + +local TASK = {} + +TASK.id = "stayneartarget" + +local taskmaster_stayneartarget_range = CreateConVar("ttt_taskmaster_stayneartarget_range", "5", FCVAR_REPLICATED, "The distance (in meters) away a player must stay within to count for the 'Stay Near Target' task", 0, 100) +local taskmaster_stayneartarget_time = CreateConVar("ttt_taskmaster_stayneartarget_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay near their target to count for the 'Stay Near Target' task", 0, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_stayneartarget_range", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_stayneartarget_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local name = "Player" + if IsPlayer(ply.StayNearTargetPlayer) then + name = ply.StayNearTargetPlayer:Nick() + end + return "Stay Near " .. name +end + +TASK.Description = function(ply) + local unit + if SERVER then + unit = 1 + else + unit = cvars.Number("ttt_distance_unit", 1) + end + local range = taskmaster_stayneartarget_range:GetInt() + local description = "Stay within " + if unit == 1 then + description = description .. range .. " meter" + if range ~= 1 then + description = description .. "s" + end + elseif unit == 2 then + local convertedRange = math.ceil(range * FEET_PER_METER) + description = description .. convertedRange + if convertedRange == 1 then + description = description .. " foot" + else + description = description .. " feet" + end + else + local convertedRange = math.ceil(range * UNITS_PER_METER) + description = description .. convertedRange .. " unit" + if convertedRange ~= 1 then + description = description .. "s" + end + end + + local name = "Target" + if IsPlayer(ply.StayNearTargetPlayer) then + name = ply.StayNearTargetPlayer:Nick() + end + + local time = taskmaster_stayneartarget_time:GetInt() + description = description .. " of " .. name .. " for " .. time .. " second" + if time == 1 then + return description + end + return description .. "s" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_StayNearTarget_Assigned") + util.AddNetworkString("TTT_Taskmaster_StayNearTarget_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + "TargetIDPlayerTargetIcon", + "ProgressBar", + "ParticleRadius" + } + + TASK.OnTaskAssigned = function(ply) + local target + -- Find the first random living player + for _, p in RandomPairs(player.GetAll()) do + if not p:Alive() or p:IsSpec() then continue end + if p == ply then continue end + target = p + break + end + + ply:SetProperty("StayNearTargetPlayer", target, ply) + + local range = taskmaster_stayneartarget_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + local time = taskmaster_stayneartarget_time:GetInt() + timer.Create("TTTTaskmasterStayNearTargetTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + if not IsPlayer(target) then return end + + -- Within range + if ply:GetPos():DistToSqr(target:GetPos()) <= rangeSqr then + -- Just starting + if not ply.StayNearTargetStart then + ply.StayNearTargetStart = CurTime() + -- Long enough + elseif CurTime() > ply.StayNearTargetStart + time then + ply:CompleteTask(TASK.id) + end + -- Not within range + else + ply:ClearProperty("StayNearTargetStart") + end + end) + + net.Start("TTT_Taskmaster_StayNearTarget_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterStayNearTargetTimer") + + ply:ClearProperty("StayNearTargetPlayer") + ply:ClearProperty("StayNearTargetStart") + + net.Start("TTT_Taskmaster_StayNearTarget_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_StayNearTarget_Assigned", function() + local sid64 = LocalPlayer():SteamID64() + local range = taskmaster_stayneartarget_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + + hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_StayNearTarget_TTTTargetIDPlayerTargetIcon_" .. sid64, function(ply, cli, showJester) + if cli:IsActiveTaskmaster() and ply == cli.StayNearTargetPlayer then + local iconColor = ROLE_COLORS_SPRITE[ROLE_TRAITOR] + if cli:GetPos():DistToSqr(ply:GetPos()) <= rangeSqr then + iconColor = ROLE_COLORS_SPRITE[ROLE_INNOCENT] + end + return "task", true, iconColor, "up" + end + end) + + hook.Add("TTTPlayerAliveClientThink", "Taskmaster_StayNearTarget_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) + local shouldDraw = false + local target = cli.StayNearTargetPlayer + if ply == cli and cli:IsActiveTaskmaster() and IsPlayer(target) then + local pos = target:GetPos() + if not ply.TaskmasterRadiusEmitter then ply.TaskmasterRadiusEmitter = ParticleEmitter(pos) end + if not ply.TaskmasterRadiusNextPart then ply.TaskmasterRadiusNextPart = CurTime() end + if not ply.TaskmasterRadiusDir then ply.TaskmasterRadiusDir = 0 end + -- Use DistToSqr as it's more efficient and this is called very frequently + -- 9000000 = 3000^2 + if ply.TaskmasterRadiusNextPart < CurTime() and cli:GetPos():DistToSqr(pos) <= 9000000 then + for _ = 1, 48 do + ply.TaskmasterRadiusEmitter:SetPos(pos) + ply.TaskmasterRadiusNextPart = CurTime() + 0.005 + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + MathPi / 24 + local vec = Vector(MathSin(ply.TaskmasterRadiusDir) * range, MathCos(ply.TaskmasterRadiusDir) * range, 10) + local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) + particle:SetVelocity(Vector(0, 0, 80)) + particle:SetDieTime(0.5) + particle:SetStartAlpha(200) + particle:SetEndAlpha(0) + particle:SetStartSize(3) + particle:SetEndSize(2) + particle:SetRoll(MathRand(0, MathPi)) + particle:SetRollDelta(0) + local color = ROLE_COLORS[ROLE_TRAITOR] + if ply:GetPos():DistToSqr(target:GetPos()) <= rangeSqr then + color = ROLE_COLORS[ROLE_INNOCENT] + end + particle:SetColor(color.r, color.g, color.b) + end + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + 0.02 + end + shouldDraw = true + end + + if not shouldDraw and ply.TaskmasterRadiusEmitter then + ply.TaskmasterRadiusEmitter:Finish() + ply.TaskmasterRadiusEmitter = nil + ply.TaskmasterRadiusDir = nil + ply.TaskmasterRadiusNextPart = nil + end + end) + end) + + net.Receive("TTT_Taskmaster_StayNearTarget_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("TTTTargetIDPlayerTargetIcon", "Taskmaster_StayNearTarget_TTTTargetIDPlayerTargetIcon_" .. sid64) + hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_StayNearTarget_TTTPlayerAliveClientThink_" .. sid64) + + if client.TaskmasterRadiusEmitter then + client.TaskmasterRadiusEmitter:Finish() + client.TaskmasterRadiusEmitter = nil + client.TaskmasterRadiusDir = nil + client.TaskmasterRadiusNextPart = nil + end + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 76fa64a81c71ac7fb8f8c7409468eaaa4cbce9f7 Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 13 Aug 2025 22:14:51 -0400 Subject: [PATCH 008/115] Added progress bar to Stay Near Target task --- .../roles/taskmaster/cl_taskmaster.lua | 4 ++ .../roles/taskmaster/tasks/stayneartarget.lua | 42 ++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 78c96574b..42aaf4c98 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -15,6 +15,10 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() -- Bonus credit popup LANG.AddToLanguage("english", "taskmaster_credit_bonus", "{role}, you have been awarded {num} credit(s) for completing a task.") + -- Tasks + -- Stay Near Target + LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") + -- Win conditions LANG.AddToLanguage("english", "win_taskmaster", "The {role} finished off their list!") LANG.AddToLanguage("english", "ev_win_taskmaster", "The methodical {role} has won the round!") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index fc0e7bfd9..cee48da9b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -5,8 +5,10 @@ local math = math local net = net local player = player local table = table +local util = util local MathCos = math.cos +local MathMax = math.max local MathPi = math.pi local MathRand = math.Rand local MathSin = math.sin @@ -116,7 +118,7 @@ if SERVER then if ply:GetPos():DistToSqr(target:GetPos()) <= rangeSqr then -- Just starting if not ply.StayNearTargetStart then - ply.StayNearTargetStart = CurTime() + ply:SetProperty("StayNearTargetStart", CurTime()) -- Long enough elseif CurTime() > ply.StayNearTargetStart + time then ply:CompleteTask(TASK.id) @@ -146,9 +148,11 @@ end if CLIENT then net.Receive("TTT_Taskmaster_StayNearTarget_Assigned", function() - local sid64 = LocalPlayer():SteamID64() + local client = LocalPlayer() + local sid64 = client:SteamID64() local range = taskmaster_stayneartarget_range:GetInt() * UNITS_PER_METER local rangeSqr = range * range + local time = taskmaster_stayneartarget_time:GetInt() hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_StayNearTarget_TTTTargetIDPlayerTargetIcon_" .. sid64, function(ply, cli, showJester) if cli:IsActiveTaskmaster() and ply == cli.StayNearTargetPlayer then @@ -174,12 +178,12 @@ if CLIENT then for _ = 1, 48 do ply.TaskmasterRadiusEmitter:SetPos(pos) ply.TaskmasterRadiusNextPart = CurTime() + 0.005 - ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + MathPi / 24 + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + MathPi / 12 local vec = Vector(MathSin(ply.TaskmasterRadiusDir) * range, MathCos(ply.TaskmasterRadiusDir) * range, 10) local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) - particle:SetVelocity(Vector(0, 0, 80)) - particle:SetDieTime(0.5) - particle:SetStartAlpha(200) + particle:SetVelocity(Vector(0, 0, 40)) + particle:SetDieTime(0.25) + particle:SetStartAlpha(60) particle:SetEndAlpha(0) particle:SetStartSize(3) particle:SetEndSize(2) @@ -203,6 +207,31 @@ if CLIENT then ply.TaskmasterRadiusNextPart = nil end end) + + hook.Add("HUDPaint", "Taskmaster_StayNearTarget_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local target = client.StayNearTargetPlayer + if not IsPlayer(target) then return end + + local startTime = client.StayNearTargetStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_stayneartarget", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = 1 - (elapsed / time) + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) end) net.Receive("TTT_Taskmaster_StayNearTarget_Cleanup", function() @@ -210,6 +239,7 @@ if CLIENT then local sid64 = client:SteamID64() hook.Remove("TTTTargetIDPlayerTargetIcon", "Taskmaster_StayNearTarget_TTTTargetIDPlayerTargetIcon_" .. sid64) hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_StayNearTarget_TTTPlayerAliveClientThink_" .. sid64) + hook.Remove("HUDPaint", "Taskmaster_StayNearTarget_HUDPaint_" .. sid64) if client.TaskmasterRadiusEmitter then client.TaskmasterRadiusEmitter:Finish() From 21b242c926b592a897608da80038ca0c648549dd Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 07:22:37 -0400 Subject: [PATCH 009/115] Changed progress bar to fill rather than drain --- .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index cee48da9b..7a064595d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -164,6 +164,7 @@ if CLIENT then end end) + local particleVelocity = Vector(0, 0, 40) hook.Add("TTTPlayerAliveClientThink", "Taskmaster_StayNearTarget_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) local shouldDraw = false local target = cli.StayNearTargetPlayer @@ -181,7 +182,7 @@ if CLIENT then ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + MathPi / 12 local vec = Vector(MathSin(ply.TaskmasterRadiusDir) * range, MathCos(ply.TaskmasterRadiusDir) * range, 10) local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) - particle:SetVelocity(Vector(0, 0, 40)) + particle:SetVelocity(particleVelocity) particle:SetDieTime(0.25) particle:SetStartAlpha(60) particle:SetEndAlpha(0) @@ -228,7 +229,7 @@ if CLIENT then y = y + (y / 3) local w = 300 - local progress = 1 - (elapsed / time) + local progress = elapsed / time CRHUD:PaintProgressBar(x, y, w, color, message, progress) end) From 4fcdedbe627ade6c2ed34559a0884b300bd8a3a3 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 07:22:41 -0400 Subject: [PATCH 010/115] Cleanup --- gamemodes/terrortown/gamemode/roles/paladin/cl_paladin.lua | 3 ++- gamemodes/terrortown/gamemode/roles/sapper/cl_sapper.lua | 3 ++- gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua | 3 ++- gamemodes/terrortown/gamemode/roles/sponge/cl_sponge.lua | 5 +++-- .../gamemode/roles/taskmaster/tasks/killfaraway.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/killnearby.lua | 3 ++- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/paladin/cl_paladin.lua b/gamemodes/terrortown/gamemode/roles/paladin/cl_paladin.lua index 129d9b6b6..9cee1dbf3 100644 --- a/gamemodes/terrortown/gamemode/roles/paladin/cl_paladin.lua +++ b/gamemodes/terrortown/gamemode/roles/paladin/cl_paladin.lua @@ -35,6 +35,7 @@ end) -- ROLE FEATURES -- ------------------- +local particleVelocity = Vector(0, 0, 20) hook.Add("TTTPlayerAliveClientThink", "Paladin_RoleFeatures_TTTPlayerAliveClientThink", function(client, ply) if ply:GetDisplayedRole() == ROLE_PALADIN and ply:GetObserverMode() == OBS_MODE_NONE then if not ply.AuraEmitter then ply.AuraEmitter = ParticleEmitter(ply:GetPos()) end @@ -50,7 +51,7 @@ hook.Add("TTTPlayerAliveClientThink", "Paladin_RoleFeatures_TTTPlayerAliveClient local radius = paladin_aura_radius:GetFloat() * UNITS_PER_METER local vec = Vector(MathSin(ply.AuraDir) * radius, MathCos(ply.AuraDir) * radius, 10) local particle = ply.AuraEmitter:Add("particle/shield.vmt", ply:GetPos() + vec) - particle:SetVelocity(Vector(0, 0, 20)) + particle:SetVelocity(particleVelocity) particle:SetDieTime(1) particle:SetStartAlpha(200) particle:SetEndAlpha(0) diff --git a/gamemodes/terrortown/gamemode/roles/sapper/cl_sapper.lua b/gamemodes/terrortown/gamemode/roles/sapper/cl_sapper.lua index cf0698ead..084041559 100644 --- a/gamemodes/terrortown/gamemode/roles/sapper/cl_sapper.lua +++ b/gamemodes/terrortown/gamemode/roles/sapper/cl_sapper.lua @@ -36,10 +36,11 @@ end) -- ROLE FEATURES -- ------------------- +local particleVelocity = Vector(0, 0, 20) local function CreateParticle(auraDir, pos, radius, emitter) local vec = Vector(MathSin(auraDir) * radius, MathCos(auraDir) * radius, 10) local particle = emitter:Add("particle/sap_barrel.vmt", pos + vec) - particle:SetVelocity(Vector(0, 0, 20)) + particle:SetVelocity(particleVelocity) particle:SetDieTime(1) particle:SetStartAlpha(200) particle:SetEndAlpha(0) diff --git a/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua b/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua index ff5decdeb..ac7d4401e 100644 --- a/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua +++ b/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua @@ -280,6 +280,7 @@ end) -- PARTICLES -- --------------- +local radiusVelocity = Vector(0, 0, 80) local function DrawRadius(ply, ent, radius) if not ent.RadiusEmitter then ent.RadiusEmitter = ParticleEmitter(ent:GetPos()) end if not ent.RadiusNextPart then ent.RadiusNextPart = CurTime() end @@ -296,7 +297,7 @@ local function DrawRadius(ply, ent, radius) ent.RadiusDir = ent.RadiusDir + MathPi / 12 local vec = Vector(MathSin(ent.RadiusDir) * radius, MathCos(ent.RadiusDir) * radius, 10) local particle = ent.RadiusEmitter:Add("particle/wisp.vmt", ent:GetPos() + vec) - particle:SetVelocity(Vector(0, 0, 80)) + particle:SetVelocity(radiusVelocity) particle:SetDieTime(0.5) particle:SetStartAlpha(200) particle:SetEndAlpha(0) diff --git a/gamemodes/terrortown/gamemode/roles/sponge/cl_sponge.lua b/gamemodes/terrortown/gamemode/roles/sponge/cl_sponge.lua index 88da157f2..3fbc82fa2 100644 --- a/gamemodes/terrortown/gamemode/roles/sponge/cl_sponge.lua +++ b/gamemodes/terrortown/gamemode/roles/sponge/cl_sponge.lua @@ -44,6 +44,7 @@ end) -- ROLE FEATURES -- ------------------- +local particleVelocity = Vector(0, 0, 20) hook.Add("TTTPlayerAliveClientThink", "Sponge_RoleFeatures_TTTPlayerAliveClientThink", function(client, ply) local shouldDraw = false if ply:GetRole() == ROLE_SPONGE and ply:GetObserverMode() == OBS_MODE_NONE then @@ -61,7 +62,7 @@ hook.Add("TTTPlayerAliveClientThink", "Sponge_RoleFeatures_TTTPlayerAliveClientT local radius = GetGlobalFloat("ttt_sponge_aura_radius", UNITS_PER_SIX_METERS) local vec = Vector(MathSin(ply.SpongeAuraDir) * radius, MathCos(ply.SpongeAuraDir) * radius, 10) local particle = ply.SpongeAuraEmitter:Add("particle/sponge.vmt", ply_pos + vec) - particle:SetVelocity(Vector(0, 0, 20)) + particle:SetVelocity(particleVelocity) particle:SetDieTime(1) particle:SetStartAlpha(200) particle:SetEndAlpha(0) @@ -104,7 +105,7 @@ hook.Add("TTTPlayerAliveClientThink", "Sponge_RoleFeatures_TTTPlayerAliveClientT local auraRadius = 20 local vec = Vector(MathSin(ply.SpongeAuraDir) * auraRadius, MathCos(ply.SpongeAuraDir) * auraRadius, 10) local particle = ply.SpongeAuraEmitter:Add("particle/sponge.vmt", ply_pos + vec) - particle:SetVelocity(Vector(0, 0, 20)) + particle:SetVelocity(particleVelocity) particle:SetDieTime(1) particle:SetStartAlpha(200) particle:SetEndAlpha(0) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua index 405956cc8..e1470d2aa 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua @@ -115,6 +115,7 @@ if CLIENT then end end) + local particleVelocity = Vector(0, 0, 80) hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillFaraway_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) local shouldDraw = false if ply == cli and cli:IsActiveTaskmaster() then @@ -129,7 +130,7 @@ if CLIENT then ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + MathPi / 24 local vec = Vector(MathSin(ply.TaskmasterRadiusDir) * range, MathCos(ply.TaskmasterRadiusDir) * range, 10) local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) - particle:SetVelocity(Vector(0, 0, 80)) + particle:SetVelocity(particleVelocity) particle:SetDieTime(0.5) particle:SetStartAlpha(200) particle:SetEndAlpha(0) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua index 5bdfcec15..389c2ca2c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua @@ -115,6 +115,7 @@ if CLIENT then end end) + local particleVelocity = Vector(0, 0, 40) hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillNearby_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) local shouldDraw = false if ply == cli and cli:IsActiveTaskmaster() then @@ -129,7 +130,7 @@ if CLIENT then ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + MathPi / 12 local vec = Vector(MathSin(ply.TaskmasterRadiusDir) * range, MathCos(ply.TaskmasterRadiusDir) * range, 10) local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) - particle:SetVelocity(Vector(0, 0, 40)) + particle:SetVelocity(particleVelocity) particle:SetDieTime(0.25) particle:SetStartAlpha(60) particle:SetEndAlpha(0) From 6ca9794447c18f210386650815d751659c25e5c7 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 07:26:17 -0400 Subject: [PATCH 011/115] Changed task features to use constants --- .luacheckrc | 4 ++++ gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua | 8 +++++++- .../gamemode/roles/taskmaster/tasks/killfaraway.lua | 4 ++-- .../gamemode/roles/taskmaster/tasks/killnearby.lua | 4 ++-- .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 6 +++--- .../gamemode/roles/taskmaster/tasks/testkilltask.lua | 6 +++--- .../gamemode/roles/taskmaster/tasks/testmisctask.lua | 6 +++--- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.luacheckrc b/.luacheckrc index 19594c979..9fd690ca5 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -1053,6 +1053,10 @@ globals = { "SPECIAL_DETECTIVE_HIDE_NONE", "SPONGE_ALL_PLAYERS", "SPONGE_ATTACKER_AND_VICTIM", + "TASKMASTER_TF_TARGETID_PLAYERICON", + "TASKMASTER_TF_TARGETID_PLAYERTEXT", + "TASKMASTER_TF_PROGRESSBAR", + "TASKMASTER_TF_PARTICLERADIUS", "TRACKRADAR", "TRAITOR_BUTTON_ROLES", "TRAITOR_ROLES", diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua index c8006afdf..f7a5fd7ea 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -1,9 +1,15 @@ AddCSLuaFile() +-- Task Features +TASKMASTER_TF_TARGETID_PLAYERICON = 0 +TASKMASTER_TF_TARGETID_PLAYERTEXT = 1 +TASKMASTER_TF_PROGRESSBAR = 2 +TASKMASTER_TF_PARTICLERADIUS = 3 + ROLE_STARTING_CREDITS[ROLE_TASKMASTER] = 1 ROLE_HAS_PASSIVE_WIN[ROLE_TASKMASTER] = false cvars.AddChangeCallback("ttt_taskmaster_is_passive", function(_, _, newValue) - ROLE_HAS_PASSIVE_WIN[ROLE_TASKMASTER] = util.tobool(newValue) + ROLE_HAS_PASSIVE_WIN[ROLE_TASKMASTER] = tobool(newValue) end) ------------------ diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua index e1470d2aa..1ffeca71c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua @@ -67,8 +67,8 @@ if SERVER then end TASK.RequiredFeatures = { - "TargetIDPlayerText", - "ParticleRadius" + TASKMASTER_TF_TARGETID_PLAYERTEXT, + TASKMASTER_TF_PARTICLERADIUS } TASK.OnTaskAssigned = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua index 389c2ca2c..c011ae869 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua @@ -67,8 +67,8 @@ if SERVER then end TASK.RequiredFeatures = { - "TargetIDPlayerText", - "ParticleRadius" + TASKMASTER_TF_TARGETID_PLAYERTEXT, + TASKMASTER_TF_PARTICLERADIUS } TASK.OnTaskAssigned = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 7a064595d..634472f05 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -90,9 +90,9 @@ if SERVER then end TASK.RequiredFeatures = { - "TargetIDPlayerTargetIcon", - "ProgressBar", - "ParticleRadius" + TASKMASTER_TF_TARGETID_PLAYERICON, + TASKMASTER_TF_PROGRESSBAR, + TASKMASTER_TF_PARTICLERADIUS } TASK.OnTaskAssigned = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua index fc1b1c01f..16fe384a2 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua @@ -17,9 +17,9 @@ if SERVER then end TASK.RequiredFeatures = { - --"TargetIDPlayerText", - --"TargetIDPlayerTargetIcon", - --"ProgressBar" + --TASKMASTER_TF_TARGETID_PLAYERTEXT, + --TASKMASTER_TF_TARGETID_PLAYERICON, + --TASKMASTER_TF_PROGRESSBAR } TASK.OnTaskAssigned = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua index 506b0bdf6..7f0bcad1e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua @@ -16,9 +16,9 @@ if SERVER then end TASK.RequiredFeatures = { - --"TargetIDPlayerText", - --"TargetIDPlayerTargetIcon", - --"ProgressBar" + --TASKMASTER_TF_TARGETID_PLAYERTEXT, + --TASKMASTER_TF_TARGETID_PLAYERICON, + --TASKMASTER_TF_PROGRESSBAR } TASK.OnTaskAssigned = function(ply) From 50d96ad17c50331bd725fd139f1b00a9d4d616bf Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 09:57:18 -0400 Subject: [PATCH 012/115] Disallow 0 for Stay Near Target convars Changed Stay Near Target player properties to be scoped instead of shared --- .../roles/taskmaster/tasks/stayneartarget.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 634472f05..aac13b41b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -17,8 +17,8 @@ local TASK = {} TASK.id = "stayneartarget" -local taskmaster_stayneartarget_range = CreateConVar("ttt_taskmaster_stayneartarget_range", "5", FCVAR_REPLICATED, "The distance (in meters) away a player must stay within to count for the 'Stay Near Target' task", 0, 100) -local taskmaster_stayneartarget_time = CreateConVar("ttt_taskmaster_stayneartarget_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay near their target to count for the 'Stay Near Target' task", 0, 240) +local taskmaster_stayneartarget_range = CreateConVar("ttt_taskmaster_stayneartarget_range", "5", FCVAR_REPLICATED, "The distance (in meters) away a player must stay within to count for the 'Stay Near Target' task", 1, 100) +local taskmaster_stayneartarget_time = CreateConVar("ttt_taskmaster_stayneartarget_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay near their target to count for the 'Stay Near Target' task", 1, 240) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_stayneartarget_range", type = ROLE_CONVAR_TYPE_NUM, @@ -118,14 +118,14 @@ if SERVER then if ply:GetPos():DistToSqr(target:GetPos()) <= rangeSqr then -- Just starting if not ply.StayNearTargetStart then - ply:SetProperty("StayNearTargetStart", CurTime()) + ply:SetProperty("StayNearTargetStart", CurTime(), ply) -- Long enough elseif CurTime() > ply.StayNearTargetStart + time then ply:CompleteTask(TASK.id) end -- Not within range else - ply:ClearProperty("StayNearTargetStart") + ply:ClearProperty("StayNearTargetStart", ply) end end) @@ -136,8 +136,8 @@ if SERVER then TASK.OnTaskRemoved = function(ply) timer.Remove("TTTTaskmasterStayNearTargetTimer") - ply:ClearProperty("StayNearTargetPlayer") - ply:ClearProperty("StayNearTargetStart") + ply:ClearProperty("StayNearTargetPlayer", ply) + ply:ClearProperty("StayNearTargetStart", ply) net.Start("TTT_Taskmaster_StayNearTarget_Cleanup") net.Send(ply) From d698f319f3b8957ae4ac798b70615dc9d55bb485 Mon Sep 17 00:00:00 2001 From: NoxxFlame Date: Thu, 14 Aug 2025 15:20:23 +0100 Subject: [PATCH 013/115] Added 'Kill a Player From Behind' task --- .../roles/taskmaster/tasks/killbehind.lua | 93 +++++++++++++++++++ .../roles/taskmaster/tasks/killfaraway.lua | 6 +- .../roles/taskmaster/tasks/killnearby.lua | 6 +- .../roles/taskmaster/tasks/testkilltask.lua | 6 +- .../roles/taskmaster/tasks/testmisctask.lua | 6 +- 5 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua new file mode 100644 index 000000000..ccfef07f2 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua @@ -0,0 +1,93 @@ +local hook = hook +local math = math +local net = net +local table = table + +local MathCos = math.cos +local MathRad = math.rad + +local TASK = {} + +TASK.id = "killbehind" +TASK.isKillTask = true + +local taskmaster_killbehind_angle = CreateConVar("ttt_taskmaster_killbehind_view_angle", "75", FCVAR_REPLICATED, "The angle (in degrees) from a player's eye angle within which the Taskmaster is 'spotted' for the 'Kill a Player From Behind' task", 0, 180) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_killbehind_view_angle", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + return "Kill a Player From Behind" +end + +TASK.Description = function(ply) + return "Kill another player while they are looking away from you" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_KillBehind_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillBehind_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERTEXT + } + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillBehind_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + local maxAngleCos = MathCos(MathRad(taskmaster_killbehind_angle:GetInt())) + local aimVector = victim:GetAimVector() + local attackVector = attacker:GetPos() - victim:GetShootPos() + local angleCos = aimVector:Dot(attackVector) / attackVector:Length() + + if angleCos <= maxAngleCos then + ply:CompleteTask(TASK.id) + end + end) + + net.Start("TTT_Taskmaster_KillBehind_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillBehind_PlayerDeath_" .. ply:SteamID64()) + net.Start("TTT_Taskmaster_KillBehind_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_KillBehind_Assigned", function() + local maxAngleCos = MathCos(MathRad(taskmaster_killbehind_angle:GetInt())) + + hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillBehind_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64(), function(ent, cli, text, col, secondaryText) + if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end + + local aimVector = ent:GetAimVector() + local attackVector = cli:GetPos() - ent:GetShootPos() + local angleCos = aimVector:Dot(attackVector) / attackVector:Length() + + if angleCos <= maxAngleCos then + return "HIDDEN", ROLE_COLORS_RADAR[ROLE_INNOCENT] + else + return "SPOTTED", ROLE_COLORS_RADAR[ROLE_TRAITOR] + end + end) + end) + + net.Receive("TTT_Taskmaster_KillBehind_Cleanup", function() + hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillBehind_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua index 1ffeca71c..9ce441172 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua @@ -15,7 +15,7 @@ local TASK = {} TASK.id = "killfaraway" TASK.isKillTask = true -local taskmaster_killfaraway_range = CreateConVar("ttt_taskmaster_killfaraway_range", "25", FCVAR_REPLICATED, "The minimum distance (in meters) away a player can be to count for the 'Kill Faraway Player' task", 0, 100) +local taskmaster_killfaraway_range = CreateConVar("ttt_taskmaster_killfaraway_range", "25", FCVAR_REPLICATED, "The minimum distance (in meters) away a player can be to count for the 'Kill a Faraway Player' task", 0, 100) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_killfaraway_range", type = ROLE_CONVAR_TYPE_NUM, @@ -23,7 +23,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { }) TASK.Name = function(ply) - return "Kill Faraway Player" + return "Kill a Faraway Player" end TASK.Description = function(ply) @@ -34,7 +34,7 @@ TASK.Description = function(ply) unit = cvars.Number("ttt_distance_unit", 1) end local range = taskmaster_killfaraway_range:GetInt() - local description = "Kill a player from outside " + local description = "Kill another player from outside " if unit == 1 then description = description .. range .. " meter" if range ~= 1 then diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua index c011ae869..ffd313b8c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua @@ -15,7 +15,7 @@ local TASK = {} TASK.id = "killnearby" TASK.isKillTask = true -local taskmaster_killnearby_range = CreateConVar("ttt_taskmaster_killnearby_range", "5", FCVAR_REPLICATED, "The maximum distance (in meters) away a player can be to count for the 'Kill Nearby Player' task", 0, 10) +local taskmaster_killnearby_range = CreateConVar("ttt_taskmaster_killnearby_range", "5", FCVAR_REPLICATED, "The maximum distance (in meters) away a player can be to count for the 'Kill a Nearby Player' task", 0, 10) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_killnearby_range", type = ROLE_CONVAR_TYPE_NUM, @@ -23,7 +23,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { }) TASK.Name = function(ply) - return "Kill Nearby Player" + return "Kill a Nearby Player" end TASK.Description = function(ply) @@ -34,7 +34,7 @@ TASK.Description = function(ply) unit = cvars.Number("ttt_distance_unit", 1) end local range = taskmaster_killnearby_range:GetInt() - local description = "Kill a player from within " + local description = "Kill another player from within " if unit == 1 then description = description .. range .. " meter" if range ~= 1 then diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua index 16fe384a2..2100bcb33 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua @@ -16,11 +16,7 @@ if SERVER then return false end - TASK.RequiredFeatures = { - --TASKMASTER_TF_TARGETID_PLAYERTEXT, - --TASKMASTER_TF_TARGETID_PLAYERICON, - --TASKMASTER_TF_PROGRESSBAR - } + TASK.RequiredFeatures = {} TASK.OnTaskAssigned = function(ply) ply:QueueMessage(MSG_PRINTBOTH, "Task Assigned: " .. TASK.Name(ply)) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua index 7f0bcad1e..c3fd97bc1 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua @@ -15,11 +15,7 @@ if SERVER then return false end - TASK.RequiredFeatures = { - --TASKMASTER_TF_TARGETID_PLAYERTEXT, - --TASKMASTER_TF_TARGETID_PLAYERICON, - --TASKMASTER_TF_PROGRESSBAR - } + TASK.RequiredFeatures = {} TASK.OnTaskAssigned = function(ply) ply:QueueMessage(MSG_PRINTBOTH, "Task Assigned: " .. TASK.Name(ply)) From a66db084096aa092ddd14c1a106566b82618fc73 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 10:21:09 -0400 Subject: [PATCH 014/115] Added Crouch Near Body task --- .../roles/taskmaster/cl_taskmaster.lua | 2 +- .../roles/taskmaster/tasks/crouchnearbody.lua | 169 ++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 42aaf4c98..c37313a32 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -16,8 +16,8 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_credit_bonus", "{role}, you have been awarded {num} credit(s) for completing a task.") -- Tasks - -- Stay Near Target LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") + LANG.AddToLanguage("english", "taskmaster_crouchnearbody", "CROUCH NEAR BODY - {time}") -- Win conditions LANG.AddToLanguage("english", "win_taskmaster", "The {role} finished off their list!") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua new file mode 100644 index 000000000..bc9cc0260 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -0,0 +1,169 @@ +local CurTime = CurTime +local cvars = cvars +local ents = ents +local hook = hook +local math = math +local net = net +local table = table +local util = util + +local EntsFindByClass = ents.FindByClass +local MathMax = math.max + +local TASK = {} + +TASK.id = "crouchnearbody" + +local taskmaster_crouchnearbody_range = CreateConVar("ttt_taskmaster_crouchnearbody_range", "1", FCVAR_REPLICATED, "The distance (in meters) away a player must stay within to count for the 'Crouch Near Body' task", 1, 100) +local taskmaster_crouchnearbody_time = CreateConVar("ttt_taskmaster_crouchnearbody_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay near a body to count for the 'Crouch Near Body' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_crouchnearbody_range", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_crouchnearbody_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + return "Crouch Near Body" +end + +TASK.Description = function(ply) + local unit + if SERVER then + unit = 1 + else + unit = cvars.Number("ttt_distance_unit", 1) + end + local range = taskmaster_crouchnearbody_range:GetInt() + local description = "Crouch within " + if unit == 1 then + description = description .. range .. " meter" + if range ~= 1 then + description = description .. "s" + end + elseif unit == 2 then + local convertedRange = math.ceil(range * FEET_PER_METER) + description = description .. convertedRange + if convertedRange == 1 then + description = description .. " foot" + else + description = description .. " feet" + end + else + local convertedRange = math.ceil(range * UNITS_PER_METER) + description = description .. convertedRange .. " unit" + if convertedRange ~= 1 then + description = description .. "s" + end + end + local time = taskmaster_crouchnearbody_time:GetInt() + description = description .. " of a body for " .. time .. " second" + if time == 1 then + return description + end + return description .. "s" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_CrouchNearBody_Assigned") + util.AddNetworkString("TTT_Taskmaster_CrouchNearBody_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + TASK.OnTaskAssigned = function(ply) + local range = taskmaster_crouchnearbody_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + local time = taskmaster_crouchnearbody_time:GetInt() + timer.Create("TTTTaskmasterCrouchNearBodyTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + if not ply:Crouching() then + if ply.CrouchNearBodyStart then + ply:ClearProperty("CrouchNearBodyStart", ply) + end + return + end + + for _, corpse in ipairs(EntsFindByClass("prop_ragdoll")) do + local sourcePlayer = CORPSE.GetPlayer(corpse) + if not IsPlayer(sourcePlayer) then continue end + if sourcePlayer:Alive() or not sourcePlayer:IsSpec() then continue end + + -- Within range + if ply:GetPos():DistToSqr(corpse:GetPos()) <= rangeSqr then + -- Just starting + if not ply.CrouchNearBodyStart then + ply:SetProperty("CrouchNearBodyStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.CrouchNearBodyStart + time then + ply:CompleteTask(TASK.id) + end + -- Not within range + else + ply:ClearProperty("CrouchNearBodyStart", ply) + end + end + end) + + net.Start("TTT_Taskmaster_CrouchNearBody_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterCrouchNearBodyTimer") + + ply:ClearProperty("CrouchNearBodyStart", ply) + + net.Start("TTT_Taskmaster_CrouchNearBody_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_CrouchNearBody_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local time = taskmaster_crouchnearbody_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_CrouchNearBody_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.CrouchNearBodyStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_crouchnearbody", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_CrouchNearBody_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("HUDPaint", "Taskmaster_CrouchNearBody_HUDPaint_" .. sid64) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From f1942b41bdf0a529ed78f768599142b6da96ea9b Mon Sep 17 00:00:00 2001 From: NoxxFlame Date: Thu, 14 Aug 2025 16:03:30 +0100 Subject: [PATCH 015/115] Added 'Kill an Airbourne Player' and 'Kill a Player While Midair' task --- .../roles/taskmaster/tasks/killairborne.lua | 70 +++++++++++++++++++ .../roles/taskmaster/tasks/killmidair.lua | 41 +++++++++++ 2 files changed, 111 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killmidair.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua new file mode 100644 index 000000000..4d87c05bc --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua @@ -0,0 +1,70 @@ +local hook = hook +local net = net + +local TASK = {} + +TASK.id = "killairbourne" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Kill an Airbourne Player" +end + +TASK.Description = function(ply) + return "Kill another player while they are in the air" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_KillAirbourne_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillAirbourne_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERTEXT + } + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillAirbourne_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if not victim:OnGround() then + ply:CompleteTask(TASK.id) + end + end) + + net.Start("TTT_Taskmaster_KillAirbourne_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillAirbourne_PlayerDeath_" .. ply:SteamID64()) + net.Start("TTT_Taskmaster_KillAirbourne_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_KillAirbourne_Assigned", function() + hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillAirbourne_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64(), function(ent, cli, text, col, secondaryText) + if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end + + if ent:OnGround() then + return "GROUNDED", ROLE_COLORS_RADAR[ROLE_TRAITOR] + else + return "AIRBORNE", ROLE_COLORS_RADAR[ROLE_INNOCENT] + end + end) + end) + + net.Receive("TTT_Taskmaster_KillAirbourne_Cleanup", function() + hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillAirbourne_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killmidair.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killmidair.lua new file mode 100644 index 000000000..a3dab87ce --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killmidair.lua @@ -0,0 +1,41 @@ +local hook = hook + +local TASK = {} + +TASK.id = "killmidair" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Kill a Player While Midair" +end + +TASK.Description = function(ply) + return "Kill another player while you are in the air" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillMidair_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if not attacker:OnGround() then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillMidair_PlayerDeath_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From c35dc607c87f44f972e6b356c1d7fce4e84f640d Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 12:08:17 -0400 Subject: [PATCH 016/115] Added `TTTDetectiveCalledToBody` hook which is called when a player calls a detective to a body --- API/HOOKS.md | 9 +++++++++ RELEASE.md | 6 ++++++ docs/api/hooks.html | 13 +++++++++++++ gamemodes/terrortown/gamemode/corpse.lua | 2 ++ gamemodes/terrortown/gamemode/shared.lua | 2 +- 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/API/HOOKS.md b/API/HOOKS.md index b625e6d55..6398a7e79 100644 --- a/API/HOOKS.md +++ b/API/HOOKS.md @@ -199,6 +199,15 @@ Called before the name and role of a player's killer is shown to the victim. Use - *killerName* - The new killerName value to use or the original passed into the hook - *role* - The new role value to use or the original passed into the hook. Use `ROLE_NONE` to hide the attacker's role from the victim +### TTTDetectiveCalledToBody(ply, owner, rag) +Called when a player calls a detective to a player ragdoll.\ +*Realm:* Server\ +*Added in:* 2.3.5\ +*Parameters:* +- *ply* - The player who is calling for a detective +- *owner* - The player who owns the corpse the detective is being called to +- *rag* - The ragdoll representing the corpse being called to + ### TTTDetectiveLikePromoted(ply) Called when a detective-like (deputy, impersonator, etc.) player is promoted.\ *Realm:* Server\ diff --git a/RELEASE.md b/RELEASE.md index 7c92fd40c..f6b0e70e9 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,5 +1,11 @@ # Release Notes +## 2.3.5 (Beta) +**Released:** + +### Developer +- Added `TTTDetectiveCalledToBody` hook which is called when a player calls a detective to a body + ## 2.3.4 (Beta) **Released: August 9th, 2025** diff --git a/docs/api/hooks.html b/docs/api/hooks.html index b2735c9f3..f4027a8bc 100644 --- a/docs/api/hooks.html +++ b/docs/api/hooks.html @@ -308,6 +308,19 @@

TTTDetectiveCalledToBody(ply, owner, rag) +

+ Called when a player calls a detective to a player ragdoll.
+ Realm: Server
+ Added in: 2.3.5
+ Parameters: +

+
    +
  • ply - The player who is calling for a detective
  • +
  • owner - The player who owns the corpse the detective is being called to
  • +
  • rag - The ragdoll representing the corpse being called to
  • +
+

TTTDetectiveLikePromoted(ply)

Called when a detective-like (deputy, impersonator, etc.) player is promoted.
diff --git a/gamemodes/terrortown/gamemode/corpse.lua b/gamemodes/terrortown/gamemode/corpse.lua index 3b58bc84a..1132862e9 100644 --- a/gamemodes/terrortown/gamemode/corpse.lua +++ b/gamemodes/terrortown/gamemode/corpse.lua @@ -316,6 +316,7 @@ local function CallDetective(ply, cmd, args) rag.last_detective_call = CurTime() if CORPSE.GetFound(rag, false) then + hook.Call("TTTDetectiveCalledToBody", nil, ply, owner, rag) -- show indicator to detectives net.Start("TTT_CorpseCall") net.WriteVector(rag:GetPos()) @@ -389,6 +390,7 @@ function CORPSE.ShowSearch(ply, rag, covert, long_range) elseif IsValid(ownerEnt) and not ply:IsSpec() and not ownerEnt:GetNWBool("det_called", false) and not ownerEnt:GetNWBool("body_searched", false) then if IsValid(rag) and rag:GetPos():Distance(ply:GetPos()) < 128 then hook.Call("TTTBodyFound", GAMEMODE, ply, ownerEnt, rag) + hook.Call("TTTDetectiveCalledToBody", nil, ply, ownerEnt, rag) net.Start("TTT_CorpseCall") net.WriteVector(rag:GetPos()) net.WriteString(rag.sid) diff --git a/gamemodes/terrortown/gamemode/shared.lua b/gamemodes/terrortown/gamemode/shared.lua index 2fdb8b4d4..db572cb50 100644 --- a/gamemodes/terrortown/gamemode/shared.lua +++ b/gamemodes/terrortown/gamemode/shared.lua @@ -24,7 +24,7 @@ local StringSub = string.sub include("player_class/player_ttt.lua") -- Version string for display and function for version checks -CR_VERSION = "2.3.4" +CR_VERSION = "2.3.5" CR_BETA = true CR_WORKSHOP_ID = CR_BETA and "2404251054" or "2421039084" From 7e16191ae93bc60fbc5e8a5ea8b9b7ae78c6515f Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 12:52:57 -0400 Subject: [PATCH 017/115] Added Call Detective to Body task --- .../roles/taskmaster/tasks/calldetective.lua | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/calldetective.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/calldetective.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/calldetective.lua new file mode 100644 index 000000000..40922233e --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/calldetective.lua @@ -0,0 +1,35 @@ +local TASK = {} + +TASK.id = "calldetective" + +TASK.Name = function(ply) + return "Call Detective to Body" +end + +TASK.Description = function(ply) + return "Call a detective to the body of a dead player" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + hook.Add("TTTDetectiveCalledToBody", "Taskmaster_CallDetective_TTTDetectiveCalledToBody_" .. ply:SteamID64(), function(caller, owner, rag) + if not IsPlayer(caller) then return end + if caller ~= ply then return end + ply:CompleteTask(TASK.id) + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("TTTDetectiveCalledToBody", "Taskmaster_CallDetective_TTTDetectiveCalledToBody_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 504ef06dab16f8dcda7ccda5e02b53a43bed415e Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 13:28:36 -0400 Subject: [PATCH 018/115] Added Pick Up Shop Item task --- .../roles/taskmaster/tasks/pickupshopitem.lua | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua new file mode 100644 index 000000000..90db16a6f --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua @@ -0,0 +1,36 @@ +local TASK = {} + +TASK.id = "pickupshopitem" + +TASK.Name = function(ply) + return "Pick Up Shop Item" +end + +TASK.Description = function(ply) + return "Pick up a shop item dropped on the ground" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + hook.Add("WeaponEquip", "Taskmaster_PickUpShopItem_WeaponEquip_" .. ply:SteamID64(), function(wep, caller) + if not IsPlayer(caller) then return end + if caller ~= ply then return end + if not IsValid(wep) or not wep.CanBuy or #wep.CanBuy == 0 then return end + ply:CompleteTask(TASK.id) + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("WeaponEquip", "Taskmaster_PickUpShopItem_WeaponEquip_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From acf1447f73dcca52c9add71cd325f0c458b7bb86 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 13:38:43 -0400 Subject: [PATCH 019/115] Added Jump task --- .../gamemode/roles/taskmaster/tasks/jump.lua | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua new file mode 100644 index 000000000..96e894cc1 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -0,0 +1,52 @@ +local TASK = {} + +TASK.id = "jump" + +local taskmaster_jump_times = CreateConVar("ttt_taskmaster_jump_times", "25", FCVAR_REPLICATED, "The jump of times a player must jump to complete the 'Jump X Times' task", 1, 100) + +TASK.Name = function(ply) + local times = taskmaster_jump_times:GetInt() + local name = "Jump " .. times .. " Time" + if times ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local times = taskmaster_jump_times:GetInt() + local name = "Jump in the air " .. times .. " time" + if times ~= 1 then + name = name .. "s" + end + return name +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + local times = taskmaster_jump_times:GetInt() + local count = 0 + hook.Add("OnPlayerJump", "Taskmaster_Jump_OnPlayerJump_" .. ply:SteamID64(), function(caller) + if not IsPlayer(caller) then return end + if caller ~= ply then return end + count = count + 1 + if count >= times then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("OnPlayerJump", "Taskmaster_Jump_OnPlayerJump_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 6c61a8f50c0aee1079282bb9ffce8e27c89cc8f8 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 13:43:00 -0400 Subject: [PATCH 020/115] Added Jump times convar to ULX --- .../terrortown/gamemode/roles/taskmaster/tasks/jump.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua index 96e894cc1..8e3298d5c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -3,6 +3,11 @@ local TASK = {} TASK.id = "jump" local taskmaster_jump_times = CreateConVar("ttt_taskmaster_jump_times", "25", FCVAR_REPLICATED, "The jump of times a player must jump to complete the 'Jump X Times' task", 1, 100) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_jump_times", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) TASK.Name = function(ply) local times = taskmaster_jump_times:GetInt() From 60b3d5fb3d85af6392b42f3a3bf4aeec222a5b0e Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 13:58:10 -0400 Subject: [PATCH 021/115] Added Crouch task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/crouch.lua | 122 ++++++++++++++++++ .../gamemode/roles/taskmaster/tasks/jump.lua | 6 +- 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index c37313a32..f27b48a9f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -18,6 +18,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() -- Tasks LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") LANG.AddToLanguage("english", "taskmaster_crouchnearbody", "CROUCH NEAR BODY - {time}") + LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") -- Win conditions LANG.AddToLanguage("english", "win_taskmaster", "The {role} finished off their list!") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua new file mode 100644 index 000000000..aa7233344 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -0,0 +1,122 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local table = table +local util = util + +local MathMax = math.max + +local TASK = {} + +TASK.id = "crouch" + +local taskmaster_crouch_time = CreateConVar("ttt_taskmaster_crouch_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay crouched to complete the 'Crouch Near Body' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_crouch_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local time = taskmaster_crouch_time:GetInt() + local name = "Crouch For " .. time .. " Second" + if time ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local time = taskmaster_crouch_time:GetInt() + local desc = "Crouch continuously for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_Crouch_Assigned") + util.AddNetworkString("TTT_Taskmaster_Crouch_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + TASK.OnTaskAssigned = function(ply) + local time = taskmaster_crouch_time:GetInt() + timer.Create("TTTTaskmasterCrouchTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + + if ply:Crouching() then + -- Just starting + if not ply.CrouchStart then + ply:SetProperty("CrouchStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.CrouchStart + time then + ply:CompleteTask(TASK.id) + end + -- Not crouching anymore + else + ply:ClearProperty("CrouchStart", ply) + end + end) + + net.Start("TTT_Taskmaster_Crouch_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterCrouchTimer") + + ply:ClearProperty("CrouchStart", ply) + + net.Start("TTT_Taskmaster_Crouch_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_Crouch_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local time = taskmaster_crouch_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_Crouch_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.CrouchStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_crouch", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_Crouch_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("HUDPaint", "Taskmaster_Crouch_HUDPaint_" .. sid64) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua index 8e3298d5c..59a8ea293 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -20,11 +20,11 @@ end TASK.Description = function(ply) local times = taskmaster_jump_times:GetInt() - local name = "Jump in the air " .. times .. " time" + local desc = "Jump in the air " .. times .. " time" if times ~= 1 then - name = name .. "s" + desc = desc .. "s" end - return name + return desc end if SERVER then From 600c488df4e492890c22f30eb0011675d371f56b Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 14:00:24 -0400 Subject: [PATCH 022/115] Prefix task property names to ensure uniqueness --- .../roles/taskmaster/tasks/crouch.lua | 12 ++++---- .../roles/taskmaster/tasks/crouchnearbody.lua | 16 +++++----- .../roles/taskmaster/tasks/stayneartarget.lua | 30 +++++++++---------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index aa7233344..38ccd5d98 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -55,15 +55,15 @@ if SERVER then if ply:Crouching() then -- Just starting - if not ply.CrouchStart then - ply:SetProperty("CrouchStart", CurTime(), ply) + if not ply.Task_CrouchStart then + ply:SetProperty("Task_CrouchStart", CurTime(), ply) -- Long enough - elseif CurTime() > ply.CrouchStart + time then + elseif CurTime() > ply.Task_CrouchStart + time then ply:CompleteTask(TASK.id) end -- Not crouching anymore else - ply:ClearProperty("CrouchStart", ply) + ply:ClearProperty("Task_CrouchStart", ply) end end) @@ -74,7 +74,7 @@ if SERVER then TASK.OnTaskRemoved = function(ply) timer.Remove("TTTTaskmasterCrouchTimer") - ply:ClearProperty("CrouchStart", ply) + ply:ClearProperty("Task_CrouchStart", ply) net.Start("TTT_Taskmaster_Crouch_Cleanup") net.Send(ply) @@ -92,7 +92,7 @@ if CLIENT then hook.Add("HUDPaint", "Taskmaster_Crouch_HUDPaint_" .. sid64, function() if not client:IsActiveTaskmaster() then return end - local startTime = client.CrouchStart + local startTime = client.Task_CrouchStart if not startTime then return end local PT = LANG.GetParamTranslation diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index bc9cc0260..015b6f2fd 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -87,8 +87,8 @@ if SERVER then timer.Create("TTTTaskmasterCrouchNearBodyTimer", 0.1, 0, function() if not IsPlayer(ply) then return end if not ply:Crouching() then - if ply.CrouchNearBodyStart then - ply:ClearProperty("CrouchNearBodyStart", ply) + if ply.Task_CrouchNearBodyStart then + ply:ClearProperty("Task_CrouchNearBodyStart", ply) end return end @@ -101,15 +101,15 @@ if SERVER then -- Within range if ply:GetPos():DistToSqr(corpse:GetPos()) <= rangeSqr then -- Just starting - if not ply.CrouchNearBodyStart then - ply:SetProperty("CrouchNearBodyStart", CurTime(), ply) + if not ply.Task_CrouchNearBodyStart then + ply:SetProperty("Task_CrouchNearBodyStart", CurTime(), ply) -- Long enough - elseif CurTime() > ply.CrouchNearBodyStart + time then + elseif CurTime() > ply.Task_CrouchNearBodyStart + time then ply:CompleteTask(TASK.id) end -- Not within range else - ply:ClearProperty("CrouchNearBodyStart", ply) + ply:ClearProperty("Task_CrouchNearBodyStart", ply) end end end) @@ -121,7 +121,7 @@ if SERVER then TASK.OnTaskRemoved = function(ply) timer.Remove("TTTTaskmasterCrouchNearBodyTimer") - ply:ClearProperty("CrouchNearBodyStart", ply) + ply:ClearProperty("Task_CrouchNearBodyStart", ply) net.Start("TTT_Taskmaster_CrouchNearBody_Cleanup") net.Send(ply) @@ -139,7 +139,7 @@ if CLIENT then hook.Add("HUDPaint", "Taskmaster_CrouchNearBody_HUDPaint_" .. sid64, function() if not client:IsActiveTaskmaster() then return end - local startTime = client.CrouchNearBodyStart + local startTime = client.Task_CrouchNearBodyStart if not startTime then return end local PT = LANG.GetParamTranslation diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index aac13b41b..540624946 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -32,8 +32,8 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local name = "Player" - if IsPlayer(ply.StayNearTargetPlayer) then - name = ply.StayNearTargetPlayer:Nick() + if IsPlayer(ply.Task_StayNearTargetPlayer) then + name = ply.Task_StayNearTargetPlayer:Nick() end return "Stay Near " .. name end @@ -69,8 +69,8 @@ TASK.Description = function(ply) end local name = "Target" - if IsPlayer(ply.StayNearTargetPlayer) then - name = ply.StayNearTargetPlayer:Nick() + if IsPlayer(ply.Task_StayNearTargetPlayer) then + name = ply.Task_StayNearTargetPlayer:Nick() end local time = taskmaster_stayneartarget_time:GetInt() @@ -105,7 +105,7 @@ if SERVER then break end - ply:SetProperty("StayNearTargetPlayer", target, ply) + ply:SetProperty("Task_StayNearTargetPlayer", target, ply) local range = taskmaster_stayneartarget_range:GetInt() * UNITS_PER_METER local rangeSqr = range * range @@ -117,15 +117,15 @@ if SERVER then -- Within range if ply:GetPos():DistToSqr(target:GetPos()) <= rangeSqr then -- Just starting - if not ply.StayNearTargetStart then - ply:SetProperty("StayNearTargetStart", CurTime(), ply) + if not ply.Task_StayNearTargetStart then + ply:SetProperty("Task_StayNearTargetStart", CurTime(), ply) -- Long enough - elseif CurTime() > ply.StayNearTargetStart + time then + elseif CurTime() > ply.Task_StayNearTargetStart + time then ply:CompleteTask(TASK.id) end -- Not within range else - ply:ClearProperty("StayNearTargetStart", ply) + ply:ClearProperty("Task_StayNearTargetStart", ply) end end) @@ -136,8 +136,8 @@ if SERVER then TASK.OnTaskRemoved = function(ply) timer.Remove("TTTTaskmasterStayNearTargetTimer") - ply:ClearProperty("StayNearTargetPlayer", ply) - ply:ClearProperty("StayNearTargetStart", ply) + ply:ClearProperty("Task_StayNearTargetPlayer", ply) + ply:ClearProperty("Task_StayNearTargetStart", ply) net.Start("TTT_Taskmaster_StayNearTarget_Cleanup") net.Send(ply) @@ -155,7 +155,7 @@ if CLIENT then local time = taskmaster_stayneartarget_time:GetInt() hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_StayNearTarget_TTTTargetIDPlayerTargetIcon_" .. sid64, function(ply, cli, showJester) - if cli:IsActiveTaskmaster() and ply == cli.StayNearTargetPlayer then + if cli:IsActiveTaskmaster() and ply == cli.Task_StayNearTargetPlayer then local iconColor = ROLE_COLORS_SPRITE[ROLE_TRAITOR] if cli:GetPos():DistToSqr(ply:GetPos()) <= rangeSqr then iconColor = ROLE_COLORS_SPRITE[ROLE_INNOCENT] @@ -167,7 +167,7 @@ if CLIENT then local particleVelocity = Vector(0, 0, 40) hook.Add("TTTPlayerAliveClientThink", "Taskmaster_StayNearTarget_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) local shouldDraw = false - local target = cli.StayNearTargetPlayer + local target = cli.Task_StayNearTargetPlayer if ply == cli and cli:IsActiveTaskmaster() and IsPlayer(target) then local pos = target:GetPos() if not ply.TaskmasterRadiusEmitter then ply.TaskmasterRadiusEmitter = ParticleEmitter(pos) end @@ -212,10 +212,10 @@ if CLIENT then hook.Add("HUDPaint", "Taskmaster_StayNearTarget_HUDPaint_" .. sid64, function() if not client:IsActiveTaskmaster() then return end - local target = client.StayNearTargetPlayer + local target = client.Task_StayNearTargetPlayer if not IsPlayer(target) then return end - local startTime = client.StayNearTargetStart + local startTime = client.Task_StayNearTargetStart if not startTime then return end local PT = LANG.GetParamTranslation From 7a530a2ad65a6a00599083edd444817a3fa418a9 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 14:18:34 -0400 Subject: [PATCH 023/115] Added Fire Bullets task --- .../roles/taskmaster/tasks/firebullets.lua | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua new file mode 100644 index 000000000..c699ec543 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua @@ -0,0 +1,57 @@ +local TASK = {} + +TASK.id = "firebullets" + +local taskmaster_firebullets_times = CreateConVar("ttt_taskmaster_firebullets_times", "100", FCVAR_REPLICATED, "The jump of times a player must fire a bullet to complete the 'Fire X Bullets' task", 1, 1000) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_firebullets_times", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local times = taskmaster_firebullets_times:GetInt() + local name = "Fire " .. times .. " Bullet" + if times ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local times = taskmaster_firebullets_times:GetInt() + local desc = "Fire " .. times .. " time" + if times ~= 1 then + desc = desc .. "s" + end + return desc .. " from a gun" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + local times = taskmaster_firebullets_times:GetInt() + local count = 0 + hook.Add("PostEntityFireBullets", "Taskmaster_FireBullets_PostEntityFireBullets_" .. ply:SteamID64(), function(entity, data) + if not IsPlayer(entity) then return end + if entity ~= ply then return end + count = count + 1 + if count >= times then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PostEntityFireBullets", "Taskmaster_FireBullets_PostEntityFireBullets_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 81a0b48f1d4b4280f89f4b5c4e09a03d2eb3b815 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 14:38:22 -0400 Subject: [PATCH 024/115] Added Do Damage task --- .../roles/taskmaster/tasks/dodamage.lua | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua new file mode 100644 index 000000000..52006f54b --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua @@ -0,0 +1,53 @@ +local TASK = {} + +TASK.id = "dodamage" + +local taskmaster_dodamage_amount = CreateConVar("ttt_taskmaster_dodamage_amount", "200", FCVAR_REPLICATED, "The amount of damage a player must do to complete the 'Do X Damage' task", 1, 1000) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_dodamage_amount", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local amount = taskmaster_dodamage_amount:GetInt() + return "Do " .. amount .. " Damage" +end + +TASK.Description = function(ply) + local amount = taskmaster_dodamage_amount:GetInt() + return "Do " .. amount .. " damage to props and other players" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + local amount = taskmaster_dodamage_amount:GetInt() + local total = 0 + hook.Add("PostEntityTakeDamage", "Taskmaster_DoDamage_PostEntityTakeDamage_" .. ply:SteamID64(), function(entity, dmginfo, wasDamageTaken) + if not wasDamageTaken then return end + if entity == ply then return end + + local attacker = dmginfo:GetAttacker() + if not IsPlayer(attacker) or attacker ~= ply then return end + + total = total + dmginfo:GetDamage() + if total >= amount then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PostEntityTakeDamage", "Taskmaster_DoDamage_PostEntityTakeDamage_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 736481cb03b5872e09e6c19c0fe5531d15b57d92 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 14:38:54 -0400 Subject: [PATCH 025/115] Removed test tasks --- .../roles/taskmaster/tasks/testkilltask.lua | 34 ------------------- .../roles/taskmaster/tasks/testmisctask.lua | 33 ------------------ 2 files changed, 67 deletions(-) delete mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua delete mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua deleted file mode 100644 index 2100bcb33..000000000 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testkilltask.lua +++ /dev/null @@ -1,34 +0,0 @@ -local TASK = {} - -TASK.id = "testkilltask" -TASK.isKillTask = true - -TASK.Name = function(ply) - return "Test Kill Task" -end - -TASK.Description = function(ply) - return "Test Kill Task Description" -end - -if SERVER then - TASK.CanAssignTask = function(ply) - return false - end - - TASK.RequiredFeatures = {} - - TASK.OnTaskAssigned = function(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Task Assigned: " .. TASK.Name(ply)) - end - - TASK.OnTaskRemoved = function(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Task Removed: " .. TASK.Name(ply)) - end - - TASK.OnTaskComplete = function(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Task Completed: " .. TASK.Name(ply)) - end -end - -TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua deleted file mode 100644 index c3fd97bc1..000000000 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/testmisctask.lua +++ /dev/null @@ -1,33 +0,0 @@ -local TASK = {} - -TASK.id = "testmisctask" - -TASK.Name = function(ply) - return "Test Misc Task" -end - -TASK.Description = function(ply) - return "Test Misc Task Description" -end - -if SERVER then - TASK.CanAssignTask = function(ply) - return false - end - - TASK.RequiredFeatures = {} - - TASK.OnTaskAssigned = function(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Task Assigned: " .. TASK.Name(ply)) - end - - TASK.OnTaskRemoved = function(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Task Removed: " .. TASK.Name(ply)) - end - - TASK.OnTaskComplete = function(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Task Completed: " .. TASK.Name(ply)) - end -end - -TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 0d386087cf4c03d2fc149cb293d71a1eedc96b7c Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 14:55:48 -0400 Subject: [PATCH 026/115] Fixed Stay Near Target not handling the case where the target died --- .../roles/taskmaster/tasks/stayneartarget.lua | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 540624946..1880f6a20 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -95,15 +95,18 @@ if SERVER then TASKMASTER_TF_PARTICLERADIUS } - TASK.OnTaskAssigned = function(ply) - local target + local function GetRandomTarget(ply) -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do if not p:Alive() or p:IsSpec() then continue end if p == ply then continue end - target = p - break + return p end + return nil + end + + TASK.OnTaskAssigned = function(ply) + local target = GetRandomTarget(ply) ply:SetProperty("Task_StayNearTargetPlayer", target, ply) @@ -129,6 +132,17 @@ if SERVER then end end) + hook.Add("PostPlayerDeath", "Taskmaster_StayNearTarget_PostPlayerDeath_" .. ply:SteamID64(), function(victim) + if ply.Task_StayNearTargetPlayer ~= victim then return end + + local newTarget = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. newTarget:Nick()) + + -- Overwrite the previous target + target = newTarget + ply:SetProperty("Task_StayNearTargetPlayer", newTarget, ply) + end) + net.Start("TTT_Taskmaster_StayNearTarget_Assigned") net.Send(ply) end @@ -139,6 +153,8 @@ if SERVER then ply:ClearProperty("Task_StayNearTargetPlayer", ply) ply:ClearProperty("Task_StayNearTargetStart", ply) + hook.Remove("PostPlayerDeath", "Taskmaster_StayNearTarget_PostPlayerDeath_" .. ply:SteamID64()) + net.Start("TTT_Taskmaster_StayNearTarget_Cleanup") net.Send(ply) end From eb13a33bde429c3af55a13c145f539d39454d340 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 15:00:05 -0400 Subject: [PATCH 027/115] Fixed Stay Near Target task not handling target player disconnect --- .../roles/taskmaster/tasks/stayneartarget.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 1880f6a20..d91818fb7 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -143,6 +143,17 @@ if SERVER then ply:SetProperty("Task_StayNearTargetPlayer", newTarget, ply) end) + hook.Add("PlayerDisconnected", "Taskmaster_StayNearTarget_PlayerDisconnected_" .. ply:SteamID64(), function(leaver) + if ply.Task_StayNearTargetPlayer ~= leaver then return end + + local newTarget = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. newTarget:Nick()) + + -- Overwrite the previous target + target = newTarget + ply:SetProperty("Task_StayNearTargetPlayer", newTarget, ply) + end) + net.Start("TTT_Taskmaster_StayNearTarget_Assigned") net.Send(ply) end From be296f83f56e1cc27a5c9f634b25e1d85bbfaf9f Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 15:08:03 -0400 Subject: [PATCH 028/115] Added Chat task --- .../gamemode/roles/taskmaster/tasks/chat.lua | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua new file mode 100644 index 000000000..f548b4b42 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua @@ -0,0 +1,57 @@ +local TASK = {} + +TASK.id = "chat" + +local taskmaster_chat_times = CreateConVar("ttt_taskmaster_chat_times", "25", FCVAR_REPLICATED, "The number of text messages a player must sent to complete the 'Send X Messages' task", 1, 100) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_chat_times", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local times = taskmaster_chat_times:GetInt() + local name = "Send " .. times .. " Message" + if times ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local times = taskmaster_chat_times:GetInt() + local desc = "Send " .. times .. " message" + if times ~= 1 then + desc = desc .. "s" + end + return desc .. " in text chat" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + local times = taskmaster_chat_times:GetInt() + local count = 0 + hook.Add("PlayerSay", "Taskmaster_Chat_PlayerSay_" .. ply:SteamID64(), function(sender, text, teamChat) + if not IsPlayer(sender) then return end + if sender ~= ply then return end + count = count + 1 + if count >= times then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerSay", "Taskmaster_Chat_PlayerSay_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 043bbcb3dfd8092397749384d40d1450b7fafe26 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 15:44:01 -0400 Subject: [PATCH 029/115] Added Health Under task --- .../roles/taskmaster/cl_taskmaster.lua | 3 +- .../roles/taskmaster/tasks/healthunder.lua | 126 ++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index f27b48a9f..729f344c2 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -16,9 +16,10 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_credit_bonus", "{role}, you have been awarded {num} credit(s) for completing a task.") -- Tasks - LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") LANG.AddToLanguage("english", "taskmaster_crouchnearbody", "CROUCH NEAR BODY - {time}") LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") + LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") + LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") -- Win conditions LANG.AddToLanguage("english", "win_taskmaster", "The {role} finished off their list!") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua new file mode 100644 index 000000000..6c526e6f5 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -0,0 +1,126 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local table = table +local util = util + +local MathMax = math.max + +local TASK = {} + +TASK.id = "healthunder" + +local taskmaster_healthunder_amount = CreateConVar("ttt_taskmaster_healthunder_amount", "15", FCVAR_REPLICATED, "The amount of health a player must stay under to complete the 'Health Under' task", 1, 240) +local taskmaster_healthunder_time = CreateConVar("ttt_taskmaster_healthunder_time", "60", FCVAR_REPLICATED, "The time (in seconds) a player must stay under the target health to complete the 'Health Under' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_healthunder_amount", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_healthunder_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local amount = taskmaster_healthunder_amount:GetInt() + return "Stay Under " .. amount .. " HP" +end + +TASK.Description = function(ply) + local time = taskmaster_healthunder_time:GetInt() + local amount = taskmaster_healthunder_amount:GetInt() + local desc = "Stay under " .. amount .. " health for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_HealthUnder_Assigned") + util.AddNetworkString("TTT_Taskmaster_HealthUnder_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + TASK.OnTaskAssigned = function(ply) + local amount = taskmaster_healthunder_amount:GetInt() + local time = taskmaster_healthunder_time:GetInt() + timer.Create("TTTTaskmasterHealthUnderTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + + if ply:Health() < amount then + -- Just starting + if not ply.Task_HealthUnderStart then + ply:SetProperty("Task_HealthUnderStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_HealthUnderStart + time then + ply:CompleteTask(TASK.id) + end + -- Not under target health anymore + else + ply:ClearProperty("Task_HealthUnderStart", ply) + end + end) + + net.Start("TTT_Taskmaster_HealthUnder_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterHealthUnderTimer") + + ply:ClearProperty("Task_HealthUnderStart", ply) + + net.Start("TTT_Taskmaster_HealthUnder_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_HealthUnder_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local time = taskmaster_healthunder_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_HealthUnder_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_HealthUnderStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_healthunder", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_HealthUnder_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("HUDPaint", "Taskmaster_HealthUnder_HUDPaint_" .. sid64) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 4bde7ad2dbc4a498cc16d230a1989163c78b9cc3 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 16:17:01 -0400 Subject: [PATCH 030/115] Cleanup --- .../terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 729f344c2..fbf074da1 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -255,8 +255,6 @@ local dtasksHeight = 0 local scrollBarWidth = 15 local creditsIconSize = 32 -local CreateTaskList - local function CreateTaskReroll(task, dscrollpanel) if table.HasValue(client.taskmasterCompletedTasks, task.id) then return false end @@ -323,7 +321,7 @@ local function CreateTaskReroll(task, dscrollpanel) return dpanel, dline end -function CreateTaskList(dscrollpanel) +local function CreateTaskList(dscrollpanel) if not dscrollpanel:IsValid() then return end for _, dtask in ipairs(dtasks) do From 5ab34b2f1d7174cbac27f78877e9f2616ace6ab2 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 16:38:27 -0400 Subject: [PATCH 031/115] Added Holstered task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/holstered.lua | 123 ++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index fbf074da1..3e1e46580 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -19,6 +19,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_crouchnearbody", "CROUCH NEAR BODY - {time}") LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") + LANG.AddToLanguage("english", "taskmaster_holstered", "STAY HOLSTERED - {time}") LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") -- Win conditions diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua new file mode 100644 index 000000000..7d5ac2c36 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -0,0 +1,123 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local table = table +local util = util + +local MathMax = math.max + +local TASK = {} + +TASK.id = "holstered" + +local taskmaster_holstered_time = CreateConVar("ttt_taskmaster_holstered_time", "60", FCVAR_REPLICATED, "The time (in seconds) a player must stay under the target health to complete the 'Health Under' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_holstered_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local time = taskmaster_holstered_time:GetInt() + local name = "Stay Holstered for " .. time .. " Second" + if time ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local time = taskmaster_holstered_time:GetInt() + local desc = "Use the 'Holstered' weapon for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s consecutively" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_Holstered_Assigned") + util.AddNetworkString("TTT_Taskmaster_Holstered_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + TASK.OnTaskAssigned = function(ply) + local time = taskmaster_holstered_time:GetInt() + timer.Create("TTTTaskmasterHolsteredTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + + local wepClass = WEPS.GetClass(ply:GetActiveWeapon()) + if wepClass == "weapon_ttt_unarmed" then + -- Just starting + if not ply.Task_HolsteredStart then + ply:SetProperty("Task_HolsteredStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_HolsteredStart + time then + ply:CompleteTask(TASK.id) + end + -- Not using "holstered" anymore + else + ply:ClearProperty("Task_HolsteredStart", ply) + end + end) + + net.Start("TTT_Taskmaster_Holstered_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterHolsteredTimer") + + ply:ClearProperty("Task_HolsteredStart", ply) + + net.Start("TTT_Taskmaster_Holstered_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_Holstered_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local time = taskmaster_holstered_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_Holstered_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_HolsteredStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_holstered", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_Holstered_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("HUDPaint", "Taskmaster_Holstered_HUDPaint_" .. sid64) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 0b55badc8c9ba4509b8b0635d9da677a60d2bb1f Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 17:30:09 -0400 Subject: [PATCH 032/115] Fixed Holstered convar description --- .../terrortown/gamemode/roles/taskmaster/tasks/holstered.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index 7d5ac2c36..f727a6f29 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -11,7 +11,7 @@ local TASK = {} TASK.id = "holstered" -local taskmaster_holstered_time = CreateConVar("ttt_taskmaster_holstered_time", "60", FCVAR_REPLICATED, "The time (in seconds) a player must stay under the target health to complete the 'Health Under' task", 1, 240) +local taskmaster_holstered_time = CreateConVar("ttt_taskmaster_holstered_time", "60", FCVAR_REPLICATED, "The time (in seconds) a player must stay holstered to complete the 'Holstered' task", 1, 240) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_holstered_time", type = ROLE_CONVAR_TYPE_NUM, From 4add9c4b8ade3587b1d3db300306128f7ec7ef09 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 17:41:12 -0400 Subject: [PATCH 033/115] Added Crowbar task --- .../roles/taskmaster/tasks/crowbar.lua | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua new file mode 100644 index 000000000..6e9dce28e --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua @@ -0,0 +1,91 @@ +local table = table + +local TASK = {} + +TASK.id = "crowbar" + +local taskmaster_crowbar_times = CreateConVar("ttt_taskmaster_crowbar_times", "50", FCVAR_REPLICATED, "The number of times a player must use their crowbar to complete the 'Swing Crowbar' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_crowbar_times", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local times = taskmaster_crowbar_times:GetInt() + local name = "Swing Crowbar " .. times .. " Time" + if times ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local times = taskmaster_crowbar_times:GetInt() + local desc = "Use the crowbar weapon " .. times .. " time" + if times ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + local function SetupPrimaryAttack(ply, wep) + if wep.Task_CrowbarPrimaryAttack then return end + + local times = taskmaster_crowbar_times:GetInt() + local total = 0 + wep.Task_CrowbarPrimaryAttack = wep.PrimaryAttack + wep.PrimaryAttack = function(this, worldsnd) + wep.Task_CrowbarPrimaryAttack(wep, worldsnd) + total = total + 1 + if total >= times then + ply:CompleteTask(TASK.id) + end + end + end + + local function ClearPrimaryAttack(wep) + if not wep.Task_CrowbarPrimaryAttack then return end + wep.PrimaryAttack = wep.Task_CrowbarPrimaryAttack + wep.Task_CrowbarPrimaryAttack = nil + end + + TASK.OnTaskAssigned = function(ply) + local crowbar = ply:GetWeapon("weapon_zm_improvised") + if IsValid(crowbar) then + SetupPrimaryAttack(ply, crowbar) + end + + local sid64 = ply:SteamID64() + hook.Add("WeaponEquip", "Taskmaster_Crowbar_WeaponEquip_" .. sid64, function(wep, owner) + if owner ~= ply then return end + if WEPS.GetClass(wep) ~= "weapon_zm_improvised" then return end + SetupPrimaryAttack(ply, wep) + end) + + hook.Add("PlayerDroppedWeapon", "Taskmaster_Crowbar_PlayerDroppedWeapon_" .. sid64, function( owner, wep) + if owner ~= ply then return end + if WEPS.GetClass(wep) ~= "weapon_zm_improvised" then return end + ClearPrimaryAttack(wep) + end) + end + + TASK.OnTaskRemoved = function(ply) + ClearPrimaryAttack(ply) + + local sid64 = ply:SteamID64() + hook.Remove("WeaponEquip", "Taskmaster_Crowbar_WeaponEquip_" .. sid64) + hook.Remove("PlayerDroppedWeapon", "Taskmaster_Crowbar_PlayerDroppedWeapon_" .. sid64) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From dc628b525ec8f90d227fa4d9a2306270f5c91c6b Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 17:51:33 -0400 Subject: [PATCH 034/115] Added Pick Up Weapons task --- .../roles/taskmaster/tasks/weaponpickups.lua | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua new file mode 100644 index 000000000..362540c06 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua @@ -0,0 +1,61 @@ +local table = table + +local TASK = {} + +TASK.id = "weaponpickups" + +local taskmaster_weaponpickups_count = CreateConVar("ttt_taskmaster_weaponpickups_count", "20", FCVAR_REPLICATED, "The number of unique weapons a player must pick up to complete the 'Pick Up Weapons' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_weaponpickups_count", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local count = taskmaster_weaponpickups_count:GetInt() + local name = "Pick Up " .. count .. " Weapon" + if count ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local count = taskmaster_weaponpickups_count:GetInt() + local desc = "Pick up " .. count + if count == 1 then + return desc .. "weapon" + end + return desc .. " unique weapons from the ground" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + local count = taskmaster_weaponpickups_count:GetInt() + local total = 0 + hook.Add("WeaponEquip", "Taskmaster_WeaponPickup_WeaponEquip_" .. ply:SteamID64(), function(wep, owner) + if owner ~= ply then return end + if not IsValid(wep) then return end + if wep.Task_WeaponPickupsUsed then return end + wep.Task_WeaponPickupsUsed = true + total = total + 1 + if total >= count then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("WeaponEquip", "Taskmaster_WeaponPickup_WeaponEquip_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 49dc4c3235b15a88955761494e770e2979a6101b Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 17:58:02 -0400 Subject: [PATCH 035/115] Added Stand on Player task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/standonplayer.lua | 122 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 3e1e46580..4e279c40f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -20,6 +20,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") LANG.AddToLanguage("english", "taskmaster_holstered", "STAY HOLSTERED - {time}") + LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") -- Win conditions diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua new file mode 100644 index 000000000..12a79542e --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -0,0 +1,122 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local table = table +local util = util + +local MathMax = math.max + +local TASK = {} + +TASK.id = "standonplayer" + +local taskmaster_standonplayer_time = CreateConVar("ttt_taskmaster_standonplayer_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay stand on top of another player to complete the 'Stand On Player' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_standonplayer_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local time = taskmaster_standonplayer_time:GetInt() + local name = "Stand On Player For " .. time .. " Second" + if time ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local time = taskmaster_standonplayer_time:GetInt() + local desc = "Stand on another player continuously for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_StandOnPlayer_Assigned") + util.AddNetworkString("TTT_Taskmaster_StandOnPlayer_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + TASK.OnTaskAssigned = function(ply) + local time = taskmaster_standonplayer_time:GetInt() + timer.Create("TTTTaskmasterStandOnPlayerTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + + if IsPlayer(ply:GetGroundEntity()) then + -- Just starting + if not ply.Task_StandOnPlayerStart then + ply:SetProperty("Task_StandOnPlayerStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_StandOnPlayerStart + time then + ply:CompleteTask(TASK.id) + end + -- Not standing on another player anymore + else + ply:ClearProperty("Task_StandOnPlayerStart", ply) + end + end) + + net.Start("TTT_Taskmaster_StandOnPlayer_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterStandOnPlayerTimer") + + ply:ClearProperty("Task_StandOnPlayerStart", ply) + + net.Start("TTT_Taskmaster_StandOnPlayer_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_StandOnPlayer_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local time = taskmaster_standonplayer_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_StandOnPlayer_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_StandOnPlayerStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_standonplayer", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_StandOnPlayer_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("HUDPaint", "Taskmaster_StandOnPlayer_HUDPaint_" .. sid64) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From a0b9803822901f12dd8731e495de9b0c21b769d5 Mon Sep 17 00:00:00 2001 From: Malivil Date: Thu, 14 Aug 2025 18:11:28 -0400 Subject: [PATCH 036/115] Added Carry Corpse task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/carrycorpse.lua | 124 ++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 4e279c40f..8e7af4307 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -16,6 +16,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_credit_bonus", "{role}, you have been awarded {num} credit(s) for completing a task.") -- Tasks + LANG.AddToLanguage("english", "taskmaster_carrycorpse", "CARRY CORPSE - {time}") LANG.AddToLanguage("english", "taskmaster_crouchnearbody", "CROUCH NEAR BODY - {time}") LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua new file mode 100644 index 000000000..d32c232eb --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -0,0 +1,124 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local table = table +local util = util + +local MathMax = math.max + +local TASK = {} + +TASK.id = "carrycorpse" + +local taskmaster_carrycorpse_time = CreateConVar("ttt_taskmaster_carrycorpse_time", "60", FCVAR_REPLICATED, "The time (in seconds) a player must carry a player corpse to complete the 'Carry Corpse' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_carrycorpse_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local time = taskmaster_carrycorpse_time:GetInt() + local name = "Carry Corpse for " .. time .. " Second" + if time ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local time = taskmaster_carrycorpse_time:GetInt() + local desc = "Carry a player corpse for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s consecutively" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_CarryCorpse_Assigned") + util.AddNetworkString("TTT_Taskmaster_CarryCorpse_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + TASK.OnTaskAssigned = function(ply) + local time = taskmaster_carrycorpse_time:GetInt() + timer.Create("TTTTaskmasterCarryCorpseTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + + local wep = ply:GetActiveWeapon() + local wepClass = WEPS.GetClass(wep) + if wepClass == "weapon_zm_carry" and IsRagdoll(wep.EntHolding) and IsPlayer(CORPSE.GetPlayer(wep.EntHolding)) then + -- Just starting + if not ply.Task_CarryCorpseStart then + ply:SetProperty("Task_CarryCorpseStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_CarryCorpseStart + time then + ply:CompleteTask(TASK.id) + end + -- Not carrying a corpse anymore + else + ply:ClearProperty("Task_CarryCorpseStart", ply) + end + end) + + net.Start("TTT_Taskmaster_CarryCorpse_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterCarryCorpseTimer") + + ply:ClearProperty("Task_CarryCorpseStart", ply) + + net.Start("TTT_Taskmaster_CarryCorpse_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_CarryCorpse_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local time = taskmaster_carrycorpse_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_CarryCorpse_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_CarryCorpseStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_carrycorpse", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_CarryCorpse_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("HUDPaint", "Taskmaster_CarryCorpse_HUDPaint_" .. sid64) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 9a3b217c3d5f08b19f9eb0941373d352ba07a759 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 10:25:17 -0400 Subject: [PATCH 037/115] Changed `SYNC` methods to not clear values that are already `nil` --- RELEASE.md | 1 + gamemodes/terrortown/gamemode/sync.lua | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index f6b0e70e9..660d507f0 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -5,6 +5,7 @@ ### Developer - Added `TTTDetectiveCalledToBody` hook which is called when a player calls a detective to a body +- Changed `SYNC` methods to not clear values that are already `nil` ## 2.3.4 (Beta) **Released: August 9th, 2025** diff --git a/gamemodes/terrortown/gamemode/sync.lua b/gamemodes/terrortown/gamemode/sync.lua index 91c5b4c72..816ee660f 100644 --- a/gamemodes/terrortown/gamemode/sync.lua +++ b/gamemodes/terrortown/gamemode/sync.lua @@ -20,6 +20,8 @@ function SYNC:SetPlayerProperty(ply, propertyName, propertyValue, targets) end function SYNC:ClearPlayerProperty(ply, propertyName, targets) + if ply[propertyName] == nil then return end + ply[propertyName] = nil net.Start("TTT_ClearPlayerProperty") @@ -47,6 +49,8 @@ function SYNC:SetEntityProperty(ent, propertyName, propertyValue, targets) end function SYNC:ClearEntityProperty(ent, propertyName, targets) + if ent[propertyName] == nil then return end + ent[propertyName] = nil net.Start("TTT_ClearEntityProperty") From 56eb3e89b710c874a1303e0fce54dfe0ef8f86d8 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 10:25:39 -0400 Subject: [PATCH 038/115] Fixed some Taskmaster tasks being doable while dead --- .../terrortown/gamemode/roles/taskmaster/tasks/chat.lua | 2 ++ .../terrortown/gamemode/roles/taskmaster/tasks/crouch.lua | 2 +- .../gamemode/roles/taskmaster/tasks/crouchnearbody.lua | 6 ++---- .../gamemode/roles/taskmaster/tasks/healthunder.lua | 2 +- .../gamemode/roles/taskmaster/tasks/holstered.lua | 4 ++++ .../gamemode/roles/taskmaster/tasks/standonplayer.lua | 2 +- .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 2 +- 7 files changed, 12 insertions(+), 8 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua index f548b4b42..5385f4e6b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua @@ -40,6 +40,8 @@ if SERVER then hook.Add("PlayerSay", "Taskmaster_Chat_PlayerSay_" .. ply:SteamID64(), function(sender, text, teamChat) if not IsPlayer(sender) then return end if sender ~= ply then return end + if not ply:Alive() or ply:IsSpec() then return end + count = count + 1 if count >= times then ply:CompleteTask(TASK.id) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 38ccd5d98..d6556975d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -53,7 +53,7 @@ if SERVER then timer.Create("TTTTaskmasterCrouchTimer", 0.1, 0, function() if not IsPlayer(ply) then return end - if ply:Crouching() then + if ply:Alive() and not ply:IsSpec() and ply:Crouching() then -- Just starting if not ply.Task_CrouchStart then ply:SetProperty("Task_CrouchStart", CurTime(), ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index 015b6f2fd..3323aec98 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -86,10 +86,8 @@ if SERVER then local time = taskmaster_crouchnearbody_time:GetInt() timer.Create("TTTTaskmasterCrouchNearBodyTimer", 0.1, 0, function() if not IsPlayer(ply) then return end - if not ply:Crouching() then - if ply.Task_CrouchNearBodyStart then - ply:ClearProperty("Task_CrouchNearBodyStart", ply) - end + if not ply:Alive() or ply:IsSpec() or not ply:Crouching() then + ply:ClearProperty("Task_CrouchNearBodyStart", ply) return end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index 6c526e6f5..797fa5f7c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -57,7 +57,7 @@ if SERVER then timer.Create("TTTTaskmasterHealthUnderTimer", 0.1, 0, function() if not IsPlayer(ply) then return end - if ply:Health() < amount then + if ply:Alive() and not ply:IsSpec() and ply:Health() < amount then -- Just starting if not ply.Task_HealthUnderStart then ply:SetProperty("Task_HealthUnderStart", CurTime(), ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index f727a6f29..7c5629ef5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -52,6 +52,10 @@ if SERVER then local time = taskmaster_holstered_time:GetInt() timer.Create("TTTTaskmasterHolsteredTimer", 0.1, 0, function() if not IsPlayer(ply) then return end + if not ply:Alive() or ply:IsSpec() then + ply:ClearProperty("Task_HolsteredStart", ply) + return + end local wepClass = WEPS.GetClass(ply:GetActiveWeapon()) if wepClass == "weapon_ttt_unarmed" then diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index 12a79542e..815b7530d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -53,7 +53,7 @@ if SERVER then timer.Create("TTTTaskmasterStandOnPlayerTimer", 0.1, 0, function() if not IsPlayer(ply) then return end - if IsPlayer(ply:GetGroundEntity()) then + if ply:Alive() and not ply:IsSpec() and IsPlayer(ply:GetGroundEntity()) then -- Just starting if not ply.Task_StandOnPlayerStart then ply:SetProperty("Task_StandOnPlayerStart", CurTime(), ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index d91818fb7..5094c65e2 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -118,7 +118,7 @@ if SERVER then if not IsPlayer(target) then return end -- Within range - if ply:GetPos():DistToSqr(target:GetPos()) <= rangeSqr then + if ply:Alive() and not ply:IsSpec() and ply:GetPos():DistToSqr(target:GetPos()) <= rangeSqr then -- Just starting if not ply.Task_StayNearTargetStart then ply:SetProperty("Task_StayNearTargetStart", CurTime(), ply) From 55ef53bdfac14be5f2ade4c49eb8af1c8fbd626e Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 11:00:33 -0400 Subject: [PATCH 039/115] Added Stay Higher and Stay Lower tasks --- .../roles/taskmaster/cl_taskmaster.lua | 2 + .../roles/taskmaster/tasks/stayhigher.lua | 146 ++++++++++++++++++ .../roles/taskmaster/tasks/staylower.lua | 146 ++++++++++++++++++ 3 files changed, 294 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 8e7af4307..8421be96e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -23,6 +23,8 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_holstered", "STAY HOLSTERED - {time}") LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") + LANG.AddToLanguage("english", "taskmaster_stayhigher", "STAY HIGHEST - {time}") + LANG.AddToLanguage("english", "taskmaster_staylower", "STAY LOWEST - {time}") -- Win conditions LANG.AddToLanguage("english", "win_taskmaster", "The {role} finished off their list!") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua new file mode 100644 index 000000000..defc6296c --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -0,0 +1,146 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local player = player +local table = table +local util = util + +local MathMax = math.max +local PlayerIterator = player.Iterator + +local TASK = {} + +TASK.id = "stayhigher" + +local taskmaster_stayhigher_time = CreateConVar("ttt_taskmaster_stayhigher_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay higher up to complete the 'Highest Player' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_stayhigher_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local time = taskmaster_stayhigher_time:GetInt() + local name = "Highest For " .. time .. " Second" + if time ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local time = taskmaster_stayhigher_time:GetInt() + local desc = "Stay higher up than all players for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_StayHigher_Assigned") + util.AddNetworkString("TTT_Taskmaster_StayHigher_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + local function GetHighestPlayer() + local highest = nil + for _, p in PlayerIterator() do + if not p:Alive() or p:IsSpec() then continue end + + local pos = p:GetPos() + if not highest or pos.z > highest.z then + highest = { + ply = p, + z = pos.z + } + end + end + + return highest.ply + end + + TASK.OnTaskAssigned = function(ply) + local time = taskmaster_stayhigher_time:GetInt() + timer.Create("TTTTaskmasterStayHigherTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + if not ply:Alive() or ply:IsSpec() then + ply:ClearProperty("Task_StayHigherStart", ply) + return + end + + local highest = GetHighestPlayer() + if IsPlayer(highest) and highest == ply then + -- Just starting + if not ply.Task_StayHigherStart then + ply:SetProperty("Task_StayHigherStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_StayHigherStart + time then + ply:CompleteTask(TASK.id) + end + -- Not highest anymore + else + ply:ClearProperty("Task_StayHigherStart", ply) + end + end) + + net.Start("TTT_Taskmaster_StayHigher_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterStayHigherTimer") + + ply:ClearProperty("Task_StayHigherStart", ply) + + net.Start("TTT_Taskmaster_StayHigher_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_StayHigher_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local time = taskmaster_stayhigher_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_StayHigher_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_StayHigherStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_stayhigher", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_StayHigher_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("HUDPaint", "Taskmaster_StayHigher_HUDPaint_" .. sid64) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua new file mode 100644 index 000000000..09766071d --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -0,0 +1,146 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local player = player +local table = table +local util = util + +local MathMax = math.max +local PlayerIterator = player.Iterator + +local TASK = {} + +TASK.id = "staylower" + +local taskmaster_staylower_time = CreateConVar("ttt_taskmaster_staylower_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay lower down to complete the 'Lowest Player' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_staylower_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local time = taskmaster_staylower_time:GetInt() + local name = "Lowest For " .. time .. " Second" + if time ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local time = taskmaster_staylower_time:GetInt() + local desc = "Stay lower down than all players for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_StayLower_Assigned") + util.AddNetworkString("TTT_Taskmaster_StayLower_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + local function GetLowestPlayer() + local lowest = nil + for _, p in PlayerIterator() do + if not p:Alive() or p:IsSpec() then continue end + + local pos = p:GetPos() + if not lowest or pos.z < lowest.z then + lowest = { + ply = p, + z = pos.z + } + end + end + + return lowest.ply + end + + TASK.OnTaskAssigned = function(ply) + local time = taskmaster_staylower_time:GetInt() + timer.Create("TTTTaskmasterStayLowerTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + if not ply:Alive() or ply:IsSpec() then + ply:ClearProperty("Task_StayLowerStart", ply) + return + end + + local lowest = GetLowestPlayer() + if IsPlayer(lowest) and lowest == ply then + -- Just starting + if not ply.Task_StayLowerStart then + ply:SetProperty("Task_StayLowerStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_StayLowerStart + time then + ply:CompleteTask(TASK.id) + end + -- Not lowest anymore + else + ply:ClearProperty("Task_StayLowerStart", ply) + end + end) + + net.Start("TTT_Taskmaster_StayLower_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterStayLowerTimer") + + ply:ClearProperty("Task_StayLowerStart", ply) + + net.Start("TTT_Taskmaster_StayLower_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_StayLower_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local time = taskmaster_staylower_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_StayLower_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_StayLowerStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_staylower", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_StayLower_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("HUDPaint", "Taskmaster_StayLower_HUDPaint_" .. sid64) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From c07323b84289b71eaa345c036b29f51b4ed653ea Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 12:13:10 -0400 Subject: [PATCH 040/115] Added Damage Everyone task --- .../roles/taskmaster/tasks/damageeveryone.lua | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua new file mode 100644 index 000000000..d76d7d414 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua @@ -0,0 +1,100 @@ +local hook = hook +local net = net +local player = player +local table = table +local util = util + +local PlayerIterator = player.Iterator +local TableHasValue = table.HasValue +local TableInsert = table.insert + +local TASK = {} + +TASK.id = "damageeveryone" + +TASK.Name = function(ply) + return "Damage All Players" +end + +TASK.Description = function(ply) + return "Damage all other living players" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_DamageEveryone_Assigned") + util.AddNetworkString("TTT_Taskmaster_DamageEveryone_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON + } + + TASK.OnTaskAssigned = function(ply) + hook.Add("PostEntityTakeDamage", "Taskmaster_DamageEveryone_PostEntityTakeDamage_" .. ply:SteamID64(), function(entity, dmginfo, wasDamageTaken) + if not wasDamageTaken then return end + if entity == ply then return end + + local attacker = dmginfo:GetAttacker() + if not IsPlayer(attacker) or attacker ~= ply then return end + + local vicSid64 = entity:SteamID64() + local damaged = ply.Task_DamageEveryoneDamaged or {} + if TableHasValue(damaged, vicSid64) then return end + + TableInsert(damaged, vicSid64) + ply:SetProperty("Task_DamageEveryoneDamaged", damaged, ply) + end) + + timer.Create("TTTTaskmasterDamageEveryoneTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + + local damaged = ply.Task_DamageEveryoneDamaged or {} + for _, p in PlayerIterator() do + if ply == p then continue end + if not p:Alive() or p:IsSpec() then continue end + + -- If this player hasn't been damaged yet, we're not done + if not TableHasValue(damaged, p:SteamID64()) then return end + end + + ply:CompleteTask(TASK.id) + end) + + net.Start("TTT_Taskmaster_DamageEveryone_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PostEntityTakeDamage", "Taskmaster_DamageEveryone_PostEntityTakeDamage_" .. ply:SteamID64()) + timer.Remove("TTTTaskmasterDamageEveryoneTimer") + + ply:ClearProperty("Task_DamageEveryoneDamaged", ply) + + net.Start("TTT_Taskmaster_DamageEveryone_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_DamageEveryone_Assigned", function() + local client = LocalPlayer() + hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_DamageEveryone_TTTTargetIDPlayerTargetIcon_" .. client:SteamID64(), function(ply, cli, showJester) + if cli:IsActiveTaskmaster() and not TableHasValue(cli.Task_DamageEveryoneDamaged, ply:SteamID64()) then + local iconColor = ROLE_COLORS_SPRITE[ROLE_TRAITOR] + return "task", true, iconColor, "up" + end + end) + end) + + net.Receive("TTT_Taskmaster_DamageEveryone_Cleanup", function() + local client = LocalPlayer() + hook.Remove("TTTTargetIDPlayerTargetIcon", "Taskmaster_DamageEveryone_TTTTargetIDPlayerTargetIcon_" .. client:SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 420e6156107c3e2f2764032ff919c3d623425dc8 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 12:59:25 -0400 Subject: [PATCH 041/115] Update names for consistency --- gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua | 2 +- .../taskmaster/tasks/{killairborne.lua => killairbourne.lua} | 0 .../gamemode/roles/taskmaster/tasks/standonplayer.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/staylower.lua | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename gamemodes/terrortown/gamemode/roles/taskmaster/tasks/{killairborne.lua => killairbourne.lua} (100%) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index d6556975d..0b8aee2fb 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -20,7 +20,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_crouch_time:GetInt() - local name = "Crouch For " .. time .. " Second" + local name = "Crouch for " .. time .. " Second" if time ~= 1 then name = name .. "s" end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairbourne.lua similarity index 100% rename from gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua rename to gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairbourne.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index 815b7530d..54d1ff118 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -20,7 +20,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_standonplayer_time:GetInt() - local name = "Stand On Player For " .. time .. " Second" + local name = "Stand on Player for " .. time .. " Second" if time ~= 1 then name = name .. "s" end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index defc6296c..e1b24fac5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -22,7 +22,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_stayhigher_time:GetInt() - local name = "Highest For " .. time .. " Second" + local name = "Highest for " .. time .. " Second" if time ~= 1 then name = name .. "s" end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index 09766071d..062a37167 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -22,7 +22,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_staylower_time:GetInt() - local name = "Lowest For " .. time .. " Second" + local name = "Lowest for " .. time .. " Second" if time ~= 1 then name = name .. "s" end From c52e97c7816cd0bb152f623deecbdfe34926d611 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 13:01:17 -0400 Subject: [PATCH 042/115] More consistency --- .../gamemode/roles/taskmaster/tasks/pickupshopitem.lua | 2 +- .../gamemode/roles/taskmaster/tasks/weaponpickups.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua index 90db16a6f..16bb0298f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua @@ -3,7 +3,7 @@ local TASK = {} TASK.id = "pickupshopitem" TASK.Name = function(ply) - return "Pick Up Shop Item" + return "Pick up Shop Item" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua index 362540c06..07f255b46 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua @@ -13,7 +13,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local count = taskmaster_weaponpickups_count:GetInt() - local name = "Pick Up " .. count .. " Weapon" + local name = "Pick up " .. count .. " Weapon" if count ~= 1 then name = name .. "s" end From de8a77e1f83a2d52f96aad2a32236b0ff4dc7f5a Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 13:09:38 -0400 Subject: [PATCH 043/115] Cleanup --- .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 5094c65e2..6b693881c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -194,15 +194,16 @@ if CLIENT then local particleVelocity = Vector(0, 0, 40) hook.Add("TTTPlayerAliveClientThink", "Taskmaster_StayNearTarget_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) local shouldDraw = false - local target = cli.Task_StayNearTargetPlayer - if ply == cli and cli:IsActiveTaskmaster() and IsPlayer(target) then + local target = ply.Task_StayNearTargetPlayer + if ply == cli and ply:IsActiveTaskmaster() and IsPlayer(target) then local pos = target:GetPos() if not ply.TaskmasterRadiusEmitter then ply.TaskmasterRadiusEmitter = ParticleEmitter(pos) end if not ply.TaskmasterRadiusNextPart then ply.TaskmasterRadiusNextPart = CurTime() end if not ply.TaskmasterRadiusDir then ply.TaskmasterRadiusDir = 0 end -- Use DistToSqr as it's more efficient and this is called very frequently + local distance = ply:GetPos():DistToSqr(pos) -- 9000000 = 3000^2 - if ply.TaskmasterRadiusNextPart < CurTime() and cli:GetPos():DistToSqr(pos) <= 9000000 then + if ply.TaskmasterRadiusNextPart < CurTime() and distance <= 9000000 then for _ = 1, 48 do ply.TaskmasterRadiusEmitter:SetPos(pos) ply.TaskmasterRadiusNextPart = CurTime() + 0.005 @@ -218,7 +219,7 @@ if CLIENT then particle:SetRoll(MathRand(0, MathPi)) particle:SetRollDelta(0) local color = ROLE_COLORS[ROLE_TRAITOR] - if ply:GetPos():DistToSqr(target:GetPos()) <= rangeSqr then + if distance <= rangeSqr then color = ROLE_COLORS[ROLE_INNOCENT] end particle:SetColor(color.r, color.g, color.b) From f4c7f46d581115bd5e07bdea72d5a92912c420eb Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 13:18:47 -0400 Subject: [PATCH 044/115] Added "Stay in Area" task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/stayinarea.lua | 196 ++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 8421be96e..f2248d6ea 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -24,6 +24,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") LANG.AddToLanguage("english", "taskmaster_stayhigher", "STAY HIGHEST - {time}") + LANG.AddToLanguage("english", "taskmaster_stayinarea", "STAY IN AREA - {time}") LANG.AddToLanguage("english", "taskmaster_staylower", "STAY LOWEST - {time}") -- Win conditions diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua new file mode 100644 index 000000000..fd91b020a --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -0,0 +1,196 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local table = table +local util = util + +local MathCos = math.cos +local MathMax = math.max +local MathPi = math.pi +local MathRand = math.Rand +local MathSin = math.sin + +local TASK = {} + +TASK.id = "stayinarea" + +local taskmaster_stayinarea_range = CreateConVar("ttt_taskmaster_stayinarea_range", "5", FCVAR_REPLICATED, "The distance (in meters) away from the location that a player must stay within to count for the 'Stay in Area' task", 1, 100) +local taskmaster_stayinarea_time = CreateConVar("ttt_taskmaster_stayinarea_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay inside the target area to count for the 'Stay in Area' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_stayinarea_range", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_stayinarea_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local time = taskmaster_stayinarea_time:GetInt() + local name = "Stay in Area for " .. time .. " Second" + if time ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local time = taskmaster_stayinarea_time:GetInt() + local desc = "Stay in the marked area for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_StayInArea_Assigned") + util.AddNetworkString("TTT_Taskmaster_StayInArea_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR, + TASKMASTER_TF_PARTICLERADIUS + } + + TASK.OnTaskAssigned = function(ply) + ply:SetProperty("Task_StayInAreaLocation", ply:GetPos(), ply) + + local range = taskmaster_stayinarea_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + local time = taskmaster_stayinarea_time:GetInt() + timer.Create("TTTTaskmasterStayInAreaTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + + -- Within range + if ply:Alive() and not ply:IsSpec() and ply:GetPos():DistToSqr(ply.Task_StayInAreaLocation) <= rangeSqr then + -- Just starting + if not ply.Task_StayInAreaStart then + ply:SetProperty("Task_StayInAreaStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_StayInAreaStart + time then + ply:CompleteTask(TASK.id) + end + -- Not within range + else + ply:ClearProperty("Task_StayInAreaStart", ply) + end + end) + + net.Start("TTT_Taskmaster_StayInArea_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterStayInAreaTimer") + + ply:ClearProperty("Task_StayInAreaLocation", ply) + ply:ClearProperty("Task_StayInAreaStart", ply) + + hook.Remove("PostPlayerDeath", "Taskmaster_StayInArea_PostPlayerDeath_" .. ply:SteamID64()) + + net.Start("TTT_Taskmaster_StayInArea_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_StayInArea_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local range = taskmaster_stayinarea_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + local time = taskmaster_stayinarea_time:GetInt() + + local particleVelocity = Vector(0, 0, 40) + hook.Add("TTTPlayerAliveClientThink", "Taskmaster_StayInArea_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) + local shouldDraw = false + local pos = ply.Task_StayInAreaLocation + if ply == cli and ply:IsActiveTaskmaster() and pos then + if not ply.TaskmasterRadiusEmitter then ply.TaskmasterRadiusEmitter = ParticleEmitter(pos) end + if not ply.TaskmasterRadiusNextPart then ply.TaskmasterRadiusNextPart = CurTime() end + if not ply.TaskmasterRadiusDir then ply.TaskmasterRadiusDir = 0 end + -- Use DistToSqr as it's more efficient and this is called very frequently + local distance = ply:GetPos():DistToSqr(pos) + -- 9000000 = 3000^2 + if ply.TaskmasterRadiusNextPart < CurTime() and distance <= 9000000 then + for _ = 1, 48 do + ply.TaskmasterRadiusEmitter:SetPos(pos) + ply.TaskmasterRadiusNextPart = CurTime() + 0.005 + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + MathPi / 12 + local vec = Vector(MathSin(ply.TaskmasterRadiusDir) * range, MathCos(ply.TaskmasterRadiusDir) * range, 10) + local particle = ply.TaskmasterRadiusEmitter:Add("particle/wisp.vmt", pos + vec) + particle:SetVelocity(particleVelocity) + particle:SetDieTime(0.25) + particle:SetStartAlpha(60) + particle:SetEndAlpha(0) + particle:SetStartSize(3) + particle:SetEndSize(2) + particle:SetRoll(MathRand(0, MathPi)) + particle:SetRollDelta(0) + local color = ROLE_COLORS[ROLE_TRAITOR] + if distance <= rangeSqr then + color = ROLE_COLORS[ROLE_INNOCENT] + end + particle:SetColor(color.r, color.g, color.b) + end + ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + 0.02 + end + shouldDraw = true + end + + if not shouldDraw and ply.TaskmasterRadiusEmitter then + ply.TaskmasterRadiusEmitter:Finish() + ply.TaskmasterRadiusEmitter = nil + ply.TaskmasterRadiusDir = nil + ply.TaskmasterRadiusNextPart = nil + end + end) + + hook.Add("HUDPaint", "Taskmaster_StayInArea_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_StayInAreaStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_stayinarea", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_StayInArea_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_StayInArea_TTTPlayerAliveClientThink_" .. sid64) + hook.Remove("HUDPaint", "Taskmaster_StayInArea_HUDPaint_" .. sid64) + + if client.TaskmasterRadiusEmitter then + client.TaskmasterRadiusEmitter:Finish() + client.TaskmasterRadiusEmitter = nil + client.TaskmasterRadiusDir = nil + client.TaskmasterRadiusNextPart = nil + end + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 568c13654ef7c3260d07b12920c7ac2ae00f244d Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 13:56:39 -0400 Subject: [PATCH 045/115] Added Stay Away task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/stayaway.lua | 154 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index f2248d6ea..f9ab4a829 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -22,6 +22,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") LANG.AddToLanguage("english", "taskmaster_holstered", "STAY HOLSTERED - {time}") LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") + LANG.AddToLanguage("english", "taskmaster_stayaway", "STAY AWAY - {time}") LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") LANG.AddToLanguage("english", "taskmaster_stayhigher", "STAY HIGHEST - {time}") LANG.AddToLanguage("english", "taskmaster_stayinarea", "STAY IN AREA - {time}") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua new file mode 100644 index 000000000..7969fbf73 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua @@ -0,0 +1,154 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local player = player +local table = table +local util = util + +local MathMax = math.max +local PlayerIterator = player.Iterator + +local TASK = {} + +TASK.id = "stayaway" + +local taskmaster_stayaway_range = CreateConVar("ttt_taskmaster_stayaway_range", "25", FCVAR_REPLICATED, "The distance (in meters) a player must stay away from other people to count for the 'Stay Away' task", 1, 100) +local taskmaster_stayaway_time = CreateConVar("ttt_taskmaster_stayaway_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay away from other people to count for the 'Stay Away' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_stayaway_range", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_stayaway_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local time = taskmaster_stayaway_time:GetInt() + local name = "Stay Away for " .. time .. " Second" + if time ~= 1 then + name = name .. "s" + end + return name +end + +TASK.Description = function(ply) + local time = taskmaster_stayaway_time:GetInt() + local desc = "Stay away from other players for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_StayAway_Assigned") + util.AddNetworkString("TTT_Taskmaster_StayAway_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + local function GetNearestPlayer(ply) + local pos = ply:GetPos() + local nearest = nil + for _, p in PlayerIterator() do + if p == ply then continue end + if not p:Alive() or p:IsSpec() then continue end + + local dist = pos:DistToSqr(p:GetPos()) + if not nearest or dist < nearest.dist then + nearest = { + ply = p, + dist = dist + } + end + end + + return nearest + end + + TASK.OnTaskAssigned = function(ply) + local range = taskmaster_stayaway_range:GetInt() * UNITS_PER_METER + local rangeSqr = range * range + local time = taskmaster_stayaway_time:GetInt() + timer.Create("TTTTaskmasterStayAwayTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + + -- Within range + local nearest = GetNearestPlayer(ply) + if ply:Alive() and not ply:IsSpec() and nearest.dist >= rangeSqr then + -- Just starting + if not ply.Task_StayAwayStart then + ply:SetProperty("Task_StayAwayStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_StayAwayStart + time then + ply:CompleteTask(TASK.id) + end + -- Not within range + else + ply:ClearProperty("Task_StayAwayStart", ply) + end + end) + + net.Start("TTT_Taskmaster_StayAway_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterStayAwayTimer") + + ply:ClearProperty("Task_StayAwayLocation", ply) + ply:ClearProperty("Task_StayAwayStart", ply) + + hook.Remove("PostPlayerDeath", "Taskmaster_StayAway_PostPlayerDeath_" .. ply:SteamID64()) + + net.Start("TTT_Taskmaster_StayAway_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_StayAway_Assigned", function() + local client = LocalPlayer() + local time = taskmaster_stayaway_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_StayAway_HUDPaint_" .. client:SteamID64(), function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_StayAwayStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_stayaway", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_StayAway_Cleanup", function() + local client = LocalPlayer() + hook.Remove("HUDPaint", "Taskmaster_StayAway_HUDPaint_" .. client:SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 25eb6e7e69b455ad26b85c795e8f07b91bccbd1a Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 14:49:20 -0400 Subject: [PATCH 046/115] Fixed Stay Near Target not cleaning up enough --- .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 6b693881c..ff8564445 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -165,6 +165,7 @@ if SERVER then ply:ClearProperty("Task_StayNearTargetStart", ply) hook.Remove("PostPlayerDeath", "Taskmaster_StayNearTarget_PostPlayerDeath_" .. ply:SteamID64()) + hook.Remove("PlayerDisconnected", "Taskmaster_StayNearTarget_PlayerDisconnected_" .. ply:SteamID64()) net.Start("TTT_Taskmaster_StayNearTarget_Cleanup") net.Send(ply) From 299401cf40754a6fe0390ec9af1e6d561ce92c3e Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 14:50:26 -0400 Subject: [PATCH 047/115] Minor cleanup --- .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index ff8564445..2456bb46a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -106,6 +106,7 @@ if SERVER then end TASK.OnTaskAssigned = function(ply) + local sid64 = ply:SteamID64() local target = GetRandomTarget(ply) ply:SetProperty("Task_StayNearTargetPlayer", target, ply) @@ -132,7 +133,7 @@ if SERVER then end end) - hook.Add("PostPlayerDeath", "Taskmaster_StayNearTarget_PostPlayerDeath_" .. ply:SteamID64(), function(victim) + hook.Add("PostPlayerDeath", "Taskmaster_StayNearTarget_PostPlayerDeath_" .. sid64, function(victim) if ply.Task_StayNearTargetPlayer ~= victim then return end local newTarget = GetRandomTarget(ply) @@ -143,7 +144,7 @@ if SERVER then ply:SetProperty("Task_StayNearTargetPlayer", newTarget, ply) end) - hook.Add("PlayerDisconnected", "Taskmaster_StayNearTarget_PlayerDisconnected_" .. ply:SteamID64(), function(leaver) + hook.Add("PlayerDisconnected", "Taskmaster_StayNearTarget_PlayerDisconnected_" .. sid64, function(leaver) if ply.Task_StayNearTargetPlayer ~= leaver then return end local newTarget = GetRandomTarget(ply) From b36ffad3f1c492b21835d8cd54153ad9b79a6ba3 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 15:28:52 -0400 Subject: [PATCH 048/115] Added Get Player Killed task --- .../taskmaster/tasks/getplayerkilled.lua | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua new file mode 100644 index 000000000..9e03202b3 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua @@ -0,0 +1,107 @@ +local hook = hook +local net = net +local player = player +local util = util + +local TASK = {} + +TASK.id = "getplayerkilled" + +TASK.Name = function(ply) + local name = "Target" + if IsPlayer(ply.Task_GetPlayerKilledPlayer) then + name = ply.Task_GetPlayerKilledPlayer:Nick() + end + return "Get " .. name .. " Killed" +end + +TASK.Description = function(ply) + local name = "Target" + if IsPlayer(ply.Task_GetPlayerKilledPlayer) then + name = ply.Task_GetPlayerKilledPlayer:Nick() + end + + return "Get " .. name .. " killed by another player" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_GetPlayerKilled_Assigned") + util.AddNetworkString("TTT_Taskmaster_GetPlayerKilled_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON + } + + local function GetRandomTarget(ply) + -- Find the first random living player + for _, p in RandomPairs(player.GetAll()) do + if not p:Alive() or p:IsSpec() then continue end + if p == ply then continue end + return p + end + return nil + end + + TASK.OnTaskAssigned = function(ply) + local target = GetRandomTarget(ply) + + ply:SetProperty("Task_GetPlayerKilledPlayer", target, ply) + + hook.Add("PlayerDeath", "Taskmaster_GetPlayerKilled_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if ply.Task_GetPlayerKilledPlayer ~= victim then return end + if attacker == ply then return end + ply:CompleteTask(TASK.id) + end) + + hook.Add("PlayerDisconnected", "Taskmaster_GetPlayerKilled_PlayerDisconnected_" .. ply:SteamID64(), function(leaver) + if ply.Task_GetPlayerKilledPlayer ~= leaver then return end + + local newTarget = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. newTarget:Nick()) + + -- Overwrite the previous target + target = newTarget + ply:SetProperty("Task_GetPlayerKilledPlayer", newTarget, ply) + end) + + net.Start("TTT_Taskmaster_GetPlayerKilled_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterGetPlayerKilledTimer") + + ply:ClearProperty("Task_GetPlayerKilledPlayer", ply) + + hook.Remove("PlayerDeath", "Taskmaster_GetPlayerKilled_PlayerDeath_" .. ply:SteamID64()) + hook.Remove("PlayerDisconnected", "Taskmaster_GetPlayerKilled_PlayerDisconnected_" .. ply:SteamID64()) + + net.Start("TTT_Taskmaster_GetPlayerKilled_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_GetPlayerKilled_Assigned", function() + local client = LocalPlayer() + hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_GetPlayerKilled_TTTTargetIDPlayerTargetIcon_" .. client:SteamID64(), function(ply, cli, showJester) + if cli:IsActiveTaskmaster() and ply == cli.Task_GetPlayerKilledPlayer then + local iconColor = ROLE_COLORS_SPRITE[ROLE_TRAITOR] + return "task", true, iconColor, "up" + end + end) + end) + + net.Receive("TTT_Taskmaster_GetPlayerKilled_Cleanup", function() + local client = LocalPlayer() + hook.Remove("TTTTargetIDPlayerTargetIcon", "Taskmaster_GetPlayerKilled_TTTTargetIDPlayerTargetIcon_" .. client:SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 39a4427d48a93bdcccdad588962207e6bb496357 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 15:36:46 -0400 Subject: [PATCH 049/115] Cleanup --- .../taskmaster/tasks/getplayerkilled.lua | 13 +++------ .../roles/taskmaster/tasks/stayneartarget.lua | 29 +++++++------------ 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua index 9e03202b3..cb4dd98ca 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua @@ -47,9 +47,7 @@ if SERVER then end TASK.OnTaskAssigned = function(ply) - local target = GetRandomTarget(ply) - - ply:SetProperty("Task_GetPlayerKilledPlayer", target, ply) + ply:SetProperty("Task_GetPlayerKilledPlayer", GetRandomTarget(ply), ply) hook.Add("PlayerDeath", "Taskmaster_GetPlayerKilled_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) if ply.Task_GetPlayerKilledPlayer ~= victim then return end @@ -60,12 +58,9 @@ if SERVER then hook.Add("PlayerDisconnected", "Taskmaster_GetPlayerKilled_PlayerDisconnected_" .. ply:SteamID64(), function(leaver) if ply.Task_GetPlayerKilledPlayer ~= leaver then return end - local newTarget = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. newTarget:Nick()) - - -- Overwrite the previous target - target = newTarget - ply:SetProperty("Task_GetPlayerKilledPlayer", newTarget, ply) + local target = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_GetPlayerKilledPlayer", target, ply) end) net.Start("TTT_Taskmaster_GetPlayerKilled_Assigned") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 2456bb46a..5b19c8021 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -107,19 +107,18 @@ if SERVER then TASK.OnTaskAssigned = function(ply) local sid64 = ply:SteamID64() - local target = GetRandomTarget(ply) - - ply:SetProperty("Task_StayNearTargetPlayer", target, ply) - local range = taskmaster_stayneartarget_range:GetInt() * UNITS_PER_METER local rangeSqr = range * range local time = taskmaster_stayneartarget_time:GetInt() + + ply:SetProperty("Task_StayNearTargetPlayer", GetRandomTarget(ply), ply) + timer.Create("TTTTaskmasterStayNearTargetTimer", 0.1, 0, function() if not IsPlayer(ply) then return end - if not IsPlayer(target) then return end + if not IsPlayer(ply.Task_StayNearTargetPlayer) then return end -- Within range - if ply:Alive() and not ply:IsSpec() and ply:GetPos():DistToSqr(target:GetPos()) <= rangeSqr then + if ply:Alive() and not ply:IsSpec() and ply:GetPos():DistToSqr(ply.Task_StayNearTargetPlayer:GetPos()) <= rangeSqr then -- Just starting if not ply.Task_StayNearTargetStart then ply:SetProperty("Task_StayNearTargetStart", CurTime(), ply) @@ -136,23 +135,17 @@ if SERVER then hook.Add("PostPlayerDeath", "Taskmaster_StayNearTarget_PostPlayerDeath_" .. sid64, function(victim) if ply.Task_StayNearTargetPlayer ~= victim then return end - local newTarget = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. newTarget:Nick()) - - -- Overwrite the previous target - target = newTarget - ply:SetProperty("Task_StayNearTargetPlayer", newTarget, ply) + local target = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. target:Nick()) + ply:SetProperty("Task_StayNearTargetPlayer", target, ply) end) hook.Add("PlayerDisconnected", "Taskmaster_StayNearTarget_PlayerDisconnected_" .. sid64, function(leaver) if ply.Task_StayNearTargetPlayer ~= leaver then return end - local newTarget = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. newTarget:Nick()) - - -- Overwrite the previous target - target = newTarget - ply:SetProperty("Task_StayNearTargetPlayer", newTarget, ply) + local target = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_StayNearTargetPlayer", target, ply) end) net.Start("TTT_Taskmaster_StayNearTarget_Assigned") From a10cbafb72e92a9800a81726df30db4bf994d2de Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 16:12:33 -0400 Subject: [PATCH 050/115] Added Get Player to Kill task --- .../taskmaster/tasks/getplayertokill.lua | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua new file mode 100644 index 000000000..37ddcdc8c --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua @@ -0,0 +1,102 @@ +local hook = hook +local net = net +local player = player +local util = util + +local TASK = {} + +TASK.id = "getplayertokill" + +TASK.Name = function(ply) + local name = "Target" + if IsPlayer(ply.Task_GetPlayerToKillPlayer) then + name = ply.Task_GetPlayerToKillPlayer:Nick() + end + return "Get " .. name .. " to Kill" +end + +TASK.Description = function(ply) + local name = "Target" + if IsPlayer(ply.Task_GetPlayerToKillPlayer) then + name = ply.Task_GetPlayerToKillPlayer:Nick() + end + + return "Get " .. name .. " to kill another player" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_GetPlayerToKill_Assigned") + util.AddNetworkString("TTT_Taskmaster_GetPlayerToKill_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON + } + + local function GetRandomTarget(ply) + -- Find the first random living player + for _, p in RandomPairs(player.GetAll()) do + if not p:Alive() or p:IsSpec() then continue end + if p == ply then continue end + return p + end + return nil + end + + TASK.OnTaskAssigned = function(ply) + ply:SetProperty("Task_GetPlayerToKillPlayer", GetRandomTarget(ply), ply) + + hook.Add("PlayerDeath", "Taskmaster_GetPlayerToKill_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if ply.Task_GetPlayerToKillPlayer ~= attacker then return end + if victim == ply then return end + ply:CompleteTask(TASK.id) + end) + + hook.Add("PlayerDisconnected", "Taskmaster_GetPlayerToKill_PlayerDisconnected_" .. ply:SteamID64(), function(leaver) + if ply.Task_GetPlayerToKillPlayer ~= leaver then return end + + local target = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_GetPlayerToKillPlayer", target, ply) + end) + + net.Start("TTT_Taskmaster_GetPlayerToKill_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterGetPlayerToKillTimer") + + ply:ClearProperty("Task_GetPlayerToKillPlayer", ply) + + hook.Remove("PlayerDeath", "Taskmaster_GetPlayerToKill_PlayerDeath_" .. ply:SteamID64()) + hook.Remove("PlayerDisconnected", "Taskmaster_GetPlayerToKill_PlayerDisconnected_" .. ply:SteamID64()) + + net.Start("TTT_Taskmaster_GetPlayerToKill_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_GetPlayerToKill_Assigned", function() + local client = LocalPlayer() + hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_GetPlayerToKill_TTTTargetIDPlayerTargetIcon_" .. client:SteamID64(), function(ply, cli, showJester) + if cli:IsActiveTaskmaster() and ply == cli.Task_GetPlayerToKillPlayer then + local iconColor = ROLE_COLORS_SPRITE[ROLE_TRAITOR] + return "task", true, iconColor, "up" + end + end) + end) + + net.Receive("TTT_Taskmaster_GetPlayerToKill_Cleanup", function() + local client = LocalPlayer() + hook.Remove("TTTTargetIDPlayerTargetIcon", "Taskmaster_GetPlayerToKill_TTTTargetIDPlayerTargetIcon_" .. client:SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From dcc5c15b97125855c9b3474b9610ba4d1d55c853 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 16:20:36 -0400 Subject: [PATCH 051/115] Standardize --- .../gamemode/roles/taskmaster/tasks/getplayerkilled.lua | 2 +- .../gamemode/roles/taskmaster/tasks/getplayertokill.lua | 2 +- .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua index cb4dd98ca..5fdbad5f3 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua @@ -16,7 +16,7 @@ TASK.Name = function(ply) end TASK.Description = function(ply) - local name = "Target" + local name = "target" if IsPlayer(ply.Task_GetPlayerKilledPlayer) then name = ply.Task_GetPlayerKilledPlayer:Nick() end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua index 37ddcdc8c..4c7442c96 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua @@ -16,7 +16,7 @@ TASK.Name = function(ply) end TASK.Description = function(ply) - local name = "Target" + local name = "target" if IsPlayer(ply.Task_GetPlayerToKillPlayer) then name = ply.Task_GetPlayerToKillPlayer:Nick() end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 5b19c8021..5aa0a758e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -31,7 +31,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { }) TASK.Name = function(ply) - local name = "Player" + local name = "Target" if IsPlayer(ply.Task_StayNearTargetPlayer) then name = ply.Task_StayNearTargetPlayer:Nick() end @@ -68,7 +68,7 @@ TASK.Description = function(ply) end end - local name = "Target" + local name = "target" if IsPlayer(ply.Task_StayNearTargetPlayer) then name = ply.Task_StayNearTargetPlayer:Nick() end From e833bffaa085e446a86c1006485762793a9712f9 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 16:24:15 -0400 Subject: [PATCH 052/115] Standardize more --- .../terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua | 1 + gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua | 1 + .../gamemode/roles/taskmaster/tasks/crouchnearbody.lua | 1 + .../gamemode/roles/taskmaster/tasks/damageeveryone.lua | 1 + .../terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua | 1 + .../terrortown/gamemode/roles/taskmaster/tasks/holstered.lua | 1 + .../terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua | 1 + .../terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua | 1 + .../terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua | 1 + .../terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua | 1 + .../terrortown/gamemode/roles/taskmaster/tasks/staylower.lua | 1 + .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 1 + 12 files changed, 12 insertions(+) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua index d32c232eb..a5a8ec5cd 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -3,6 +3,7 @@ local hook = hook local math = math local net = net local table = table +local timer = timer local util = util local MathMax = math.max diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 0b8aee2fb..51d67a9e7 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -3,6 +3,7 @@ local hook = hook local math = math local net = net local table = table +local timer = timer local util = util local MathMax = math.max diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index 3323aec98..6c20ddf9d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -5,6 +5,7 @@ local hook = hook local math = math local net = net local table = table +local timer = timer local util = util local EntsFindByClass = ents.FindByClass diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua index d76d7d414..21cf87801 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua @@ -2,6 +2,7 @@ local hook = hook local net = net local player = player local table = table +local timer = timer local util = util local PlayerIterator = player.Iterator diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index 797fa5f7c..63818420c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -3,6 +3,7 @@ local hook = hook local math = math local net = net local table = table +local timer = timer local util = util local MathMax = math.max diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index 7c5629ef5..446d90f1b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -3,6 +3,7 @@ local hook = hook local math = math local net = net local table = table +local timer = timer local util = util local MathMax = math.max diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index 54d1ff118..9c2b19cce 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -3,6 +3,7 @@ local hook = hook local math = math local net = net local table = table +local timer = timer local util = util local MathMax = math.max diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua index 7969fbf73..055b9a832 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua @@ -4,6 +4,7 @@ local math = math local net = net local player = player local table = table +local timer = timer local util = util local MathMax = math.max diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index e1b24fac5..c3c02966f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -4,6 +4,7 @@ local math = math local net = net local player = player local table = table +local timer = timer local util = util local MathMax = math.max diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index fd91b020a..e53fb1b18 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -3,6 +3,7 @@ local hook = hook local math = math local net = net local table = table +local timer = timer local util = util local MathCos = math.cos diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index 062a37167..febcd63dc 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -4,6 +4,7 @@ local math = math local net = net local player = player local table = table +local timer = timer local util = util local MathMax = math.max diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 5aa0a758e..493959139 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -5,6 +5,7 @@ local math = math local net = net local player = player local table = table +local timer = timer local util = util local MathCos = math.cos From 7d7eb9ea7d5c8b8ad617c0afc80c273c4d19c291 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 16:34:20 -0400 Subject: [PATCH 053/115] Added Look at Player task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/crouch.lua | 6 +- .../roles/taskmaster/tasks/lookatplayer.lua | 166 ++++++++++++++++++ 3 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index f9ab4a829..fa0aeb33c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -21,6 +21,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") LANG.AddToLanguage("english", "taskmaster_holstered", "STAY HOLSTERED - {time}") + LANG.AddToLanguage("english", "taskmaster_lookatplayer", "KEEP LOOKING - {time}") LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") LANG.AddToLanguage("english", "taskmaster_stayaway", "STAY AWAY - {time}") LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 51d67a9e7..121f26b2b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -87,10 +87,9 @@ end if CLIENT then net.Receive("TTT_Taskmaster_Crouch_Assigned", function() local client = LocalPlayer() - local sid64 = client:SteamID64() local time = taskmaster_crouch_time:GetInt() - hook.Add("HUDPaint", "Taskmaster_Crouch_HUDPaint_" .. sid64, function() + hook.Add("HUDPaint", "Taskmaster_Crouch_HUDPaint_" .. client:SteamID64(), function() if not client:IsActiveTaskmaster() then return end local startTime = client.Task_CrouchStart @@ -115,8 +114,7 @@ if CLIENT then net.Receive("TTT_Taskmaster_Crouch_Cleanup", function() local client = LocalPlayer() - local sid64 = client:SteamID64() - hook.Remove("HUDPaint", "Taskmaster_Crouch_HUDPaint_" .. sid64) + hook.Remove("HUDPaint", "Taskmaster_Crouch_HUDPaint_" .. client:SteamID64()) end) end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua new file mode 100644 index 000000000..e8459be3f --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -0,0 +1,166 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local table = table +local timer = timer +local util = util + +local MathMax = math.max + +local TASK = {} + +TASK.id = "lookatplayer" + +local taskmaster_lookatplayer_time = CreateConVar("ttt_taskmaster_lookatplayer_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must look at their target to complete for the 'Look at Player' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_lookatplayer_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + local name = "Target" + if IsPlayer(ply.Task_LookAtPlayerPlayer) then + name = ply.Task_LookAtPlayerPlayer:Nick() + end + return "Look at " .. name +end + +TASK.Description = function(ply) + local name = "target" + if IsPlayer(ply.Task_LookAtPlayerPlayer) then + name = ply.Task_LookAtPlayerPlayer:Nick() + end + local time = taskmaster_lookatplayer_time:GetInt() + local desc = "Look at " .. name .. " continuously for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_LookAtPlayer_Assigned") + util.AddNetworkString("TTT_Taskmaster_LookAtPlayer_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON, + TASKMASTER_TF_PROGRESSBAR + } + + local function GetRandomTarget(ply) + -- Find the first random living player + for _, p in RandomPairs(player.GetAll()) do + if not p:Alive() or p:IsSpec() then continue end + if p == ply then continue end + return p + end + return nil + end + + TASK.OnTaskAssigned = function(ply) + ply:SetProperty("Task_LookAtPlayerPlayer", GetRandomTarget(ply), ply) + + local time = taskmaster_lookatplayer_time:GetInt() + timer.Create("TTTTaskmasterLookAtPlayerTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + if not IsPlayer(ply.Task_LookAtPlayerPlayer) then return end + + if ply:Alive() and not ply:IsSpec() and ply:IsLineOfSightClear(ply.Task_LookAtPlayerPlayer) then + -- Just starting + if not ply.Task_LookAtPlayerStart then + ply:SetProperty("Task_LookAtPlayerStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_LookAtPlayerStart + time then + ply:CompleteTask(TASK.id) + end + -- Not within range + else + ply:ClearProperty("Task_LookAtPlayerStart", ply) + end + end) + + hook.Add("PlayerDeath", "Taskmaster_LookAtPlayer_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if ply.Task_LookAtPlayerPlayer ~= victim then return end + if attacker == ply then return end + ply:CompleteTask(TASK.id) + end) + + hook.Add("PlayerDisconnected", "Taskmaster_LookAtPlayer_PlayerDisconnected_" .. ply:SteamID64(), function(leaver) + if ply.Task_LookAtPlayerPlayer ~= leaver then return end + + local target = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_LookAtPlayerPlayer", target, ply) + end) + + net.Start("TTT_Taskmaster_LookAtPlayer_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterLookAtPlayerTimer") + + hook.Remove("PlayerDeath", "Taskmaster_LookAtPlayer_PlayerDeath_" .. ply:SteamID64()) + hook.Remove("PlayerDisconnected", "Taskmaster_LookAtPlayer_PlayerDisconnected_" .. ply:SteamID64()) + + ply:ClearProperty("Task_LookAtPlayerStart", ply) + ply:ClearProperty("Task_LookAtPlayerPlayer", ply) + + net.Start("TTT_Taskmaster_LookAtPlayer_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_LookAtPlayer_Assigned", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + local time = taskmaster_lookatplayer_time:GetInt() + + hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_LookAtPlayer_TTTTargetIDPlayerTargetIcon_" .. sid64, function(ply, cli, showJester) + if cli:IsActiveTaskmaster() and ply == cli.Task_LookAtPlayerPlayer then + local iconColor = ROLE_COLORS_SPRITE[ROLE_INNOCENT] + return "task", true, iconColor, "up" + end + end) + + hook.Add("HUDPaint", "Taskmaster_LookAtPlayer_HUDPaint_" .. sid64, function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_LookAtPlayerStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_lookatplayer", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_LookAtPlayer_Cleanup", function() + local client = LocalPlayer() + local sid64 = client:SteamID64() + hook.Remove("TTTTargetIDPlayerTargetIcon", "Taskmaster_LookAtPlayer_TTTTargetIDPlayerTargetIcon_" .. sid64) + hook.Remove("HUDPaint", "Taskmaster_LookAtPlayer_HUDPaint_" .. sid64) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 387cfdd34d5a7ac2df71c26d8049d1ef1aea0c35 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 16:52:12 -0400 Subject: [PATCH 054/115] Changed Look at Player to work more like the Informant scan --- .../gamemode/roles/taskmaster/tasks/lookatplayer.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index e8459be3f..b948b592e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -63,6 +63,13 @@ if SERVER then return nil end + local function IsTargetInView(ply) + if not IsValid(ply) then return false end + + local tr = ply:GetEyeTrace(MASK_SHOT) + return tr.Entity == ply.Task_LookAtPlayerPlayer + end + TASK.OnTaskAssigned = function(ply) ply:SetProperty("Task_LookAtPlayerPlayer", GetRandomTarget(ply), ply) @@ -71,7 +78,8 @@ if SERVER then if not IsPlayer(ply) then return end if not IsPlayer(ply.Task_LookAtPlayerPlayer) then return end - if ply:Alive() and not ply:IsSpec() and ply:IsLineOfSightClear(ply.Task_LookAtPlayerPlayer) then + -- Check IsOnScreen first because math is more efficient then sending traces this often + if ply:Alive() and not ply:IsSpec() and ply:IsOnScreen(ply.Task_LookAtPlayerPlayer, 0.35) and IsTargetInView(ply) then -- Just starting if not ply.Task_LookAtPlayerStart then ply:SetProperty("Task_LookAtPlayerStart", CurTime(), ply) From 5d76a23fd3b6417645a3c5940ddcbdff99510e2a Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 17:05:41 -0400 Subject: [PATCH 055/115] Cleanup --- .../gamemode/roles/taskmaster/tasks/lookatplayer.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index b948b592e..bd60517cb 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -73,6 +73,7 @@ if SERVER then TASK.OnTaskAssigned = function(ply) ply:SetProperty("Task_LookAtPlayerPlayer", GetRandomTarget(ply), ply) + local sid64 = ply:SteamID64() local time = taskmaster_lookatplayer_time:GetInt() timer.Create("TTTTaskmasterLookAtPlayerTimer", 0.1, 0, function() if not IsPlayer(ply) then return end @@ -93,13 +94,13 @@ if SERVER then end end) - hook.Add("PlayerDeath", "Taskmaster_LookAtPlayer_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + hook.Add("PlayerDeath", "Taskmaster_LookAtPlayer_PlayerDeath_" .. sid64, function(victim, inflictor, attacker) if ply.Task_LookAtPlayerPlayer ~= victim then return end if attacker == ply then return end ply:CompleteTask(TASK.id) end) - hook.Add("PlayerDisconnected", "Taskmaster_LookAtPlayer_PlayerDisconnected_" .. ply:SteamID64(), function(leaver) + hook.Add("PlayerDisconnected", "Taskmaster_LookAtPlayer_PlayerDisconnected_" .. sid64, function(leaver) if ply.Task_LookAtPlayerPlayer ~= leaver then return end local target = GetRandomTarget(ply) @@ -114,8 +115,9 @@ if SERVER then TASK.OnTaskRemoved = function(ply) timer.Remove("TTTTaskmasterLookAtPlayerTimer") - hook.Remove("PlayerDeath", "Taskmaster_LookAtPlayer_PlayerDeath_" .. ply:SteamID64()) - hook.Remove("PlayerDisconnected", "Taskmaster_LookAtPlayer_PlayerDisconnected_" .. ply:SteamID64()) + local sid64 = ply:SteamID64() + hook.Remove("PlayerDeath", "Taskmaster_LookAtPlayer_PlayerDeath_" .. sid64) + hook.Remove("PlayerDisconnected", "Taskmaster_LookAtPlayer_PlayerDisconnected_" .. sid64) ply:ClearProperty("Task_LookAtPlayerStart", ply) ply:ClearProperty("Task_LookAtPlayerPlayer", ply) From db446646dd533308f0cb44506da0c6867093b501 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 17:08:14 -0400 Subject: [PATCH 056/115] Fixed comment --- .../terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index bd60517cb..0c4d9b711 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -88,7 +88,7 @@ if SERVER then elseif CurTime() > ply.Task_LookAtPlayerStart + time then ply:CompleteTask(TASK.id) end - -- Not within range + -- Not looking at the player else ply:ClearProperty("Task_LookAtPlayerStart", ply) end From e95f5a169097d26cf1a566788ff572ef4c6fb8a7 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 17:13:10 -0400 Subject: [PATCH 057/115] Added Stay Hidden task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/stayhidden.lua | 137 ++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index fa0aeb33c..0b3e71e4b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -25,6 +25,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") LANG.AddToLanguage("english", "taskmaster_stayaway", "STAY AWAY - {time}") LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") + LANG.AddToLanguage("english", "taskmaster_stayhidden", "STAY HIDDEN - {time}") LANG.AddToLanguage("english", "taskmaster_stayhigher", "STAY HIGHEST - {time}") LANG.AddToLanguage("english", "taskmaster_stayinarea", "STAY IN AREA - {time}") LANG.AddToLanguage("english", "taskmaster_staylower", "STAY LOWEST - {time}") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua new file mode 100644 index 000000000..b3c9ae4ee --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua @@ -0,0 +1,137 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local player = player +local table = table +local timer = timer +local util = util + +local MathMax = math.max +local PlayerIterator = player.Iterator + +local TASK = {} + +TASK.id = "stayhidden" + +local taskmaster_stayhidden_time = CreateConVar("ttt_taskmaster_stayhidden_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must hide to complete for the 'Stay Hidden' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_stayhidden_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + return "Stay Hidden" +end + +TASK.Description = function(ply) + local time = taskmaster_stayhidden_time:GetInt() + local desc = "Stay hidden from other players for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_StayHidden_Assigned") + util.AddNetworkString("TTT_Taskmaster_StayHidden_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + local function IsTargetInView(ply, target) + if not IsValid(ply) then return false end + + local tr = ply:GetEyeTrace(MASK_SHOT) + return tr.Entity == target + end + + local function IsHidden(ply) + for _, p in PlayerIterator() do + if ply == p then continue end + + -- Check IsOnScreen first because math is more efficient then sending traces this often + if p:IsOnScreen(ply, 0.35) and IsTargetInView(p, ply) then + return false + end + end + return true + end + + TASK.OnTaskAssigned = function(ply) + local time = taskmaster_stayhidden_time:GetInt() + timer.Create("TTTTaskmasterStayHiddenTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + + if ply:Alive() and not ply:IsSpec() and IsHidden(ply) then + -- Just starting + if not ply.Task_StayHiddenStart then + ply:SetProperty("Task_StayHiddenStart", CurTime(), ply) + -- Long enough + elseif CurTime() > ply.Task_StayHiddenStart + time then + ply:CompleteTask(TASK.id) + end + -- Not within hidden + else + ply:ClearProperty("Task_StayHiddenStart", ply) + end + end) + + net.Start("TTT_Taskmaster_StayHidden_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterStayHiddenTimer") + + ply:ClearProperty("Task_StayHiddenStart", ply) + + net.Start("TTT_Taskmaster_StayHidden_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_StayHidden_Assigned", function() + local client = LocalPlayer() + local time = taskmaster_stayhidden_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_StayHidden_HUDPaint_" .. client:SteamID64(), function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_StayHiddenStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_stayhidden", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_StayHidden_Cleanup", function() + local client = LocalPlayer() + hook.Remove("HUDPaint", "Taskmaster_StayHidden_HUDPaint_" .. client:SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 78b51ea562031803923f4413d5905afb90000821 Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 17:31:54 -0400 Subject: [PATCH 058/115] Added Take Damage task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/healthunder.lua | 6 +- .../roles/taskmaster/tasks/takedamage.lua | 116 ++++++++++++++++++ 3 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 0b3e71e4b..2102738d2 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -29,6 +29,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_stayhigher", "STAY HIGHEST - {time}") LANG.AddToLanguage("english", "taskmaster_stayinarea", "STAY IN AREA - {time}") LANG.AddToLanguage("english", "taskmaster_staylower", "STAY LOWEST - {time}") + LANG.AddToLanguage("english", "taskmaster_takedamage", "AVOID DAMAGE - {time}") -- Win conditions LANG.AddToLanguage("english", "win_taskmaster", "The {role} finished off their list!") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index 63818420c..56c9f92e1 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -91,10 +91,9 @@ end if CLIENT then net.Receive("TTT_Taskmaster_HealthUnder_Assigned", function() local client = LocalPlayer() - local sid64 = client:SteamID64() local time = taskmaster_healthunder_time:GetInt() - hook.Add("HUDPaint", "Taskmaster_HealthUnder_HUDPaint_" .. sid64, function() + hook.Add("HUDPaint", "Taskmaster_HealthUnder_HUDPaint_" .. client:SteamID64(), function() if not client:IsActiveTaskmaster() then return end local startTime = client.Task_HealthUnderStart @@ -119,8 +118,7 @@ if CLIENT then net.Receive("TTT_Taskmaster_HealthUnder_Cleanup", function() local client = LocalPlayer() - local sid64 = client:SteamID64() - hook.Remove("HUDPaint", "Taskmaster_HealthUnder_HUDPaint_" .. sid64) + hook.Remove("HUDPaint", "Taskmaster_HealthUnder_HUDPaint_" .. client:SteamID64()) end) end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua new file mode 100644 index 000000000..c48785d98 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua @@ -0,0 +1,116 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local table = table +local timer = timer +local util = util + +local MathMax = math.max + +local TASK = {} + +TASK.id = "takedamage" + +local taskmaster_takedamage_time = CreateConVar("ttt_taskmaster_takedamage_time", "60", FCVAR_REPLICATED, "The time (in seconds) a player must survive without taking further damage to complete the 'Take Damage' task", 1, 240) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_takedamage_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + return "Take Damage" +end + +TASK.Description = function(ply) + local time = taskmaster_takedamage_time:GetInt() + local desc = "Take damage and survive for " .. time .. " second" + if time ~= 1 then + desc = desc .. "s" + end + return desc +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_TakeDamage_Assigned") + util.AddNetworkString("TTT_Taskmaster_TakeDamage_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + TASK.OnTaskAssigned = function(ply) + local time = taskmaster_takedamage_time:GetInt() + timer.Create("TTTTaskmasterTakeDamageTimer", 0.1, 0, function() + if not IsPlayer(ply) then return end + if not ply:Alive() or ply:IsSpec() then return end + if not ply.Task_TakeDamageStart then return end + if CurTime() <= ply.Task_TakeDamageStart + time then return end + + ply:CompleteTask(TASK.id) + end) + + hook.Add("PostEntityTakeDamage", "Taskmaster_TakeDamage_PostEntityTakeDamage_" .. ply:SteamID64(), function(entity, dmginfo, wasDamageTaken) + if not wasDamageTaken then return end + if entity ~= ply then return end + ply:SetProperty("Task_TakeDamageStart", CurTime(), ply) + end) + + net.Start("TTT_Taskmaster_TakeDamage_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + timer.Remove("TTTTaskmasterTakeDamageTimer") + + hook.Remove("PostEntityTakeDamage", "Taskmaster_TakeDamage_PostEntityTakeDamage_" .. ply:SteamID64()) + + ply:ClearProperty("Task_TakeDamageStart", ply) + + net.Start("TTT_Taskmaster_TakeDamage_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_TakeDamage_Assigned", function() + local client = LocalPlayer() + local time = taskmaster_takedamage_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_TakeDamage_HUDPaint_" .. client:SteamID64(), function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_TakeDamageStart + if not startTime then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_takedamage", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_TakeDamage_Cleanup", function() + local client = LocalPlayer() + hook.Remove("HUDPaint", "Taskmaster_TakeDamage_HUDPaint_" .. client:SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From cd1ffce805c9e3008775e3b05fb3e2920958d47f Mon Sep 17 00:00:00 2001 From: Malivil Date: Fri, 15 Aug 2025 18:10:31 -0400 Subject: [PATCH 059/115] Added ability for tasks to be marked as not blocking the round from ending Added Survive task --- .../gamemode/roles/taskmaster/taskmaster.lua | 30 ++++++++++++++- .../roles/taskmaster/tasks/survive.lua | 38 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index 3f9907e86..e1796f433 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -100,13 +100,22 @@ function plymeta:RerollTask(taskId, free) table.insert(self.taskmasterRerolledTasks, taskId) self:SetProperty("taskmasterRerolledTasks", self.taskmasterRerolledTasks, self) - self:AssignTask(isKillTask, index) + local newTask = self:AssignTask(isKillTask, index) self:RemoveTask(taskId) if not free then self:SubtractCredits(1) end + -- Reset their win state if they rerolled. + -- If they have already "won" and they are re-rolling, that means + -- they only had tasks left that don't block a win condition. + -- Rerolling one of those tasks no longer guarantees that they are winning, + -- unless the newly rolled task ALSO does not block a win condition. + if not newTask.allowRoundEnd and self.taskmasterShouldWin then + self:SetProperty("taskmasterShouldWin", false) + end + net.Start("TTT_TaskmasterUpdateTaskList") net.Send(self) end @@ -135,7 +144,24 @@ function plymeta:CompleteTask(taskId) break end end - if #activeTasksList == 0 then + + local tasksRemaining = #activeTasksList + for _, id in pairs(activeTasksList) do + local task = TASKMASTER.killTasks[id] + if not task then + task = TASKMASTER.miscTasks[id] + end + + if not task then continue end + + -- Tasks that allow the round to end should not count for this check + -- since the Taskmaster wins even if they are still active + if task.allowRoundEnd then + tasksRemaining = tasksRemaining - 1 + end + end + + if tasksRemaining <= 0 then self:SetProperty("taskmasterShouldWin", true) -- TODO: Alert the player that they have finished all their tasks end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua new file mode 100644 index 000000000..7626f3cdb --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua @@ -0,0 +1,38 @@ +local hook = hook + +local TASK = {} + +TASK.id = "survive" +TASK.allowRoundEnd = true + +TASK.Name = function(ply) + return "Survive" +end + +TASK.Description = function(ply) + return "Survive until the end of the round" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + hook.Add("TTTWinCheckComplete", "Taskmaster_Survive_TTTWinCheckComplete_" .. ply:SteamID64(), function(win) + if not IsPlayer(ply) then return end + if not ply:Alive() or ply:IsSpec() then return end + ply:CompleteTask(TASK.id) + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("TTTWinCheckComplete", "Taskmaster_Survive_TTTWinCheckComplete_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From bedc045ad40452273a8c1b810f04e915442dc04f Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 08:52:23 +0100 Subject: [PATCH 060/115] Added 'Kill Target' task --- .../{killairbourne.lua => killairborne.lua} | 24 ++-- .../roles/taskmaster/tasks/killtarget.lua | 114 ++++++++++++++++++ 2 files changed, 126 insertions(+), 12 deletions(-) rename gamemodes/terrortown/gamemode/roles/taskmaster/tasks/{killairbourne.lua => killairborne.lua} (58%) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairbourne.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua similarity index 58% rename from gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairbourne.lua rename to gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua index 4d87c05bc..f6af6821c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairbourne.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua @@ -3,11 +3,11 @@ local net = net local TASK = {} -TASK.id = "killairbourne" +TASK.id = "killairborne" TASK.isKillTask = true TASK.Name = function(ply) - return "Kill an Airbourne Player" + return "Kill an Airborne Player" end TASK.Description = function(ply) @@ -15,8 +15,8 @@ TASK.Description = function(ply) end if SERVER then - util.AddNetworkString("TTT_Taskmaster_KillAirbourne_Assigned") - util.AddNetworkString("TTT_Taskmaster_KillAirbourne_Cleanup") + util.AddNetworkString("TTT_Taskmaster_KillAirborne_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillAirborne_Cleanup") TASK.CanAssignTask = function(ply) return true @@ -27,7 +27,7 @@ if SERVER then } TASK.OnTaskAssigned = function(ply) - hook.Add("PlayerDeath", "Taskmaster_KillAirbourne_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + hook.Add("PlayerDeath", "Taskmaster_KillAirborne_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) if not IsPlayer(victim) then return end if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end @@ -36,13 +36,13 @@ if SERVER then end end) - net.Start("TTT_Taskmaster_KillAirbourne_Assigned") + net.Start("TTT_Taskmaster_KillAirborne_Assigned") net.Send(ply) end TASK.OnTaskRemoved = function(ply) - hook.Remove("PlayerDeath", "Taskmaster_KillAirbourne_PlayerDeath_" .. ply:SteamID64()) - net.Start("TTT_Taskmaster_KillAirbourne_Cleanup") + hook.Remove("PlayerDeath", "Taskmaster_KillAirborne_PlayerDeath_" .. ply:SteamID64()) + net.Start("TTT_Taskmaster_KillAirborne_Cleanup") net.Send(ply) end @@ -50,8 +50,8 @@ if SERVER then end if CLIENT then - net.Receive("TTT_Taskmaster_KillAirbourne_Assigned", function() - hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillAirbourne_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64(), function(ent, cli, text, col, secondaryText) + net.Receive("TTT_Taskmaster_KillAirborne_Assigned", function() + hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillAirborne_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64(), function(ent, cli, text, col, secondaryText) if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end if ent:OnGround() then @@ -62,8 +62,8 @@ if CLIENT then end) end) - net.Receive("TTT_Taskmaster_KillAirbourne_Cleanup", function() - hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillAirbourne_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64()) + net.Receive("TTT_Taskmaster_KillAirborne_Cleanup", function() + hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillAirborne_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64()) end) end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua new file mode 100644 index 000000000..75e072fc8 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua @@ -0,0 +1,114 @@ +local hook = hook +local net = net +local player = player +local util = util + +local TASK = {} + +TASK.id = "killtarget" +TASK.isKillTask = true + +TASK.Name = function(ply) + local name = "Target" + if IsPlayer(ply.Task_KillTargetPlayer) then + name = ply.Task_KillTargetPlayer:Nick() + end + return "Kill " .. name +end + +TASK.Description = function(ply) + local name = "target" + if IsPlayer(ply.Task_KillTargetPlayer) then + name = ply.Task_KillTargetPlayer:Nick() + end + return "Kill " .. name .. " by any means necessary" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_KillTarget_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillTarget_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON + } + + local function GetRandomTarget(ply) + -- Find the first random living player + for _, p in RandomPairs(player.GetAll()) do + if not p:Alive() or p:IsSpec() then continue end + if p == ply then continue end + return p + end + return nil + end + + TASK.OnTaskAssigned = function(ply) + local sid64 = ply:SteamID64() + + ply:SetProperty("Task_KillTargetPlayer", GetRandomTarget(ply), ply) + + hook.Add("PlayerDeath", "Taskmaster_KillTarget_PlayerDeath_" .. sid64, function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if victim == ply.Task_KillTargetPlayer then + ply:CompleteTask(TASK.id) + end + end) + + hook.Add("PostPlayerDeath", "Taskmaster_KillTarget_PostPlayerDeath_" .. sid64, function(victim) + if ply.Task_KillTargetPlayer ~= victim then return end + + local target = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. target:Nick()) + ply:SetProperty("Task_KillTargetPlayer", target, ply) + end) + + hook.Add("PlayerDisconnected", "Taskmaster_KillTarget_PlayerDisconnected_" .. sid64, function(leaver) + if ply.Task_KillTargetPlayer ~= leaver then return end + + local target = GetRandomTarget(ply) + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_KillTargetPlayer", target, ply) + end) + + net.Start("TTT_Taskmaster_KillTarget_Assigned") + net.Send(ply) + end + + TASK.OnTaskComplete = function(ply) + local sid64 = ply:SteamID64() + + hook.Remove("PlayerDeath", "Taskmaster_KillTarget_PlayerDeath_" .. sid64) + hook.Remove("PostPlayerDeath", "Taskmaster_KillTarget_PostPlayerDeath_" .. sid64) + hook.Remove("PlayerDisconnected", "Taskmaster_KillTarget_PlayerDisconnected_" .. sid64) + + net.Start("TTT_Taskmaster_KillTarget_Cleanup") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + TASK.OnTaskComplete(ply) + ply:ClearProperty("Task_KillTargetPlayer", ply) + end +end + +if CLIENT then + net.Receive("TTT_Taskmaster_KillTarget_Assigned", function() + hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_KillTarget_TTTTargetIDPlayerTargetIcon_" .. LocalPlayer():SteamID64(), function(ply, cli, showJester) + if cli:IsActiveTaskmaster() and ply == cli.Task_KillTargetPlayer then + return "task", true, ROLE_COLORS_SPRITE[ROLE_TASKMASTER], "down" + end + end) + end) + + net.Receive("TTT_Taskmaster_KillTarget_Cleanup", function() + hook.Remove("TTTTargetIDPlayerTargetIcon", "Taskmaster_KillTarget_TTTTargetIDPlayerTargetIcon_" .. LocalPlayer():SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 39c7e9a5257df0c45c1b0086671bfa243f5efbe5 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 09:04:34 +0100 Subject: [PATCH 061/115] Added 'Kill Kill a Player With a Pistol' task --- .../roles/taskmaster/tasks/killwithpistol.lua | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killwithpistol.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killwithpistol.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killwithpistol.lua new file mode 100644 index 000000000..d4f3cec4b --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killwithpistol.lua @@ -0,0 +1,41 @@ +local hook = hook + +local TASK = {} + +TASK.id = "killwithpistol" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Kill a Player With a Pistol" +end + +TASK.Description = function(ply) + return "Kill another player using a pistol" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillWithPistol_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if IsValid(inflictor) and inflictor:IsWeapon() and inflictor.Kind == WEAPON_PISTOL then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillWithPistol_PlayerDeath_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 1e0449cfc8d48bd02d089f582df14684259f0a22 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 09:12:50 +0100 Subject: [PATCH 062/115] Added 'Kill a Player While Aiming' task --- .../roles/taskmaster/tasks/killaiming.lua | 41 +++++++++++++++++++ .../{killwithpistol.lua => killpistol.lua} | 6 +-- 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killaiming.lua rename gamemodes/terrortown/gamemode/roles/taskmaster/tasks/{killwithpistol.lua => killpistol.lua} (76%) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killaiming.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killaiming.lua new file mode 100644 index 000000000..df6c34850 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killaiming.lua @@ -0,0 +1,41 @@ +local hook = hook + +local TASK = {} + +TASK.id = "killaiming" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Kill a Player While Aiming" +end + +TASK.Description = function(ply) + return "Kill another player while aiming down sights" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillAiming_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if IsValid(inflictor) and inflictor:IsWeapon() and inflictor.GetIronsights and inflictor:GetIronsights() then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillAiming_PlayerDeath_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killwithpistol.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killpistol.lua similarity index 76% rename from gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killwithpistol.lua rename to gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killpistol.lua index d4f3cec4b..e48b6a7a0 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killwithpistol.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killpistol.lua @@ -2,7 +2,7 @@ local hook = hook local TASK = {} -TASK.id = "killwithpistol" +TASK.id = "killpistol" TASK.isKillTask = true TASK.Name = function(ply) @@ -21,7 +21,7 @@ if SERVER then TASK.RequiredFeatures = {} TASK.OnTaskAssigned = function(ply) - hook.Add("PlayerDeath", "Taskmaster_KillWithPistol_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + hook.Add("PlayerDeath", "Taskmaster_KillPistol_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) if not IsPlayer(victim) then return end if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end @@ -32,7 +32,7 @@ if SERVER then end TASK.OnTaskRemoved = function(ply) - hook.Remove("PlayerDeath", "Taskmaster_KillWithPistol_PlayerDeath_" .. ply:SteamID64()) + hook.Remove("PlayerDeath", "Taskmaster_KillPistol_PlayerDeath_" .. ply:SteamID64()) end TASK.OnTaskComplete = TASK.OnTaskRemoved From 984f08f0aa35f1ecd543b0627a950e23cf8d9d3a Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 09:19:20 +0100 Subject: [PATCH 063/115] Added 'Kill a Player With Your Last Bullet' task --- .../roles/taskmaster/tasks/killlastbullet.lua | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua new file mode 100644 index 000000000..f8b5d6875 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua @@ -0,0 +1,43 @@ +local hook = hook + +local TASK = {} + +TASK.id = "killlastbullet" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Kill a Player With Your Last Bullet" +end + +TASK.Description = function(ply) + return "Kill another player with the last bullet in your gun's clip" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillLastBullet_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + timer.Simple(0, function() + if IsValid(inflictor) and inflictor:IsWeapon() and inflictor:GetMaxClip1() > 0 and inflictor:Clip1() == 0 then + ply:CompleteTask(TASK.id) + end + end) + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillLastBullet_PlayerDeath_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 360e391a5043aa853f3fad1b963df2c9acbbd401 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 09:27:41 +0100 Subject: [PATCH 064/115] Added 'Kill a Player With a Crowbar' task --- .../roles/taskmaster/tasks/killcrowbar.lua | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killcrowbar.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killcrowbar.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killcrowbar.lua new file mode 100644 index 000000000..9b6d4bc59 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killcrowbar.lua @@ -0,0 +1,41 @@ +local hook = hook + +local TASK = {} + +TASK.id = "killcrowbar" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Kill a Player With a Crowbar" +end + +TASK.Description = function(ply) + return "Kill another player using a crowbar" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillCrowbar_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if IsValid(inflictor) and inflictor:GetClass() == "weapon_zm_improvised" then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillCrowbar_PlayerDeath_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 2fe2830666fbe84c79c09c435163c45ed25e1b27 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 09:52:05 +0100 Subject: [PATCH 065/115] Added 'Kill a Player With a Headshot' task --- .../roles/taskmaster/tasks/killheadshot.lua | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killheadshot.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killheadshot.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killheadshot.lua new file mode 100644 index 000000000..e23785cec --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killheadshot.lua @@ -0,0 +1,59 @@ +local hook = hook +local player = player + +local PlayerIterator = player.Iterator + +local TASK = {} + +TASK.id = "killheadshot" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Kill a Player With a Headshot" +end + +TASK.Description = function(ply) + return "Kill another player by shooting them in the head" +end + +if SERVER then + TASK.CanAssignTask = function(ply) + local allHaveHeadbox = true + for _, p in PlayerIterator() do + local missingHeadbox = true + local set = p:GetHitboxSet() + for hitbox = 0, p:GetHitBoxCount(set) - 1 do + if p:GetHitBoxHitGroup(hitbox, set) == HITGROUP_HEAD then + missingHeadbox = false + break + end + end + if missingHeadbox then + allHaveHeadbox = false + break + end + end + return allHaveHeadbox + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillHeadshot_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if victim:GetNWBool("LastHitCrit") then + ply:CompleteTask(TASK.id) + end + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillHeadshot_PlayerDeath_" .. ply:SteamID64()) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 4168b20db4cf2bc565733faab3c68edddd5257ff Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 10:18:21 +0100 Subject: [PATCH 066/115] Added 'Kill a Player Who Attacked First' task --- .../roles/taskmaster/tasks/killretaliate.lua | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua new file mode 100644 index 000000000..40f1c7f27 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua @@ -0,0 +1,111 @@ +local hook = hook +local player = player + +local PlayerIterator = player.Iterator + +local TASK = {} + +TASK.id = "killretaliate" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Kill a Player Who Attacked First" +end + +TASK.Description = function(ply) + return "Kill another player who attacked you first" +end + +local TASK_KILLRETALIATE_NONE = 0 +local TASK_KILLRETALIATE_THEYATTACKED = 1 +local TASK_KILLRETALIATE_YOUATTACKED = 2 + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_KillRetaliate_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillRetaliate_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERTEXT + } + + TASK.OnTaskAssigned = function(ply) + + for _, p in PlayerIterator() do + if ply == p then continue end + p:SetProperty("Task_KillRetaliateAttacked", TASK_KILLRETALIATE_NONE, ply) + end + + local sid64 = ply:SteamID64() + + hook.Add("PlayerDeath", "Taskmaster_KillRetaliate_PlayerDeath_" .. sid64, function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if victim.Task_KillRetaliateAttacked == TASK_KILLRETALIATE_THEYATTACKED then + ply:CompleteTask(TASK.id) + end + end) + + hook.Add("PostEntityTakeDamage", "Taskmaster_KillRetaliate_PostEntityTakeDamage_" .. sid64, function(entity, dmginfo, wasDamageTaken) + if not wasDamageTaken then return end + if not IsPlayer(entity) then return end + + local attacker = dmginfo:GetAttacker() + if not IsPlayer(attacker) then return end + + if entity == ply and attacker.Task_KillRetaliateAttacked == TASK_KILLRETALIATE_NONE then + attacker:SetProperty("Task_KillRetaliateAttacked", TASK_KILLRETALIATE_THEYATTACKED, ply) + elseif attacker == ply and entity.Task_KillRetaliateAttacked == TASK_KILLRETALIATE_NONE then + entity:SetProperty("Task_KillRetaliateAttacked", TASK_KILLRETALIATE_YOUATTACKED, ply) + end + end) + + net.Start("TTT_Taskmaster_KillRetaliate_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + for _, p in PlayerIterator() do + if ply == p then continue end + p:ClearProperty("Task_KillRetaliateAttacked", ply) + end + + local sid64 = ply:SteamID64() + + hook.Remove("PlayerDeath", "Taskmaster_KillRetaliate_PlayerDeath_" .. sid64) + hook.Remove("PostEntityTakeDamage", "Taskmaster_KillRetaliate_PostEntityTakeDamage_" .. sid64) + + net.Start("TTT_Taskmaster_KillRetaliate_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_KillRetaliate_Assigned", function() + hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillRetaliate_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64(), function(ent, cli, text, col, secondaryText) + if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end + + local state = ent.Task_KillRetaliateAttacked + + if state == TASK_KILLRETALIATE_THEYATTACKED then + return "THEY ATTACKED FIRST", ROLE_COLORS_RADAR[ROLE_INNOCENT] + elseif state == TASK_KILLRETALIATE_YOUATTACKED then + return "YOU ATTACKED FIRST", ROLE_COLORS_RADAR[ROLE_TRAITOR] + else + return "HASN'T ATTACKED", ROLE_COLORS_RADAR[ROLE_TRAITOR] + end + end) + end) + + net.Receive("TTT_Taskmaster_KillRetaliate_Cleanup", function() + hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillRetaliate_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 04e0130ccac20254aa123781e9128abef2ca4fb4 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 10:34:04 +0100 Subject: [PATCH 067/115] Added 'Kill a Player in One Hit' task --- .../roles/taskmaster/tasks/killonehit.lua | 95 +++++++++++++++++++ .../roles/taskmaster/tasks/killretaliate.lua | 6 +- 2 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua new file mode 100644 index 000000000..1d20a0249 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua @@ -0,0 +1,95 @@ +local hook = hook +local player = player + +local PlayerIterator = player.Iterator + +local TASK = {} + +TASK.id = "killonehit" +TASK.isKillTask = true + +TASK.Name = function(ply) + return "Kill a Player in One Hit" +end + +TASK.Description = function(ply) + return "Kill another player with a single attack" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_KillOneHit_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillOneHit_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERTEXT + } + + TASK.OnTaskAssigned = function(ply) + local sid64 = ply:SteamID64() + + hook.Add("PlayerDeath", "Taskmaster_KillOneHit_PlayerDeath_" .. sid64, function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if not victim.Task_KillOneHitAttacked or victim.Task_KillOneHitAttacked + 0.1 > CurTime() then -- Allow for a very small delay to account for things such as shotgun pellets + ply:CompleteTask(TASK.id) + end + end) + + hook.Add("PostEntityTakeDamage", "Taskmaster_KillOneHit_PostEntityTakeDamage_" .. sid64, function(entity, dmginfo, wasDamageTaken) + if not wasDamageTaken then return end + if not IsPlayer(entity) then return end + + local attacker = dmginfo:GetAttacker() + if not IsPlayer(attacker) or attacker ~= ply then return end + + if not entity.Task_KillOneHitAttacked then + entity:SetProperty("Task_KillOneHitAttacked", CurTime(), ply) + end + end) + + net.Start("TTT_Taskmaster_KillOneHit_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + for _, p in PlayerIterator() do + if ply == p then continue end + p:ClearProperty("Task_KillOneHitAttacked", ply) + end + + local sid64 = ply:SteamID64() + + hook.Remove("PlayerDeath", "Taskmaster_KillOneHit_PlayerDeath_" .. sid64) + hook.Remove("PostEntityTakeDamage", "Taskmaster_KillOneHit_PostEntityTakeDamage_" .. sid64) + + net.Start("TTT_Taskmaster_KillOneHit_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_KillOneHit_Assigned", function() + hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillOneHit_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64(), function(ent, cli, text, col, secondaryText) + if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end + + if ent.Task_KillOneHitAttacked then + return "DAMAGED", ROLE_COLORS_RADAR[ROLE_TRAITOR] + else + return "UNHARMED", ROLE_COLORS_RADAR[ROLE_INNOCENT] + end + end) + end) + + net.Receive("TTT_Taskmaster_KillOneHit_Cleanup", function() + hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillOneHit_TTTTargetIDPlayerText_" .. LocalPlayer():SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua index 40f1c7f27..a1a12ff89 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua @@ -94,11 +94,11 @@ if CLIENT then local state = ent.Task_KillRetaliateAttacked if state == TASK_KILLRETALIATE_THEYATTACKED then - return "THEY ATTACKED FIRST", ROLE_COLORS_RADAR[ROLE_INNOCENT] + return "AGGRESSIVE", ROLE_COLORS_RADAR[ROLE_INNOCENT] elseif state == TASK_KILLRETALIATE_YOUATTACKED then - return "YOU ATTACKED FIRST", ROLE_COLORS_RADAR[ROLE_TRAITOR] + return "DEFENSIVE", ROLE_COLORS_RADAR[ROLE_TRAITOR] else - return "HASN'T ATTACKED", ROLE_COLORS_RADAR[ROLE_TRAITOR] + return "PASSIVE", ROLE_COLORS_RADAR[ROLE_TRAITOR] end end) end) From 5b228652749b8d81fdbacccdb45939fb152d5d87 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 10:54:05 +0100 Subject: [PATCH 068/115] Added 'Get a Double Kill' task --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/killdouble.lua | 110 ++++++++++++++++++ .../roles/taskmaster/tasks/killonehit.lua | 2 +- 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 2102738d2..5a0f148a2 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -21,6 +21,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") LANG.AddToLanguage("english", "taskmaster_holstered", "STAY HOLSTERED - {time}") + LANG.AddToLanguage("english", "taskmaster_killdouble", "KILL ANOTHER - {time}") LANG.AddToLanguage("english", "taskmaster_lookatplayer", "KEEP LOOKING - {time}") LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") LANG.AddToLanguage("english", "taskmaster_stayaway", "STAY AWAY - {time}") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua new file mode 100644 index 000000000..8fa6bb181 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua @@ -0,0 +1,110 @@ +local CurTime = CurTime +local hook = hook +local math = math +local net = net +local table = table +local util = util + +local MathMax = math.max + +local TASK = {} + +TASK.id = "killdouble" +TASK.isKillTask = true + +local taskmaster_killdouble_time = CreateConVar("ttt_taskmaster_killdouble_time", "5", FCVAR_REPLICATED, "The time (in seconds) the taskmaster has between kills to complete the 'Get a Double Kill' task", 0, 30) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_stayneartarget_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + return "Get a Double Kill" +end + +TASK.Description = function(ply) + local description = "Kill two players within " + + local time = taskmaster_killdouble_time:GetInt() + description = description .. time .. " second" + if time ~= 1 then + description = description .. "s" + end + return description .. " of each other" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_KillDouble_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillDouble_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + TASK.OnTaskAssigned = function(ply) + hook.Add("PlayerDeath", "Taskmaster_KillPistol_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if not ply.Task_KillDoubleLastKill or CurTime() > ply.Task_KillDoubleLastKill + taskmaster_killdouble_time:GetInt() then + ply:SetProperty("Task_KillDoubleLastKill", CurTime(), ply) + else + ply:CompleteTask(TASK.id) + end + end) + + net.Start("TTT_Taskmaster_KillDouble_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + ply:ClearProperty("Task_KillDoubleLastKill", ply) + + hook.Remove("PlayerDeath", "Taskmaster_KillPistol_PlayerDeath_" .. ply:SteamID64()) + + net.Start("TTT_Taskmaster_KillDouble_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_KillDouble_Assigned", function() + local client = LocalPlayer() + local time = taskmaster_killdouble_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_KillDouble_HUDPaint_" .. client:SteamID64(), function() + if not client:IsActiveTaskmaster() then return end + + local startTime = client.Task_KillDoubleLastKill + if not startTime or CurTime() > startTime + time then return end + + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + local message = PT("taskmaster_killdouble", { time = util.SimpleTime(remaining, "%02i:%02i") }) + local color = Color(25, 200, 25, 155) + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + local progress = elapsed / time + + CRHUD:PaintProgressBar(x, y, w, color, message, 1 - progress) + end) + end) + + net.Receive("TTT_Taskmaster_KillDouble_Cleanup", function() + hook.Remove("HUDPaint", "Taskmaster_KillDouble_HUDPaint_" .. LocalPlayer():SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua index 1d20a0249..e8c40ab81 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua @@ -35,7 +35,7 @@ if SERVER then if not IsPlayer(victim) then return end if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end - if not victim.Task_KillOneHitAttacked or victim.Task_KillOneHitAttacked + 0.1 > CurTime() then -- Allow for a very small delay to account for things such as shotgun pellets + if not victim.Task_KillOneHitAttacked or CurTime() < victim.Task_KillOneHitAttacked + 0.1 then -- Allow for a very small delay to account for things such as shotgun pellets ply:CompleteTask(TASK.id) end end) From 8b980be9a0dfd83d06e00e6ac3b06c8796458bdd Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 11:55:53 +0100 Subject: [PATCH 069/115] Added 'Kill a Player After a 360' task and fixed progress bar colour inconsistency --- .../gamemode/roles/shadow/cl_shadow.lua | 2 +- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/carrycorpse.lua | 2 +- .../roles/taskmaster/tasks/crouch.lua | 2 +- .../roles/taskmaster/tasks/crouchnearbody.lua | 2 +- .../roles/taskmaster/tasks/healthunder.lua | 2 +- .../roles/taskmaster/tasks/holstered.lua | 2 +- .../roles/taskmaster/tasks/kill360.lua | 174 ++++++++++++++++++ .../roles/taskmaster/tasks/killdouble.lua | 5 +- .../roles/taskmaster/tasks/lookatplayer.lua | 2 +- .../roles/taskmaster/tasks/standonplayer.lua | 2 +- .../roles/taskmaster/tasks/stayaway.lua | 2 +- .../roles/taskmaster/tasks/stayhidden.lua | 2 +- .../roles/taskmaster/tasks/stayhigher.lua | 2 +- .../roles/taskmaster/tasks/stayinarea.lua | 2 +- .../roles/taskmaster/tasks/staylower.lua | 2 +- .../roles/taskmaster/tasks/stayneartarget.lua | 2 +- .../roles/taskmaster/tasks/takedamage.lua | 2 +- 18 files changed, 192 insertions(+), 18 deletions(-) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua diff --git a/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua b/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua index ac7d4401e..697736341 100644 --- a/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua +++ b/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua @@ -492,7 +492,7 @@ AddHook("HUDPaint", "Shadow_HUDPaint", function() message = PT("shadow_buff_progress", { time = util.SimpleTime(remaining, "%02i:%02i") }) total = shadow_target_buff_delay:GetInt() - color = Color(25, 200, 25, 155) + color = Color(0, 255, 0, 155) end -- If we didn't get everything set, forget it diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 5a0f148a2..e877fb4ef 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -21,6 +21,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") LANG.AddToLanguage("english", "taskmaster_holstered", "STAY HOLSTERED - {time}") + LANG.AddToLanguage("english", "taskmaster_kill360", "KILL SOMEONE - {time}") LANG.AddToLanguage("english", "taskmaster_killdouble", "KILL ANOTHER - {time}") LANG.AddToLanguage("english", "taskmaster_lookatplayer", "KEEP LOOKING - {time}") LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua index a5a8ec5cd..9f15f7020 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -102,7 +102,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_carrycorpse", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 121f26b2b..de4a1fbdf 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -99,7 +99,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_crouch", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index 6c20ddf9d..a878e9f61 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -145,7 +145,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_crouchnearbody", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index 56c9f92e1..8375da54c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -103,7 +103,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_healthunder", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index 446d90f1b..412672efe 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -105,7 +105,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_holstered", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua new file mode 100644 index 000000000..4d474f62b --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua @@ -0,0 +1,174 @@ +local hook = hook +local math = math + +local MathAbs = math.abs +local MathMax = math.max + +local TASK = {} + +TASK.id = "kill360" +TASK.isKillTask = true + +local taskmaster_kill360_time = CreateConVar("ttt_taskmaster_kill360_time", "3", FCVAR_REPLICATED, "The time (in seconds) a player has after completing a 360 to kill a player for the 'Kill a Player After a 360' task", 1, 10) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_kill360_time", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) + +TASK.Name = function(ply) + return "Kill a Player After a 360" +end + +TASK.Description = function(ply) + local description = "Kill another player within " + local time = taskmaster_kill360_time:GetInt() + description = description .. time .. " second" + if time ~= 1 then + description = description .. "s" + end + return description .. " of turning 360 degrees" +end + +if SERVER then + util.AddNetworkString("TTT_Taskmaster_Kill360_Assigned") + util.AddNetworkString("TTT_Taskmaster_Kill360_Cleanup") + + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_PROGRESSBAR + } + + TASK.OnTaskAssigned = function(ply) + local sid64 = ply:SteamID64() + + ply.Task_Kill360LastAngle = ply:GetAimVector():Angle().y + ply.Task_Kill360RotationDecay = 0 + ply.Task_Kill360RotationClockwise = 0 + ply.Task_Kill360RotationCounterClockwise = 0 + ply.Task_Kill360RotationDirection = 1 + + hook.Add("PlayerDeath", "Taskmaster_Kill360_PlayerDeath_" .. sid64, function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if ply.Task_Kill360Start and CurTime() < ply.Task_Kill360Start + taskmaster_kill360_time:GetInt() then + ply:CompleteTask(TASK.id) + end + end) + + hook.Add("Think", "Taskmaster_Kill360_Think_" ..sid64, function() + local angle = ply:GetAimVector():Angle().y + local angleDiff = angle - ply.Task_Kill360LastAngle + while angleDiff > 180 do + angleDiff = angleDiff - 360 + end + while angleDiff < -180 do + angleDiff = angleDiff + 360 + end + ply.Task_Kill360LastAngle = angle + + if ply.Task_Kill360Start and CurTime() < ply.Task_Kill360Start + taskmaster_kill360_time:GetInt() then return end + + -- If the player is turning fast enough quickly decrease the decay value, otherwise slowly increase it + if MathAbs(angleDiff) > 5 then + ply.Task_Kill360RotationDecay = MathMax(ply.Task_Kill360RotationDecay - 0.3, 0); + else + ply.Task_Kill360RotationDecay = MathMax(ply.Task_Kill360RotationDecay + 0.015, 1.5); + end + ply.Task_Kill360RotationClockwise = MathMax(ply.Task_Kill360RotationClockwise + angleDiff - ply.Task_Kill360RotationDecay, 0) + ply.Task_Kill360RotationCounterClockwise = MathMax(ply.Task_Kill360RotationCounterClockwise - angleDiff - ply.Task_Kill360RotationDecay, 0) + + -- Smoothly transition if the player changes rotation direction + if ply.Task_Kill360RotationClockwise > ply.Task_Kill360RotationCounterClockwise and ply.Task_Kill360RotationDirection == -1 then + ply.Task_Kill360RotationDirection = 1 + ply.Task_Kill360RotationCounterClockwise = 0 + elseif ply.Task_Kill360RotationCounterClockwise > ply.Task_Kill360RotationClockwise and ply.Task_Kill360RotationDirection == 1 then + ply.Task_Kill360RotationDirection = -1 + ply.Task_Kill360RotationClockwise = 0 + end + + if ply.Task_Kill360RotationDirection == 1 then + ply:SetProperty("Task_Kill360Progress", ply.Task_Kill360RotationClockwise, ply) + else + ply:SetProperty("Task_Kill360Progress", ply.Task_Kill360RotationCounterClockwise, ply) + end + + -- Give the player a little bit of leeway so they don't need to reach exactly 360 degrees + if ply.Task_Kill360RotationClockwise > 320 or ply.Task_Kill360RotationCounterClockwise > 320 then + ply.Task_Kill360RotationClockwise = 0 + ply.Task_Kill360RotationCounterClockwise = 0 + ply:SetProperty("Task_Kill360Start", CurTime(), ply) + end + end) + + net.Start("TTT_Taskmaster_Kill360_Assigned") + net.Send(ply) + end + + TASK.OnTaskRemoved = function(ply) + ply:ClearProperty("Task_Kill360Start", ply) + ply:ClearProperty("Task_Kill360Progress", ply) + ply.Task_Kill360LastAngle = nil + ply.Task_Kill360RotationDecay = nil + ply.Task_Kill360RotationClockwise = nil + ply.Task_Kill360RotationCounterClockwise = nil + ply.Task_Kill360RotationDirection = nil + + local sid64 = ply:SteamID64() + + hook.Remove("PlayerDeath", "Taskmaster_Kill360_PlayerDeath_" .. sid64) + hook.Remove("Think", "Taskmaster_Kill360_Think_" .. sid64) + + net.Start("TTT_Taskmaster_Kill360_Cleanup") + net.Send(ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +if CLIENT then + net.Receive("TTT_Taskmaster_Kill360_Assigned", function() + local client = LocalPlayer() + local time = taskmaster_kill360_time:GetInt() + + hook.Add("HUDPaint", "Taskmaster_Kill360_HUDPaint_" .. client:SteamID64(), function() + if not client:IsActiveTaskmaster() then return end + + local progress + local message + local color + + local startTime = client.Task_Kill360Start + if not startTime or CurTime() > startTime + time then + progress = client.Task_Kill360Progress / 320 + message = "DO A 360" + color = Color(255, 0, 0, 155) + else + local PT = LANG.GetParamTranslation + local elapsed = MathMax(0, CurTime() - startTime) + local remaining = time - elapsed + progress = 1 - (elapsed / time) + message = PT("taskmaster_kill360", { time = util.SimpleTime(remaining, "%02i:%02i") }) + color = Color(0, 255, 0, 155) + end + + local x = ScrW() / 2.0 + local y = ScrH() / 2.0 + y = y + (y / 3) + + local w = 300 + + CRHUD:PaintProgressBar(x, y, w, color, message, progress) + end) + end) + + net.Receive("TTT_Taskmaster_Kill360_Cleanup", function() + hook.Remove("HUDPaint", "Taskmaster_Kill360_HUDPaint_" .. LocalPlayer():SteamID64()) + end) +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua index 8fa6bb181..27bf51538 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua @@ -14,7 +14,7 @@ TASK.isKillTask = true local taskmaster_killdouble_time = CreateConVar("ttt_taskmaster_killdouble_time", "5", FCVAR_REPLICATED, "The time (in seconds) the taskmaster has between kills to complete the 'Get a Double Kill' task", 0, 30) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { - cvar = "ttt_taskmaster_stayneartarget_time", + cvar = "ttt_taskmaster_killdouble_time", type = ROLE_CONVAR_TYPE_NUM, decimal = 0 }) @@ -25,7 +25,6 @@ end TASK.Description = function(ply) local description = "Kill two players within " - local time = taskmaster_killdouble_time:GetInt() description = description .. time .. " second" if time ~= 1 then @@ -89,7 +88,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_killdouble", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index 0c4d9b711..d04b04edf 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -152,7 +152,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_lookatplayer", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index 9c2b19cce..79a9c4595 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -100,7 +100,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_standonplayer", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua index 055b9a832..855825820 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua @@ -133,7 +133,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_stayaway", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua index b3c9ae4ee..e8e141d8e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua @@ -115,7 +115,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_stayhidden", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index c3c02966f..76b1d0c6b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -124,7 +124,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_stayhigher", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index e53fb1b18..3d51939ef 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -166,7 +166,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_stayinarea", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index febcd63dc..c55673fdc 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -124,7 +124,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_staylower", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 493959139..6e86ae50d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -246,7 +246,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_stayneartarget", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua index c48785d98..c95d59785 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua @@ -94,7 +94,7 @@ if CLIENT then local elapsed = MathMax(0, CurTime() - startTime) local remaining = time - elapsed local message = PT("taskmaster_takedamage", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(25, 200, 25, 155) + local color = Color(0, 255, 0, 155) local x = ScrW() / 2.0 local y = ScrH() / 2.0 From 4a3a7492673beadf877dc09e1f2c88d39f00e809 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 13:13:01 +0100 Subject: [PATCH 070/115] Added 'Kill a Player With a Specific Weapon' task (almost) --- .../roles/taskmaster/tasks/killweapon.lua | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua new file mode 100644 index 000000000..9c6af7650 --- /dev/null +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua @@ -0,0 +1,106 @@ +local hook = hook +local table = table +local math = math + +local TableInsert = table.insert +local MathRandom = math.random + +local TryTranslation = LANG.TryTranslation + +local TASK = {} + +TASK.id = "killweapon" +TASK.isKillTask = true + +TASK.Name = function(ply) + local weapon = "Specific Weapon" + if ply.Task_KillWeaponClass then + local wep = util.WeaponForClass(wep) + if IsValid(wep) then + weapon = TryTranslation(wep.GetPrintName and wep:GetPrintName() or wep.PrintName) + end + end + return "Kill a Player With a " .. weapon +end + +TASK.Description = function(ply) + local weapon = "specific weapon" + if ply.Task_KillWeaponClass then + local wep = util.WeaponForClass(wep) + if IsValid(wep) then + weapon = TryTranslation(wep.GetPrintName and wep:GetPrintName() or wep.PrintName) + end + end + return "Kill another player using a " .. weapon +end + +if SERVER then + TASK.CanAssignTask = function(ply) + return true + end + + TASK.RequiredFeatures = {} + + TASK.OnTaskAssigned = function(ply) + local weps = {} + for _, wep in ipairs(weapons.GetList()) do + if wep.AutoSpawnable and wep.Kind == WEAPON_HEAVY and wep.Primary and wep.Primary.ClipMax and wep.Primary.Ammo and wep.Primary.Damage then + TableInsert(weps, wep) + end + end + ply:SetProperty("Task_KillWeaponClass", weps[MathRandom(#weps)].ClassName, ply) + + local equipped = false + if ply:GetActiveWeapon().Kind == WEAPON_HEAVY then + equipped = true + end + + for _, wep in pairs(ply:GetWeapons()) do + if wep.Kind == WEAPON_HEAVY then + ply:StripWeapon(wep:GetClass()) + end + end + + local weapon = ply:Give(ply.Task_KillWeaponClass) + local ammoMax = weapon.Primary.ClipMax + local ammoType = weapon.Primary.Ammo + weapon.AllowDrop = false + + if equipped then + ply:SetFOV(0, 0.2) + ply:SelectWeapon(ply.Task_KillWeaponClass) + end + + local sid64 = ply:SteamID64() + + hook.Add("PlayerDeath", "Taskmaster_KillWeapon_PlayerDeath_" .. sid64, function(victim, inflictor, attacker) + if not IsPlayer(victim) then return end + if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + + if IsValid(inflictor) and inflictor:IsWeapon() and inflictor:GetClass() == ply.Task_KillWeaponClass then + ply:CompleteTask(TASK.id) + end + end) + + hook.Add("Think", "Taskmaster_KillWeapon_Think_" ..sid64, function() + ply:SetAmmo(ammoMax, ammoType) + end) + end + + TASK.OnTaskRemoved = function(ply) + hook.Remove("PlayerDeath", "Taskmaster_KillWeapon_PlayerDeath_" .. ply:SteamID64()) + hook.Remove("Think", "Taskmaster_KillWeapon_Think_" .. ply:SteamID64()) + + for _, wep in pairs(ply:GetWeapons()) do + if wep:GetClass() == ply.Task_KillWeaponClass then + wep.AllowDrop = true + end + end + + ply:ClearProperty("Task_KillWeaponClass", ply) + end + + TASK.OnTaskComplete = TASK.OnTaskRemoved +end + +TASKMASTER.RegisterTask(TASK) \ No newline at end of file From 40c5b16d246754c05f63f3bb71884286019dd908 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Sun, 17 Aug 2025 14:51:28 +0100 Subject: [PATCH 071/115] Misc changes --- .../roles/taskmaster/cl_taskmaster.lua | 1 + .../roles/taskmaster/tasks/calldetective.lua | 2 +- .../roles/taskmaster/tasks/carrycorpse.lua | 18 +- .../gamemode/roles/taskmaster/tasks/chat.lua | 18 +- .../roles/taskmaster/tasks/crouch.lua | 16 +- .../roles/taskmaster/tasks/crouchnearbody.lua | 19 ++- .../roles/taskmaster/tasks/crowbar.lua | 22 ++- .../roles/taskmaster/tasks/damageeveryone.lua | 24 ++- .../roles/taskmaster/tasks/dodamage.lua | 20 ++- .../roles/taskmaster/tasks/firebullets.lua | 18 +- .../taskmaster/tasks/getplayerkilled.lua | 50 ++++-- .../taskmaster/tasks/getplayertokill.lua | 52 +++--- .../roles/taskmaster/tasks/healthunder.lua | 17 +- .../roles/taskmaster/tasks/holstered.lua | 14 +- .../gamemode/roles/taskmaster/tasks/jump.lua | 20 ++- .../{killfaraway.lua => killdistant.lua} | 38 ++--- .../roles/taskmaster/tasks/killretaliate.lua | 4 +- .../roles/taskmaster/tasks/killtarget.lua | 47 +++--- .../roles/taskmaster/tasks/killweapon.lua | 16 +- .../roles/taskmaster/tasks/lookatplayer.lua | 59 +++++-- .../roles/taskmaster/tasks/pickupshopitem.lua | 4 +- .../roles/taskmaster/tasks/standonplayer.lua | 18 +- .../roles/taskmaster/tasks/stayaway.lua | 155 ------------------ .../roles/taskmaster/tasks/stayhidden.lua | 19 ++- .../roles/taskmaster/tasks/stayhigher.lua | 16 +- .../roles/taskmaster/tasks/stayinarea.lua | 16 +- .../roles/taskmaster/tasks/staylower.lua | 16 +- .../roles/taskmaster/tasks/stayneartarget.lua | 59 +++++-- .../roles/taskmaster/tasks/takedamage.lua | 20 ++- .../roles/taskmaster/tasks/weaponpickups.lua | 18 +- 30 files changed, 484 insertions(+), 332 deletions(-) rename gamemodes/terrortown/gamemode/roles/taskmaster/tasks/{killfaraway.lua => killdistant.lua} (78%) delete mode 100644 gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index e877fb4ef..b5ed18a9a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -16,6 +16,7 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_credit_bonus", "{role}, you have been awarded {num} credit(s) for completing a task.") -- Tasks + -- TODO: Create init method for tasks and move these into task files LANG.AddToLanguage("english", "taskmaster_carrycorpse", "CARRY CORPSE - {time}") LANG.AddToLanguage("english", "taskmaster_crouchnearbody", "CROUCH NEAR BODY - {time}") LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/calldetective.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/calldetective.lua index 40922233e..18dc36f31 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/calldetective.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/calldetective.lua @@ -3,7 +3,7 @@ local TASK = {} TASK.id = "calldetective" TASK.Name = function(ply) - return "Call Detective to Body" + return "Call a Detective to a Body" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua index 9f15f7020..39184cbc2 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -7,6 +7,7 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local TASK = {} @@ -21,16 +22,27 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_carrycorpse_time:GetInt() - local name = "Carry Corpse for " .. time .. " Second" + local name = "Carry a Corpse for " .. time .. " Second" if time ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_CarryCorpseStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) local time = taskmaster_carrycorpse_time:GetInt() - local desc = "Carry a player corpse for " .. time .. " second" + local desc = "Carry a dead player's corpse for " .. time .. " second" if time ~= 1 then desc = desc .. "s consecutively" end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua index 5385f4e6b..1526fac38 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua @@ -15,7 +15,15 @@ TASK.Name = function(ply) if times ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = times + else + progress = ply.Task_ChatCount + end + + return name .. " (" .. progress .. "/" .. times .. ")" end TASK.Description = function(ply) @@ -36,14 +44,14 @@ if SERVER then TASK.OnTaskAssigned = function(ply) local times = taskmaster_chat_times:GetInt() - local count = 0 + ply:SetProperty("Task_ChatCount", 0, ply) hook.Add("PlayerSay", "Taskmaster_Chat_PlayerSay_" .. ply:SteamID64(), function(sender, text, teamChat) if not IsPlayer(sender) then return end if sender ~= ply then return end if not ply:Alive() or ply:IsSpec() then return end - count = count + 1 - if count >= times then + ply:SetProperty("Task_ChatCount", ply.Task_ChatCount + 1, ply) + if ply.Task_ChatCount >= times then ply:CompleteTask(TASK.id) end end) @@ -51,6 +59,8 @@ if SERVER then TASK.OnTaskRemoved = function(ply) hook.Remove("PlayerSay", "Taskmaster_Chat_PlayerSay_" .. ply:SteamID64()) + + ply:ClearProperty("Task_ChatCount", ply) end TASK.OnTaskComplete = TASK.OnTaskRemoved diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index de4a1fbdf..85cc4f517 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -7,12 +7,13 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local TASK = {} TASK.id = "crouch" -local taskmaster_crouch_time = CreateConVar("ttt_taskmaster_crouch_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay crouched to complete the 'Crouch Near Body' task", 1, 240) +local taskmaster_crouch_time = CreateConVar("ttt_taskmaster_crouch_time", "40", FCVAR_REPLICATED, "The time (in seconds) a player must stay crouched to complete the 'Crouch Near Body' task", 1, 240) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_crouch_time", type = ROLE_CONVAR_TYPE_NUM, @@ -25,7 +26,18 @@ TASK.Name = function(ply) if time ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_CrouchStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index a878e9f61..958a2afaf 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -10,13 +10,14 @@ local util = util local EntsFindByClass = ents.FindByClass local MathMax = math.max +local MathFloor = math.floor local TASK = {} TASK.id = "crouchnearbody" local taskmaster_crouchnearbody_range = CreateConVar("ttt_taskmaster_crouchnearbody_range", "1", FCVAR_REPLICATED, "The distance (in meters) away a player must stay within to count for the 'Crouch Near Body' task", 1, 100) -local taskmaster_crouchnearbody_time = CreateConVar("ttt_taskmaster_crouchnearbody_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay near a body to count for the 'Crouch Near Body' task", 1, 240) +local taskmaster_crouchnearbody_time = CreateConVar("ttt_taskmaster_crouchnearbody_time", "20", FCVAR_REPLICATED, "The time (in seconds) a player must stay near a body to count for the 'Crouch Near Body' task", 1, 240) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_crouchnearbody_range", type = ROLE_CONVAR_TYPE_NUM, @@ -29,7 +30,19 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { }) TASK.Name = function(ply) - return "Crouch Near Body" + local time = taskmaster_crouchnearbody_time:GetInt() + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_CrouchNearBodyStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return "Crouch Near a Body (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) @@ -62,7 +75,7 @@ TASK.Description = function(ply) end end local time = taskmaster_crouchnearbody_time:GetInt() - description = description .. " of a body for " .. time .. " second" + description = description .. " of a dead body for " .. time .. " second" if time == 1 then return description end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua index 6e9dce28e..b6e3b096c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua @@ -13,16 +13,24 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local times = taskmaster_crowbar_times:GetInt() - local name = "Swing Crowbar " .. times .. " Time" + local name = "Swing a Crowbar " .. times .. " Time" if times ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = times + else + progress = ply.Task_CrowbarCount + end + + return name .. " (" .. progress .. "/" .. times .. ")" end TASK.Description = function(ply) local times = taskmaster_crowbar_times:GetInt() - local desc = "Use the crowbar weapon " .. times .. " time" + local desc = "Attack with a crowbar " .. times .. " time" if times ~= 1 then desc = desc .. "s" end @@ -40,12 +48,12 @@ if SERVER then if wep.Task_CrowbarPrimaryAttack then return end local times = taskmaster_crowbar_times:GetInt() - local total = 0 + ply:SetProperty("Task_CrowbarCount", 0, ply) wep.Task_CrowbarPrimaryAttack = wep.PrimaryAttack wep.PrimaryAttack = function(this, worldsnd) wep.Task_CrowbarPrimaryAttack(wep, worldsnd) - total = total + 1 - if total >= times then + ply:SetProperty("Task_CrowbarCount", ply.Task_CrowbarCount + 1, ply) + if ply.Task_CrowbarCount >= times then ply:CompleteTask(TASK.id) end end @@ -83,6 +91,8 @@ if SERVER then local sid64 = ply:SteamID64() hook.Remove("WeaponEquip", "Taskmaster_Crowbar_WeaponEquip_" .. sid64) hook.Remove("PlayerDroppedWeapon", "Taskmaster_Crowbar_PlayerDroppedWeapon_" .. sid64) + + ply:ClearProperty("Task_CrowbarCount", ply) end TASK.OnTaskComplete = TASK.OnTaskRemoved diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua index 21cf87801..21b58f946 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua @@ -14,11 +14,27 @@ local TASK = {} TASK.id = "damageeveryone" TASK.Name = function(ply) - return "Damage All Players" + local damaged = ply.Task_DamageEveryoneDamaged or {} + local total = 0 + local progress = 0 + for _, p in PlayerIterator() do + if ply == p then continue end + if not p:Alive() or p:IsSpec() then continue end + total = total + 1 + if TableHasValue(damaged, p:SteamID64()) then + progress = progress + 1 + end + end + + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = total + end + + return "Damage Everyone Else (" .. progress .. "/" .. total .. ")" end TASK.Description = function(ply) - return "Damage all other living players" + return "Deal damage to all other living players" end if SERVER then @@ -86,8 +102,8 @@ if CLIENT then local client = LocalPlayer() hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_DamageEveryone_TTTTargetIDPlayerTargetIcon_" .. client:SteamID64(), function(ply, cli, showJester) if cli:IsActiveTaskmaster() and not TableHasValue(cli.Task_DamageEveryoneDamaged, ply:SteamID64()) then - local iconColor = ROLE_COLORS_SPRITE[ROLE_TRAITOR] - return "task", true, iconColor, "up" + local iconColor = ROLE_COLORS_SPRITE[ROLE_TASKMASTER] + return "task", true, iconColor, "down" end end) end) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua index 52006f54b..fdda1a945 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua @@ -11,12 +11,20 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local amount = taskmaster_dodamage_amount:GetInt() - return "Do " .. amount .. " Damage" + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = amount + else + progress = ply.Task_DoDamageTotal + end + + return "Deal " .. amount .. " Damage (" .. progress .. "/" .. amount .. ")" end TASK.Description = function(ply) local amount = taskmaster_dodamage_amount:GetInt() - return "Do " .. amount .. " damage to props and other players" + return "Deal " .. amount .. " damage to props and other players" end if SERVER then @@ -28,7 +36,7 @@ if SERVER then TASK.OnTaskAssigned = function(ply) local amount = taskmaster_dodamage_amount:GetInt() - local total = 0 + ply:SetProperty("Task_DoDamageTotal", 0, ply) hook.Add("PostEntityTakeDamage", "Taskmaster_DoDamage_PostEntityTakeDamage_" .. ply:SteamID64(), function(entity, dmginfo, wasDamageTaken) if not wasDamageTaken then return end if entity == ply then return end @@ -36,8 +44,8 @@ if SERVER then local attacker = dmginfo:GetAttacker() if not IsPlayer(attacker) or attacker ~= ply then return end - total = total + dmginfo:GetDamage() - if total >= amount then + ply:SetProperty("Task_DoDamageTotal", ply.Task_DoDamageTotal + dmginfo:GetDamage(), ply) + if ply.Task_DoDamageTotal >= amount then ply:CompleteTask(TASK.id) end end) @@ -45,6 +53,8 @@ if SERVER then TASK.OnTaskRemoved = function(ply) hook.Remove("PostEntityTakeDamage", "Taskmaster_DoDamage_PostEntityTakeDamage_" .. ply:SteamID64()) + + ply:ClearProperty("Task_DoDamageTotal", ply) end TASK.OnTaskComplete = TASK.OnTaskRemoved diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua index c699ec543..b4be58a5b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua @@ -15,7 +15,15 @@ TASK.Name = function(ply) if times ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = times + else + progress = ply.Task_FireBulletsCount + end + + return name .. " (" .. progress .. "/" .. times .. ")" end TASK.Description = function(ply) @@ -36,12 +44,12 @@ if SERVER then TASK.OnTaskAssigned = function(ply) local times = taskmaster_firebullets_times:GetInt() - local count = 0 + ply:SetProperty("Task_FireBulletsCount", 0, ply) hook.Add("PostEntityFireBullets", "Taskmaster_FireBullets_PostEntityFireBullets_" .. ply:SteamID64(), function(entity, data) if not IsPlayer(entity) then return end if entity ~= ply then return end - count = count + 1 - if count >= times then + ply:SetProperty("Task_FireBulletsCount", ply.Task_FireBulletsCount + 1, ply) + if ply.Task_FireBulletsCount >= times then ply:CompleteTask(TASK.id) end end) @@ -49,6 +57,8 @@ if SERVER then TASK.OnTaskRemoved = function(ply) hook.Remove("PostEntityFireBullets", "Taskmaster_FireBullets_PostEntityFireBullets_" .. ply:SteamID64()) + + ply:ClearProperty("Task_FireBulletsCount", ply) end TASK.OnTaskComplete = TASK.OnTaskRemoved diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua index 5fdbad5f3..218779c27 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua @@ -21,21 +21,13 @@ TASK.Description = function(ply) name = ply.Task_GetPlayerKilledPlayer:Nick() end - return "Get " .. name .. " killed by another player" + return "Get " .. name .. " killed by another player (not you)" end if SERVER then util.AddNetworkString("TTT_Taskmaster_GetPlayerKilled_Assigned") util.AddNetworkString("TTT_Taskmaster_GetPlayerKilled_Cleanup") - TASK.CanAssignTask = function(ply) - return true - end - - TASK.RequiredFeatures = { - TASKMASTER_TF_TARGETID_PLAYERICON - } - local function GetRandomTarget(ply) -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do @@ -46,32 +38,51 @@ if SERVER then return nil end + TASK.CanAssignTask = function(ply) + return GetRandomTarget(ply) ~= nil + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON + } + TASK.OnTaskAssigned = function(ply) ply:SetProperty("Task_GetPlayerKilledPlayer", GetRandomTarget(ply), ply) hook.Add("PlayerDeath", "Taskmaster_GetPlayerKilled_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) if ply.Task_GetPlayerKilledPlayer ~= victim then return end - if attacker == ply then return end - ply:CompleteTask(TASK.id) + if attacker == ply then + local target = GetRandomTarget(ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "You killed your target for the '" .. TASK.Name(ply) .. "' task! Your new target is " .. target:Nick()) + ply:SetProperty("Task_GetPlayerKilledPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "You killed your target for the '" .. TASK.Name(ply) .. "' task! There are no new valid targets and you must reroll.") + end + else + ply:CompleteTask(TASK.id) + end end) hook.Add("PlayerDisconnected", "Taskmaster_GetPlayerKilled_PlayerDisconnected_" .. ply:SteamID64(), function(leaver) if ply.Task_GetPlayerKilledPlayer ~= leaver then return end local target = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) - ply:SetProperty("Task_GetPlayerKilledPlayer", target, ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_GetPlayerKilledPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! There are no new valid targets and you must reroll.") + end end) net.Start("TTT_Taskmaster_GetPlayerKilled_Assigned") net.Send(ply) end - TASK.OnTaskRemoved = function(ply) + TASK.OnTaskComplete = function(ply) timer.Remove("TTTTaskmasterGetPlayerKilledTimer") - ply:ClearProperty("Task_GetPlayerKilledPlayer", ply) - hook.Remove("PlayerDeath", "Taskmaster_GetPlayerKilled_PlayerDeath_" .. ply:SteamID64()) hook.Remove("PlayerDisconnected", "Taskmaster_GetPlayerKilled_PlayerDisconnected_" .. ply:SteamID64()) @@ -79,7 +90,10 @@ if SERVER then net.Send(ply) end - TASK.OnTaskComplete = TASK.OnTaskRemoved + TASK.OnTaskRemoved = function(ply) + TASK.OnTaskComplete(ply) + ply:ClearProperty("Task_GetPlayerKilledPlayer", ply) -- Don't clear the player name if the task was completed so it still shows up in the task name/description + end end if CLIENT then @@ -87,7 +101,7 @@ if CLIENT then local client = LocalPlayer() hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_GetPlayerKilled_TTTTargetIDPlayerTargetIcon_" .. client:SteamID64(), function(ply, cli, showJester) if cli:IsActiveTaskmaster() and ply == cli.Task_GetPlayerKilledPlayer then - local iconColor = ROLE_COLORS_SPRITE[ROLE_TRAITOR] + local iconColor = ROLE_COLORS_SPRITE[ROLE_TASKMASTER] return "task", true, iconColor, "up" end end) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua index 4c7442c96..42b242322 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua @@ -21,21 +21,13 @@ TASK.Description = function(ply) name = ply.Task_GetPlayerToKillPlayer:Nick() end - return "Get " .. name .. " to kill another player" + return "Get " .. name .. " to kill another player (not you)" end if SERVER then util.AddNetworkString("TTT_Taskmaster_GetPlayerToKill_Assigned") util.AddNetworkString("TTT_Taskmaster_GetPlayerToKill_Cleanup") - TASK.CanAssignTask = function(ply) - return true - end - - TASK.RequiredFeatures = { - TASKMASTER_TF_TARGETID_PLAYERICON - } - local function GetRandomTarget(ply) -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do @@ -46,32 +38,51 @@ if SERVER then return nil end + TASK.CanAssignTask = function(ply) + return GetRandomTarget(ply) ~= nil + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON + } + TASK.OnTaskAssigned = function(ply) ply:SetProperty("Task_GetPlayerToKillPlayer", GetRandomTarget(ply), ply) hook.Add("PlayerDeath", "Taskmaster_GetPlayerToKill_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) - if ply.Task_GetPlayerToKillPlayer ~= attacker then return end - if victim == ply then return end - ply:CompleteTask(TASK.id) + if ply.Task_GetPlayerToKillPlayer == attacker and attacker ~= victim then + if victim == ply then return end + ply:CompleteTask(TASK.id) + elseif ply.Task_GetPlayerToKillPlayer == victim then + local target = GetRandomTarget(ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. target:Nick()) + ply:SetProperty("Task_GetPlayerToKillPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! There are no new valid targets and you must reroll.") + end + end end) hook.Add("PlayerDisconnected", "Taskmaster_GetPlayerToKill_PlayerDisconnected_" .. ply:SteamID64(), function(leaver) if ply.Task_GetPlayerToKillPlayer ~= leaver then return end local target = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) - ply:SetProperty("Task_GetPlayerToKillPlayer", target, ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_GetPlayerToKillPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! There are no new valid targets and you must reroll.") + end end) net.Start("TTT_Taskmaster_GetPlayerToKill_Assigned") net.Send(ply) end - TASK.OnTaskRemoved = function(ply) + TASK.OnTaskComplete = function(ply) timer.Remove("TTTTaskmasterGetPlayerToKillTimer") - ply:ClearProperty("Task_GetPlayerToKillPlayer", ply) - hook.Remove("PlayerDeath", "Taskmaster_GetPlayerToKill_PlayerDeath_" .. ply:SteamID64()) hook.Remove("PlayerDisconnected", "Taskmaster_GetPlayerToKill_PlayerDisconnected_" .. ply:SteamID64()) @@ -79,7 +90,10 @@ if SERVER then net.Send(ply) end - TASK.OnTaskComplete = TASK.OnTaskRemoved + TASK.OnTaskRemoved = function(ply) + TASK.OnTaskComplete(ply) + ply:ClearProperty("Task_GetPlayerToKillPlayer", ply) -- Don't clear the player name if the task was completed so it still shows up in the task name/description + end end if CLIENT then @@ -87,7 +101,7 @@ if CLIENT then local client = LocalPlayer() hook.Add("TTTTargetIDPlayerTargetIcon", "Taskmaster_GetPlayerToKill_TTTTargetIDPlayerTargetIcon_" .. client:SteamID64(), function(ply, cli, showJester) if cli:IsActiveTaskmaster() and ply == cli.Task_GetPlayerToKillPlayer then - local iconColor = ROLE_COLORS_SPRITE[ROLE_TRAITOR] + local iconColor = ROLE_COLORS_SPRITE[ROLE_TASKMASTER] return "task", true, iconColor, "up" end end) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index 8375da54c..877fcca71 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -7,6 +7,7 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local TASK = {} @@ -27,13 +28,25 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local amount = taskmaster_healthunder_amount:GetInt() - return "Stay Under " .. amount .. " HP" + local time = taskmaster_healthunder_time:GetInt() + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_HealthUnderStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return "Survive Under " .. amount .. " Health (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) local time = taskmaster_healthunder_time:GetInt() local amount = taskmaster_healthunder_amount:GetInt() - local desc = "Stay under " .. amount .. " health for " .. time .. " second" + local desc = "Survive under " .. amount .. " health for " .. time .. " second" if time ~= 1 then desc = desc .. "s" end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index 412672efe..f09e556de 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -7,6 +7,7 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local TASK = {} @@ -25,7 +26,18 @@ TASK.Name = function(ply) if time ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_HolsteredStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua index 59a8ea293..d769f1189 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -2,7 +2,7 @@ local TASK = {} TASK.id = "jump" -local taskmaster_jump_times = CreateConVar("ttt_taskmaster_jump_times", "25", FCVAR_REPLICATED, "The jump of times a player must jump to complete the 'Jump X Times' task", 1, 100) +local taskmaster_jump_times = CreateConVar("ttt_taskmaster_jump_times", "100", FCVAR_REPLICATED, "The jump of times a player must jump to complete the 'Jump X Times' task", 1, 500) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_jump_times", type = ROLE_CONVAR_TYPE_NUM, @@ -15,7 +15,15 @@ TASK.Name = function(ply) if times ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = times + else + progress = ply.Task_CrowbarCount + end + + return name .. " (" .. progress .. "/" .. times .. ")" end TASK.Description = function(ply) @@ -36,12 +44,12 @@ if SERVER then TASK.OnTaskAssigned = function(ply) local times = taskmaster_jump_times:GetInt() - local count = 0 + ply:SetProperty("Task_JumpCount", 0, ply) hook.Add("OnPlayerJump", "Taskmaster_Jump_OnPlayerJump_" .. ply:SteamID64(), function(caller) if not IsPlayer(caller) then return end if caller ~= ply then return end - count = count + 1 - if count >= times then + ply:SetProperty("Task_JumpCount", ply.Task_JumpCount + 1, ply) + if ply.Task_JumpCount >= times then ply:CompleteTask(TASK.id) end end) @@ -49,6 +57,8 @@ if SERVER then TASK.OnTaskRemoved = function(ply) hook.Remove("OnPlayerJump", "Taskmaster_Jump_OnPlayerJump_" .. ply:SteamID64()) + + ply:ClearProperty("Task_JumpCount", ply) end TASK.OnTaskComplete = TASK.OnTaskRemoved diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua similarity index 78% rename from gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua rename to gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua index 9ce441172..a49844331 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killfaraway.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua @@ -12,18 +12,18 @@ local MathSin = math.sin local TASK = {} -TASK.id = "killfaraway" +TASK.id = "killdistant" TASK.isKillTask = true -local taskmaster_killfaraway_range = CreateConVar("ttt_taskmaster_killfaraway_range", "25", FCVAR_REPLICATED, "The minimum distance (in meters) away a player can be to count for the 'Kill a Faraway Player' task", 0, 100) +local taskmaster_killdistant_range = CreateConVar("ttt_taskmaster_killdistant_range", "25", FCVAR_REPLICATED, "The minimum distance (in meters) away a player can be to count for the 'Kill a Distant Player' task", 0, 100) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { - cvar = "ttt_taskmaster_killfaraway_range", + cvar = "ttt_taskmaster_killdistant_range", type = ROLE_CONVAR_TYPE_NUM, decimal = 0 }) TASK.Name = function(ply) - return "Kill a Faraway Player" + return "Kill a Distant Player" end TASK.Description = function(ply) @@ -33,7 +33,7 @@ TASK.Description = function(ply) else unit = cvars.Number("ttt_distance_unit", 1) end - local range = taskmaster_killfaraway_range:GetInt() + local range = taskmaster_killdistant_range:GetInt() local description = "Kill another player from outside " if unit == 1 then description = description .. range .. " meter" @@ -59,8 +59,8 @@ TASK.Description = function(ply) end if SERVER then - util.AddNetworkString("TTT_Taskmaster_KillFaraway_Assigned") - util.AddNetworkString("TTT_Taskmaster_KillFaraway_Cleanup") + util.AddNetworkString("TTT_Taskmaster_KillDistant_Assigned") + util.AddNetworkString("TTT_Taskmaster_KillDistant_Cleanup") TASK.CanAssignTask = function(ply) return true @@ -72,12 +72,12 @@ if SERVER then } TASK.OnTaskAssigned = function(ply) - hook.Add("PlayerDeath", "Taskmaster_KillFaraway_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + hook.Add("PlayerDeath", "Taskmaster_KillDistant_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) if not IsPlayer(victim) then return end if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end local distanceSqr = victim:GetPos():DistToSqr(attacker:GetPos()) - local range = taskmaster_killfaraway_range:GetInt() * UNITS_PER_METER + local range = taskmaster_killdistant_range:GetInt() * UNITS_PER_METER local rangeSqr = range * range if distanceSqr >= rangeSqr then @@ -85,13 +85,13 @@ if SERVER then end end) - net.Start("TTT_Taskmaster_KillFaraway_Assigned") + net.Start("TTT_Taskmaster_KillDistant_Assigned") net.Send(ply) end TASK.OnTaskRemoved = function(ply) - hook.Remove("PlayerDeath", "Taskmaster_KillFaraway_PlayerDeath_" .. ply:SteamID64()) - net.Start("TTT_Taskmaster_KillFaraway_Cleanup") + hook.Remove("PlayerDeath", "Taskmaster_KillDistant_PlayerDeath_" .. ply:SteamID64()) + net.Start("TTT_Taskmaster_KillDistant_Cleanup") net.Send(ply) end @@ -99,12 +99,12 @@ if SERVER then end if CLIENT then - net.Receive("TTT_Taskmaster_KillFaraway_Assigned", function() + net.Receive("TTT_Taskmaster_KillDistant_Assigned", function() local sid64 = LocalPlayer():SteamID64() - local range = taskmaster_killfaraway_range:GetInt() * UNITS_PER_METER + local range = taskmaster_killdistant_range:GetInt() * UNITS_PER_METER local rangeSqr = range * range - hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillFaraway_TTTTargetIDPlayerText_" .. sid64, function(ent, cli, text, col, secondaryText) + hook.Add("TTTTargetIDPlayerText", "Taskmaster_KillDistant_TTTTargetIDPlayerText_" .. sid64, function(ent, cli, text, col, secondaryText) if not cli:IsActiveTaskmaster() or not IsPlayer(ent) then return end local distanceSqr = ent:GetPos():DistToSqr(cli:GetPos()) @@ -116,7 +116,7 @@ if CLIENT then end) local particleVelocity = Vector(0, 0, 80) - hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillFaraway_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) + hook.Add("TTTPlayerAliveClientThink", "Taskmaster_KillDistant_TTTPlayerAliveClientThink_" .. sid64, function(cli, ply) local shouldDraw = false if ply == cli and cli:IsActiveTaskmaster() then local pos = ply:GetPos() @@ -154,11 +154,11 @@ if CLIENT then end) end) - net.Receive("TTT_Taskmaster_KillFaraway_Cleanup", function() + net.Receive("TTT_Taskmaster_KillDistant_Cleanup", function() local client = LocalPlayer() local sid64 = client:SteamID64() - hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillFaraway_TTTTargetIDPlayerText_" .. sid64) - hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_KillFaraway_TTTPlayerAliveClientThink_" .. sid64) + hook.Remove("TTTTargetIDPlayerText", "Taskmaster_KillDistant_TTTTargetIDPlayerText_" .. sid64) + hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_KillDistant_TTTPlayerAliveClientThink_" .. sid64) if client.TaskmasterRadiusEmitter then client.TaskmasterRadiusEmitter:Finish() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua index a1a12ff89..43052091d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua @@ -9,11 +9,11 @@ TASK.id = "killretaliate" TASK.isKillTask = true TASK.Name = function(ply) - return "Kill a Player Who Attacked First" + return "Kill a Player That Attacked First" end TASK.Description = function(ply) - return "Kill another player who attacked you first" + return "Kill another player that attacked you first" end local TASK_KILLRETALIATE_NONE = 0 diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua index 75e072fc8..4c49238a9 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua @@ -28,24 +28,25 @@ if SERVER then util.AddNetworkString("TTT_Taskmaster_KillTarget_Assigned") util.AddNetworkString("TTT_Taskmaster_KillTarget_Cleanup") - TASK.CanAssignTask = function(ply) - return true - end - - TASK.RequiredFeatures = { - TASKMASTER_TF_TARGETID_PLAYERICON - } - local function GetRandomTarget(ply) -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do if not p:Alive() or p:IsSpec() then continue end + if p:ShouldActLikeJester() then continue end if p == ply then continue end return p end return nil end + TASK.CanAssignTask = function(ply) + return GetRandomTarget(ply) ~= nil + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON + } + TASK.OnTaskAssigned = function(ply) local sid64 = ply:SteamID64() @@ -53,27 +54,31 @@ if SERVER then hook.Add("PlayerDeath", "Taskmaster_KillTarget_PlayerDeath_" .. sid64, function(victim, inflictor, attacker) if not IsPlayer(victim) then return end - if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end + if victim ~= ply.Task_KillTargetPlayer then return end - if victim == ply.Task_KillTargetPlayer then + if IsPlayer(attacker) and attacker:IsActiveTaskmaster() and attacker == ply then ply:CompleteTask(TASK.id) + else + local target = GetRandomTarget(ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. target:Nick()) + ply:SetProperty("Task_KillTargetPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! There are no new valid targets and you must reroll.") + end end end) - hook.Add("PostPlayerDeath", "Taskmaster_KillTarget_PostPlayerDeath_" .. sid64, function(victim) - if ply.Task_KillTargetPlayer ~= victim then return end - - local target = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. target:Nick()) - ply:SetProperty("Task_KillTargetPlayer", target, ply) - end) - hook.Add("PlayerDisconnected", "Taskmaster_KillTarget_PlayerDisconnected_" .. sid64, function(leaver) if ply.Task_KillTargetPlayer ~= leaver then return end local target = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) - ply:SetProperty("Task_KillTargetPlayer", target, ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_KillTargetPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! There are no new valid targets and you must reroll.") + end end) net.Start("TTT_Taskmaster_KillTarget_Assigned") @@ -93,7 +98,7 @@ if SERVER then TASK.OnTaskRemoved = function(ply) TASK.OnTaskComplete(ply) - ply:ClearProperty("Task_KillTargetPlayer", ply) + ply:ClearProperty("Task_KillTargetPlayer", ply) -- Don't clear the player name if the task was completed so it still shows up in the task name/description end end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua index 9c6af7650..c2d14e392 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua @@ -15,9 +15,11 @@ TASK.isKillTask = true TASK.Name = function(ply) local weapon = "Specific Weapon" if ply.Task_KillWeaponClass then - local wep = util.WeaponForClass(wep) - if IsValid(wep) then - weapon = TryTranslation(wep.GetPrintName and wep:GetPrintName() or wep.PrintName) + for _, wep in ipairs(weapons.GetList()) do + if ply.Task_KillWeaponClass == WEPS.GetClass(wep) then + weapon = TryTranslation(wep.PrintName) + break + end end end return "Kill a Player With a " .. weapon @@ -26,9 +28,11 @@ end TASK.Description = function(ply) local weapon = "specific weapon" if ply.Task_KillWeaponClass then - local wep = util.WeaponForClass(wep) - if IsValid(wep) then - weapon = TryTranslation(wep.GetPrintName and wep:GetPrintName() or wep.PrintName) + for _, wep in ipairs(weapons.GetList()) do + if ply.Task_KillWeaponClass == WEPS.GetClass(wep) then + weapon = TryTranslation(wep.PrintName) + break + end end end return "Kill another player using a " .. weapon diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index d04b04edf..6087c8ef5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -7,6 +7,7 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local TASK = {} @@ -24,7 +25,19 @@ TASK.Name = function(ply) if IsPlayer(ply.Task_LookAtPlayerPlayer) then name = ply.Task_LookAtPlayerPlayer:Nick() end - return "Look at " .. name + + local time = taskmaster_lookatplayer_time:GetInt() + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_LookAtPlayerStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return "Look at " .. name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) @@ -44,15 +57,6 @@ if SERVER then util.AddNetworkString("TTT_Taskmaster_LookAtPlayer_Assigned") util.AddNetworkString("TTT_Taskmaster_LookAtPlayer_Cleanup") - TASK.CanAssignTask = function(ply) - return true - end - - TASK.RequiredFeatures = { - TASKMASTER_TF_TARGETID_PLAYERICON, - TASKMASTER_TF_PROGRESSBAR - } - local function GetRandomTarget(ply) -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do @@ -63,6 +67,15 @@ if SERVER then return nil end + TASK.CanAssignTask = function(ply) + return GetRandomTarget(ply) ~= nil + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON, + TASKMASTER_TF_PROGRESSBAR + } + local function IsTargetInView(ply) if not IsValid(ply) then return false end @@ -96,23 +109,33 @@ if SERVER then hook.Add("PlayerDeath", "Taskmaster_LookAtPlayer_PlayerDeath_" .. sid64, function(victim, inflictor, attacker) if ply.Task_LookAtPlayerPlayer ~= victim then return end - if attacker == ply then return end - ply:CompleteTask(TASK.id) + + local target = GetRandomTarget(ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. target:Nick()) + ply:SetProperty("Task_LookAtPlayerPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! There are no new valid targets and you must reroll.") + end end) hook.Add("PlayerDisconnected", "Taskmaster_LookAtPlayer_PlayerDisconnected_" .. sid64, function(leaver) if ply.Task_LookAtPlayerPlayer ~= leaver then return end local target = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) - ply:SetProperty("Task_LookAtPlayerPlayer", target, ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_LookAtPlayerPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! There are no new valid targets and you must reroll.") + end end) net.Start("TTT_Taskmaster_LookAtPlayer_Assigned") net.Send(ply) end - TASK.OnTaskRemoved = function(ply) + TASK.OnTaskComplete = function(ply) timer.Remove("TTTTaskmasterLookAtPlayerTimer") local sid64 = ply:SteamID64() @@ -120,13 +143,15 @@ if SERVER then hook.Remove("PlayerDisconnected", "Taskmaster_LookAtPlayer_PlayerDisconnected_" .. sid64) ply:ClearProperty("Task_LookAtPlayerStart", ply) - ply:ClearProperty("Task_LookAtPlayerPlayer", ply) net.Start("TTT_Taskmaster_LookAtPlayer_Cleanup") net.Send(ply) end - TASK.OnTaskComplete = TASK.OnTaskRemoved + TASK.OnTaskRemoved = function(ply) + TASK.OnTaskComplete(ply) + ply:ClearProperty("Task_LookAtPlayerPlayer", ply) -- Don't clear the player name if the task was completed so it still shows up in the task name/description + end end if CLIENT then diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua index 16bb0298f..00c6aca33 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/pickupshopitem.lua @@ -3,11 +3,11 @@ local TASK = {} TASK.id = "pickupshopitem" TASK.Name = function(ply) - return "Pick up Shop Item" + return "Pick up a Shop Item" end TASK.Description = function(ply) - return "Pick up a shop item dropped on the ground" + return "Pick up a shop item that another player dropped on the ground" end if SERVER then diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index 79a9c4595..d740e09db 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -7,12 +7,13 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local TASK = {} TASK.id = "standonplayer" -local taskmaster_standonplayer_time = CreateConVar("ttt_taskmaster_standonplayer_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay stand on top of another player to complete the 'Stand On Player' task", 1, 240) +local taskmaster_standonplayer_time = CreateConVar("ttt_taskmaster_standonplayer_time", "15", FCVAR_REPLICATED, "The time (in seconds) a player must stay stand on top of another player to complete the 'Stand On Player' task", 1, 240) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_standonplayer_time", type = ROLE_CONVAR_TYPE_NUM, @@ -21,11 +22,22 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_standonplayer_time:GetInt() - local name = "Stand on Player for " .. time .. " Second" + local name = "Stand on a Player for " .. time .. " Second" if time ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_StandOnPlayerStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua deleted file mode 100644 index 855825820..000000000 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayaway.lua +++ /dev/null @@ -1,155 +0,0 @@ -local CurTime = CurTime -local hook = hook -local math = math -local net = net -local player = player -local table = table -local timer = timer -local util = util - -local MathMax = math.max -local PlayerIterator = player.Iterator - -local TASK = {} - -TASK.id = "stayaway" - -local taskmaster_stayaway_range = CreateConVar("ttt_taskmaster_stayaway_range", "25", FCVAR_REPLICATED, "The distance (in meters) a player must stay away from other people to count for the 'Stay Away' task", 1, 100) -local taskmaster_stayaway_time = CreateConVar("ttt_taskmaster_stayaway_time", "30", FCVAR_REPLICATED, "The time (in seconds) a player must stay away from other people to count for the 'Stay Away' task", 1, 240) -table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { - cvar = "ttt_taskmaster_stayaway_range", - type = ROLE_CONVAR_TYPE_NUM, - decimal = 0 -}) -table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { - cvar = "ttt_taskmaster_stayaway_time", - type = ROLE_CONVAR_TYPE_NUM, - decimal = 0 -}) - -TASK.Name = function(ply) - local time = taskmaster_stayaway_time:GetInt() - local name = "Stay Away for " .. time .. " Second" - if time ~= 1 then - name = name .. "s" - end - return name -end - -TASK.Description = function(ply) - local time = taskmaster_stayaway_time:GetInt() - local desc = "Stay away from other players for " .. time .. " second" - if time ~= 1 then - desc = desc .. "s" - end - return desc -end - -if SERVER then - util.AddNetworkString("TTT_Taskmaster_StayAway_Assigned") - util.AddNetworkString("TTT_Taskmaster_StayAway_Cleanup") - - TASK.CanAssignTask = function(ply) - return true - end - - TASK.RequiredFeatures = { - TASKMASTER_TF_PROGRESSBAR - } - - local function GetNearestPlayer(ply) - local pos = ply:GetPos() - local nearest = nil - for _, p in PlayerIterator() do - if p == ply then continue end - if not p:Alive() or p:IsSpec() then continue end - - local dist = pos:DistToSqr(p:GetPos()) - if not nearest or dist < nearest.dist then - nearest = { - ply = p, - dist = dist - } - end - end - - return nearest - end - - TASK.OnTaskAssigned = function(ply) - local range = taskmaster_stayaway_range:GetInt() * UNITS_PER_METER - local rangeSqr = range * range - local time = taskmaster_stayaway_time:GetInt() - timer.Create("TTTTaskmasterStayAwayTimer", 0.1, 0, function() - if not IsPlayer(ply) then return end - - -- Within range - local nearest = GetNearestPlayer(ply) - if ply:Alive() and not ply:IsSpec() and nearest.dist >= rangeSqr then - -- Just starting - if not ply.Task_StayAwayStart then - ply:SetProperty("Task_StayAwayStart", CurTime(), ply) - -- Long enough - elseif CurTime() > ply.Task_StayAwayStart + time then - ply:CompleteTask(TASK.id) - end - -- Not within range - else - ply:ClearProperty("Task_StayAwayStart", ply) - end - end) - - net.Start("TTT_Taskmaster_StayAway_Assigned") - net.Send(ply) - end - - TASK.OnTaskRemoved = function(ply) - timer.Remove("TTTTaskmasterStayAwayTimer") - - ply:ClearProperty("Task_StayAwayLocation", ply) - ply:ClearProperty("Task_StayAwayStart", ply) - - hook.Remove("PostPlayerDeath", "Taskmaster_StayAway_PostPlayerDeath_" .. ply:SteamID64()) - - net.Start("TTT_Taskmaster_StayAway_Cleanup") - net.Send(ply) - end - - TASK.OnTaskComplete = TASK.OnTaskRemoved -end - -if CLIENT then - net.Receive("TTT_Taskmaster_StayAway_Assigned", function() - local client = LocalPlayer() - local time = taskmaster_stayaway_time:GetInt() - - hook.Add("HUDPaint", "Taskmaster_StayAway_HUDPaint_" .. client:SteamID64(), function() - if not client:IsActiveTaskmaster() then return end - - local startTime = client.Task_StayAwayStart - if not startTime then return end - - local PT = LANG.GetParamTranslation - local elapsed = MathMax(0, CurTime() - startTime) - local remaining = time - elapsed - local message = PT("taskmaster_stayaway", { time = util.SimpleTime(remaining, "%02i:%02i") }) - local color = Color(0, 255, 0, 155) - - local x = ScrW() / 2.0 - local y = ScrH() / 2.0 - y = y + (y / 3) - - local w = 300 - local progress = elapsed / time - - CRHUD:PaintProgressBar(x, y, w, color, message, progress) - end) - end) - - net.Receive("TTT_Taskmaster_StayAway_Cleanup", function() - local client = LocalPlayer() - hook.Remove("HUDPaint", "Taskmaster_StayAway_HUDPaint_" .. client:SteamID64()) - end) -end - -TASKMASTER.RegisterTask(TASK) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua index e8e141d8e..4c465513f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua @@ -8,6 +8,7 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local PlayerIterator = player.Iterator local TASK = {} @@ -22,7 +23,23 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { }) TASK.Name = function(ply) - return "Stay Hidden" + local time = taskmaster_stayhidden_time:GetInt() + local name = "Stay Hidden for " .. time .. " Second" + if time ~= 1 then + name = name .. "s" + end + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_StayHiddenStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index 76b1d0c6b..66959e616 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -8,6 +8,7 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local PlayerIterator = player.Iterator local TASK = {} @@ -23,11 +24,22 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_stayhigher_time:GetInt() - local name = "Highest for " .. time .. " Second" + local name = "Be Highest for " .. time .. " Second" if time ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_StayHigherStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index 3d51939ef..d6b9f3cd8 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -11,6 +11,7 @@ local MathMax = math.max local MathPi = math.pi local MathRand = math.Rand local MathSin = math.sin +local MathFloor = math.floor local TASK = {} @@ -35,7 +36,18 @@ TASK.Name = function(ply) if time ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_StayInAreaStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) @@ -156,6 +168,8 @@ if CLIENT then end end) + -- TODO: Needs a visual to help locate the area if you can't immediately see it. Maybe copy the same thing we have for the shadow? + hook.Add("HUDPaint", "Taskmaster_StayInArea_HUDPaint_" .. sid64, function() if not client:IsActiveTaskmaster() then return end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index c55673fdc..91dfcacd2 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -8,6 +8,7 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local PlayerIterator = player.Iterator local TASK = {} @@ -23,11 +24,22 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_staylower_time:GetInt() - local name = "Lowest for " .. time .. " Second" + local name = "Be Lowest for " .. time .. " Second" if time ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_StayLowerStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 6e86ae50d..744df5c41 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -13,6 +13,7 @@ local MathMax = math.max local MathPi = math.pi local MathRand = math.Rand local MathSin = math.sin +local MathFloor = math.floor local TASK = {} @@ -36,7 +37,19 @@ TASK.Name = function(ply) if IsPlayer(ply.Task_StayNearTargetPlayer) then name = ply.Task_StayNearTargetPlayer:Nick() end - return "Stay Near " .. name + + local time = taskmaster_stayneartarget_time:GetInt() + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_StayNearTargetStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return "Stay Near " .. name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) @@ -86,16 +99,6 @@ if SERVER then util.AddNetworkString("TTT_Taskmaster_StayNearTarget_Assigned") util.AddNetworkString("TTT_Taskmaster_StayNearTarget_Cleanup") - TASK.CanAssignTask = function(ply) - return true - end - - TASK.RequiredFeatures = { - TASKMASTER_TF_TARGETID_PLAYERICON, - TASKMASTER_TF_PROGRESSBAR, - TASKMASTER_TF_PARTICLERADIUS - } - local function GetRandomTarget(ply) -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do @@ -106,6 +109,16 @@ if SERVER then return nil end + TASK.CanAssignTask = function(ply) + return GetRandomTarget(ply) ~= nil + end + + TASK.RequiredFeatures = { + TASKMASTER_TF_TARGETID_PLAYERICON, + TASKMASTER_TF_PROGRESSBAR, + TASKMASTER_TF_PARTICLERADIUS + } + TASK.OnTaskAssigned = function(ply) local sid64 = ply:SteamID64() local range = taskmaster_stayneartarget_range:GetInt() * UNITS_PER_METER @@ -137,26 +150,33 @@ if SERVER then if ply.Task_StayNearTargetPlayer ~= victim then return end local target = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. target:Nick()) - ply:SetProperty("Task_StayNearTargetPlayer", target, ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! Your new target is " .. target:Nick()) + ply:SetProperty("Task_StayNearTargetPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has died! There are no new valid targets and you must reroll.") + end end) hook.Add("PlayerDisconnected", "Taskmaster_StayNearTarget_PlayerDisconnected_" .. sid64, function(leaver) if ply.Task_StayNearTargetPlayer ~= leaver then return end local target = GetRandomTarget(ply) - ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) - ply:SetProperty("Task_StayNearTargetPlayer", target, ply) + if target then + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! Your new target is " .. target:Nick()) + ply:SetProperty("Task_StayNearTargetPlayer", target, ply) + else + ply:QueueMessage(MSG_PRINTBOTH, "Your target for the '" .. TASK.Name(ply) .. "' task has disappeared! There are no new valid targets and you must reroll.") + end end) net.Start("TTT_Taskmaster_StayNearTarget_Assigned") net.Send(ply) end - TASK.OnTaskRemoved = function(ply) + TASK.OnTaskComplete = function(ply) timer.Remove("TTTTaskmasterStayNearTargetTimer") - ply:ClearProperty("Task_StayNearTargetPlayer", ply) ply:ClearProperty("Task_StayNearTargetStart", ply) hook.Remove("PostPlayerDeath", "Taskmaster_StayNearTarget_PostPlayerDeath_" .. ply:SteamID64()) @@ -166,7 +186,10 @@ if SERVER then net.Send(ply) end - TASK.OnTaskComplete = TASK.OnTaskRemoved + TASK.OnTaskRemoved = function(ply) + TASK.OnTaskComplete(ply) + ply:ClearProperty("Task_StayNearTargetPlayer", ply) -- Don't clear the player name if the task was completed so it still shows up in the task name/description + end end if CLIENT then diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua index c95d59785..f574f174a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua @@ -7,6 +7,7 @@ local timer = timer local util = util local MathMax = math.max +local MathFloor = math.floor local TASK = {} @@ -20,12 +21,23 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { }) TASK.Name = function(ply) - return "Take Damage" + local time = taskmaster_takedamage_time:GetInt() + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = time + else + local startTime = ply.Task_TakeDamageStart + if startTime then + progress = MathFloor(MathMax(0, CurTime() - startTime)) + end + end + + return "Take Damage and Survive (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) local time = taskmaster_takedamage_time:GetInt() - local desc = "Take damage and survive for " .. time .. " second" + local desc = "Get another player to deal damage to you and survive for " .. time .. " second" if time ~= 1 then desc = desc .. "s" end @@ -58,6 +70,10 @@ if SERVER then hook.Add("PostEntityTakeDamage", "Taskmaster_TakeDamage_PostEntityTakeDamage_" .. ply:SteamID64(), function(entity, dmginfo, wasDamageTaken) if not wasDamageTaken then return end if entity ~= ply then return end + + local attacker = dmginfo:GetAttacker() + if not IsPlayer(attacker) or attacker == entity then return end + ply:SetProperty("Task_TakeDamageStart", CurTime(), ply) end) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua index 07f255b46..1b2c5e28d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua @@ -17,7 +17,15 @@ TASK.Name = function(ply) if count ~= 1 then name = name .. "s" end - return name + + local progress = 0 + if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + progress = count + else + progress = ply.Task_WeaponPickupsCount + end + + return name .. " (" .. progress .. "/" .. count .. ")" end TASK.Description = function(ply) @@ -38,14 +46,14 @@ if SERVER then TASK.OnTaskAssigned = function(ply) local count = taskmaster_weaponpickups_count:GetInt() - local total = 0 + ply:SetProperty("Task_WeaponPickupsCount", 0, ply) hook.Add("WeaponEquip", "Taskmaster_WeaponPickup_WeaponEquip_" .. ply:SteamID64(), function(wep, owner) if owner ~= ply then return end if not IsValid(wep) then return end if wep.Task_WeaponPickupsUsed then return end wep.Task_WeaponPickupsUsed = true - total = total + 1 - if total >= count then + ply:SetProperty("Task_WeaponPickupsCount", ply.Task_WeaponPickupsCount + 1, ply) + if ply.Task_WeaponPickupsCount >= count then ply:CompleteTask(TASK.id) end end) @@ -53,6 +61,8 @@ if SERVER then TASK.OnTaskRemoved = function(ply) hook.Remove("WeaponEquip", "Taskmaster_WeaponPickup_WeaponEquip_" .. ply:SteamID64()) + + ply:ClearProperty("Task_WeaponPickupsCount", ply) end TASK.OnTaskComplete = TASK.OnTaskRemoved From 6f7be995dade80fa754aad4f9bf6415fe97d7b23 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 10:32:46 -0400 Subject: [PATCH 072/115] Cleanup --- .../gamemode/roles/taskmaster/tasks/carrycorpse.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/chat.lua | 7 ++++++- .../gamemode/roles/taskmaster/tasks/crouch.lua | 3 ++- .../roles/taskmaster/tasks/crouchnearbody.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/crowbar.lua | 5 ++++- .../roles/taskmaster/tasks/damageeveryone.lua | 2 +- .../gamemode/roles/taskmaster/tasks/dodamage.lua | 7 ++++++- .../gamemode/roles/taskmaster/tasks/firebullets.lua | 7 ++++++- .../roles/taskmaster/tasks/getplayerkilled.lua | 13 +++++++++++-- .../roles/taskmaster/tasks/getplayertokill.lua | 13 +++++++++++-- .../gamemode/roles/taskmaster/tasks/healthunder.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/holstered.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/jump.lua | 7 ++++++- .../gamemode/roles/taskmaster/tasks/kill360.lua | 2 ++ .../roles/taskmaster/tasks/killlastbullet.lua | 1 + .../roles/taskmaster/tasks/killretaliate.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/killtarget.lua | 2 +- .../gamemode/roles/taskmaster/tasks/killweapon.lua | 6 ++++-- .../roles/taskmaster/tasks/lookatplayer.lua | 3 ++- .../roles/taskmaster/tasks/standonplayer.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/stayhidden.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/stayhigher.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/stayinarea.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/staylower.lua | 3 ++- .../roles/taskmaster/tasks/stayneartarget.lua | 3 ++- .../gamemode/roles/taskmaster/tasks/takedamage.lua | 3 ++- .../roles/taskmaster/tasks/weaponpickups.lua | 7 +++++-- 27 files changed, 92 insertions(+), 29 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua index 39184cbc2..2905c6346 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -8,6 +8,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -28,7 +29,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_CarryCorpseStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua index 1526fac38..2a31ec6c8 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua @@ -1,3 +1,8 @@ +local hook = hook +local table = table + +local TableHasValue = table.HasValue + local TASK = {} TASK.id = "chat" @@ -17,7 +22,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times else progress = ply.Task_ChatCount diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 85cc4f517..27a73c0c5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -8,6 +8,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -28,7 +29,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_CrouchStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index 958a2afaf..6fecedc4a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -11,6 +11,7 @@ local util = util local EntsFindByClass = ents.FindByClass local MathMax = math.max local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -33,7 +34,7 @@ TASK.Name = function(ply) local time = taskmaster_crouchnearbody_time:GetInt() local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_CrouchNearBodyStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua index b6e3b096c..414766b3b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua @@ -1,5 +1,8 @@ +local hook = hook local table = table +local TableHasValue = table.HasValue + local TASK = {} TASK.id = "crowbar" @@ -19,7 +22,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times else progress = ply.Task_CrowbarCount diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua index 21b58f946..841990b1a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua @@ -26,7 +26,7 @@ TASK.Name = function(ply) end end - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = total end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua index fdda1a945..e7024846b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua @@ -1,3 +1,8 @@ +local hook = hook +local table = table + +local TableHasValue = table.HasValue + local TASK = {} TASK.id = "dodamage" @@ -13,7 +18,7 @@ TASK.Name = function(ply) local amount = taskmaster_dodamage_amount:GetInt() local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = amount else progress = ply.Task_DoDamageTotal diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua index b4be58a5b..ef6671c1d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua @@ -1,3 +1,8 @@ +local hook = hook +local table = table + +local TableHasValue = table.HasValue + local TASK = {} TASK.id = "firebullets" @@ -17,7 +22,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times else progress = ply.Task_FireBulletsCount diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua index 218779c27..e487f109e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua @@ -29,13 +29,22 @@ if SERVER then util.AddNetworkString("TTT_Taskmaster_GetPlayerKilled_Cleanup") local function GetRandomTarget(ply) + local passive = nil -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do - if not p:Alive() or p:IsSpec() then continue end if p == ply then continue end + if not p:Alive() or p:IsSpec() then continue end + if p:ShouldActLikeJester() then continue end + -- They just want live, leave them alone + if ROLE_HAS_PASSIVE_WIN[p:GetRole()] then + passive = p + continue + end return p end - return nil + + -- Return the passive winner (if we have one) as a last resort + return passive end TASK.CanAssignTask = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua index 42b242322..48997cc7a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua @@ -29,13 +29,22 @@ if SERVER then util.AddNetworkString("TTT_Taskmaster_GetPlayerToKill_Cleanup") local function GetRandomTarget(ply) + local passive = nil -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do - if not p:Alive() or p:IsSpec() then continue end if p == ply then continue end + if not p:Alive() or p:IsSpec() then continue end + if p:ShouldActLikeJester() then continue end + -- They just want live, they aren't going to kill anyone + if ROLE_HAS_PASSIVE_WIN[p:GetRole()] then + passive = p + continue + end return p end - return nil + + -- Return the passive winner (if we have one) as a last resort + return passive end TASK.CanAssignTask = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index 877fcca71..926536737 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -8,6 +8,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -31,7 +32,7 @@ TASK.Name = function(ply) local time = taskmaster_healthunder_time:GetInt() local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_HealthUnderStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index f09e556de..e12b7e3c9 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -8,6 +8,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -28,7 +29,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_HolsteredStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua index d769f1189..ac909a7a5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -1,3 +1,8 @@ +local hook = hook +local table = table + +local TableHasValue = table.HasValue + local TASK = {} TASK.id = "jump" @@ -17,7 +22,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times else progress = ply.Task_CrowbarCount diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua index 4d474f62b..fa3b17adf 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua @@ -1,5 +1,7 @@ local hook = hook local math = math +local table = table +local util = util local MathAbs = math.abs local MathMax = math.max diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua index f8b5d6875..820417906 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua @@ -1,4 +1,5 @@ local hook = hook +local timer = timer local TASK = {} diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua index 43052091d..80ee20c65 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua @@ -1,5 +1,7 @@ local hook = hook +local net = net local player = player +local util = util local PlayerIterator = player.Iterator @@ -33,7 +35,6 @@ if SERVER then } TASK.OnTaskAssigned = function(ply) - for _, p in PlayerIterator() do if ply == p then continue end p:SetProperty("Task_KillRetaliateAttacked", TASK_KILLRETALIATE_NONE, ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua index 4c49238a9..61efc03dc 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua @@ -31,9 +31,9 @@ if SERVER then local function GetRandomTarget(ply) -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do + if p == ply then continue end if not p:Alive() or p:IsSpec() then continue end if p:ShouldActLikeJester() then continue end - if p == ply then continue end return p end return nil diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua index c2d14e392..ad8cd1730 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua @@ -1,9 +1,10 @@ local hook = hook +local ipairs = ipairs local table = table local math = math -local TableInsert = table.insert local MathRandom = math.random +local TableInsert = table.insert local TryTranslation = LANG.TryTranslation @@ -55,7 +56,8 @@ if SERVER then ply:SetProperty("Task_KillWeaponClass", weps[MathRandom(#weps)].ClassName, ply) local equipped = false - if ply:GetActiveWeapon().Kind == WEAPON_HEAVY then + local active = ply:GetActiveWeapon() + if active and active.Kind == WEAPON_HEAVY then equipped = true end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index 6087c8ef5..cc81d3d4f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -8,6 +8,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -28,7 +29,7 @@ TASK.Name = function(ply) local time = taskmaster_lookatplayer_time:GetInt() local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_LookAtPlayerStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index d740e09db..a7f862893 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -8,6 +8,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -28,7 +29,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StandOnPlayerStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua index 4c465513f..36a2c8b08 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua @@ -10,6 +10,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor local PlayerIterator = player.Iterator +local TableHasValue = table.HasValue local TASK = {} @@ -30,7 +31,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayHiddenStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index 66959e616..fd6e77e14 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -10,6 +10,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor local PlayerIterator = player.Iterator +local TableHasValue = table.HasValue local TASK = {} @@ -30,7 +31,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayHigherStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index d6b9f3cd8..3b4eaad85 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -12,6 +12,7 @@ local MathPi = math.pi local MathRand = math.Rand local MathSin = math.sin local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -38,7 +39,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayInAreaStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index 91dfcacd2..986ce5136 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -10,6 +10,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor local PlayerIterator = player.Iterator +local TableHasValue = table.HasValue local TASK = {} @@ -30,7 +31,7 @@ TASK.Name = function(ply) end local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayLowerStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 744df5c41..5d55b9199 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -14,6 +14,7 @@ local MathPi = math.pi local MathRand = math.Rand local MathSin = math.sin local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -40,7 +41,7 @@ TASK.Name = function(ply) local time = taskmaster_stayneartarget_time:GetInt() local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayNearTargetStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua index f574f174a..76577e1e1 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua @@ -8,6 +8,7 @@ local util = util local MathMax = math.max local MathFloor = math.floor +local TableHasValue = table.HasValue local TASK = {} @@ -23,7 +24,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_takedamage_time:GetInt() local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_TakeDamageStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua index 1b2c5e28d..7a04f78c8 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua @@ -1,5 +1,8 @@ +local hook = hook local table = table +local TableHasValue = table.HasValue + local TASK = {} TASK.id = "weaponpickups" @@ -18,8 +21,8 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 - if (table.HasValue(ply.taskmasterCompletedTasks, TASK.id)) then + local progress + if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = count else progress = ply.Task_WeaponPickupsCount From 0d2ecc050bc6b2224951ff639f9cf4d0619aa247 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 10:34:23 -0400 Subject: [PATCH 073/115] Luacheck fixes --- .../terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua | 2 +- gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua | 2 +- gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua | 2 +- .../gamemode/roles/taskmaster/tasks/crouchnearbody.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua | 2 +- .../gamemode/roles/taskmaster/tasks/damageeveryone.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua | 2 +- .../gamemode/roles/taskmaster/tasks/getplayerkilled.lua | 2 +- .../gamemode/roles/taskmaster/tasks/getplayertokill.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/holstered.lua | 2 +- gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua | 2 +- .../gamemode/roles/taskmaster/tasks/standonplayer.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/staylower.lua | 2 +- .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua index 2905c6346..e7e9e2b05 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua index 2a31ec6c8..d95c756ce 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua @@ -21,7 +21,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 27a73c0c5..2295891d5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index 6fecedc4a..f71820921 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -33,7 +33,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_crouchnearbody_time:GetInt() - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua index 414766b3b..0f90cd1b3 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua @@ -21,7 +21,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua index 841990b1a..a94f27e87 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua @@ -16,7 +16,7 @@ TASK.id = "damageeveryone" TASK.Name = function(ply) local damaged = ply.Task_DamageEveryoneDamaged or {} local total = 0 - local progress = 0 + local progress for _, p in PlayerIterator() do if ply == p then continue end if not p:Alive() or p:IsSpec() then continue end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua index e7024846b..a85c327a0 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua @@ -17,7 +17,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local amount = taskmaster_dodamage_amount:GetInt() - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = amount else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua index ef6671c1d..4e097f009 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua @@ -21,7 +21,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua index e487f109e..4c17fa07e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua @@ -29,7 +29,7 @@ if SERVER then util.AddNetworkString("TTT_Taskmaster_GetPlayerKilled_Cleanup") local function GetRandomTarget(ply) - local passive = nil + local passive -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do if p == ply then continue end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua index 48997cc7a..683ca836e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua @@ -29,7 +29,7 @@ if SERVER then util.AddNetworkString("TTT_Taskmaster_GetPlayerToKill_Cleanup") local function GetRandomTarget(ply) - local passive = nil + local passive -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do if p == ply then continue end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index 926536737..02e77de2e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -31,7 +31,7 @@ TASK.Name = function(ply) local amount = taskmaster_healthunder_amount:GetInt() local time = taskmaster_healthunder_time:GetInt() - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index e12b7e3c9..42489e9c3 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua index ac909a7a5..fb36541bb 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -21,7 +21,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index cc81d3d4f..41efe9ccc 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) end local time = taskmaster_lookatplayer_time:GetInt() - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index a7f862893..33c8070cd 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua index 36a2c8b08..1ea5e5f7b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua @@ -30,7 +30,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index fd6e77e14..98149eb65 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -30,7 +30,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index 3b4eaad85..36c39a040 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -38,7 +38,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index 986ce5136..aa78977c8 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -30,7 +30,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 5d55b9199..dc1cc8d66 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -40,7 +40,7 @@ TASK.Name = function(ply) end local time = taskmaster_stayneartarget_time:GetInt() - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua index 76577e1e1..532edbc1e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua @@ -23,7 +23,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_takedamage_time:GetInt() - local progress = 0 + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else From 128d863f3d85b44952acf58d6e930a5f24ac32d9 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 10:36:25 -0400 Subject: [PATCH 074/115] Revert wrong luacheck fix --- .../gamemode/roles/taskmaster/tasks/getplayerkilled.lua | 2 +- .../gamemode/roles/taskmaster/tasks/getplayertokill.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua index 4c17fa07e..e487f109e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua @@ -29,7 +29,7 @@ if SERVER then util.AddNetworkString("TTT_Taskmaster_GetPlayerKilled_Cleanup") local function GetRandomTarget(ply) - local passive + local passive = nil -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do if p == ply then continue end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua index 683ca836e..48997cc7a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua @@ -29,7 +29,7 @@ if SERVER then util.AddNetworkString("TTT_Taskmaster_GetPlayerToKill_Cleanup") local function GetRandomTarget(ply) - local passive + local passive = nil -- Find the first random living player for _, p in RandomPairs(player.GetAll()) do if p == ply then continue end From 89052eceb44df126e22d5a15c815a8e9ac985d69 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 10:39:58 -0400 Subject: [PATCH 075/115] Try a different fork of gluacheck --- .github/workflows/luacheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml index 82944c75a..7bbd5e50c 100644 --- a/.github/workflows/luacheck.yml +++ b/.github/workflows/luacheck.yml @@ -17,7 +17,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - repository: 'Malivil/gluacheck' + repository: 'impulsh/gluacheck' path: 'gluacheck' - name: Setup ‘lua’ From ae6aa98575414c451599572bb69d4ef437b1fc71 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 10:42:26 -0400 Subject: [PATCH 076/115] Try the right rockspec --- .github/workflows/luacheck.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml index 7bbd5e50c..c6d63daa1 100644 --- a/.github/workflows/luacheck.yml +++ b/.github/workflows/luacheck.yml @@ -30,10 +30,10 @@ jobs: uses: leafo/gh-actions-luarocks@v4 - name: Setup dependencies - run: luarocks install --deps-only gluacheck-dev-1.rockspec + run: luarocks install --deps-only luacheck-dev-1.rockspec - name: Build ‘luacheck’ (bootstrap) - run: luarocks make gluacheck-dev-1.rockspec + run: luarocks make luacheck-dev-1.rockspec - name: Run ‘luacheck’ (dogfood) run: lua -e 'package.path="./gluacheck/src/?.lua;./gluacheck/src/?/init.lua;"..package.path' gluacheck/bin/luacheck.lua gamemodes scripts From 4a69303fbc24cceb38e3911af14b1ee71e09f37e Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 10:44:02 -0400 Subject: [PATCH 077/115] Change to the actual right rockspec --- .github/workflows/luacheck.yml | 4 +- gluacheck-dev-1.rockspec | 147 ++++++++++++++------------------- 2 files changed, 64 insertions(+), 87 deletions(-) diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml index c6d63daa1..7bbd5e50c 100644 --- a/.github/workflows/luacheck.yml +++ b/.github/workflows/luacheck.yml @@ -30,10 +30,10 @@ jobs: uses: leafo/gh-actions-luarocks@v4 - name: Setup dependencies - run: luarocks install --deps-only luacheck-dev-1.rockspec + run: luarocks install --deps-only gluacheck-dev-1.rockspec - name: Build ‘luacheck’ (bootstrap) - run: luarocks make luacheck-dev-1.rockspec + run: luarocks make gluacheck-dev-1.rockspec - name: Run ‘luacheck’ (dogfood) run: lua -e 'package.path="./gluacheck/src/?.lua;./gluacheck/src/?/init.lua;"..package.path' gluacheck/bin/luacheck.lua gamemodes scripts diff --git a/gluacheck-dev-1.rockspec b/gluacheck-dev-1.rockspec index 3ae109c3b..d002f242a 100644 --- a/gluacheck-dev-1.rockspec +++ b/gluacheck-dev-1.rockspec @@ -1,105 +1,82 @@ -local package_name = "gluacheck" -local package_version = "dev" -local rockspec_revision = "1" -local github_account_name = "Malivil" -local github_repo_name = package_name - -rockspec_format = "3.0" -package = package_name -version = package_version .. "-" .. rockspec_revision - +package = "luacheck" +version = "dev-1" source = { - url = "git+https://github.com/" .. github_account_name .. "/" .. github_repo_name .. ".git" + url = "git+https://github.com/mpeterv/luacheck.git" } - -if package_version == "dev" then source.branch = "master" else source.tag = "v" .. package_version end - description = { summary = "A static analyzer and a linter for Lua", detailed = [[ - Luacheck is a command-line tool for linting and static analysis of Lua - code. It is able to spot usage of undefined global variables, unused - local variables and a few other typical problems within Lua programs. - ]], - homepage = "https://github.com/lunarmodules/luacheck", +Luacheck is a command-line tool for linting and static analysis of Lua code. +It is able to spot usage of undefined global variables, unused local variables and +a few other typical problems within Lua programs. +]], + homepage = "https://github.com/mpeterv/luacheck", license = "MIT" } - dependencies = { - "lua >= 5.1", + "lua >= 5.1, < 5.4", "argparse >= 0.6.0", "luafilesystem >= 1.6.3" } - -test_dependencies = { - "busted", -} - -test = { - type = "busted", -} - build = { type = "builtin", modules = { - luacheck = "gluacheck/src/luacheck/init.lua", - ["luacheck.builtin_standards"] = "gluacheck/src/luacheck/builtin_standards/init.lua", - ["luacheck.builtin_standards.love"] = "gluacheck/src/luacheck/builtin_standards/love.lua", - ["luacheck.builtin_standards.playdate"] = "gluacheck/src/luacheck/builtin_standards/playdate.lua", - ["luacheck.builtin_standards.ngx"] = "gluacheck/src/luacheck/builtin_standards/ngx.lua", - ["luacheck.cache"] = "gluacheck/src/luacheck/cache.lua", - ["luacheck.check"] = "gluacheck/src/luacheck/check.lua", - ["luacheck.check_state"] = "gluacheck/src/luacheck/check_state.lua", - ["luacheck.config"] = "gluacheck/src/luacheck/config.lua", - ["luacheck.core_utils"] = "gluacheck/src/luacheck/core_utils.lua", - ["luacheck.decoder"] = "gluacheck/src/luacheck/decoder.lua", - ["luacheck.expand_rockspec"] = "gluacheck/src/luacheck/expand_rockspec.lua", - ["luacheck.filter"] = "gluacheck/src/luacheck/filter.lua", - ["luacheck.format"] = "gluacheck/src/luacheck/format.lua", - ["luacheck.fs"] = "gluacheck/src/luacheck/fs.lua", - ["luacheck.globbing"] = "gluacheck/src/luacheck/globbing.lua", - ["luacheck.lexer"] = "gluacheck/src/luacheck/lexer.lua", - ["luacheck.main"] = "gluacheck/src/luacheck/main.lua", - ["luacheck.multithreading"] = "gluacheck/src/luacheck/multithreading.lua", - ["luacheck.options"] = "gluacheck/src/luacheck/options.lua", - ["luacheck.parser"] = "gluacheck/src/luacheck/parser.lua", - ["luacheck.profiler"] = "gluacheck/src/luacheck/profiler.lua", - ["luacheck.runner"] = "gluacheck/src/luacheck/runner.lua", - ["luacheck.serializer"] = "gluacheck/src/luacheck/serializer.lua", - ["luacheck.stages"] = "gluacheck/src/luacheck/stages/init.lua", - ["luacheck.stages.detect_bad_whitespace"] = "gluacheck/src/luacheck/stages/detect_bad_whitespace.lua", - ["luacheck.stages.detect_compound_operators"] = "gluacheck/src/luacheck/stages/detect_compound_operators.lua", - ["luacheck.stages.detect_cyclomatic_complexity"] = "gluacheck/src/luacheck/stages/detect_cyclomatic_complexity.lua", - ["luacheck.stages.detect_empty_blocks"] = "gluacheck/src/luacheck/stages/detect_empty_blocks.lua", - ["luacheck.stages.detect_empty_statements"] = "gluacheck/src/luacheck/stages/detect_empty_statements.lua", - ["luacheck.stages.detect_globals"] = "gluacheck/src/luacheck/stages/detect_globals.lua", - ["luacheck.stages.detect_reversed_fornum_loops"] = "gluacheck/src/luacheck/stages/detect_reversed_fornum_loops.lua", - ["luacheck.stages.detect_unbalanced_assignments"] = "gluacheck/src/luacheck/stages/detect_unbalanced_assignments.lua", - ["luacheck.stages.detect_uninit_accesses"] = "gluacheck/src/luacheck/stages/detect_uninit_accesses.lua", - ["luacheck.stages.detect_unreachable_code"] = "gluacheck/src/luacheck/stages/detect_unreachable_code.lua", - ["luacheck.stages.detect_unused_fields"] = "gluacheck/src/luacheck/stages/detect_unused_fields.lua", - ["luacheck.stages.detect_unused_locals"] = "gluacheck/src/luacheck/stages/detect_unused_locals.lua", - ["luacheck.stages.linearize"] = "gluacheck/src/luacheck/stages/linearize.lua", - ["luacheck.stages.name_functions"] = "gluacheck/src/luacheck/stages/name_functions.lua", - ["luacheck.stages.parse"] = "gluacheck/src/luacheck/stages/parse.lua", - ["luacheck.stages.parse_inline_options"] = "gluacheck/src/luacheck/stages/parse_inline_options.lua", - ["luacheck.stages.resolve_locals"] = "gluacheck/src/luacheck/stages/resolve_locals.lua", - ["luacheck.stages.unwrap_parens"] = "gluacheck/src/luacheck/stages/unwrap_parens.lua", - ["luacheck.standards"] = "gluacheck/src/luacheck/standards.lua", - ["luacheck.unicode"] = "gluacheck/src/luacheck/unicode.lua", - ["luacheck.unicode_printability_boundaries"] = "gluacheck/src/luacheck/unicode_printability_boundaries.lua", - ["luacheck.utils"] = "gluacheck/src/luacheck/utils.lua", - ["luacheck.vendor.sha1"] = "gluacheck/src/luacheck/vendor/sha1/init.lua", - ["luacheck.vendor.sha1.bit32_ops"] = "gluacheck/src/luacheck/vendor/sha1/bit32_ops.lua", - ["luacheck.vendor.sha1.bit_ops"] = "gluacheck/src/luacheck/vendor/sha1/bit_ops.lua", - ["luacheck.vendor.sha1.common"] = "gluacheck/src/luacheck/vendor/sha1/common.lua", - ["luacheck.vendor.sha1.lua53_ops"] = "gluacheck/src/luacheck/vendor/sha1/lua53_ops.lua", - ["luacheck.vendor.sha1.pure_lua_ops"] = "gluacheck/src/luacheck/vendor/sha1/pure_lua_ops.lua", - ["luacheck.version"] = "gluacheck/src/luacheck/version.lua" + luacheck = "src/luacheck/init.lua", + ["luacheck.builtin_standards"] = "src/luacheck/builtin_standards/init.lua", + ["luacheck.builtin_standards.love"] = "src/luacheck/builtin_standards/love.lua", + ["luacheck.builtin_standards.ngx"] = "src/luacheck/builtin_standards/ngx.lua", + ["luacheck.cache"] = "src/luacheck/cache.lua", + ["luacheck.check"] = "src/luacheck/check.lua", + ["luacheck.check_state"] = "src/luacheck/check_state.lua", + ["luacheck.config"] = "src/luacheck/config.lua", + ["luacheck.core_utils"] = "src/luacheck/core_utils.lua", + ["luacheck.decoder"] = "src/luacheck/decoder.lua", + ["luacheck.expand_rockspec"] = "src/luacheck/expand_rockspec.lua", + ["luacheck.filter"] = "src/luacheck/filter.lua", + ["luacheck.format"] = "src/luacheck/format.lua", + ["luacheck.fs"] = "src/luacheck/fs.lua", + ["luacheck.globbing"] = "src/luacheck/globbing.lua", + ["luacheck.lexer"] = "src/luacheck/lexer.lua", + ["luacheck.main"] = "src/luacheck/main.lua", + ["luacheck.multithreading"] = "src/luacheck/multithreading.lua", + ["luacheck.options"] = "src/luacheck/options.lua", + ["luacheck.parser"] = "src/luacheck/parser.lua", + ["luacheck.profiler"] = "src/luacheck/profiler.lua", + ["luacheck.runner"] = "src/luacheck/runner.lua", + ["luacheck.serializer"] = "src/luacheck/serializer.lua", + ["luacheck.stages"] = "src/luacheck/stages/init.lua", + ["luacheck.stages.detect_bad_whitespace"] = "src/luacheck/stages/detect_bad_whitespace.lua", + ["luacheck.stages.detect_cyclomatic_complexity"] = "src/luacheck/stages/detect_cyclomatic_complexity.lua", + ["luacheck.stages.detect_empty_blocks"] = "src/luacheck/stages/detect_empty_blocks.lua", + ["luacheck.stages.detect_empty_statements"] = "src/luacheck/stages/detect_empty_statements.lua", + ["luacheck.stages.detect_globals"] = "src/luacheck/stages/detect_globals.lua", + ["luacheck.stages.detect_reversed_fornum_loops"] = "src/luacheck/stages/detect_reversed_fornum_loops.lua", + ["luacheck.stages.detect_unbalanced_assignments"] = "src/luacheck/stages/detect_unbalanced_assignments.lua", + ["luacheck.stages.detect_uninit_accesses"] = "src/luacheck/stages/detect_uninit_accesses.lua", + ["luacheck.stages.detect_unreachable_code"] = "src/luacheck/stages/detect_unreachable_code.lua", + ["luacheck.stages.detect_unused_fields"] = "src/luacheck/stages/detect_unused_fields.lua", + ["luacheck.stages.detect_unused_locals"] = "src/luacheck/stages/detect_unused_locals.lua", + ["luacheck.stages.linearize"] = "src/luacheck/stages/linearize.lua", + ["luacheck.stages.name_functions"] = "src/luacheck/stages/name_functions.lua", + ["luacheck.stages.parse"] = "src/luacheck/stages/parse.lua", + ["luacheck.stages.parse_inline_options"] = "src/luacheck/stages/parse_inline_options.lua", + ["luacheck.stages.resolve_locals"] = "src/luacheck/stages/resolve_locals.lua", + ["luacheck.stages.unwrap_parens"] = "src/luacheck/stages/unwrap_parens.lua", + ["luacheck.standards"] = "src/luacheck/standards.lua", + ["luacheck.unicode"] = "src/luacheck/unicode.lua", + ["luacheck.unicode_printability_boundaries"] = "src/luacheck/unicode_printability_boundaries.lua", + ["luacheck.utils"] = "src/luacheck/utils.lua", + ["luacheck.vendor.sha1"] = "src/luacheck/vendor/sha1/init.lua", + ["luacheck.vendor.sha1.bit_ops"] = "src/luacheck/vendor/sha1/bit_ops.lua", + ["luacheck.vendor.sha1.bit32_ops"] = "src/luacheck/vendor/sha1/bit32_ops.lua", + ["luacheck.vendor.sha1.common"] = "src/luacheck/vendor/sha1/common.lua", + ["luacheck.vendor.sha1.lua53_ops"] = "src/luacheck/vendor/sha1/lua53_ops.lua", + ["luacheck.vendor.sha1.pure_lua_ops"] = "src/luacheck/vendor/sha1/pure_lua_ops.lua", + ["luacheck.version"] = "src/luacheck/version.lua" }, install = { bin = { - luacheck = "gluacheck/bin/luacheck.lua" + luacheck = "bin/luacheck.lua" } } } From bbebdca2042d99d734d78330b03de08dbcb93d66 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 10:45:05 -0400 Subject: [PATCH 078/115] I'll get this right eventually --- .github/workflows/luacheck.yml | 4 ++-- gluacheck-dev-1.rockspec => luacheck-dev-1.rockspec | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename gluacheck-dev-1.rockspec => luacheck-dev-1.rockspec (100%) diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml index 7bbd5e50c..c6d63daa1 100644 --- a/.github/workflows/luacheck.yml +++ b/.github/workflows/luacheck.yml @@ -30,10 +30,10 @@ jobs: uses: leafo/gh-actions-luarocks@v4 - name: Setup dependencies - run: luarocks install --deps-only gluacheck-dev-1.rockspec + run: luarocks install --deps-only luacheck-dev-1.rockspec - name: Build ‘luacheck’ (bootstrap) - run: luarocks make gluacheck-dev-1.rockspec + run: luarocks make luacheck-dev-1.rockspec - name: Run ‘luacheck’ (dogfood) run: lua -e 'package.path="./gluacheck/src/?.lua;./gluacheck/src/?/init.lua;"..package.path' gluacheck/bin/luacheck.lua gamemodes scripts diff --git a/gluacheck-dev-1.rockspec b/luacheck-dev-1.rockspec similarity index 100% rename from gluacheck-dev-1.rockspec rename to luacheck-dev-1.rockspec From 6b7842731a938bb59721dbfb19270385b04bcfc4 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 10:47:41 -0400 Subject: [PATCH 079/115] Fixed paths --- luacheck-dev-1.rockspec | 104 ++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/luacheck-dev-1.rockspec b/luacheck-dev-1.rockspec index d002f242a..db6ed3001 100644 --- a/luacheck-dev-1.rockspec +++ b/luacheck-dev-1.rockspec @@ -21,58 +21,58 @@ dependencies = { build = { type = "builtin", modules = { - luacheck = "src/luacheck/init.lua", - ["luacheck.builtin_standards"] = "src/luacheck/builtin_standards/init.lua", - ["luacheck.builtin_standards.love"] = "src/luacheck/builtin_standards/love.lua", - ["luacheck.builtin_standards.ngx"] = "src/luacheck/builtin_standards/ngx.lua", - ["luacheck.cache"] = "src/luacheck/cache.lua", - ["luacheck.check"] = "src/luacheck/check.lua", - ["luacheck.check_state"] = "src/luacheck/check_state.lua", - ["luacheck.config"] = "src/luacheck/config.lua", - ["luacheck.core_utils"] = "src/luacheck/core_utils.lua", - ["luacheck.decoder"] = "src/luacheck/decoder.lua", - ["luacheck.expand_rockspec"] = "src/luacheck/expand_rockspec.lua", - ["luacheck.filter"] = "src/luacheck/filter.lua", - ["luacheck.format"] = "src/luacheck/format.lua", - ["luacheck.fs"] = "src/luacheck/fs.lua", - ["luacheck.globbing"] = "src/luacheck/globbing.lua", - ["luacheck.lexer"] = "src/luacheck/lexer.lua", - ["luacheck.main"] = "src/luacheck/main.lua", - ["luacheck.multithreading"] = "src/luacheck/multithreading.lua", - ["luacheck.options"] = "src/luacheck/options.lua", - ["luacheck.parser"] = "src/luacheck/parser.lua", - ["luacheck.profiler"] = "src/luacheck/profiler.lua", - ["luacheck.runner"] = "src/luacheck/runner.lua", - ["luacheck.serializer"] = "src/luacheck/serializer.lua", - ["luacheck.stages"] = "src/luacheck/stages/init.lua", - ["luacheck.stages.detect_bad_whitespace"] = "src/luacheck/stages/detect_bad_whitespace.lua", - ["luacheck.stages.detect_cyclomatic_complexity"] = "src/luacheck/stages/detect_cyclomatic_complexity.lua", - ["luacheck.stages.detect_empty_blocks"] = "src/luacheck/stages/detect_empty_blocks.lua", - ["luacheck.stages.detect_empty_statements"] = "src/luacheck/stages/detect_empty_statements.lua", - ["luacheck.stages.detect_globals"] = "src/luacheck/stages/detect_globals.lua", - ["luacheck.stages.detect_reversed_fornum_loops"] = "src/luacheck/stages/detect_reversed_fornum_loops.lua", - ["luacheck.stages.detect_unbalanced_assignments"] = "src/luacheck/stages/detect_unbalanced_assignments.lua", - ["luacheck.stages.detect_uninit_accesses"] = "src/luacheck/stages/detect_uninit_accesses.lua", - ["luacheck.stages.detect_unreachable_code"] = "src/luacheck/stages/detect_unreachable_code.lua", - ["luacheck.stages.detect_unused_fields"] = "src/luacheck/stages/detect_unused_fields.lua", - ["luacheck.stages.detect_unused_locals"] = "src/luacheck/stages/detect_unused_locals.lua", - ["luacheck.stages.linearize"] = "src/luacheck/stages/linearize.lua", - ["luacheck.stages.name_functions"] = "src/luacheck/stages/name_functions.lua", - ["luacheck.stages.parse"] = "src/luacheck/stages/parse.lua", - ["luacheck.stages.parse_inline_options"] = "src/luacheck/stages/parse_inline_options.lua", - ["luacheck.stages.resolve_locals"] = "src/luacheck/stages/resolve_locals.lua", - ["luacheck.stages.unwrap_parens"] = "src/luacheck/stages/unwrap_parens.lua", - ["luacheck.standards"] = "src/luacheck/standards.lua", - ["luacheck.unicode"] = "src/luacheck/unicode.lua", - ["luacheck.unicode_printability_boundaries"] = "src/luacheck/unicode_printability_boundaries.lua", - ["luacheck.utils"] = "src/luacheck/utils.lua", - ["luacheck.vendor.sha1"] = "src/luacheck/vendor/sha1/init.lua", - ["luacheck.vendor.sha1.bit_ops"] = "src/luacheck/vendor/sha1/bit_ops.lua", - ["luacheck.vendor.sha1.bit32_ops"] = "src/luacheck/vendor/sha1/bit32_ops.lua", - ["luacheck.vendor.sha1.common"] = "src/luacheck/vendor/sha1/common.lua", - ["luacheck.vendor.sha1.lua53_ops"] = "src/luacheck/vendor/sha1/lua53_ops.lua", - ["luacheck.vendor.sha1.pure_lua_ops"] = "src/luacheck/vendor/sha1/pure_lua_ops.lua", - ["luacheck.version"] = "src/luacheck/version.lua" + luacheck = "gluacheck/src/luacheck/init.lua", + ["luacheck.builtin_standards"] = "gluacheck/src/luacheck/builtin_standards/init.lua", + ["luacheck.builtin_standards.love"] = "gluacheck/src/luacheck/builtin_standards/love.lua", + ["luacheck.builtin_standards.ngx"] = "gluacheck/src/luacheck/builtin_standards/ngx.lua", + ["luacheck.cache"] = "gluacheck/src/luacheck/cache.lua", + ["luacheck.check"] = "gluacheck/src/luacheck/check.lua", + ["luacheck.check_state"] = "gluacheck/src/luacheck/check_state.lua", + ["luacheck.config"] = "gluacheck/src/luacheck/config.lua", + ["luacheck.core_utils"] = "gluacheck/src/luacheck/core_utils.lua", + ["luacheck.decoder"] = "gluacheck/src/luacheck/decoder.lua", + ["luacheck.expand_rockspec"] = "gluacheck/src/luacheck/expand_rockspec.lua", + ["luacheck.filter"] = "gluacheck/src/luacheck/filter.lua", + ["luacheck.format"] = "gluacheck/src/luacheck/format.lua", + ["luacheck.fs"] = "gluacheck/src/luacheck/fs.lua", + ["luacheck.globbing"] = "gluacheck/src/luacheck/globbing.lua", + ["luacheck.lexer"] = "gluacheck/src/luacheck/lexer.lua", + ["luacheck.main"] = "gluacheck/src/luacheck/main.lua", + ["luacheck.multithreading"] = "gluacheck/src/luacheck/multithreading.lua", + ["luacheck.options"] = "gluacheck/src/luacheck/options.lua", + ["luacheck.parser"] = "gluacheck/src/luacheck/parser.lua", + ["luacheck.profiler"] = "gluacheck/src/luacheck/profiler.lua", + ["luacheck.runner"] = "gluacheck/src/luacheck/runner.lua", + ["luacheck.serializer"] = "gluacheck/src/luacheck/serializer.lua", + ["luacheck.stages"] = "gluacheck/src/luacheck/stages/init.lua", + ["luacheck.stages.detect_bad_whitespace"] = "gluacheck/src/luacheck/stages/detect_bad_whitespace.lua", + ["luacheck.stages.detect_cyclomatic_complexity"] = "gluacheck/src/luacheck/stages/detect_cyclomatic_complexity.lua", + ["luacheck.stages.detect_empty_blocks"] = "gluacheck/src/luacheck/stages/detect_empty_blocks.lua", + ["luacheck.stages.detect_empty_statements"] = "gluacheck/src/luacheck/stages/detect_empty_statements.lua", + ["luacheck.stages.detect_globals"] = "gluacheck/src/luacheck/stages/detect_globals.lua", + ["luacheck.stages.detect_reversed_fornum_loops"] = "gluacheck/src/luacheck/stages/detect_reversed_fornum_loops.lua", + ["luacheck.stages.detect_unbalanced_assignments"] = "gluacheck/src/luacheck/stages/detect_unbalanced_assignments.lua", + ["luacheck.stages.detect_uninit_accesses"] = "gluacheck/src/luacheck/stages/detect_uninit_accesses.lua", + ["luacheck.stages.detect_unreachable_code"] = "gluacheck/src/luacheck/stages/detect_unreachable_code.lua", + ["luacheck.stages.detect_unused_fields"] = "gluacheck/src/luacheck/stages/detect_unused_fields.lua", + ["luacheck.stages.detect_unused_locals"] = "gluacheck/src/luacheck/stages/detect_unused_locals.lua", + ["luacheck.stages.linearize"] = "gluacheck/src/luacheck/stages/linearize.lua", + ["luacheck.stages.name_functions"] = "gluacheck/src/luacheck/stages/name_functions.lua", + ["luacheck.stages.parse"] = "gluacheck/src/luacheck/stages/parse.lua", + ["luacheck.stages.parse_inline_options"] = "gluacheck/src/luacheck/stages/parse_inline_options.lua", + ["luacheck.stages.resolve_locals"] = "gluacheck/src/luacheck/stages/resolve_locals.lua", + ["luacheck.stages.unwrap_parens"] = "gluacheck/src/luacheck/stages/unwrap_parens.lua", + ["luacheck.standards"] = "gluacheck/src/luacheck/standards.lua", + ["luacheck.unicode"] = "gluacheck/src/luacheck/unicode.lua", + ["luacheck.unicode_printability_boundaries"] = "gluacheck/src/luacheck/unicode_printability_boundaries.lua", + ["luacheck.utils"] = "gluacheck/src/luacheck/utils.lua", + ["luacheck.vendor.sha1"] = "gluacheck/src/luacheck/vendor/sha1/init.lua", + ["luacheck.vendor.sha1.bit_ops"] = "gluacheck/src/luacheck/vendor/sha1/bit_ops.lua", + ["luacheck.vendor.sha1.bit32_ops"] = "gluacheck/src/luacheck/vendor/sha1/bit32_ops.lua", + ["luacheck.vendor.sha1.common"] = "gluacheck/src/luacheck/vendor/sha1/common.lua", + ["luacheck.vendor.sha1.lua53_ops"] = "gluacheck/src/luacheck/vendor/sha1/lua53_ops.lua", + ["luacheck.vendor.sha1.pure_lua_ops"] = "gluacheck/src/luacheck/vendor/sha1/pure_lua_ops.lua", + ["luacheck.version"] = "gluacheck/src/luacheck/version.lua" }, install = { bin = { From 2539bf97dd27b54ef018aab826192f514208252f Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 10:48:48 -0400 Subject: [PATCH 080/115] Fixed another path --- luacheck-dev-1.rockspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/luacheck-dev-1.rockspec b/luacheck-dev-1.rockspec index db6ed3001..22b7d4f48 100644 --- a/luacheck-dev-1.rockspec +++ b/luacheck-dev-1.rockspec @@ -76,7 +76,7 @@ build = { }, install = { bin = { - luacheck = "bin/luacheck.lua" + luacheck = "gluacheck/bin/luacheck.lua" } } } From c25e078e31f325aa315ecd9e53b5248bcad88553 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 11:13:01 -0400 Subject: [PATCH 081/115] Fixed load error --- .../gamemode/roles/taskmaster/tasks/killweapon.lua | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua index ad8cd1730..9b211af9c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua @@ -6,8 +6,6 @@ local math = math local MathRandom = math.random local TableInsert = table.insert -local TryTranslation = LANG.TryTranslation - local TASK = {} TASK.id = "killweapon" @@ -15,10 +13,10 @@ TASK.isKillTask = true TASK.Name = function(ply) local weapon = "Specific Weapon" - if ply.Task_KillWeaponClass then + if CLIENT and ply.Task_KillWeaponClass then for _, wep in ipairs(weapons.GetList()) do if ply.Task_KillWeaponClass == WEPS.GetClass(wep) then - weapon = TryTranslation(wep.PrintName) + weapon = LANG.TryTranslation(wep.PrintName) break end end @@ -28,10 +26,10 @@ end TASK.Description = function(ply) local weapon = "specific weapon" - if ply.Task_KillWeaponClass then + if CLIENT and ply.Task_KillWeaponClass then for _, wep in ipairs(weapons.GetList()) do if ply.Task_KillWeaponClass == WEPS.GetClass(wep) then - weapon = TryTranslation(wep.PrintName) + weapon = LANG.TryTranslation(wep.PrintName) break end end From 3f42e69893550d4a74f5baddcded970edbda96ba Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 14:30:17 -0400 Subject: [PATCH 082/115] Change to my updated luacheck fork for better continue support --- .github/workflows/luacheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml index c6d63daa1..1c4800a6f 100644 --- a/.github/workflows/luacheck.yml +++ b/.github/workflows/luacheck.yml @@ -17,7 +17,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - repository: 'impulsh/gluacheck' + repository: 'Malivil/gluacheck' path: 'gluacheck' - name: Setup ‘lua’ From d57b23f7972b693aabf9c0e2f220abcec2e3b40f Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 17:27:18 -0400 Subject: [PATCH 083/115] Revert overzealous luacheck changes --- .../terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua | 2 +- gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua | 2 +- .../gamemode/roles/taskmaster/tasks/crouchnearbody.lua | 2 +- .../gamemode/roles/taskmaster/tasks/damageeveryone.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/holstered.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua | 2 +- .../gamemode/roles/taskmaster/tasks/standonplayer.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/staylower.lua | 2 +- .../gamemode/roles/taskmaster/tasks/stayneartarget.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua index e7e9e2b05..2905c6346 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 2295891d5..27a73c0c5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index f71820921..6fecedc4a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -33,7 +33,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_crouchnearbody_time:GetInt() - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua index a94f27e87..841990b1a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua @@ -16,7 +16,7 @@ TASK.id = "damageeveryone" TASK.Name = function(ply) local damaged = ply.Task_DamageEveryoneDamaged or {} local total = 0 - local progress + local progress = 0 for _, p in PlayerIterator() do if ply == p then continue end if not p:Alive() or p:IsSpec() then continue end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index 02e77de2e..926536737 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -31,7 +31,7 @@ TASK.Name = function(ply) local amount = taskmaster_healthunder_amount:GetInt() local time = taskmaster_healthunder_time:GetInt() - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index 42489e9c3..e12b7e3c9 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index 41efe9ccc..cc81d3d4f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) end local time = taskmaster_lookatplayer_time:GetInt() - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index 33c8070cd..a7f862893 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua index 1ea5e5f7b..36a2c8b08 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua @@ -30,7 +30,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index 98149eb65..fd6e77e14 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -30,7 +30,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index aa78977c8..986ce5136 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -30,7 +30,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index dc1cc8d66..5d55b9199 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -40,7 +40,7 @@ TASK.Name = function(ply) end local time = taskmaster_stayneartarget_time:GetInt() - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua index 532edbc1e..76577e1e1 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua @@ -23,7 +23,7 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_takedamage_time:GetInt() - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else From 47730379dd095440d98fc2f3adf5f1ffde540d12 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 17:27:57 -0400 Subject: [PATCH 084/115] Fixed wrong variable usage --- gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua index fb36541bb..95c662960 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -25,7 +25,7 @@ TASK.Name = function(ply) if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times else - progress = ply.Task_CrowbarCount + progress = ply.Task_JumpCount end return name .. " (" .. progress .. "/" .. times .. ")" From 3b55777b129e2db6fa2a5e9a509ff2a8d9a72b45 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 17:29:44 -0400 Subject: [PATCH 085/115] Fixed error --- .../terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index 36c39a040..3b4eaad85 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -38,7 +38,7 @@ TASK.Name = function(ply) name = name .. "s" end - local progress + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time else From 042a94e37a2bcff3a51a3c325a8a3b7a191a608a Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 17:31:53 -0400 Subject: [PATCH 086/115] Added line pointing to the area in the Stay in Area task --- .../roles/taskmaster/tasks/stayinarea.lua | 78 +++++++++++++++---- 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index 3b4eaad85..88e552de3 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -117,6 +117,60 @@ if SERVER then end if CLIENT then + + local function DrawLink(ply, targetPos) + if not ply.TaskmasterStayInAreaLinkEmitter then ply.TaskmasterStayInAreaLinkEmitter = ParticleEmitter(targetPos) end + if not ply.TaskmasterStayInAreaLinkNextPart then ply.TaskmasterStayInAreaLinkNextPart = CurTime() end + if not ply.TaskmasterStayInAreaLinkOffset then ply.TaskmasterStayInAreaLinkOffset = 0 end + local startPos = ply:GetPos() + Vector(0, 0, 30) + local endPos = targetPos + Vector(0, 0, 30) + local dir = endPos - startPos + dir = dir:GetNormalized() * 50 + if ply.TaskmasterStayInAreaLinkNextPart < CurTime() then + local pos = startPos + (dir * ply.TaskmasterStayInAreaLinkOffset) + -- Use DistToSqr as it's more efficient and this is called very frequently + -- 9000000 = 3000^2 + while startPos:DistToSqr(pos) <= 9000000 and startPos:DistToSqr(pos) <= startPos:DistToSqr(endPos) do + ply.TaskmasterStayInAreaLinkEmitter:SetPos(pos) + ply.TaskmasterStayInAreaLinkNextPart = CurTime() + 0.02 + local particle = ply.TaskmasterStayInAreaLinkEmitter:Add("particle/wisp.vmt", pos) + particle:SetVelocity(vector_origin) + particle:SetDieTime(0.25) + particle:SetStartAlpha(200) + particle:SetEndAlpha(0) + particle:SetStartSize(3) + particle:SetEndSize(2) + particle:SetRoll(MathRand(0, MathPi)) + particle:SetRollDelta(0) + local color = ROLE_COLORS[ROLE_TRAITOR] + particle:SetColor(color.r, color.g, color.b) + pos:Add(dir) + end + ply.TaskmasterStayInAreaLinkOffset = ply.TaskmasterStayInAreaLinkOffset + 0.04 + if ply.TaskmasterStayInAreaLinkOffset > 1 then + ply.TaskmasterStayInAreaLinkOffset = 0 + end + end + end + + local function RemoveLink(ply) + if ply.TaskmasterStayInAreaLinkEmitter then + ply.TaskmasterStayInAreaLinkEmitter:Finish() + ply.TaskmasterStayInAreaLinkEmitter = nil + ply.TaskmasterStayInAreaLinkNextPart = nil + ply.TaskmasterStayInAreaLinkOffset = nil + end + end + + local function RemoveRadius(ply) + if ply.TaskmasterRadiusEmitter then + ply.TaskmasterRadiusEmitter:Finish() + ply.TaskmasterRadiusEmitter = nil + ply.TaskmasterRadiusNextPart = nil + ply.TaskmasterRadiusDir = nil + end + end + net.Receive("TTT_Taskmaster_StayInArea_Assigned", function() local client = LocalPlayer() local sid64 = client:SteamID64() @@ -158,19 +212,21 @@ if CLIENT then end ply.TaskmasterRadiusDir = ply.TaskmasterRadiusDir + 0.02 end + + if distance > rangeSqr then + DrawLink(ply, pos) + else + RemoveLink(ply) + end shouldDraw = true end - if not shouldDraw and ply.TaskmasterRadiusEmitter then - ply.TaskmasterRadiusEmitter:Finish() - ply.TaskmasterRadiusEmitter = nil - ply.TaskmasterRadiusDir = nil - ply.TaskmasterRadiusNextPart = nil + if not shouldDraw then + RemoveRadius(ply) + RemoveLink(ply) end end) - -- TODO: Needs a visual to help locate the area if you can't immediately see it. Maybe copy the same thing we have for the shadow? - hook.Add("HUDPaint", "Taskmaster_StayInArea_HUDPaint_" .. sid64, function() if not client:IsActiveTaskmaster() then return end @@ -200,12 +256,8 @@ if CLIENT then hook.Remove("TTTPlayerAliveClientThink", "Taskmaster_StayInArea_TTTPlayerAliveClientThink_" .. sid64) hook.Remove("HUDPaint", "Taskmaster_StayInArea_HUDPaint_" .. sid64) - if client.TaskmasterRadiusEmitter then - client.TaskmasterRadiusEmitter:Finish() - client.TaskmasterRadiusEmitter = nil - client.TaskmasterRadiusDir = nil - client.TaskmasterRadiusNextPart = nil - end + RemoveRadius(client) + RemoveLink(client) end) end From 51fee1fb710eb5623f74d9142d67db772b6e7713 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 18:38:18 -0400 Subject: [PATCH 087/115] Fixed descriptions being cut off in the reroll list if they were too long --- .../terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index b5ed18a9a..77cda3e78 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -297,7 +297,11 @@ local function CreateTaskReroll(task, dscrollpanel) ddesc:SetPos(margin, (margin * 1.5) + nameHeight) ddesc:SetWidth(width - (margin * 2) - buttonWidth - scrollBarWidth) ddesc:SetWrap(true) - ddesc:SetAutoStretchVertical(true) + -- This text has wrapped to another line, increase the height so it doesn't get cut off + -- SizeToContents and SetAutoStretchVertical both weren't working, so here we are... + if #desc > 55 then + ddesc:SetHeight(ddesc:GetTall() + 20) + end local _, descHeight = ddesc:GetSize() local height = (margin * 2.5) + nameHeight + descHeight From 77a33d12e786516cba8f944b7796c849b8551554 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 21:25:11 -0400 Subject: [PATCH 088/115] Cleanup --- .../gamemode/roles/taskmaster/tasks/getplayerkilled.lua | 1 - .../gamemode/roles/taskmaster/tasks/getplayertokill.lua | 1 - .../gamemode/roles/taskmaster/tasks/killdistant.lua | 5 +++-- .../gamemode/roles/taskmaster/tasks/killnearby.lua | 5 +++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua index e487f109e..08aab0207 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua @@ -20,7 +20,6 @@ TASK.Description = function(ply) if IsPlayer(ply.Task_GetPlayerKilledPlayer) then name = ply.Task_GetPlayerKilledPlayer:Nick() end - return "Get " .. name .. " killed by another player (not you)" end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua index 48997cc7a..73493e4b1 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua @@ -20,7 +20,6 @@ TASK.Description = function(ply) if IsPlayer(ply.Task_GetPlayerToKillPlayer) then name = ply.Task_GetPlayerToKillPlayer:Nick() end - return "Get " .. name .. " to kill another player (not you)" end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua index a49844331..7da029861 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua @@ -5,6 +5,7 @@ local math = math local net = net local table = table +local MathCeil = math.ceil local MathCos = math.cos local MathPi = math.pi local MathRand = math.Rand @@ -41,7 +42,7 @@ TASK.Description = function(ply) description = description .. "s" end elseif unit == 2 then - local convertedRange = math.ceil(range * FEET_PER_METER) + local convertedRange = MathCeil(range * FEET_PER_METER) description = description .. convertedRange if convertedRange == 1 then description = description .. " foot" @@ -49,7 +50,7 @@ TASK.Description = function(ply) description = description .. " feet" end else - local convertedRange = math.ceil(range * UNITS_PER_METER) + local convertedRange = MathCeil(range * UNITS_PER_METER) description = description .. convertedRange .. " unit" if convertedRange ~= 1 then description = description .. "s" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua index ffd313b8c..9cd640f68 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua @@ -5,6 +5,7 @@ local math = math local net = net local table = table +local MathCeil = math.ceil local MathCos = math.cos local MathPi = math.pi local MathRand = math.Rand @@ -41,7 +42,7 @@ TASK.Description = function(ply) description = description .. "s" end elseif unit == 2 then - local convertedRange = math.ceil(range * FEET_PER_METER) + local convertedRange = MathCeil(range * FEET_PER_METER) description = description .. convertedRange if convertedRange == 1 then description = description .. " foot" @@ -49,7 +50,7 @@ TASK.Description = function(ply) description = description .. " feet" end else - local convertedRange = math.ceil(range * UNITS_PER_METER) + local convertedRange = MathCeil(range * UNITS_PER_METER) description = description .. convertedRange .. " unit" if convertedRange ~= 1 then description = description .. "s" From e77d4abeff93a2732c00f96fdd6a592f1d431d0b Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 17 Aug 2025 21:28:32 -0400 Subject: [PATCH 089/115] Fixed error rerolling when there are no available tasks remaining --- gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index e1796f433..cce794786 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -112,7 +112,7 @@ function plymeta:RerollTask(taskId, free) -- they only had tasks left that don't block a win condition. -- Rerolling one of those tasks no longer guarantees that they are winning, -- unless the newly rolled task ALSO does not block a win condition. - if not newTask.allowRoundEnd and self.taskmasterShouldWin then + if newTask and not newTask.allowRoundEnd and self.taskmasterShouldWin then self:SetProperty("taskmasterShouldWin", false) end From d1c86e9d972b406d2483bd3ed9c723b452211e3c Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 14:05:58 -0400 Subject: [PATCH 090/115] Added Task.Initialize optional method Moved translations into individual tasks Added placeholders for missing translations and features --- .../roles/taskmaster/cl_taskmaster.lua | 48 +++++++++++-------- .../gamemode/roles/taskmaster/shared.lua | 19 +++++++- .../gamemode/roles/taskmaster/taskmaster.lua | 10 ++++ .../roles/taskmaster/tasks/carrycorpse.lua | 4 ++ .../roles/taskmaster/tasks/crouch.lua | 4 ++ .../roles/taskmaster/tasks/crouchnearbody.lua | 4 ++ .../roles/taskmaster/tasks/healthunder.lua | 4 ++ .../roles/taskmaster/tasks/holstered.lua | 4 ++ .../roles/taskmaster/tasks/kill360.lua | 4 ++ .../roles/taskmaster/tasks/killdouble.lua | 4 ++ .../roles/taskmaster/tasks/lookatplayer.lua | 4 ++ .../roles/taskmaster/tasks/standonplayer.lua | 4 ++ .../roles/taskmaster/tasks/stayhidden.lua | 4 ++ .../roles/taskmaster/tasks/stayhigher.lua | 4 ++ .../roles/taskmaster/tasks/stayinarea.lua | 3 ++ .../roles/taskmaster/tasks/staylower.lua | 4 ++ .../roles/taskmaster/tasks/stayneartarget.lua | 4 ++ .../roles/taskmaster/tasks/takedamage.lua | 4 ++ 18 files changed, 116 insertions(+), 20 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 77cda3e78..90c85afde 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -1,3 +1,16 @@ +local CurTime = CurTime +local draw = draw +local hook = hook +local ipairs = ipairs +local math = math +local net = net +local player = player +local string = string +local surface = surface +local table = table +local util = util +local vgui = vgui + ------------------ -- TRANSLATIONS -- ------------------ @@ -15,31 +28,18 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() -- Bonus credit popup LANG.AddToLanguage("english", "taskmaster_credit_bonus", "{role}, you have been awarded {num} credit(s) for completing a task.") - -- Tasks - -- TODO: Create init method for tasks and move these into task files - LANG.AddToLanguage("english", "taskmaster_carrycorpse", "CARRY CORPSE - {time}") - LANG.AddToLanguage("english", "taskmaster_crouchnearbody", "CROUCH NEAR BODY - {time}") - LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") - LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") - LANG.AddToLanguage("english", "taskmaster_holstered", "STAY HOLSTERED - {time}") - LANG.AddToLanguage("english", "taskmaster_kill360", "KILL SOMEONE - {time}") - LANG.AddToLanguage("english", "taskmaster_killdouble", "KILL ANOTHER - {time}") - LANG.AddToLanguage("english", "taskmaster_lookatplayer", "KEEP LOOKING - {time}") - LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") - LANG.AddToLanguage("english", "taskmaster_stayaway", "STAY AWAY - {time}") - LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") - LANG.AddToLanguage("english", "taskmaster_stayhidden", "STAY HIDDEN - {time}") - LANG.AddToLanguage("english", "taskmaster_stayhigher", "STAY HIGHEST - {time}") - LANG.AddToLanguage("english", "taskmaster_stayinarea", "STAY IN AREA - {time}") - LANG.AddToLanguage("english", "taskmaster_staylower", "STAY LOWEST - {time}") - LANG.AddToLanguage("english", "taskmaster_takedamage", "AVOID DAMAGE - {time}") - -- Win conditions LANG.AddToLanguage("english", "win_taskmaster", "The {role} finished off their list!") LANG.AddToLanguage("english", "ev_win_taskmaster", "The methodical {role} has won the round!") -- HUD LANG.AddToLanguage("english", "taskmaster_hud", "You will lose in: {time}") + + -- Cheat Sheet + LANG.AddToLanguage("english", "cheatsheet_desc_taskmaster", "TODO") + + -- Popup + LANG.AddToLanguage("english", "info_popup_taskmaster", [[You are {role}! TODO]]) end) ------------- @@ -452,4 +452,14 @@ hook.Add("TTTEquipmentTabs", "Taskmaster_TTTEquipmentTabs", function(dsheet, dfr dsheet:AddSheet(LANG.GetTranslation("taskmaster_reroll_name"), dscrollpanel, "icon16/table_edit.png", false, false, LANG.GetTranslation("equip_tooltip_taskmaster_reroll")) return true end +end) + +-------------- +-- TUTORIAL -- +-------------- + +hook.Add("TTTTutorialRoleText", "Taskmaster_TTTTutorialRoleText", function(role, titleLabel) + --if role == ROLE_TASKMASTER then + -- -- TODO + --end end) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua index f7a5fd7ea..7d13bb683 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -1,5 +1,9 @@ AddCSLuaFile() +local hook = hook +local ipairs = ipairs +local table = table + -- Task Features TASKMASTER_TF_TARGETID_PLAYERICON = 0 TASKMASTER_TF_TARGETID_PLAYERTEXT = 1 @@ -80,4 +84,17 @@ local function AddTaskFiles(root) end AddTaskFiles("terrortown/gamemode/roles/taskmaster/tasks/") -- Internal tasks -AddTaskFiles("taskmastertasks/") -- External tasks \ No newline at end of file +AddTaskFiles("taskmastertasks/") -- External tasks + +hook.Add("Initialize", "Taskmaster_Task_Initialize", function() + for _, t in pairs(TASKMASTER.killTasks) do + if t.Initialize then + t.Initialize() + end + end + for _, t in pairs(TASKMASTER.miscTasks) do + if t.Initialize then + t.Initialize() + end + end +end) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index cce794786..f9abe4a5d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -1,5 +1,15 @@ AddCSLuaFile() +local CurTime = CurTime +local hook = hook +local ipairs = ipairs +local math = math +local net = net +local pairs = pairs +local player = player +local table = table +local util = util + local plymeta = FindMetaTable("Player") util.AddNetworkString("TTT_TaskmasterRerollTask") diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua index 2905c6346..ca2446b52 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -100,6 +100,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_carrycorpse", "CARRY CORPSE - {time}") + end + net.Receive("TTT_Taskmaster_CarryCorpse_Assigned", function() local client = LocalPlayer() local sid64 = client:SteamID64() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 27a73c0c5..4b01626b2 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -98,6 +98,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_crouch", "STAY CROUCHING - {time}") + end + net.Receive("TTT_Taskmaster_Crouch_Assigned", function() local client = LocalPlayer() local time = taskmaster_crouch_time:GetInt() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index 6fecedc4a..ee1479863 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -144,6 +144,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_crouchnearbody", "CROUCH NEAR BODY - {time}") + end + net.Receive("TTT_Taskmaster_CrouchNearBody_Assigned", function() local client = LocalPlayer() local sid64 = client:SteamID64() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index 926536737..feabfd965 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -103,6 +103,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_healthunder", "DON'T HEAL - {time}") + end + net.Receive("TTT_Taskmaster_HealthUnder_Assigned", function() local client = LocalPlayer() local time = taskmaster_healthunder_time:GetInt() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index e12b7e3c9..bddc89da9 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -103,6 +103,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_holstered", "STAY HOLSTERED - {time}") + end + net.Receive("TTT_Taskmaster_Holstered_Assigned", function() local client = LocalPlayer() local sid64 = client:SteamID64() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua index fa3b17adf..4a2f1916d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua @@ -133,6 +133,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_kill360", "KILL SOMEONE - {time}") + end + net.Receive("TTT_Taskmaster_Kill360_Assigned", function() local client = LocalPlayer() local time = taskmaster_kill360_time:GetInt() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua index 27bf51538..bd049cd63 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua @@ -74,6 +74,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_killdouble", "KILL ANOTHER - {time}") + end + net.Receive("TTT_Taskmaster_KillDouble_Assigned", function() local client = LocalPlayer() local time = taskmaster_killdouble_time:GetInt() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index cc81d3d4f..67113bc87 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -156,6 +156,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_lookatplayer", "KEEP LOOKING - {time}") + end + net.Receive("TTT_Taskmaster_LookAtPlayer_Assigned", function() local client = LocalPlayer() local sid64 = client:SteamID64() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index a7f862893..e60116a64 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -98,6 +98,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_standonplayer", "STAY ON PLAYER - {time}") + end + net.Receive("TTT_Taskmaster_StandOnPlayer_Assigned", function() local client = LocalPlayer() local sid64 = client:SteamID64() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua index 36a2c8b08..d0c49baa0 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua @@ -119,6 +119,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_stayhidden", "STAY HIDDEN - {time}") + end + net.Receive("TTT_Taskmaster_StayHidden_Assigned", function() local client = LocalPlayer() local time = taskmaster_stayhidden_time:GetInt() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index fd6e77e14..08ef21d00 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -122,6 +122,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_stayhigher", "STAY HIGHEST - {time}") + end + net.Receive("TTT_Taskmaster_StayHigher_Assigned", function() local client = LocalPlayer() local sid64 = client:SteamID64() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index 88e552de3..c637c7322 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -117,6 +117,9 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_stayinarea", "STAY IN AREA - {time}") + end local function DrawLink(ply, targetPos) if not ply.TaskmasterStayInAreaLinkEmitter then ply.TaskmasterStayInAreaLinkEmitter = ParticleEmitter(targetPos) end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index 986ce5136..90bb888e0 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -122,6 +122,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_staylower", "STAY LOWEST - {time}") + end + net.Receive("TTT_Taskmaster_StayLower_Assigned", function() local client = LocalPlayer() local sid64 = client:SteamID64() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 5d55b9199..2bc86ac3a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -194,6 +194,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_stayneartarget", "STAY NEAR TARGET - {time}") + end + net.Receive("TTT_Taskmaster_StayNearTarget_Assigned", function() local client = LocalPlayer() local sid64 = client:SteamID64() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua index 76577e1e1..ce4833fad 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua @@ -97,6 +97,10 @@ if SERVER then end if CLIENT then + TASK.Initialize = function() + LANG.AddToLanguage("english", "taskmaster_takedamage", "AVOID DAMAGE - {time}") + end + net.Receive("TTT_Taskmaster_TakeDamage_Assigned", function() local client = LocalPlayer() local time = taskmaster_takedamage_time:GetInt() From c519767329f6e19b452b3b2fd1e85320b8ccb117 Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 14:07:57 -0400 Subject: [PATCH 091/115] Cleanup --- gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua index 7d13bb683..bb7271272 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -29,7 +29,6 @@ CreateConVar("ttt_taskmaster_wins_with_others", "1", FCVAR_REPLICATED, "If the T CreateConVar("ttt_taskmaster_is_passive", "0", FCVAR_REPLICATED, "Whether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if 'ttt_taskmaster_wins_with_others' is enabled)") ROLE_CONVARS[ROLE_TASKMASTER] = {} - table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_kill_tasks", type = ROLE_CONVAR_TYPE_NUM, From 62fa5dbe4b19ae7351f0ee23efc8c5b913783be5 Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 14:48:17 -0400 Subject: [PATCH 092/115] Added tutorial, popup, and cheatsheet text --- .../roles/taskmaster/cl_taskmaster.lua | 38 ++++++++++++++++--- .../roles/taskmaster/tasks/carrycorpse.lua | 2 + .../gamemode/roles/taskmaster/tasks/chat.lua | 2 + .../roles/taskmaster/tasks/crouch.lua | 2 + .../roles/taskmaster/tasks/crouchnearbody.lua | 5 ++- .../roles/taskmaster/tasks/crowbar.lua | 2 + .../roles/taskmaster/tasks/damageeveryone.lua | 6 ++- .../roles/taskmaster/tasks/dodamage.lua | 5 ++- .../roles/taskmaster/tasks/firebullets.lua | 2 + .../taskmaster/tasks/getplayerkilled.lua | 4 +- .../taskmaster/tasks/getplayertokill.lua | 4 +- .../roles/taskmaster/tasks/healthunder.lua | 5 ++- .../roles/taskmaster/tasks/holstered.lua | 2 + .../gamemode/roles/taskmaster/tasks/jump.lua | 2 + .../roles/taskmaster/tasks/killtarget.lua | 4 +- .../roles/taskmaster/tasks/killweapon.lua | 4 +- .../roles/taskmaster/tasks/lookatplayer.lua | 14 ++++--- .../roles/taskmaster/tasks/standonplayer.lua | 2 + .../roles/taskmaster/tasks/stayhidden.lua | 2 + .../roles/taskmaster/tasks/stayhigher.lua | 2 + .../roles/taskmaster/tasks/stayinarea.lua | 2 + .../roles/taskmaster/tasks/staylower.lua | 2 + .../roles/taskmaster/tasks/stayneartarget.lua | 14 ++++--- .../roles/taskmaster/tasks/takedamage.lua | 6 ++- .../roles/taskmaster/tasks/weaponpickups.lua | 2 + 25 files changed, 107 insertions(+), 28 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 90c85afde..3d45829b1 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -36,10 +36,13 @@ hook.Add("Initialize", "Taskmaster_Translations_Initialize", function() LANG.AddToLanguage("english", "taskmaster_hud", "You will lose in: {time}") -- Cheat Sheet - LANG.AddToLanguage("english", "cheatsheet_desc_taskmaster", "TODO") + LANG.AddToLanguage("english", "cheatsheet_desc_taskmaster", "Has a list of tasks that they must complete before the end of the round.") -- Popup - LANG.AddToLanguage("english", "info_popup_taskmaster", [[You are {role}! TODO]]) + LANG.AddToLanguage("english", "info_popup_taskmaster", [[You are {role}! Complete your tasks +before the end of the round! + +Press {menukey} to pay a credit to replace a task you don't like!]]) end) ------------- @@ -459,7 +462,32 @@ end) -------------- hook.Add("TTTTutorialRoleText", "Taskmaster_TTTTutorialRoleText", function(role, titleLabel) - --if role == ROLE_TASKMASTER then - -- -- TODO - --end + if role == ROLE_TASKMASTER then + local roleColor = GetRoleTeamColor(ROLE_TEAM_INDEPENDENT) + local html = "The " .. ROLE_STRINGS[ROLE_TASKMASTER] .. " is an independent role whose goal is to complete a series of tasks before the round ends." + + -- Reroll + html = html .. "Undesired or uncompletable tasks can be rerolled by spending a credit in the equipment menu (press '" .. Key("+menu_context", "C") .. "')" + + -- Show all enabled tasks + local tasks = {} + for _, t in pairs(TASKMASTER.killTasks) do + if not t.Enabled() then continue end + table.insert(tasks, { name = t.Name(), desc = t.Description() }) + end + for _, t in pairs(TASKMASTER.miscTasks) do + if not t.Enabled() then continue end + table.insert(tasks, { name = t.Name(), desc = t.Description() }) + end + table.SortByMember(tasks, "name", true) + + html = html .. "Available tasks:" + html = html .. "

    " + for _, t in ipairs(tasks) do + html = html .. "
  • " .. t.name .. " - " .. t.desc .. "
  • " + end + html = html .. "
" + + return html + end end) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua index ca2446b52..87032b2af 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -28,6 +28,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua index d95c756ce..4262b2474 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua @@ -21,6 +21,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 4b01626b2..e0a9d9fe3 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -28,6 +28,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index ee1479863..6829fde8c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -32,6 +32,9 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_crouchnearbody_time:GetInt() + local name = "Crouch Near a Body" + + if not ply then return name end local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then @@ -43,7 +46,7 @@ TASK.Name = function(ply) end end - return "Crouch Near a Body (" .. progress .. "/" .. time .. ")" + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua index 0f90cd1b3..5fb2a0e38 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua @@ -21,6 +21,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua index 841990b1a..723ea256d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua @@ -14,6 +14,10 @@ local TASK = {} TASK.id = "damageeveryone" TASK.Name = function(ply) + local name = "Damage Everyone Else" + + if not ply then return name end + local damaged = ply.Task_DamageEveryoneDamaged or {} local total = 0 local progress = 0 @@ -30,7 +34,7 @@ TASK.Name = function(ply) progress = total end - return "Damage Everyone Else (" .. progress .. "/" .. total .. ")" + return name .. " (" .. progress .. "/" .. total .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua index a85c327a0..b597c263c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua @@ -16,6 +16,9 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local amount = taskmaster_dodamage_amount:GetInt() + local name = "Deal " .. amount .. " Damage" + + if not ply then return name end local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then @@ -24,7 +27,7 @@ TASK.Name = function(ply) progress = ply.Task_DoDamageTotal end - return "Deal " .. amount .. " Damage (" .. progress .. "/" .. amount .. ")" + return name .. " (" .. progress .. "/" .. amount .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua index 4e097f009..7adc4b804 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua @@ -21,6 +21,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua index 08aab0207..90af4fffb 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayerkilled.lua @@ -9,7 +9,7 @@ TASK.id = "getplayerkilled" TASK.Name = function(ply) local name = "Target" - if IsPlayer(ply.Task_GetPlayerKilledPlayer) then + if ply and IsPlayer(ply.Task_GetPlayerKilledPlayer) then name = ply.Task_GetPlayerKilledPlayer:Nick() end return "Get " .. name .. " Killed" @@ -17,7 +17,7 @@ end TASK.Description = function(ply) local name = "target" - if IsPlayer(ply.Task_GetPlayerKilledPlayer) then + if ply and IsPlayer(ply.Task_GetPlayerKilledPlayer) then name = ply.Task_GetPlayerKilledPlayer:Nick() end return "Get " .. name .. " killed by another player (not you)" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua index 73493e4b1..21f22dae9 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/getplayertokill.lua @@ -9,7 +9,7 @@ TASK.id = "getplayertokill" TASK.Name = function(ply) local name = "Target" - if IsPlayer(ply.Task_GetPlayerToKillPlayer) then + if ply and IsPlayer(ply.Task_GetPlayerToKillPlayer) then name = ply.Task_GetPlayerToKillPlayer:Nick() end return "Get " .. name .. " to Kill" @@ -17,7 +17,7 @@ end TASK.Description = function(ply) local name = "target" - if IsPlayer(ply.Task_GetPlayerToKillPlayer) then + if ply and IsPlayer(ply.Task_GetPlayerToKillPlayer) then name = ply.Task_GetPlayerToKillPlayer:Nick() end return "Get " .. name .. " to kill another player (not you)" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index feabfd965..da83974fd 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -30,6 +30,9 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local amount = taskmaster_healthunder_amount:GetInt() local time = taskmaster_healthunder_time:GetInt() + local name = "Survive Under " .. amount .. " Health" + + if not ply then return name end local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then @@ -41,7 +44,7 @@ TASK.Name = function(ply) end end - return "Survive Under " .. amount .. " Health (" .. progress .. "/" .. time .. ")" + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index bddc89da9..9c7c085d5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -28,6 +28,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua index 95c662960..f38dd4abb 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -21,6 +21,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = times diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua index 61efc03dc..25a14f20c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua @@ -10,7 +10,7 @@ TASK.isKillTask = true TASK.Name = function(ply) local name = "Target" - if IsPlayer(ply.Task_KillTargetPlayer) then + if ply and IsPlayer(ply.Task_KillTargetPlayer) then name = ply.Task_KillTargetPlayer:Nick() end return "Kill " .. name @@ -18,7 +18,7 @@ end TASK.Description = function(ply) local name = "target" - if IsPlayer(ply.Task_KillTargetPlayer) then + if ply and IsPlayer(ply.Task_KillTargetPlayer) then name = ply.Task_KillTargetPlayer:Nick() end return "Kill " .. name .. " by any means necessary" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua index 9b211af9c..7ed1549e7 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua @@ -13,7 +13,7 @@ TASK.isKillTask = true TASK.Name = function(ply) local weapon = "Specific Weapon" - if CLIENT and ply.Task_KillWeaponClass then + if CLIENT and ply and ply.Task_KillWeaponClass then for _, wep in ipairs(weapons.GetList()) do if ply.Task_KillWeaponClass == WEPS.GetClass(wep) then weapon = LANG.TryTranslation(wep.PrintName) @@ -26,7 +26,7 @@ end TASK.Description = function(ply) local weapon = "specific weapon" - if CLIENT and ply.Task_KillWeaponClass then + if CLIENT and ply and ply.Task_KillWeaponClass then for _, wep in ipairs(weapons.GetList()) do if ply.Task_KillWeaponClass == WEPS.GetClass(wep) then weapon = LANG.TryTranslation(wep.PrintName) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index 67113bc87..3f76291d3 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -22,11 +22,15 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { }) TASK.Name = function(ply) - local name = "Target" - if IsPlayer(ply.Task_LookAtPlayerPlayer) then - name = ply.Task_LookAtPlayerPlayer:Nick() + local name = "Look at " + if ply and IsPlayer(ply.Task_LookAtPlayerPlayer) then + name = name .. ply.Task_LookAtPlayerPlayer:Nick() + else + name = name .. "Target" end + if not ply then return name end + local time = taskmaster_lookatplayer_time:GetInt() local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then @@ -38,12 +42,12 @@ TASK.Name = function(ply) end end - return "Look at " .. name .. " (" .. progress .. "/" .. time .. ")" + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) local name = "target" - if IsPlayer(ply.Task_LookAtPlayerPlayer) then + if ply and IsPlayer(ply.Task_LookAtPlayerPlayer) then name = ply.Task_LookAtPlayerPlayer:Nick() end local time = taskmaster_lookatplayer_time:GetInt() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index e60116a64..37c3f2c44 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -28,6 +28,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua index d0c49baa0..b81666efa 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua @@ -30,6 +30,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index 08ef21d00..48cd7b8a9 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -30,6 +30,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index c637c7322..96f767a62 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -38,6 +38,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index 90bb888e0..8f55bd655 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -30,6 +30,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 2bc86ac3a..51d7b1117 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -34,11 +34,15 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { }) TASK.Name = function(ply) - local name = "Target" - if IsPlayer(ply.Task_StayNearTargetPlayer) then - name = ply.Task_StayNearTargetPlayer:Nick() + local name = "Stay Near " + if ply and IsPlayer(ply.Task_StayNearTargetPlayer) then + name = name .. ply.Task_StayNearTargetPlayer:Nick() + else + name = name .. "Target" end + if not ply then return name end + local time = taskmaster_stayneartarget_time:GetInt() local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then @@ -50,7 +54,7 @@ TASK.Name = function(ply) end end - return "Stay Near " .. name .. " (" .. progress .. "/" .. time .. ")" + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) @@ -84,7 +88,7 @@ TASK.Description = function(ply) end local name = "target" - if IsPlayer(ply.Task_StayNearTargetPlayer) then + if ply and IsPlayer(ply.Task_StayNearTargetPlayer) then name = ply.Task_StayNearTargetPlayer:Nick() end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua index ce4833fad..d99f16231 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua @@ -23,6 +23,10 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { TASK.Name = function(ply) local time = taskmaster_takedamage_time:GetInt() + local name = "Take Damage and Survive" + + if not ply then return name end + local progress = 0 if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = time @@ -33,7 +37,7 @@ TASK.Name = function(ply) end end - return "Take Damage and Survive (" .. progress .. "/" .. time .. ")" + return name .. " (" .. progress .. "/" .. time .. ")" end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua index 7a04f78c8..cc72c9aad 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua @@ -21,6 +21,8 @@ TASK.Name = function(ply) name = name .. "s" end + if not ply then return name end + local progress if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then progress = count From ce2320f3ef4baa5819d34db16e98319ca5eda55f Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 15:00:44 -0400 Subject: [PATCH 093/115] Changed Taskmaster to see jesters and MIA in case they need to kill everyone to win --- gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua index bb7271272..1bdef54d5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -10,6 +10,9 @@ TASKMASTER_TF_TARGETID_PLAYERTEXT = 1 TASKMASTER_TF_PROGRESSBAR = 2 TASKMASTER_TF_PARTICLERADIUS = 3 +-- Initialize role features +ROLE_CAN_SEE_JESTERS[ROLE_TASKMASTER] = true +ROLE_CAN_SEE_MIA[ROLE_TASKMASTER] = true ROLE_STARTING_CREDITS[ROLE_TASKMASTER] = 1 ROLE_HAS_PASSIVE_WIN[ROLE_TASKMASTER] = false cvars.AddChangeCallback("ttt_taskmaster_is_passive", function(_, _, newValue) From b6860f741fdae90ab4ba7260d562efb2b5a35c05 Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 15:06:56 -0400 Subject: [PATCH 094/115] Expanded Taskmaster tutorial --- .../roles/taskmaster/cl_taskmaster.lua | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 3d45829b1..b16d915f7 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -50,6 +50,9 @@ end) ------------- local taskmaster_wins_with_others = GetConVar("ttt_taskmaster_wins_with_others") +local taskmaster_kill_tasks = GetConVar("ttt_taskmaster_kill_tasks") +local taskmaster_misc_tasks = GetConVar("ttt_taskmaster_misc_tasks") +local taskmaster_win_block_length = GetConVar("ttt_taskmaster_win_block_length") local xOffset = CreateClientConVar("ttt_taskmaster_list_x_pos", "10", true, false, "The X (horizontal) position of the Taskmaster's task list HUD", 0, ScrW()) local yOffset = CreateClientConVar("ttt_taskmaster_list_y_pos", "10", true, false, "The Y (vertical) position of the Taskmaster's task list HUD", 0, ScrH()) @@ -466,6 +469,36 @@ hook.Add("TTTTutorialRoleText", "Taskmaster_TTTTutorialRoleText", function(role, local roleColor = GetRoleTeamColor(ROLE_TEAM_INDEPENDENT) local html = "The " .. ROLE_STRINGS[ROLE_TASKMASTER] .. " is an independent role whose goal is to complete a series of tasks before the round ends." + -- Task counts + local kill_count = taskmaster_kill_tasks:GetInt() + local kill_plural = "" + if kill_count ~= 1 then + kill_plural = "s" + end + local misc_count = taskmaster_misc_tasks:GetInt() + local misc_plural = "" + if misc_count ~= 1 then + misc_plural = "s" + end + html = html .. "The " .. ROLE_STRINGS[ROLE_TASKMASTER] .. " must complete " .. kill_count .. " task" .. kill_plural .. " that require killing a player (or multiple) and " .. misc_count .. " other task" .. misc_plural .. "." + + -- Win condition + if taskmaster_wins_with_others:GetBool() then + html = html .. "If another team wins after the " .. ROLE_STRINGS[ROLE_TASKMASTER] .. " finishes their tasks, they will share the win." + else + html = html .. "In addition to completing all tasks, the " .. ROLE_STRINGS[ROLE_TASKMASTER] .. " must also eliminate all other players." + end + + -- Win block + local block_length = taskmaster_win_block_length:GetInt() + if block_length > 0 then + local plural = "" + if block_length ~= 1 then + plural = "s" + end + html = html .. "If the " .. ROLE_STRINGS[ROLE_TASKMASTER] .. " has not completed all tasks by the time another team wins, the round will be extended by " .. block_length .. " second" .. plural .. ", giving them extra time to finish." + end + -- Reroll html = html .. "Undesired or uncompletable tasks can be rerolled by spending a credit in the equipment menu (press '" .. Key("+menu_context", "C") .. "')" From ef75c38ae93fa27a65b4bed80fff6f0e08f75c73 Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 15:17:03 -0400 Subject: [PATCH 095/115] Standardize naming on PascalCase --- .../roles/taskmaster/cl_taskmaster.lua | 30 +++--- .../gamemode/roles/taskmaster/shared.lua | 12 +-- .../gamemode/roles/taskmaster/taskmaster.lua | 91 ++++++++++--------- .../roles/taskmaster/tasks/carrycorpse.lua | 2 +- .../gamemode/roles/taskmaster/tasks/chat.lua | 2 +- .../roles/taskmaster/tasks/crouch.lua | 2 +- .../roles/taskmaster/tasks/crouchnearbody.lua | 2 +- .../roles/taskmaster/tasks/crowbar.lua | 2 +- .../roles/taskmaster/tasks/damageeveryone.lua | 2 +- .../roles/taskmaster/tasks/dodamage.lua | 2 +- .../roles/taskmaster/tasks/firebullets.lua | 2 +- .../roles/taskmaster/tasks/healthunder.lua | 2 +- .../roles/taskmaster/tasks/holstered.lua | 2 +- .../gamemode/roles/taskmaster/tasks/jump.lua | 2 +- .../roles/taskmaster/tasks/kill360.lua | 2 +- .../roles/taskmaster/tasks/killaiming.lua | 2 +- .../roles/taskmaster/tasks/killairborne.lua | 2 +- .../roles/taskmaster/tasks/killbehind.lua | 2 +- .../roles/taskmaster/tasks/killcrowbar.lua | 2 +- .../roles/taskmaster/tasks/killdistant.lua | 2 +- .../roles/taskmaster/tasks/killdouble.lua | 2 +- .../roles/taskmaster/tasks/killheadshot.lua | 2 +- .../roles/taskmaster/tasks/killlastbullet.lua | 2 +- .../roles/taskmaster/tasks/killmidair.lua | 2 +- .../roles/taskmaster/tasks/killnearby.lua | 2 +- .../roles/taskmaster/tasks/killonehit.lua | 2 +- .../roles/taskmaster/tasks/killpistol.lua | 2 +- .../roles/taskmaster/tasks/killretaliate.lua | 2 +- .../roles/taskmaster/tasks/killtarget.lua | 2 +- .../roles/taskmaster/tasks/killweapon.lua | 2 +- .../roles/taskmaster/tasks/lookatplayer.lua | 2 +- .../roles/taskmaster/tasks/standonplayer.lua | 2 +- .../roles/taskmaster/tasks/stayhidden.lua | 2 +- .../roles/taskmaster/tasks/stayhigher.lua | 2 +- .../roles/taskmaster/tasks/stayinarea.lua | 2 +- .../roles/taskmaster/tasks/staylower.lua | 2 +- .../roles/taskmaster/tasks/stayneartarget.lua | 2 +- .../roles/taskmaster/tasks/survive.lua | 2 +- .../roles/taskmaster/tasks/takedamage.lua | 2 +- .../roles/taskmaster/tasks/weaponpickups.lua | 2 +- 40 files changed, 104 insertions(+), 103 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index b16d915f7..c6e36732a 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -82,7 +82,7 @@ hook.Add("TTTScoringSecondaryWins", "Taskmaster_TTTScoringSecondaryWins", functi for _, ply in player.Iterator() do if not ply:IsTaskmaster() then continue end - if ply.taskmasterShouldWin then + if ply.TaskmasterShouldWin then table.insert(secondary_wins, ROLE_TASKMASTER) break end @@ -135,7 +135,7 @@ local function DrawTask(task, height, isShadow) progress = task.Progress(client) desc = desc .. " " .. progress end - local completed = table.HasValue(client.taskmasterCompletedTasks, task.id) + local completed = table.HasValue(client.TaskmasterCompletedTasks, task.id) -- The checkboxes don't naturally align with the text, thus the '+2's everywhere to make it line up surface.DrawRect(xPos + margin + 2 + offset, height + 2 + offset, 2, checkboxSize) @@ -228,14 +228,14 @@ hook.Add("HUDPaint", "Taskmaster_HUDPaint", function() local height = yOffset:GetInt() + margin - for _, id in ipairs(client.taskmasterKillTasks) do - DrawTask(TASKMASTER.killTasks[id], height, true) - height = DrawTask(TASKMASTER.killTasks[id], height) + for _, id in ipairs(client.TaskmasterKillTasks) do + DrawTask(TASKMASTER.KillTasks[id], height, true) + height = DrawTask(TASKMASTER.KillTasks[id], height) end - for _, id in ipairs(client.taskmasterMiscTasks) do - DrawTask(TASKMASTER.miscTasks[id], height, true) - height = DrawTask(TASKMASTER.miscTasks[id], height) + for _, id in ipairs(client.TaskmasterMiscTasks) do + DrawTask(TASKMASTER.MiscTasks[id], height, true) + height = DrawTask(TASKMASTER.MiscTasks[id], height) end maxHeight = height - yOffset:GetInt() @@ -275,7 +275,7 @@ local scrollBarWidth = 15 local creditsIconSize = 32 local function CreateTaskReroll(task, dscrollpanel) - if table.HasValue(client.taskmasterCompletedTasks, task.id) then return false end + if table.HasValue(client.TaskmasterCompletedTasks, task.id) then return false end local name = task.Name(client) local desc = task.Description(client) @@ -353,16 +353,16 @@ local function CreateTaskList(dscrollpanel) dtasks = {} dtasksHeight = 0 - for _, id in ipairs(client.taskmasterKillTasks) do - local dtask, dline = CreateTaskReroll(TASKMASTER.killTasks[id], dscrollpanel) + for _, id in ipairs(client.TaskmasterKillTasks) do + local dtask, dline = CreateTaskReroll(TASKMASTER.KillTasks[id], dscrollpanel) if dtask then table.insert(dtasks, dtask) table.insert(dtasks, dline) end end - for _, id in ipairs(client.taskmasterMiscTasks) do - local dtask, dline = CreateTaskReroll(TASKMASTER.miscTasks[id], dscrollpanel) + for _, id in ipairs(client.TaskmasterMiscTasks) do + local dtask, dline = CreateTaskReroll(TASKMASTER.MiscTasks[id], dscrollpanel) if dtask then table.insert(dtasks, dtask) table.insert(dtasks, dline) @@ -504,11 +504,11 @@ hook.Add("TTTTutorialRoleText", "Taskmaster_TTTTutorialRoleText", function(role, -- Show all enabled tasks local tasks = {} - for _, t in pairs(TASKMASTER.killTasks) do + for _, t in pairs(TASKMASTER.KillTasks) do if not t.Enabled() then continue end table.insert(tasks, { name = t.Name(), desc = t.Description() }) end - for _, t in pairs(TASKMASTER.miscTasks) do + for _, t in pairs(TASKMASTER.MiscTasks) do if not t.Enabled() then continue end table.insert(tasks, { name = t.Name(), desc = t.Description() }) end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua index 1bdef54d5..55b376a7c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -55,7 +55,7 @@ TASKMASTER = { function TASKMASTER.RegisterTask(task) task.id = task.id or task.Id or task.ID - if TASKMASTER.killTasks[task.id] or TASKMASTER.miscTasks[task.id] then + if TASKMASTER.KillTasks[task.id] or TASKMASTER.MiscTasks[task.id] then ErrorNoHalt("ERROR: Attempted to register Taskmaster task '" .. task.id .. "' with duplicate task ID.\n") return end @@ -70,10 +70,10 @@ function TASKMASTER.RegisterTask(task) type = ROLE_CONVAR_TYPE_BOOL }) - if task.isKillTask then - TASKMASTER.killTasks[task.id] = task + if task.IsKillTask then + TASKMASTER.KillTasks[task.id] = task else - TASKMASTER.miscTasks[task.id] = task + TASKMASTER.MiscTasks[task.id] = task end end @@ -89,12 +89,12 @@ AddTaskFiles("terrortown/gamemode/roles/taskmaster/tasks/") -- Internal tasks AddTaskFiles("taskmastertasks/") -- External tasks hook.Add("Initialize", "Taskmaster_Task_Initialize", function() - for _, t in pairs(TASKMASTER.killTasks) do + for _, t in pairs(TASKMASTER.KillTasks) do if t.Initialize then t.Initialize() end end - for _, t in pairs(TASKMASTER.miscTasks) do + for _, t in pairs(TASKMASTER.MiscTasks) do if t.Initialize then t.Initialize() end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index f9abe4a5d..fb4905b06 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -33,14 +33,14 @@ local taskmaster_wins_with_others = GetConVar("ttt_taskmaster_wins_with_others") function plymeta:AssignTask(isKillTask, index) if not self:IsTaskmaster() then return end - local taskList = isKillTask and TASKMASTER.killTasks or TASKMASTER.miscTasks + local taskList = isKillTask and TASKMASTER.KillTasks or TASKMASTER.MiscTasks local taskIds = table.GetKeys(taskList) - local activeTasksName = isKillTask and "taskmasterKillTasks" or "taskmasterMiscTasks" + local activeTasksName = isKillTask and "TaskmasterKillTasks" or "TaskmasterMiscTasks" for _, activeId in ipairs(self[activeTasksName]) do table.RemoveByValue(taskIds, activeId) end - for _, rerolledId in ipairs(self.taskmasterRerolledTasks) do + for _, rerolledId in ipairs(self.TaskmasterRerolledTasks) do table.RemoveByValue(taskIds, rerolledId) end table.Shuffle(taskIds) @@ -49,9 +49,9 @@ function plymeta:AssignTask(isKillTask, index) if taskList[id].CanAssignTask(self) then local blockedByFeature = false for _, feature in pairs(taskList[id].RequiredFeatures) do - for _, killTaskId in pairs(self.taskmasterKillTasks) do - if not table.HasValue(self.taskmasterCompletedTasks, killTaskId) and not table.HasValue(self.taskmasterRerolledTasks, killTaskId) then - if table.HasValue(TASKMASTER.killTasks[killTaskId].RequiredFeatures, feature) then + for _, killTaskId in pairs(self.TaskmasterKillTasks) do + if not table.HasValue(self.TaskmasterCompletedTasks, killTaskId) and not table.HasValue(self.TaskmasterRerolledTasks, killTaskId) then + if table.HasValue(TASKMASTER.KillTasks[killTaskId].RequiredFeatures, feature) then blockedByFeature = true break end @@ -59,9 +59,9 @@ function plymeta:AssignTask(isKillTask, index) end if blockedByFeature then break end - for _, miscTaskId in pairs(self.taskmasterMiscTasks) do - if not table.HasValue(self.taskmasterCompletedTasks, miscTaskId) and not table.HasValue(self.taskmasterRerolledTasks, miscTaskId) then - if table.HasValue(TASKMASTER.miscTasks[miscTaskId].RequiredFeatures, feature) then + for _, miscTaskId in pairs(self.TaskmasterMiscTasks) do + if not table.HasValue(self.TaskmasterCompletedTasks, miscTaskId) and not table.HasValue(self.TaskmasterRerolledTasks, miscTaskId) then + if table.HasValue(TASKMASTER.MiscTasks[miscTaskId].RequiredFeatures, feature) then blockedByFeature = true break end @@ -88,9 +88,9 @@ function plymeta:AssignTask(isKillTask, index) end function plymeta:RemoveTask(taskId) - local isKillTask = TASKMASTER.killTasks[taskId] and true or false - local taskList = isKillTask and TASKMASTER.killTasks or TASKMASTER.miscTasks - local activeTasksName = isKillTask and "taskmasterKillTasks" or "taskmasterMiscTasks" + local isKillTask = TASKMASTER.KillTasks[taskId] and true or false + local taskList = isKillTask and TASKMASTER.KillTasks or TASKMASTER.MiscTasks + local activeTasksName = isKillTask and "TaskmasterKillTasks" or "TaskmasterMiscTasks" taskList[taskId].OnTaskRemoved(self) @@ -102,13 +102,13 @@ function plymeta:RerollTask(taskId, free) if not self:IsTaskmaster() then return end if not free and self:GetCredits() == 0 then return end - local isKillTask = TASKMASTER.killTasks[taskId] and true or false - local activeTasksName = isKillTask and "taskmasterKillTasks" or "taskmasterMiscTasks" + local isKillTask = TASKMASTER.KillTasks[taskId] and true or false + local activeTasksName = isKillTask and "TaskmasterKillTasks" or "TaskmasterMiscTasks" local index = table.KeyFromValue(self[activeTasksName], taskId) if not index then return end - table.insert(self.taskmasterRerolledTasks, taskId) - self:SetProperty("taskmasterRerolledTasks", self.taskmasterRerolledTasks, self) + table.insert(self.TaskmasterRerolledTasks, taskId) + self:SetProperty("TaskmasterRerolledTasks", self.TaskmasterRerolledTasks, self) local newTask = self:AssignTask(isKillTask, index) self:RemoveTask(taskId) @@ -122,8 +122,9 @@ function plymeta:RerollTask(taskId, free) -- they only had tasks left that don't block a win condition. -- Rerolling one of those tasks no longer guarantees that they are winning, -- unless the newly rolled task ALSO does not block a win condition. - if newTask and not newTask.allowRoundEnd and self.taskmasterShouldWin then - self:SetProperty("taskmasterShouldWin", false) + if newTask and not newTask.AllowRoundEnd and self.TaskmasterShouldWin then + self:SetProperty("TaskmasterShouldWin", false) + -- TODO: Alert the player that they have more tasks to do again end net.Start("TTT_TaskmasterUpdateTaskList") @@ -137,17 +138,17 @@ end) function plymeta:CompleteTask(taskId) if not self:IsActiveTaskmaster() then return end - local isKillTask = TASKMASTER.killTasks[taskId] and true or false - local taskList = isKillTask and TASKMASTER.killTasks or TASKMASTER.miscTasks - local activeTasksName = isKillTask and "taskmasterKillTasks" or "taskmasterMiscTasks" + local isKillTask = TASKMASTER.KillTasks[taskId] and true or false + local taskList = isKillTask and TASKMASTER.KillTasks or TASKMASTER.MiscTasks + local activeTasksName = isKillTask and "TaskmasterKillTasks" or "TaskmasterMiscTasks" if table.HasValue(self[activeTasksName], taskId) then taskList[taskId].OnTaskComplete(self) - table.insert(self.taskmasterCompletedTasks, taskId) - self:SetProperty("taskmasterCompletedTasks", self.taskmasterCompletedTasks, self) + table.insert(self.TaskmasterCompletedTasks, taskId) + self:SetProperty("TaskmasterCompletedTasks", self.TaskmasterCompletedTasks, self) - local activeTasksList = table.Copy(self.taskmasterKillTasks) - table.Add(activeTasksList, self.taskmasterMiscTasks) - for _, id in ipairs(self.taskmasterCompletedTasks) do + local activeTasksList = table.Copy(self.TaskmasterKillTasks) + table.Add(activeTasksList, self.TaskmasterMiscTasks) + for _, id in ipairs(self.TaskmasterCompletedTasks) do if table.HasValue(activeTasksList, id) then table.RemoveByValue(activeTasksList, id) else @@ -157,22 +158,22 @@ function plymeta:CompleteTask(taskId) local tasksRemaining = #activeTasksList for _, id in pairs(activeTasksList) do - local task = TASKMASTER.killTasks[id] + local task = TASKMASTER.KillTasks[id] if not task then - task = TASKMASTER.miscTasks[id] + task = TASKMASTER.MiscTasks[id] end if not task then continue end -- Tasks that allow the round to end should not count for this check -- since the Taskmaster wins even if they are still active - if task.allowRoundEnd then + if task.AllowRoundEnd then tasksRemaining = tasksRemaining - 1 end end if tasksRemaining <= 0 then - self:SetProperty("taskmasterShouldWin", true) + self:SetProperty("TaskmasterShouldWin", true) -- TODO: Alert the player that they have finished all their tasks end @@ -196,10 +197,10 @@ function plymeta:CompleteTask(taskId) end ROLE_ON_ROLE_ASSIGNED[ROLE_TASKMASTER] = function(ply) - ply:SetProperty("taskmasterKillTasks", {}, ply) - ply:SetProperty("taskmasterMiscTasks", {}, ply) - ply:SetProperty("taskmasterCompletedTasks", {}, ply) - ply:SetProperty("taskmasterRerolledTasks", {}, ply) + ply:SetProperty("TaskmasterKillTasks", {}, ply) + ply:SetProperty("TaskmasterMiscTasks", {}, ply) + ply:SetProperty("TaskmasterCompletedTasks", {}, ply) + ply:SetProperty("TaskmasterRerolledTasks", {}, ply) for _ = 1, taskmaster_kill_tasks:GetInt() do ply:AssignTask(true) end @@ -219,7 +220,7 @@ hook.Add("TTTWinCheckBlocks", "Taskmaster_TTTWinCheckBlocks", function(win_block local taskmaster = player.GetLivingRole(ROLE_TASKMASTER) if not IsPlayer(taskmaster) then return win_type end - if taskmaster.taskmasterShouldWin then return win_type end + if taskmaster.TaskmasterShouldWin then return win_type end if not taskmaster_blocks_team_wins:GetBool() then return win_type end @@ -259,7 +260,7 @@ hook.Add("TTTCheckForWin", "Taskmaster_TTTCheckForWin", function() local other_alive = false for _, v in player.Iterator() do if v:IsActive() then - if v:IsTaskmaster() and v.taskmasterShouldWin then + if v:IsTaskmaster() and v.TaskmasterShouldWin then winning_taskmaster_alive = true elseif not v:ShouldActLikeJester() and not ROLE_HAS_PASSIVE_WIN[v:GetRole()] then other_alive = true @@ -285,23 +286,23 @@ end) ------------- local function CleanupTasks(ply) - if ply.taskmasterKillTasks then - for _, id in pairs(ply.taskmasterKillTasks) do + if ply.TaskmasterKillTasks then + for _, id in pairs(ply.TaskmasterKillTasks) do ply:RemoveTask(id) end end - if ply.taskmasterMiscTasks then - for _, id in pairs(ply.taskmasterMiscTasks) do + if ply.TaskmasterMiscTasks then + for _, id in pairs(ply.TaskmasterMiscTasks) do ply:RemoveTask(id) end end - ply:ClearProperty("taskmasterKillTasks", ply) - ply:ClearProperty("taskmasterMiscTasks", ply) - ply:ClearProperty("taskmasterCompletedTasks", ply) - ply:ClearProperty("taskmasterRerolledTasks", ply) - ply:ClearProperty("taskmasterShouldWin") + ply:ClearProperty("TaskmasterKillTasks", ply) + ply:ClearProperty("TaskmasterMiscTasks", ply) + ply:ClearProperty("TaskmasterCompletedTasks", ply) + ply:ClearProperty("TaskmasterRerolledTasks", ply) + ply:ClearProperty("TaskmasterShouldWin") end hook.Add("TTTPrepareRound", "Taskmaster_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua index 87032b2af..088946e12 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/carrycorpse.lua @@ -31,7 +31,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_CarryCorpseStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua index 4262b2474..208fc1129 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua @@ -24,7 +24,7 @@ TASK.Name = function(ply) if not ply then return name end local progress - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = times else progress = ply.Task_ChatCount diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index e0a9d9fe3..752dd0969 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -31,7 +31,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_CrouchStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua index 6829fde8c..1a62e4fe1 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouchnearbody.lua @@ -37,7 +37,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_CrouchNearBodyStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua index 5fb2a0e38..5435b8326 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua @@ -24,7 +24,7 @@ TASK.Name = function(ply) if not ply then return name end local progress - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = times else progress = ply.Task_CrowbarCount diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua index 723ea256d..735f7511c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua @@ -30,7 +30,7 @@ TASK.Name = function(ply) end end - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = total end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua index b597c263c..542918e7b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua @@ -21,7 +21,7 @@ TASK.Name = function(ply) if not ply then return name end local progress - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = amount else progress = ply.Task_DoDamageTotal diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua index 7adc4b804..ecd081152 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua @@ -24,7 +24,7 @@ TASK.Name = function(ply) if not ply then return name end local progress - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = times else progress = ply.Task_FireBulletsCount diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua index da83974fd..69a06280c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/healthunder.lua @@ -35,7 +35,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_HealthUnderStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua index 9c7c085d5..8637a5899 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/holstered.lua @@ -31,7 +31,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_HolsteredStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua index f38dd4abb..ef27470db 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -24,7 +24,7 @@ TASK.Name = function(ply) if not ply then return name end local progress - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = times else progress = ply.Task_JumpCount diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua index 4a2f1916d..ea89f21c3 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua @@ -9,7 +9,7 @@ local MathMax = math.max local TASK = {} TASK.id = "kill360" -TASK.isKillTask = true +TASK.IsKillTask = true local taskmaster_kill360_time = CreateConVar("ttt_taskmaster_kill360_time", "3", FCVAR_REPLICATED, "The time (in seconds) a player has after completing a 360 to kill a player for the 'Kill a Player After a 360' task", 1, 10) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killaiming.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killaiming.lua index df6c34850..6cc0ad58f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killaiming.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killaiming.lua @@ -3,7 +3,7 @@ local hook = hook local TASK = {} TASK.id = "killaiming" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) return "Kill a Player While Aiming" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua index f6af6821c..bdfe3b4c3 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killairborne.lua @@ -4,7 +4,7 @@ local net = net local TASK = {} TASK.id = "killairborne" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) return "Kill an Airborne Player" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua index ccfef07f2..d988de2b6 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua @@ -9,7 +9,7 @@ local MathRad = math.rad local TASK = {} TASK.id = "killbehind" -TASK.isKillTask = true +TASK.IsKillTask = true local taskmaster_killbehind_angle = CreateConVar("ttt_taskmaster_killbehind_view_angle", "75", FCVAR_REPLICATED, "The angle (in degrees) from a player's eye angle within which the Taskmaster is 'spotted' for the 'Kill a Player From Behind' task", 0, 180) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killcrowbar.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killcrowbar.lua index 9b6d4bc59..2d3b32cef 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killcrowbar.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killcrowbar.lua @@ -3,7 +3,7 @@ local hook = hook local TASK = {} TASK.id = "killcrowbar" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) return "Kill a Player With a Crowbar" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua index 7da029861..4284b7ab9 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdistant.lua @@ -14,7 +14,7 @@ local MathSin = math.sin local TASK = {} TASK.id = "killdistant" -TASK.isKillTask = true +TASK.IsKillTask = true local taskmaster_killdistant_range = CreateConVar("ttt_taskmaster_killdistant_range", "25", FCVAR_REPLICATED, "The minimum distance (in meters) away a player can be to count for the 'Kill a Distant Player' task", 0, 100) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua index bd049cd63..7b67a4ec0 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua @@ -10,7 +10,7 @@ local MathMax = math.max local TASK = {} TASK.id = "killdouble" -TASK.isKillTask = true +TASK.IsKillTask = true local taskmaster_killdouble_time = CreateConVar("ttt_taskmaster_killdouble_time", "5", FCVAR_REPLICATED, "The time (in seconds) the taskmaster has between kills to complete the 'Get a Double Kill' task", 0, 30) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killheadshot.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killheadshot.lua index e23785cec..1c77b72ae 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killheadshot.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killheadshot.lua @@ -6,7 +6,7 @@ local PlayerIterator = player.Iterator local TASK = {} TASK.id = "killheadshot" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) return "Kill a Player With a Headshot" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua index 820417906..c48c67443 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killlastbullet.lua @@ -4,7 +4,7 @@ local timer = timer local TASK = {} TASK.id = "killlastbullet" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) return "Kill a Player With Your Last Bullet" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killmidair.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killmidair.lua index a3dab87ce..e46a7f48b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killmidair.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killmidair.lua @@ -3,7 +3,7 @@ local hook = hook local TASK = {} TASK.id = "killmidair" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) return "Kill a Player While Midair" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua index 9cd640f68..e5da6619f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killnearby.lua @@ -14,7 +14,7 @@ local MathSin = math.sin local TASK = {} TASK.id = "killnearby" -TASK.isKillTask = true +TASK.IsKillTask = true local taskmaster_killnearby_range = CreateConVar("ttt_taskmaster_killnearby_range", "5", FCVAR_REPLICATED, "The maximum distance (in meters) away a player can be to count for the 'Kill a Nearby Player' task", 0, 10) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua index e8c40ab81..9c40ca2b7 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killonehit.lua @@ -6,7 +6,7 @@ local PlayerIterator = player.Iterator local TASK = {} TASK.id = "killonehit" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) return "Kill a Player in One Hit" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killpistol.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killpistol.lua index e48b6a7a0..1e04d8d2d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killpistol.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killpistol.lua @@ -3,7 +3,7 @@ local hook = hook local TASK = {} TASK.id = "killpistol" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) return "Kill a Player With a Pistol" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua index 80ee20c65..daffcafa9 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killretaliate.lua @@ -8,7 +8,7 @@ local PlayerIterator = player.Iterator local TASK = {} TASK.id = "killretaliate" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) return "Kill a Player That Attacked First" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua index 25a14f20c..4c26f2eb8 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killtarget.lua @@ -6,7 +6,7 @@ local util = util local TASK = {} TASK.id = "killtarget" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) local name = "Target" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua index 7ed1549e7..25a3d01b2 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua @@ -9,7 +9,7 @@ local TableInsert = table.insert local TASK = {} TASK.id = "killweapon" -TASK.isKillTask = true +TASK.IsKillTask = true TASK.Name = function(ply) local weapon = "Specific Weapon" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua index 3f76291d3..4e496c388 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/lookatplayer.lua @@ -33,7 +33,7 @@ TASK.Name = function(ply) local time = taskmaster_lookatplayer_time:GetInt() local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_LookAtPlayerStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua index 37c3f2c44..bfd877b5d 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/standonplayer.lua @@ -31,7 +31,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StandOnPlayerStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua index b81666efa..c763579c6 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhidden.lua @@ -33,7 +33,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayHiddenStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua index 48cd7b8a9..49b015147 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayhigher.lua @@ -33,7 +33,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayHigherStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua index 96f767a62..efa641f76 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayinarea.lua @@ -41,7 +41,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayInAreaStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua index 8f55bd655..c3683c9d1 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/staylower.lua @@ -33,7 +33,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayLowerStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua index 51d7b1117..dbb631cfa 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/stayneartarget.lua @@ -45,7 +45,7 @@ TASK.Name = function(ply) local time = taskmaster_stayneartarget_time:GetInt() local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_StayNearTargetStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua index 7626f3cdb..2f7ba69da 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua @@ -3,7 +3,7 @@ local hook = hook local TASK = {} TASK.id = "survive" -TASK.allowRoundEnd = true +TASK.AllowRoundEnd = true TASK.Name = function(ply) return "Survive" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua index d99f16231..add9732fd 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/takedamage.lua @@ -28,7 +28,7 @@ TASK.Name = function(ply) if not ply then return name end local progress = 0 - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = time else local startTime = ply.Task_TakeDamageStart diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua index cc72c9aad..c5b30c643 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua @@ -24,7 +24,7 @@ TASK.Name = function(ply) if not ply then return name end local progress - if TableHasValue(ply.taskmasterCompletedTasks, TASK.id) then + if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = count else progress = ply.Task_WeaponPickupsCount From 3c3876f2f44ac07da8fe051d0fdc06379051f28e Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 15:17:55 -0400 Subject: [PATCH 096/115] Fixed missing changes --- gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua index 55b376a7c..42ba53ad3 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -48,8 +48,8 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { ----------------------- TASKMASTER = { - killTasks = {}, - miscTasks = {} + KillTasks = {}, + MiscTasks = {} } function TASKMASTER.RegisterTask(task) From b932682c745131b26294d61953aa52f138d11b02 Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 16:55:17 -0400 Subject: [PATCH 097/115] Rework logic for events that complete on round end to fix winning if they die before the round ends but after they finish their other tasks --- .../gamemode/roles/taskmaster/taskmaster.lua | 73 +++++++++---------- .../roles/taskmaster/tasks/survive.lua | 2 +- 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index fb4905b06..c72be464b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -110,23 +110,13 @@ function plymeta:RerollTask(taskId, free) table.insert(self.TaskmasterRerolledTasks, taskId) self:SetProperty("TaskmasterRerolledTasks", self.TaskmasterRerolledTasks, self) - local newTask = self:AssignTask(isKillTask, index) + self:AssignTask(isKillTask, index) self:RemoveTask(taskId) if not free then self:SubtractCredits(1) end - -- Reset their win state if they rerolled. - -- If they have already "won" and they are re-rolling, that means - -- they only had tasks left that don't block a win condition. - -- Rerolling one of those tasks no longer guarantees that they are winning, - -- unless the newly rolled task ALSO does not block a win condition. - if newTask and not newTask.AllowRoundEnd and self.TaskmasterShouldWin then - self:SetProperty("TaskmasterShouldWin", false) - -- TODO: Alert the player that they have more tasks to do again - end - net.Start("TTT_TaskmasterUpdateTaskList") net.Send(self) end @@ -135,6 +125,33 @@ net.Receive("TTT_TaskmasterRerollTask", function(len, ply) ply:RerollTask(net.ReadString()) end) +function plymeta:GetActiveTasks(roundEnd) + local activeTasksList = table.Copy(self.TaskmasterKillTasks) + table.Add(activeTasksList, self.TaskmasterMiscTasks) + for _, id in ipairs(self.TaskmasterCompletedTasks) do + if table.HasValue(activeTasksList, id) then + table.RemoveByValue(activeTasksList, id) + end + end + + if roundEnd then + -- Loop backwards so removing something from this list doesn't mess us up + for i = #activeTasksList, 1, -1 do + local id = activeTasksList[i] + local task = TASKMASTER.KillTasks[id] + if not task then + task = TASKMASTER.MiscTasks[id] + end + + if task and task.CompleteOnRoundEnd then + table.RemoveByValue(activeTasksList, id) + end + end + end + + return activeTasksList +end + function plymeta:CompleteTask(taskId) if not self:IsActiveTaskmaster() then return end @@ -146,33 +163,8 @@ function plymeta:CompleteTask(taskId) table.insert(self.TaskmasterCompletedTasks, taskId) self:SetProperty("TaskmasterCompletedTasks", self.TaskmasterCompletedTasks, self) - local activeTasksList = table.Copy(self.TaskmasterKillTasks) - table.Add(activeTasksList, self.TaskmasterMiscTasks) - for _, id in ipairs(self.TaskmasterCompletedTasks) do - if table.HasValue(activeTasksList, id) then - table.RemoveByValue(activeTasksList, id) - else - break - end - end - - local tasksRemaining = #activeTasksList - for _, id in pairs(activeTasksList) do - local task = TASKMASTER.KillTasks[id] - if not task then - task = TASKMASTER.MiscTasks[id] - end - - if not task then continue end - - -- Tasks that allow the round to end should not count for this check - -- since the Taskmaster wins even if they are still active - if task.AllowRoundEnd then - tasksRemaining = tasksRemaining - 1 - end - end - - if tasksRemaining <= 0 then + local activeTasksList = self:GetActiveTasks() + if #activeTasksList == 0 then self:SetProperty("TaskmasterShouldWin", true) -- TODO: Alert the player that they have finished all their tasks end @@ -221,6 +213,8 @@ hook.Add("TTTWinCheckBlocks", "Taskmaster_TTTWinCheckBlocks", function(win_block if not IsPlayer(taskmaster) then return win_type end if taskmaster.TaskmasterShouldWin then return win_type end + -- If we only have tasks remaining that complete on round end, let the round end as normal + if #taskmaster:GetActiveTasks(true) == 0 then return win_type end if not taskmaster_blocks_team_wins:GetBool() then return win_type end @@ -260,7 +254,8 @@ hook.Add("TTTCheckForWin", "Taskmaster_TTTCheckForWin", function() local other_alive = false for _, v in player.Iterator() do if v:IsActive() then - if v:IsTaskmaster() and v.TaskmasterShouldWin then + -- If they have won or the only active tasks they have remaining complete on round end, they win + if v:IsTaskmaster() and (v.TaskmasterShouldWin or #v:GetActiveTasks(true) == 0) then winning_taskmaster_alive = true elseif not v:ShouldActLikeJester() and not ROLE_HAS_PASSIVE_WIN[v:GetRole()] then other_alive = true diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua index 2f7ba69da..e1463ae32 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/survive.lua @@ -3,7 +3,7 @@ local hook = hook local TASK = {} TASK.id = "survive" -TASK.AllowRoundEnd = true +TASK.CompleteOnRoundEnd = true TASK.Name = function(ply) return "Survive" From 8647eb53b3a291d1b9b3e079e7885dfade407446 Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 17:20:19 -0400 Subject: [PATCH 098/115] Changed taskmaster to allow rerolled tasks to show back up in future rerolls (can be disabled by convar) Fixed tutorial section on win block length showing when win blocking was disabled --- .../roles/taskmaster/cl_taskmaster.lua | 23 ++++++++++++------- .../gamemode/roles/taskmaster/shared.lua | 5 ++-- .../gamemode/roles/taskmaster/taskmaster.lua | 8 +++++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index c6e36732a..977913d69 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -49,9 +49,11 @@ end) -- CONVARS -- ------------- -local taskmaster_wins_with_others = GetConVar("ttt_taskmaster_wins_with_others") local taskmaster_kill_tasks = GetConVar("ttt_taskmaster_kill_tasks") local taskmaster_misc_tasks = GetConVar("ttt_taskmaster_misc_tasks") +local taskmaster_repeat_rerolls = GetConVar("ttt_taskmaster_repeat_rerolls") +local taskmaster_wins_with_others = GetConVar("ttt_taskmaster_wins_with_others") +local taskmaster_blocks_team_wins = GetConVar("ttt_taskmaster_blocks_team_wins") local taskmaster_win_block_length = GetConVar("ttt_taskmaster_win_block_length") local xOffset = CreateClientConVar("ttt_taskmaster_list_x_pos", "10", true, false, "The X (horizontal) position of the Taskmaster's task list HUD", 0, ScrW()) @@ -490,17 +492,22 @@ hook.Add("TTTTutorialRoleText", "Taskmaster_TTTTutorialRoleText", function(role, end -- Win block - local block_length = taskmaster_win_block_length:GetInt() - if block_length > 0 then - local plural = "" - if block_length ~= 1 then - plural = "s" + if taskmaster_blocks_team_wins:GetBool() then + local block_length = taskmaster_win_block_length:GetInt() + if block_length > 0 then + local plural = "" + if block_length ~= 1 then + plural = "s" + end + html = html .. "If the " .. ROLE_STRINGS[ROLE_TASKMASTER] .. " has not completed all tasks by the time another team wins, the round will be extended by " .. block_length .. " second" .. plural .. ", giving them extra time to finish." end - html = html .. "If the " .. ROLE_STRINGS[ROLE_TASKMASTER] .. " has not completed all tasks by the time another team wins, the round will be extended by " .. block_length .. " second" .. plural .. ", giving them extra time to finish." end -- Reroll - html = html .. "Undesired or uncompletable tasks can be rerolled by spending a credit in the equipment menu (press '" .. Key("+menu_context", "C") .. "')" + html = html .. "Undesired or uncompletable tasks can be rerolled by spending a credit in the equipment menu (press '" .. Key("+menu_context", "C") .. "')." + if taskmaster_repeat_rerolls:GetBool() then + html = html .. "Note, however, that tasks that have previously been rerolled can appear again when rerolling other tasks in the future." + end -- Show all enabled tasks local tasks = {} diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua index 42ba53ad3..253eb2973 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -25,11 +25,12 @@ end) CreateConVar("ttt_taskmaster_kill_tasks", "1", FCVAR_REPLICATED, "The number of kill tasks assigned to the Taskmaster", 0, 10) CreateConVar("ttt_taskmaster_misc_tasks", "2", FCVAR_REPLICATED, "The number of miscellaneous tasks assigned to the Taskmaster", 0, 10) -CreateConVar("ttt_taskmaster_completion_bonus", "1", FCVAR_REPLICATED, "How many credits the Taskmaster should get whenever they complete a task", 0, 10) +CreateConVar("ttt_taskmaster_completion_bonus", "1", FCVAR_NONE, "How many credits the Taskmaster should get whenever they complete a task", 0, 10) +CreateConVar("ttt_taskmaster_repeat_rerolls", "1", FCVAR_REPLICATED, "Whether the Taskmaster can be assigned tasks they previously rerolled away from", 0, 1) CreateConVar("ttt_taskmaster_blocks_team_wins", "1", FCVAR_REPLICATED, "Whether the Taskmaster should block teams (innocent, traitor, monster) from winning if they are alive and haven't finished their tasks.") CreateConVar("ttt_taskmaster_win_block_length", "60", FCVAR_REPLICATED, "How long (in seconds) the Taskmaster should block teams (innocent, traitor, monster) from winning for (if 'ttt_taskmaster_blocks_team_wins' is enabled). Set to 0 to block until time runs out", 0, 300) CreateConVar("ttt_taskmaster_wins_with_others", "1", FCVAR_REPLICATED, "If the Taskmaster should be allowed to win alongside other teams/players") -CreateConVar("ttt_taskmaster_is_passive", "0", FCVAR_REPLICATED, "Whether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if 'ttt_taskmaster_wins_with_others' is enabled)") +CreateConVar("ttt_taskmaster_is_passive", "0", FCVAR_NONE, "Whether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if 'ttt_taskmaster_wins_with_others' is enabled)") ROLE_CONVARS[ROLE_TASKMASTER] = {} table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index c72be464b..c5d85ff05 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -21,6 +21,7 @@ util.AddNetworkString("TTT_TaskmasterUpdateTaskList") local taskmaster_kill_tasks = GetConVar("ttt_taskmaster_kill_tasks") local taskmaster_misc_tasks = GetConVar("ttt_taskmaster_misc_tasks") +local taskmaster_repeat_rerolls = GetConVar("ttt_taskmaster_repeat_rerolls") local taskmaster_completion_bonus = GetConVar("ttt_taskmaster_completion_bonus") local taskmaster_blocks_team_wins = GetConVar("ttt_taskmaster_blocks_team_wins") local taskmaster_win_block_length = GetConVar("ttt_taskmaster_win_block_length") @@ -107,8 +108,11 @@ function plymeta:RerollTask(taskId, free) local index = table.KeyFromValue(self[activeTasksName], taskId) if not index then return end - table.insert(self.TaskmasterRerolledTasks, taskId) - self:SetProperty("TaskmasterRerolledTasks", self.TaskmasterRerolledTasks, self) + -- Don't track what we rerolled if we allow the player to reroll back to the same tasks + if not taskmaster_repeat_rerolls:GetBool() then + table.insert(self.TaskmasterRerolledTasks, taskId) + self:SetProperty("TaskmasterRerolledTasks", self.TaskmasterRerolledTasks, self) + end self:AssignTask(isKillTask, index) self:RemoveTask(taskId) From 71699f073634b2220590802296e989453b77ff66 Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 17:32:25 -0400 Subject: [PATCH 099/115] Fixed error in Damage Everyone task when a non-player is shot --- .../gamemode/roles/taskmaster/tasks/damageeveryone.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua index 735f7511c..e52628ea4 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/damageeveryone.lua @@ -57,6 +57,7 @@ if SERVER then hook.Add("PostEntityTakeDamage", "Taskmaster_DamageEveryone_PostEntityTakeDamage_" .. ply:SteamID64(), function(entity, dmginfo, wasDamageTaken) if not wasDamageTaken then return end if entity == ply then return end + if not IsPlayer(entity) then return end local attacker = dmginfo:GetAttacker() if not IsPlayer(attacker) or attacker ~= ply then return end From cc417f031e751b006cd1f6f99b206c81368520bf Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 18 Aug 2025 17:32:36 -0400 Subject: [PATCH 100/115] Implemented IsRoleAbilityDisabled logic --- .../gamemode/roles/taskmaster/taskmaster.lua | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index c5d85ff05..1c29efacc 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -163,6 +163,18 @@ function plymeta:CompleteTask(taskId) local taskList = isKillTask and TASKMASTER.KillTasks or TASKMASTER.MiscTasks local activeTasksName = isKillTask and "TaskmasterKillTasks" or "TaskmasterMiscTasks" if table.HasValue(self[activeTasksName], taskId) then + -- If our role ability was disabled, keep track of which tasks were completed + -- so we can instantly complete them if/when we become un-disabled + if self:IsRoleAbilityDisabled() then + if not self.TaskmasterCompletedButBlocked then + self.TaskmasterCompletedButBlocked = {} + end + if not table.HasValue(self.TaskmasterCompletedButBlocked, taskId) then + table.insert(self.TaskmasterCompletedButBlocked, taskId) + end + return false + end + taskList[taskId].OnTaskComplete(self) table.insert(self.TaskmasterCompletedTasks, taskId) self:SetProperty("TaskmasterCompletedTasks", self.TaskmasterCompletedTasks, self) @@ -192,6 +204,16 @@ function plymeta:CompleteTask(taskId) return false end +hook.Add("TTTOnRoleAbilityEnabled", "Taskmaster_TTTOnRoleAbilityEnabled", function(ply) + if not ply:IsTaskmaster() then return end + if not ply.TaskmasterCompletedButBlocked then return end + + for _, taskId in ipairs(ply.TaskmasterCompletedButBlocked) do + ply:CompleteTask(taskId) + end + ply.TaskmasterCompletedButBlocked = nil +end) + ROLE_ON_ROLE_ASSIGNED[ROLE_TASKMASTER] = function(ply) ply:SetProperty("TaskmasterKillTasks", {}, ply) ply:SetProperty("TaskmasterMiscTasks", {}, ply) @@ -302,6 +324,7 @@ local function CleanupTasks(ply) ply:ClearProperty("TaskmasterCompletedTasks", ply) ply:ClearProperty("TaskmasterRerolledTasks", ply) ply:ClearProperty("TaskmasterShouldWin") + ply.TaskmasterCompletedButBlocked = nil end hook.Add("TTTPrepareRound", "Taskmaster_TTTPrepareRound", function() From f54712566dac4c0932a5caf0b1ea4caf12b4213c Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 20 Aug 2025 10:13:31 -0400 Subject: [PATCH 101/115] Added missing convars to ULX Added missing convar description --- .../gamemode/roles/taskmaster/shared.lua | 35 ++++++++++++++++--- .../gamemode/roles/taskmaster/taskmaster.lua | 3 +- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua index 253eb2973..2169c58a8 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/shared.lua @@ -25,12 +25,11 @@ end) CreateConVar("ttt_taskmaster_kill_tasks", "1", FCVAR_REPLICATED, "The number of kill tasks assigned to the Taskmaster", 0, 10) CreateConVar("ttt_taskmaster_misc_tasks", "2", FCVAR_REPLICATED, "The number of miscellaneous tasks assigned to the Taskmaster", 0, 10) -CreateConVar("ttt_taskmaster_completion_bonus", "1", FCVAR_NONE, "How many credits the Taskmaster should get whenever they complete a task", 0, 10) CreateConVar("ttt_taskmaster_repeat_rerolls", "1", FCVAR_REPLICATED, "Whether the Taskmaster can be assigned tasks they previously rerolled away from", 0, 1) -CreateConVar("ttt_taskmaster_blocks_team_wins", "1", FCVAR_REPLICATED, "Whether the Taskmaster should block teams (innocent, traitor, monster) from winning if they are alive and haven't finished their tasks.") +CreateConVar("ttt_taskmaster_blocks_team_wins", "1", FCVAR_REPLICATED, "Whether the Taskmaster should block teams (innocent, traitor, monster) from winning if they are alive and haven't finished their tasks.", 0, 1) CreateConVar("ttt_taskmaster_win_block_length", "60", FCVAR_REPLICATED, "How long (in seconds) the Taskmaster should block teams (innocent, traitor, monster) from winning for (if 'ttt_taskmaster_blocks_team_wins' is enabled). Set to 0 to block until time runs out", 0, 300) -CreateConVar("ttt_taskmaster_wins_with_others", "1", FCVAR_REPLICATED, "If the Taskmaster should be allowed to win alongside other teams/players") -CreateConVar("ttt_taskmaster_is_passive", "0", FCVAR_NONE, "Whether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if 'ttt_taskmaster_wins_with_others' is enabled)") +CreateConVar("ttt_taskmaster_wins_with_others", "1", FCVAR_REPLICATED, "If the Taskmaster should be allowed to win alongside other teams/players", 0, 1) +CreateConVar("ttt_taskmaster_is_passive", "0", FCVAR_REPLICATED, "Whether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if 'ttt_taskmaster_wins_with_others' is enabled)", 0, 1) ROLE_CONVARS[ROLE_TASKMASTER] = {} table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { @@ -43,6 +42,32 @@ table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { type = ROLE_CONVAR_TYPE_NUM, decimal = 0 }) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_completion_bonus", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_repeat_rerolls", + type = ROLE_CONVAR_TYPE_BOOL +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_blocks_team_wins", + type = ROLE_CONVAR_TYPE_BOOL +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_win_block_length", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_wins_with_others", + type = ROLE_CONVAR_TYPE_BOOL +}) +table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { + cvar = "ttt_taskmaster_is_passive", + type = ROLE_CONVAR_TYPE_BOOL +}) ----------------------- -- TASK REGISTRATION -- @@ -62,7 +87,7 @@ function TASKMASTER.RegisterTask(task) end local cvarName = "ttt_taskmaster_" .. task.id .. "_enabled" - local enabled = CreateConVar(cvarName, 1, FCVAR_REPLICATED) + local enabled = CreateConVar(cvarName, 1, FCVAR_REPLICATED, "Whether the '" .. task.Name() .. "' task should be enabled", 0, 1) task.Enabled = function() return enabled:GetBool() end diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index 1c29efacc..db9f11aa7 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -19,10 +19,11 @@ util.AddNetworkString("TTT_TaskmasterUpdateTaskList") -- CONVARS -- ------------- +local taskmaster_completion_bonus = CreateConVar("ttt_taskmaster_completion_bonus", "1", FCVAR_NONE, "How many credits the Taskmaster should get whenever they complete a task", 0, 10) + local taskmaster_kill_tasks = GetConVar("ttt_taskmaster_kill_tasks") local taskmaster_misc_tasks = GetConVar("ttt_taskmaster_misc_tasks") local taskmaster_repeat_rerolls = GetConVar("ttt_taskmaster_repeat_rerolls") -local taskmaster_completion_bonus = GetConVar("ttt_taskmaster_completion_bonus") local taskmaster_blocks_team_wins = GetConVar("ttt_taskmaster_blocks_team_wins") local taskmaster_win_block_length = GetConVar("ttt_taskmaster_win_block_length") local taskmaster_wins_with_others = GetConVar("ttt_taskmaster_wins_with_others") From 307ae7879f5e1c1ea279f4a9cd7d1845eb734bac Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 20 Aug 2025 10:18:11 -0400 Subject: [PATCH 102/115] Added description and ranges to some auto-generated convars --- gamemodes/terrortown/gamemode/init_shd.lua | 4 ++-- gamemodes/terrortown/gamemode/shared.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gamemodes/terrortown/gamemode/init_shd.lua b/gamemodes/terrortown/gamemode/init_shd.lua index d41286a23..490248117 100644 --- a/gamemodes/terrortown/gamemode/init_shd.lua +++ b/gamemodes/terrortown/gamemode/init_shd.lua @@ -11,9 +11,9 @@ for role = 0, ROLE_MAX do if INDEPENDENT_ROLES[role] then local jesterVisible = ROLE_CAN_SEE_JESTERS[role] and "1" or "0" - CreateConVar("ttt_" .. rolestring .. "_can_see_jesters", jesterVisible, FCVAR_REPLICATED) + CreateConVar("ttt_" .. rolestring .. "_can_see_jesters", jesterVisible, FCVAR_REPLICATED, "Whether jesters are revealed (via head icons, color/icon on the scoreboard, etc.) to this role", 0, 1) local miaVisible = ROLE_CAN_SEE_MIA[role] and "1" or "0" - CreateConVar("ttt_" .. rolestring .. "_update_scoreboard", miaVisible, FCVAR_REPLICATED) + CreateConVar("ttt_" .. rolestring .. "_update_scoreboard", miaVisible, FCVAR_REPLICATED, "Whether this role shows dead players as missing in action", 0, 1) end end diff --git a/gamemodes/terrortown/gamemode/shared.lua b/gamemodes/terrortown/gamemode/shared.lua index db572cb50..def8ff8e3 100644 --- a/gamemodes/terrortown/gamemode/shared.lua +++ b/gamemodes/terrortown/gamemode/shared.lua @@ -488,7 +488,7 @@ function CreateShopConVars(role) CreateCreditConVar(role) CreateConVar("ttt_" .. rolestring .. "_shop_random_percent", "0", FCVAR_REPLICATED, "The percent chance that a weapon in the shop will not be shown for the " .. rolestring, 0, 100) - CreateConVar("ttt_" .. rolestring .. "_shop_random_enabled", "0", FCVAR_REPLICATED, "Whether shop randomization should run for the " .. rolestring) + CreateConVar("ttt_" .. rolestring .. "_shop_random_enabled", "0", FCVAR_REPLICATED, "Whether shop randomization should run for the " .. rolestring, 0, 1) local hassync = (TRAITOR_ROLES[role] and role ~= ROLE_TRAITOR) or (DETECTIVE_ROLES[role] and role ~= ROLE_DETECTIVE) or ROLE_HAS_SHOP_SYNC[role] if hassync then From ab362a057402e9044a159422a338b02df3ec59e4 Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 20 Aug 2025 10:37:20 -0400 Subject: [PATCH 103/115] Added markdown docs --- CONVARS.md | 88 ++++++++++++++++++- .../roles/taskmaster/tasks/crouch.lua | 2 +- .../roles/taskmaster/tasks/dodamage.lua | 2 +- .../roles/taskmaster/tasks/kill360.lua | 2 +- .../roles/taskmaster/tasks/killbehind.lua | 2 +- 5 files changed, 91 insertions(+), 5 deletions(-) diff --git a/CONVARS.md b/CONVARS.md index 528fa3cd6..d65b4ee69 100644 --- a/CONVARS.md +++ b/CONVARS.md @@ -116,6 +116,7 @@ ttt_shadow_enabled 0 // Whether or not the Sha ttt_arsonist_enabled 0 // Whether or not the Arsonist should spawn ttt_hivemind_enabled 0 // Whether or not the Hive Mind should spawn ttt_plaguemaster_enabled 0 // Whether or not the Plaguemaster should spawn +ttt_taskmaster_enabled 0 // Whether or not the Taskmaster should spawn // Individual Role Spawn Weights ttt_hypnotist_spawn_weight 1 // The weight assigned to spawning the Hypnotist @@ -165,6 +166,7 @@ ttt_shadow_spawn_weight 1 // The weight assigned to ttt_arsonist_spawn_weight 1 // The weight assigned to spawning the Arsonist ttt_hivemind_spawn_weight 1 // The weight assigned to spawning the Hive Mind ttt_plaguemaster_spawn_weight 1 // The weight assigned to spawning the Plaguemaster +ttt_taskmaster_spawn_weight 1 // The weight assigned to spawning the Taskmaster // (Note: Each role is limited to one player per round.) @@ -216,6 +218,7 @@ ttt_shadow_min_players 0 // The minimum number of ttt_arsonist_min_players 0 // The minimum number of players required to spawn the Arsonist ttt_hivemind_min_players 0 // The minimum number of players required to spawn the Hive Mind ttt_plaguemaster_min_players 0 // The minimum number of players required to spawn the Plaguemaster +ttt_taskmaster_min_players 0 // The minimum number of players required to spawn the Taskmaster // Grouped Role Spawn Settings ttt_twins_enabled 0 // Whether or not the Twins should spawn @@ -965,7 +968,88 @@ ttt_plaguemaster_dart_replace_timer 0 // How long (in seconds) ttt_plaguemaster_body_search_mode 1 // Whether dead bodies reveal if they had the plague when searched. 0 - Don't show. 1 - Show if died from plague. 2 - Show if Infected with plague. ttt_plaguemaster_can_see_jesters 0 // Whether jesters are revealed (via head icons, color/icon on the scoreboard, etc.) to the Plaguemaster ttt_plaguemaster_update_scoreboard 1 // Whether the Plaguemaster shows dead players as missing in action - + +// Taskmaster +ttt_taskmaster_blocks_team_wins 1 // Whether the Taskmaster should block teams (innocent, traitor, monster) from winning if they are alive and haven't finished their tasks. +ttt_taskmaster_is_passive 0 // Whether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if 'ttt_taskmaster_wins_with_others' is enabled) +ttt_taskmaster_kill_tasks 1 // The number of kill tasks assigned to the Taskmaster +ttt_taskmaster_misc_tasks 2 // The number of miscellaneous tasks assigned to the Taskmaster +ttt_taskmaster_repeat_rerolls 1 // Whether the Taskmaster can be assigned tasks they previously rerolled away from +ttt_taskmaster_win_block_length 60 // How long (in seconds) the Taskmaster should block teams (innocent, traitor, monster) from winning for (if 'ttt_taskmaster_blocks_team_wins' is enabled). Set to 0 to block until time runs out +ttt_taskmaster_wins_with_others 1 // If the Taskmaster should be allowed to win alongside other teams/players + +// Taskmaster tasks +ttt_taskmaster_calldetective_enabled 1 // Whether the 'Call a Detective to a Body' task should be enabled +ttt_taskmaster_carrycorpse_enabled 1 // Whether the 'Carry a Corpse for X Seconds' task should be enabled +ttt_taskmaster_carrycorpse_time 60 // The time (in seconds) a player must carry a player corpse to complete the 'Carry Corpse' task +ttt_taskmaster_chat_enabled 1 // Whether the 'Send X Messages' task should be enabled +ttt_taskmaster_chat_times 25 // The number of text messages a player must sent to complete the 'Send X Messages' task +ttt_taskmaster_completion_bonus 1 // How many credits the Taskmaster should get whenever they complete a task +ttt_taskmaster_crouch_enabled 1 // Whether the 'Crouch for X Seconds' task should be enabled +ttt_taskmaster_crouch_time 40 // The time (in seconds) a player must stay crouched to complete the 'Crouch' task +ttt_taskmaster_crouchnearbody_enabled 1 // Whether the 'Crouch Near a Body' task should be enabled +ttt_taskmaster_crouchnearbody_range 1 // The distance (in meters) away a player must stay within to count for the 'Crouch Near Body' task +ttt_taskmaster_crouchnearbody_time 20 // The time (in seconds) a player must stay near a body to count for the 'Crouch Near Body' task +ttt_taskmaster_crowbar_enabled 1 // Whether the 'Swing a Crowbar 50 Times' task should be enabled +ttt_taskmaster_crowbar_times 50 // The number of times a player must use their crowbar to complete the 'Swing Crowbar' task +ttt_taskmaster_damageeveryone_enabled 1 // Whether the 'Damage Everyone Else' task should be enabled +ttt_taskmaster_dodamage_amount 200 // The amount of damage a player must do to complete the 'Deal X Damage' task +ttt_taskmaster_dodamage_enabled 1 // Whether the 'Deal X Damage' task should be enabled +ttt_taskmaster_firebullets_enabled 1 // Whether the 'Fire X Bullets' task should be enabled +ttt_taskmaster_firebullets_times 100 // The jump of times a player must fire a bullet to complete the 'Fire X Bullets' task +ttt_taskmaster_getplayerkilled_enabled 1 // Whether the 'Get Target Killed' task should be enabled +ttt_taskmaster_getplayertokill_enabled 1 // Whether the 'Get Target to Kill' task should be enabled +ttt_taskmaster_healthunder_amount 15 // The amount of health a player must stay under to complete the 'Health Under' task +ttt_taskmaster_healthunder_enabled 1 // Whether the 'Survive Under X Health' task should be enabled +ttt_taskmaster_healthunder_time 60 // The time (in seconds) a player must stay under the target health to complete the 'Health Under' task +ttt_taskmaster_holstered_enabled 1 // Whether the 'Stay Holstered for X Seconds' task should be enabled +ttt_taskmaster_holstered_time 60 // The time (in seconds) a player must stay holstered to complete the 'Holstered' task +ttt_taskmaster_jump_enabled 1 // Whether the 'Jump x Times' task should be enabled +ttt_taskmaster_jump_times 100 // The jump of times a player must jump to complete the 'Jump X Times' task +ttt_taskmaster_kill360_enabled 1 // Whether the 'Kill a Player After a 360' task should be enabled +ttt_taskmaster_kill360_time 3 // The time (in seconds) a player has after completing a 360 to kill a player for the 'Kill a Player After a 360' task +ttt_taskmaster_killaiming_enabled 1 // Whether the 'Kill a Player While Aiming' task should be enabled +ttt_taskmaster_killairborne_enabled 1 // Whether the 'Kill an Airborne Player' task should be enabled +ttt_taskmaster_killbehind_enabled 1 // Whether the 'Kill a Player From Behind' task should be enabled +ttt_taskmaster_killbehind_view_angle 75 // The angle (in degrees) from a player's eye angle within which the Taskmaster is 'spotted' for the 'Kill a Player From Behind' task +ttt_taskmaster_killcrowbar_enabled 1 // Whether the 'Kill a Player With a Crowbar' task should be enabled +ttt_taskmaster_killdistant_enabled 1 // Whether the 'Kill a Distant Player' task should be enabled +ttt_taskmaster_killdistant_range 25 // The minimum distance (in meters) away a player can be to count for the 'Kill a Distant Player' task +ttt_taskmaster_killdouble_enabled 1 // Whether the 'Get a Double Kill' task should be enabled +ttt_taskmaster_killdouble_time 5 // The time (in seconds) the taskmaster has between kills to complete the 'Get a Double Kill' task +ttt_taskmaster_killheadshot_enabled 1 // Whether the 'Kill a Player With a Headshot' task should be enabled +ttt_taskmaster_killlastbullet_enabled 1 // Whether the 'Kill a Player With Your Last Bullet' task should be enabled +ttt_taskmaster_killmidair_enabled 1 // Whether the 'Kill a Player While Midair' task should be enabled +ttt_taskmaster_killnearby_enabled 1 // Whether the 'Kill a Nearby Player' task should be enabled +ttt_taskmaster_killnearby_range 5 // The maximum distance (in meters) away a player can be to count for the 'Kill a Nearby Player' task +ttt_taskmaster_killonehit_enabled 1 // Whether the 'Kill a Player in One Hit' task should be enabled +ttt_taskmaster_killpistol_enabled 1 // Whether the 'Kill a Player With a Pistol' task should be enabled +ttt_taskmaster_killretaliate_enabled 1 // Whether the 'Kill a Player That Attacked First' task should be enabled +ttt_taskmaster_killtarget_enabled 1 // Whether the 'Kill Target' task should be enabled +ttt_taskmaster_killweapon_enabled 1 // Whether the 'Kill a Player With a Specific Weapon' task should be enabled +ttt_taskmaster_lookatplayer_enabled 1 // Whether the 'Look at Target' task should be enabled +ttt_taskmaster_lookatplayer_time 30 // The time (in seconds) a player must look at their target to complete for the 'Look at Player' task +ttt_taskmaster_pickupshopitem_enabled 1 // Whether the 'Pick up a Shop Item' task should be enabled +ttt_taskmaster_standonplayer_enabled 1 // Whether the 'Stand on a Player for X Seconds' task should be enabled +ttt_taskmaster_standonplayer_time 15 // The time (in seconds) a player must stay stand on top of another player to complete the 'Stand On Player' task +ttt_taskmaster_stayhidden_enabled 1 // Whether the 'Stay Hidden for X Seconds' task should be enabled +ttt_taskmaster_stayhidden_time 30 // The time (in seconds) a player must hide to complete for the 'Stay Hidden' task +ttt_taskmaster_stayhigher_enabled 1 // Whether the 'Be Highest for X Seconds' task should be enabled +ttt_taskmaster_stayhigher_time 30 // The time (in seconds) a player must stay higher up to complete the 'Highest Player' task +ttt_taskmaster_stayinarea_enabled 1 // Whether the 'Stay in Area for X Seconds' task should be enabled +ttt_taskmaster_stayinarea_range 5 // The distance (in meters) away from the location that a player must stay within to count for the 'Stay in Area' task +ttt_taskmaster_stayinarea_time 30 // The time (in seconds) a player must stay inside the target area to count for the 'Stay in Area' task +ttt_taskmaster_staylower_enabled 1 // Whether the 'Be Lowest for X Seconds' task should be enabled +ttt_taskmaster_staylower_time 30 // The time (in seconds) a player must stay lower down to complete the 'Lowest Player' task +ttt_taskmaster_stayneartarget_enabled 1 // Whether the 'Stay Near Target' task should be enabled +ttt_taskmaster_stayneartarget_range 5 // The distance (in meters) away a player must stay within to count for the 'Stay Near Target' task +ttt_taskmaster_stayneartarget_time 30 // The time (in seconds) a player must stay near their target to count for the 'Stay Near Target' task +ttt_taskmaster_survive_enabled 1 // Whether the 'Survive' task should be enabled +ttt_taskmaster_takedamage_enabled 1 // Whether the 'Take Damage and Survive' task should be enabled +ttt_taskmaster_takedamage_time 60 // The time (in seconds) a player must survive without taking further damage to complete the 'Take Damage' task +ttt_taskmaster_weaponpickups_count 20 // The number of unique weapons a player must pick up to complete the 'Pick Up Weapons' task +ttt_taskmaster_weaponpickups_enabled 1 // Whether the 'Pick up X Weapons' task should be enabled + // ---------------------------------------- // GROUPED ROLE SETTINGS @@ -1143,6 +1227,7 @@ ttt_shadow_starting_health 100 // The amount of health t ttt_arsonist_starting_health 100 // The amount of health the Arsonist starts with ttt_hivemind_starting_health 100 // The amount of health the Hive Mind starts with ttt_plaguemaster_starting_health 100 // The amount of health the Plaguemaster starts with +ttt_taskmaster_starting_health 100 // The amount of health the Taskmaster starts with // Individual Role Max Health. Set to 0 or -1 to use the game's default maximum health. ttt_traitor_max_health 100 // The maximum amount of health a Traitor can have @@ -1197,6 +1282,7 @@ ttt_shadow_max_health 100 // The maximum amount of ttt_arsonist_max_health 100 // The maximum amount of health the Arsonist can have ttt_hivemind_max_health 100 // The maximum amount of health the Hive Mind can have ttt_plaguemaster_max_health 100 // The maximum amount of health the Plaguemaster can have +ttt_taskmaster_max_health 100 // The maximum amount of health the Taskmaster can have // Round Time ttt_roundtime_win_draw 0 // Whether a round that ends because the round time limit has passed counts as a draw. If it is not a draw, the traitor team loses diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua index 752dd0969..b9930368b 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crouch.lua @@ -14,7 +14,7 @@ local TASK = {} TASK.id = "crouch" -local taskmaster_crouch_time = CreateConVar("ttt_taskmaster_crouch_time", "40", FCVAR_REPLICATED, "The time (in seconds) a player must stay crouched to complete the 'Crouch Near Body' task", 1, 240) +local taskmaster_crouch_time = CreateConVar("ttt_taskmaster_crouch_time", "40", FCVAR_REPLICATED, "The time (in seconds) a player must stay crouched to complete the 'Crouch' task", 1, 240) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_crouch_time", type = ROLE_CONVAR_TYPE_NUM, diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua index 542918e7b..d495884dc 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua @@ -7,7 +7,7 @@ local TASK = {} TASK.id = "dodamage" -local taskmaster_dodamage_amount = CreateConVar("ttt_taskmaster_dodamage_amount", "200", FCVAR_REPLICATED, "The amount of damage a player must do to complete the 'Do X Damage' task", 1, 1000) +local taskmaster_dodamage_amount = CreateConVar("ttt_taskmaster_dodamage_amount", "200", FCVAR_REPLICATED, "The amount of damage a player must do to complete the 'Deal X Damage' task", 1, 1000) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_dodamage_amount", type = ROLE_CONVAR_TYPE_NUM, diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua index ea89f21c3..95bb8f037 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/kill360.lua @@ -11,7 +11,7 @@ local TASK = {} TASK.id = "kill360" TASK.IsKillTask = true -local taskmaster_kill360_time = CreateConVar("ttt_taskmaster_kill360_time", "3", FCVAR_REPLICATED, "The time (in seconds) a player has after completing a 360 to kill a player for the 'Kill a Player After a 360' task", 1, 10) +local taskmaster_kill360_time = CreateConVar("ttt_taskmaster_kill360_time", "3", FCVAR_REPLICATED, "The time (in seconds) a player has after completing a 360 to kill a player for the 'Kill a Player After a 360' task", 1, 10) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_kill360_time", type = ROLE_CONVAR_TYPE_NUM, diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua index d988de2b6..228cba27c 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killbehind.lua @@ -11,7 +11,7 @@ local TASK = {} TASK.id = "killbehind" TASK.IsKillTask = true -local taskmaster_killbehind_angle = CreateConVar("ttt_taskmaster_killbehind_view_angle", "75", FCVAR_REPLICATED, "The angle (in degrees) from a player's eye angle within which the Taskmaster is 'spotted' for the 'Kill a Player From Behind' task", 0, 180) +local taskmaster_killbehind_angle = CreateConVar("ttt_taskmaster_killbehind_view_angle", "75", FCVAR_REPLICATED, "The angle (in degrees) from a player's eye angle within which the Taskmaster is 'spotted' for the 'Kill a Player From Behind' task", 0, 180) table.insert(ROLE_CONVARS[ROLE_TASKMASTER], { cvar = "ttt_taskmaster_killbehind_view_angle", type = ROLE_CONVAR_TYPE_NUM, From 84a45979b003bc92d72e0897af556c5c953417d3 Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 20 Aug 2025 10:56:15 -0400 Subject: [PATCH 104/115] Added cr4ttt_role_cvars script --- scripts/server/cr4ttt_functions.lua | 143 ++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 scripts/server/cr4ttt_functions.lua diff --git a/scripts/server/cr4ttt_functions.lua b/scripts/server/cr4ttt_functions.lua new file mode 100644 index 000000000..297290f99 --- /dev/null +++ b/scripts/server/cr4ttt_functions.lua @@ -0,0 +1,143 @@ +local function PrintRoleCvars(ply, cmd, args) + if #args == 0 then + ErrorNoHalt("Missing role name argument. Usage: cr4ttt_role_cvars role_name [format] [min_name_length_for_md_fmt] [min_default_length_for_md_fmt]\n") + return + end + + local roleName = args[1] + local roleId + if table.HasValue(ROLE_STRINGS_RAW, roleName) then + roleId = table.KeyFromValue(ROLE_STRINGS_RAW, roleName) + elseif table.HasValue(ROLE_STRINGS_SHORT, roleName) then + roleId = table.KeyFromValue(ROLE_STRINGS_SHORT, roleName) + else + ErrorNoHalt("Unknown role: " .. roleName .. "\n") + return + end + + if roleId <= ROLE_NONE or roleId > ROLE_MAX then + ErrorNoHalt("Invalid role: " .. roleName .. "\n") + return + end + + local fmt + if #args > 1 then + fmt = args[2] + end + + local nameLengthMin = 46 + if #args > 2 then + nameLengthMin = tonumber(args[3]) or nameLengthMin + end + + local defaultLengthMin = 8 + if #args > 3 then + defaultLengthMin = tonumber(args[4]) or defaultLengthMin + end + + local formatFn + if fmt == "md" or fmt == "markdown" then + formatFn = function(cvar) + local convar = GetConVar(cvar.cvar) + + local namePadded = convar:GetName() + while #namePadded < nameLengthMin do + namePadded = namePadded .. " " + end + + local defaultPadded = convar:GetDefault() + while #defaultPadded < defaultLengthMin do + defaultPadded = defaultPadded .. " " + end + + print(namePadded .. " " .. defaultPadded .. "// " .. convar:GetHelpText()) + end + elseif fmt == "html" or fmt == "web" then + local function GetCvarType(convar, cvar) + if cvar.type == ROLE_CONVAR_TYPE_NUM then + local typeName + if not cvar.decimal or cvar.decimal == 0 then + typeName = "Integer" + else + typeName = "Float" + end + + if convar:GetMin() and convar:GetMax() then + return typeName .. " (" .. convar:GetMin() .. "-" .. convar:GetMax() .. ")" + end + return typeName + elseif cvar.type == ROLE_CONVAR_TYPE_BOOL then + return "Boolean" + elseif cvar.type == ROLE_CONVAR_TYPE_TEXT then + return "String" + elseif cvar.type == ROLE_CONVAR_TYPE_DROPDOWN then + if cvar.isNumeric then + if convar:GetMin() and convar:GetMax() then + return "Integer (" .. convar:GetMin() .. "-" .. convar:GetMax() .. ")" + end + return "Integer" + end + return "String" + end + end + + local function GetCvarDesc(convar, cvar) + local desc = convar:GetHelpText() + if cvar.type == ROLE_CONVAR_TYPE_DROPDOWN then + desc = desc .. ":" + desc = desc .. "\r\n
    " + for _, choice in ipairs(cvar.choices) do + desc = desc .. "\r\n
  1. " .. choice .. ".
  2. " + end + desc = desc .. "\r\n
\r\n " + end + + return desc + end + + formatFn = function(cvar) + local convar = GetConVar(cvar.cvar) + print("") + print(" " .. cvar.cvar .. "") + print(" " .. convar:GetDefault() .. "") + print(" " .. GetCvarType(convar, cvar) .. "") + print(" " .. GetCvarDesc(convar, cvar) .. "") + print("") + end + else + formatFn = function(cvar) + local convar = GetConVar(cvar.cvar) + print(convar:GetName() .. " (def. " .. convar:GetDefault() .. ") - " .. convar:GetHelpText()) + end + end + + local roleCvars = table.Copy(ROLE_CONVARS[roleId]) + table.SortByMember(roleCvars, "cvar", true) + + for _, cvar in ipairs(roleCvars) do + formatFn(cvar) + end +end + +function PrintRoleCvarsComplete(cmd, argStr, args) + if #args == 1 then + local filtered = {} + for _, r in ipairs(ROLE_STRINGS_RAW) do + if string.StartsWith(r, args[1]) then + table.insert(filtered, cmd .. " \"" .. r .. "\" ") + end + end + return filtered + elseif #args == 2 then + local options = {"html", "markdown", "ulx"} + local filtered = {} + for _, f in ipairs(options) do + if string.StartsWith(f, args[2]) then + table.insert(filtered, cmd .. " \"" .. args[1] .. "\" \"" .. f .. "\"") + end + end + return filtered + end +end + +concommand.Add("cr4ttt_role_cvars", PrintRoleCvars, PrintRoleCvarsComplete, "Prints all role custom convars in the desired format. Usage: cr4ttt_role_cvars role_name [format] [min_name_length_for_md_fmt] [min_default_length_for_md_fmt]") \ No newline at end of file From 37bedfdb591242ae02d7639772976a6833e8ab95 Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 20 Aug 2025 10:57:57 -0400 Subject: [PATCH 105/115] Fixed global bleed --- scripts/server/cr4ttt_functions.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/server/cr4ttt_functions.lua b/scripts/server/cr4ttt_functions.lua index 297290f99..a6c2cb333 100644 --- a/scripts/server/cr4ttt_functions.lua +++ b/scripts/server/cr4ttt_functions.lua @@ -119,7 +119,7 @@ local function PrintRoleCvars(ply, cmd, args) end end -function PrintRoleCvarsComplete(cmd, argStr, args) +local function PrintRoleCvarsComplete(cmd, argStr, args) if #args == 1 then local filtered = {} for _, r in ipairs(ROLE_STRINGS_RAW) do From d103ec71348d7c276f6cda21267df08a2d5a3889 Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 20 Aug 2025 11:15:20 -0400 Subject: [PATCH 106/115] Added support for non-numeric dropdowns to HTML docs generator --- scripts/server/cr4ttt_functions.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/server/cr4ttt_functions.lua b/scripts/server/cr4ttt_functions.lua index a6c2cb333..e9d400176 100644 --- a/scripts/server/cr4ttt_functions.lua +++ b/scripts/server/cr4ttt_functions.lua @@ -85,11 +85,19 @@ local function PrintRoleCvars(ply, cmd, args) local desc = convar:GetHelpText() if cvar.type == ROLE_CONVAR_TYPE_DROPDOWN then desc = desc .. ":" - desc = desc .. "\r\n
    " - for _, choice in ipairs(cvar.choices) do - desc = desc .. "\r\n
  1. " .. choice .. ".
  2. " + if cvar.isNumeric then + desc = desc .. "\r\n
      " + for _, choice in ipairs(cvar.choices) do + desc = desc .. "\r\n
    1. " .. choice .. ".
    2. " + end + desc = desc .. "\r\n
    \r\n " + else + desc = desc .. "\r\n
      " + for _, choice in ipairs(cvar.choices) do + desc = desc .. "\r\n
    • " .. choice .. ".
    • " + end + desc = desc .. "\r\n
    \r\n " end - desc = desc .. "\r\n
\r\n " end return desc From 1d7000ed91ccb36f1deb41d36e507da84e2c4edf Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 20 Aug 2025 11:29:49 -0400 Subject: [PATCH 107/115] Added taskmaster HTML docs --- docs/teams/independent.html | 513 +++++++++++++++++++++++++++++++++++- 1 file changed, 503 insertions(+), 10 deletions(-) diff --git a/docs/teams/independent.html b/docs/teams/independent.html index 705007d60..9598326c6 100644 --- a/docs/teams/independent.html +++ b/docs/teams/independent.html @@ -791,16 +791,18 @@

Role Configuration:

- ttt_plaguemaster_body_search_mode - 0 - Integer (0-2) - Whether dead bodies reveal if they had the plague when searched: -
    -
  1. Don't show.
  2. -
  3. Show if died from plague.
  4. -
  5. Show if infected with plague.
  6. -
- + + ttt_plaguemaster_body_search_mode + 0 + Integer (0-2) + Whether dead bodies reveal if they had the plague when searched: +
    +
  1. Don't show.
  2. +
  3. Show if died from plague.
  4. +
  5. Show if infected with plague.
  6. +
+ + ttt_plaguemaster_can_see_jesters 0 @@ -1111,6 +1113,497 @@

Role Configuration:

+
+ +
+
[more]
+

The Taskmaster has a list of tasks that they must complete before the end of the round.

+
+

The Taskmaster's tasks are divided into two types: Kill and Miscellaneous.

+

A Kill-type task requires that the Taskmaster themselves kill another player, and the Miscellaneous tasks are everything else.

+

The number of Kill tasks that a Taskmaster must complete is controlled by the ttt_taskmaster_kill_tasks convar, and the ttt_taskmaster_misc_tasks convar for Miscellaneous tasks.

+

If a task cannot be completed (or the Taskmaster deems it too difficult), they can spend a credit to reroll that task to get something different.

+

If the ttt_taskmaster_wins_with_others convar is disabled, the Taskmaster must also kill all other (non-passive) players to win.

+

The ttt_taskmaster_blocks_team_wins convar controls whether the Taskmaster blocks another team for winning for a short period of time if their tasks have not been completed yet, giving them extra time to finish.

+

Role Configuration:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ConVarDefaultTypeDescription
ttt_taskmaster_is_passive0BooleanWhether the Taskmaster should count as a 'passive' role for roles that need to kill other players, allowing them to win while the Taskmaster is still alive (if ttt_taskmaster_wins_with_others is enabled)
ttt_taskmaster_kill_tasks1Integer (0-10)The number of kill tasks assigned to the Taskmaster
ttt_taskmaster_misc_tasks2Integer (0-10)The number of miscellaneous tasks assigned to the Taskmaster
ttt_taskmaster_repeat_rerolls1BooleanWhether the Taskmaster can be assigned tasks they previously rerolled away from
ttt_taskmaster_win_block_length60Integer (0-300)How long (in seconds) the Taskmaster should block teams (innocent, traitor, monster) from winning for (if ttt_taskmaster_blocks_team_wins is enabled). Set to 0 to block until time runs out
ttt_taskmaster_wins_with_others1BooleanIf the Taskmaster should be allowed to win alongside other teams/players
ttt_taskmaster_blocks_team_wins1BooleanWhether the Taskmaster should block teams (innocent, traitor, monster) from winning if they are alive and haven't finished their tasks.
ttt_taskmaster_calldetective_enabled1BooleanWhether the 'Call a Detective to a Body' task should be enabled
ttt_taskmaster_carrycorpse_enabled1BooleanWhether the 'Carry a Corpse for X Seconds' task should be enabled
ttt_taskmaster_carrycorpse_time60Integer (1-240)The time (in seconds) a player must carry a player corpse to complete the 'Carry Corpse' task
ttt_taskmaster_chat_enabled1BooleanWhether the 'Send X Messages' task should be enabled
ttt_taskmaster_chat_times25Integer (1-100)The number of text messages a player must sent to complete the 'Send X Messages' task
ttt_taskmaster_completion_bonus1Integer (0-10)How many credits the Taskmaster should get whenever they complete a task
ttt_taskmaster_crouch_enabled1BooleanWhether the 'Crouch for X Seconds' task should be enabled
ttt_taskmaster_crouch_time40Integer (1-240)The time (in seconds) a player must stay crouched to complete the 'Crouch' task
ttt_taskmaster_crouchnearbody_enabled1BooleanWhether the 'Crouch Near a Body' task should be enabled
ttt_taskmaster_crouchnearbody_range1Integer (1-100)The distance (in meters) away a player must stay within to count for the 'Crouch Near Body' task
ttt_taskmaster_crouchnearbody_time20Integer (1-240)The time (in seconds) a player must stay near a body to count for the 'Crouch Near Body' task
ttt_taskmaster_crowbar_enabled1BooleanWhether the 'Swing a Crowbar X Times' task should be enabled
ttt_taskmaster_crowbar_times50Integer (1-240)The number of times a player must use their crowbar to complete the 'Swing Crowbar' task
ttt_taskmaster_damageeveryone_enabled1BooleanWhether the 'Damage Everyone Else' task should be enabled
ttt_taskmaster_dodamage_amount200Integer (1-1000)The amount of damage a player must do to complete the 'Deal X Damage' task
ttt_taskmaster_dodamage_enabled1BooleanWhether the 'Deal X Damage' task should be enabled
ttt_taskmaster_firebullets_enabled1BooleanWhether the 'Fire X Bullets' task should be enabled
ttt_taskmaster_firebullets_times100Integer (1-1000)The jump of times a player must fire a bullet to complete the 'Fire X Bullets' task
ttt_taskmaster_getplayerkilled_enabled1BooleanWhether the 'Get Target Killed' task should be enabled
ttt_taskmaster_getplayertokill_enabled1BooleanWhether the 'Get Target to Kill' task should be enabled
ttt_taskmaster_healthunder_amount15Integer (1-240)The amount of health a player must stay under to complete the 'Health Under' task
ttt_taskmaster_healthunder_enabled1BooleanWhether the 'Survive Under X Health' task should be enabled
ttt_taskmaster_healthunder_time60Integer (1-240)The time (in seconds) a player must stay under the target health to complete the 'Health Under' task
ttt_taskmaster_holstered_enabled1BooleanWhether the 'Stay Holstered for X Seconds' task should be enabled
ttt_taskmaster_holstered_time60Integer (1-240)The time (in seconds) a player must stay holstered to complete the 'Holstered' task
ttt_taskmaster_jump_enabled1BooleanWhether the 'Jump X Times' task should be enabled
ttt_taskmaster_jump_times100Integer (1-500)The jump of times a player must jump to complete the 'Jump X Times' task
ttt_taskmaster_kill360_enabled1BooleanWhether the 'Kill a Player After a 360' task should be enabled
ttt_taskmaster_kill360_time3Integer (1-10)The time (in seconds) a player has after completing a 360 to kill a player for the 'Kill a Player After a 360' task
ttt_taskmaster_killaiming_enabled1BooleanWhether the 'Kill a Player While Aiming' task should be enabled
ttt_taskmaster_killairborne_enabled1BooleanWhether the 'Kill an Airborne Player' task should be enabled
ttt_taskmaster_killbehind_enabled1BooleanWhether the 'Kill a Player From Behind' task should be enabled
ttt_taskmaster_killbehind_view_angle75Integer (0-180)The angle (in degrees) from a player's eye angle within which the Taskmaster is 'spotted' for the 'Kill a Player From Behind' task
ttt_taskmaster_killcrowbar_enabled1BooleanWhether the 'Kill a Player With a Crowbar' task should be enabled
ttt_taskmaster_killdistant_enabled1BooleanWhether the 'Kill a Distant Player' task should be enabled
ttt_taskmaster_killdistant_range25Integer (0-100)The minimum distance (in meters) away a player can be to count for the 'Kill a Distant Player' task
ttt_taskmaster_killdouble_enabled1BooleanWhether the 'Get a Double Kill' task should be enabled
ttt_taskmaster_killdouble_time5Integer (0-30)The time (in seconds) the taskmaster has between kills to complete the 'Get a Double Kill' task
ttt_taskmaster_killheadshot_enabled1BooleanWhether the 'Kill a Player With a Headshot' task should be enabled
ttt_taskmaster_killlastbullet_enabled1BooleanWhether the 'Kill a Player With Your Last Bullet' task should be enabled
ttt_taskmaster_killmidair_enabled1BooleanWhether the 'Kill a Player While Midair' task should be enabled
ttt_taskmaster_killnearby_enabled1BooleanWhether the 'Kill a Nearby Player' task should be enabled
ttt_taskmaster_killnearby_range5Integer (0-10)The maximum distance (in meters) away a player can be to count for the 'Kill a Nearby Player' task
ttt_taskmaster_killonehit_enabled1BooleanWhether the 'Kill a Player in One Hit' task should be enabled
ttt_taskmaster_killpistol_enabled1BooleanWhether the 'Kill a Player With a Pistol' task should be enabled
ttt_taskmaster_killretaliate_enabled1BooleanWhether the 'Kill a Player That Attacked First' task should be enabled
ttt_taskmaster_killtarget_enabled1BooleanWhether the 'Kill Target' task should be enabled
ttt_taskmaster_killweapon_enabled1BooleanWhether the 'Kill a Player With a Specific Weapon' task should be enabled
ttt_taskmaster_lookatplayer_enabled1BooleanWhether the 'Look at Target' task should be enabled
ttt_taskmaster_lookatplayer_time30Integer (1-240)The time (in seconds) a player must look at their target to complete for the 'Look at Player' task
ttt_taskmaster_pickupshopitem_enabled1BooleanWhether the 'Pick up a Shop Item' task should be enabled
ttt_taskmaster_standonplayer_enabled1BooleanWhether the 'Stand on a Player for X Seconds' task should be enabled
ttt_taskmaster_standonplayer_time15Integer (1-240)The time (in seconds) a player must stay stand on top of another player to complete the 'Stand On Player' task
ttt_taskmaster_stayhidden_enabled1BooleanWhether the 'Stay Hidden for X Seconds' task should be enabled
ttt_taskmaster_stayhidden_time30Integer (1-240)The time (in seconds) a player must hide to complete for the 'Stay Hidden' task
ttt_taskmaster_stayhigher_enabled1BooleanWhether the 'Be Highest for X Seconds' task should be enabled
ttt_taskmaster_stayhigher_time30Integer (1-240)The time (in seconds) a player must stay higher up to complete the 'Highest Player' task
ttt_taskmaster_stayinarea_enabled1BooleanWhether the 'Stay in Area for X Seconds' task should be enabled
ttt_taskmaster_stayinarea_range5Integer (1-100)The distance (in meters) away from the location that a player must stay within to count for the 'Stay in Area' task
ttt_taskmaster_stayinarea_time30Integer (1-240)The time (in seconds) a player must stay inside the target area to count for the 'Stay in Area' task
ttt_taskmaster_staylower_enabled1BooleanWhether the 'Be Lowest for X Seconds' task should be enabled
ttt_taskmaster_staylower_time30Integer (1-240)The time (in seconds) a player must stay lower down to complete the 'Lowest Player' task
ttt_taskmaster_stayneartarget_enabled1BooleanWhether the 'Stay Near Target' task should be enabled
ttt_taskmaster_stayneartarget_range5Integer (1-100)The distance (in meters) away a player must stay within to count for the 'Stay Near Target' task
ttt_taskmaster_stayneartarget_time30Integer (1-240)The time (in seconds) a player must stay near their target to count for the 'Stay Near Target' task
ttt_taskmaster_survive_enabled1BooleanWhether the 'Survive' task should be enabled
ttt_taskmaster_takedamage_enabled1BooleanWhether the 'Take Damage and Survive' task should be enabled
ttt_taskmaster_takedamage_time60Integer (1-240)The time (in seconds) a player must survive without taking further damage to complete the 'Take Damage' task
ttt_taskmaster_weaponpickups_count20Integer (1-240)The number of unique weapons a player must pick up to complete the 'Pick Up Weapons' task
ttt_taskmaster_weaponpickups_enabled1BooleanWhether the 'Pick up X Weapons' task should be enabled
+

A list of ConVars shared by every role and instructions for using ConVars can be found on the Configuring ConVars tutorial page.

+
+
+
From 2cc6e143bf63c2985d9b096d9823bbf6d73a7c87 Mon Sep 17 00:00:00 2001 From: Malivil Date: Wed, 20 Aug 2025 11:40:11 -0400 Subject: [PATCH 108/115] Error prevention and cleanup --- .../terrortown/gamemode/roles/taskmaster/tasks/chat.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua | 2 +- .../gamemode/roles/taskmaster/tasks/dodamage.lua | 2 +- .../gamemode/roles/taskmaster/tasks/firebullets.lua | 2 +- .../terrortown/gamemode/roles/taskmaster/tasks/jump.lua | 2 +- .../gamemode/roles/taskmaster/tasks/killweapon.lua | 7 ++++++- .../gamemode/roles/taskmaster/tasks/weaponpickups.lua | 2 +- 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua index 208fc1129..572c54858 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/chat.lua @@ -27,7 +27,7 @@ TASK.Name = function(ply) if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = times else - progress = ply.Task_ChatCount + progress = ply.Task_ChatCount or 0 end return name .. " (" .. progress .. "/" .. times .. ")" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua index 5435b8326..ae7554f39 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/crowbar.lua @@ -27,7 +27,7 @@ TASK.Name = function(ply) if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = times else - progress = ply.Task_CrowbarCount + progress = ply.Task_CrowbarCount or 0 end return name .. " (" .. progress .. "/" .. times .. ")" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua index d495884dc..b04489ac9 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/dodamage.lua @@ -24,7 +24,7 @@ TASK.Name = function(ply) if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = amount else - progress = ply.Task_DoDamageTotal + progress = ply.Task_DoDamageTotal or 0 end return name .. " (" .. progress .. "/" .. amount .. ")" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua index ecd081152..d39bd2dd8 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/firebullets.lua @@ -27,7 +27,7 @@ TASK.Name = function(ply) if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = times else - progress = ply.Task_FireBulletsCount + progress = ply.Task_FireBulletsCount or 0 end return name .. " (" .. progress .. "/" .. times .. ")" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua index ef27470db..48e6add24 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/jump.lua @@ -27,7 +27,7 @@ TASK.Name = function(ply) if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = times else - progress = ply.Task_JumpCount + progress = ply.Task_JumpCount or 0 end return name .. " (" .. progress .. "/" .. times .. ")" diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua index 25a3d01b2..0def1c842 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killweapon.lua @@ -21,7 +21,12 @@ TASK.Name = function(ply) end end end - return "Kill a Player With a " .. weapon + + local article = "a" + if StartsWithVowel(weapon) then + article = article .. "n" + end + return "Kill a Player With " .. article .. " " .. weapon end TASK.Description = function(ply) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua index c5b30c643..07bb38437 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/weaponpickups.lua @@ -27,7 +27,7 @@ TASK.Name = function(ply) if TableHasValue(ply.TaskmasterCompletedTasks, TASK.id) then progress = count else - progress = ply.Task_WeaponPickupsCount + progress = ply.Task_WeaponPickupsCount or 0 end return name .. " (" .. progress .. "/" .. count .. ")" From c4848e55e37dab197c24b66ba14bee8880683e70 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 24 Aug 2025 17:25:06 -0400 Subject: [PATCH 109/115] Change create HTML tutorial to link to HTML convars page --- docs/tutorials/create_your_own_role.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/tutorials/create_your_own_role.html b/docs/tutorials/create_your_own_role.html index 78c019705..e2552601e 100644 --- a/docs/tutorials/create_your_own_role.html +++ b/docs/tutorials/create_your_own_role.html @@ -669,8 +669,7 @@

ConVars

ttt_%NAMERAW%_shop_mode (Whether the role should have access to traitor and/or detective shop items) [INDEPENDENT ONLY]
- -

For more information on the specifics of these ConVars you can read the full list of ConVars here.

+

For more information on the specifics of these ConVars you can read the full list of ConVars here.

If you would like to add your own ConVars that aren't automatically created you can do so here. First create the ConVars as you would normally with CreateConVar. (Note: Please try to keep your ConVars as consistently named as possible. The recommended naming scheme for role specific convars is ttt_%NAMERAW%_....)

Once you have defined your ConVar you can add it to the convars table to get it to show up inside ULX menus. Each entry in the convars table needs two properties. cvar is the name of the ConVar you want to add and type is one of three values depending on if you want your ConVar to show up as a slider, checkbox or textbox.

From 2c0d786ee2f8459119c0a0d4beb6d7b12bf32751 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sun, 24 Aug 2025 17:41:22 -0400 Subject: [PATCH 110/115] Added task complete messages --- .../gamemode/roles/taskmaster/taskmaster.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index db9f11aa7..f50da047f 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -176,14 +176,19 @@ function plymeta:CompleteTask(taskId) return false end - taskList[taskId].OnTaskComplete(self) + local task = taskList[taskId] + task.OnTaskComplete(self) table.insert(self.TaskmasterCompletedTasks, taskId) self:SetProperty("TaskmasterCompletedTasks", self.TaskmasterCompletedTasks, self) local activeTasksList = self:GetActiveTasks() if #activeTasksList == 0 then self:SetProperty("TaskmasterShouldWin", true) - -- TODO: Alert the player that they have finished all their tasks + -- TODO: Play a sound + self:QueueMessage(MSG_PRINTBOTH, "All tasks complete!", nil, "tskTaskComplete") + else + -- TODO: Play a sound + self:QueueMessage(MSG_PRINTBOTH, "'" .. task.Name(self) .. "' complete!", nil, "tskTaskComplete") end net.Start("TTT_TaskmasterUpdateTaskList") @@ -198,8 +203,6 @@ function plymeta:CompleteTask(taskId) }) end - -- TODO: Play a sound and/or send a message when a task is completed - return true end return false From 44bf3b6c4dcb33a2ae0221875452cf04e1123bc7 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Mon, 25 Aug 2025 16:09:24 +0100 Subject: [PATCH 111/115] Mixed duplicate hook name --- .../terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua index 7b67a4ec0..4b1d1ceb8 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/tasks/killdouble.lua @@ -46,7 +46,7 @@ if SERVER then } TASK.OnTaskAssigned = function(ply) - hook.Add("PlayerDeath", "Taskmaster_KillPistol_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) + hook.Add("PlayerDeath", "Taskmaster_KillDouble_PlayerDeath_" .. ply:SteamID64(), function(victim, inflictor, attacker) if not IsPlayer(victim) then return end if not IsPlayer(attacker) or not attacker:IsActiveTaskmaster() or attacker ~= ply then return end @@ -64,7 +64,7 @@ if SERVER then TASK.OnTaskRemoved = function(ply) ply:ClearProperty("Task_KillDoubleLastKill", ply) - hook.Remove("PlayerDeath", "Taskmaster_KillPistol_PlayerDeath_" .. ply:SteamID64()) + hook.Remove("PlayerDeath", "Taskmaster_KillDouble_PlayerDeath_" .. ply:SteamID64()) net.Start("TTT_Taskmaster_KillDouble_Cleanup") net.Send(ply) From 685b186adb7761717879bb0a45b77a03062ab762 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Mon, 25 Aug 2025 17:27:17 +0100 Subject: [PATCH 112/115] Added task complete sounds and reworked reroll logic to account for edge cases where no valid tasks exist --- .../roles/taskmaster/cl_taskmaster.lua | 8 ++++ .../gamemode/roles/taskmaster/taskmaster.lua | 37 +++++++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua index 977913d69..6a0813c6e 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/cl_taskmaster.lua @@ -530,4 +530,12 @@ hook.Add("TTTTutorialRoleText", "Taskmaster_TTTTutorialRoleText", function(role, return html end +end) + +------------ +-- SOUNDS -- +------------ + +net.Receive("TTT_TaskmasterTaskComplete", function(len, ply) + surface.PlaySound("buttons/bell1.wav") end) \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index f50da047f..f871f22c5 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -14,6 +14,7 @@ local plymeta = FindMetaTable("Player") util.AddNetworkString("TTT_TaskmasterRerollTask") util.AddNetworkString("TTT_TaskmasterUpdateTaskList") +util.AddNetworkString("TTT_TaskmasterTaskComplete") ------------- -- CONVARS -- @@ -32,6 +33,20 @@ local taskmaster_wins_with_others = GetConVar("ttt_taskmaster_wins_with_others") -- TASK ASSIGNMENT -- --------------------- +local function CheckTaskmasterWin(ply) + local activeTasksList = ply:GetActiveTasks() + if #activeTasksList == 0 then + ply:SetProperty("TaskmasterShouldWin", true) + local message = "All tasks complete!" + if taskmaster_wins_with_others then + message = message .. " You will win at the end of the round." + end + ply:QueueMessage(MSG_PRINTBOTH, message, nil, "tskTaskComplete") + return true + end + return false +end + function plymeta:AssignTask(isKillTask, index) if not self:IsTaskmaster() then return end @@ -85,7 +100,6 @@ function plymeta:AssignTask(isKillTask, index) end end end - -- TODO: Handle edge case where there are no valid tasks. Maybe we need to change their role? Or just have a free fallback task? return false end @@ -115,7 +129,7 @@ function plymeta:RerollTask(taskId, free) self:SetProperty("TaskmasterRerolledTasks", self.TaskmasterRerolledTasks, self) end - self:AssignTask(isKillTask, index) + local rerolled = self:AssignTask(isKillTask, index) self:RemoveTask(taskId) if not free then @@ -124,6 +138,11 @@ function plymeta:RerollTask(taskId, free) net.Start("TTT_TaskmasterUpdateTaskList") net.Send(self) + + if not rerolled then + self:QueueMessage(MSG_PRINTTALK, "Ran out of valid tasks to assign! You can have this one for free.", nil, "tskTaskRerollFailed") + CheckTaskmasterWin(self) + end end net.Receive("TTT_TaskmasterRerollTask", function(len, ply) @@ -181,15 +200,11 @@ function plymeta:CompleteTask(taskId) table.insert(self.TaskmasterCompletedTasks, taskId) self:SetProperty("TaskmasterCompletedTasks", self.TaskmasterCompletedTasks, self) - local activeTasksList = self:GetActiveTasks() - if #activeTasksList == 0 then - self:SetProperty("TaskmasterShouldWin", true) - -- TODO: Play a sound - self:QueueMessage(MSG_PRINTBOTH, "All tasks complete!", nil, "tskTaskComplete") - else - -- TODO: Play a sound - self:QueueMessage(MSG_PRINTBOTH, "'" .. task.Name(self) .. "' complete!", nil, "tskTaskComplete") - end + net.Start("TTT_TaskmasterTaskComplete") + net.Send(self) + self:QueueMessage(MSG_PRINTTALK, "'" .. task.Name(self) .. "' complete!", nil, "tskTaskComplete") + + CheckTaskmasterWin(self) net.Start("TTT_TaskmasterUpdateTaskList") net.Send(self) From 95588031537afaf322652d08e922c54d4b1a9714 Mon Sep 17 00:00:00 2001 From: donaldsonnick Date: Mon, 25 Aug 2025 17:37:27 +0100 Subject: [PATCH 113/115] Small fix --- gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua index f871f22c5..6ad2507e0 100644 --- a/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua +++ b/gamemodes/terrortown/gamemode/roles/taskmaster/taskmaster.lua @@ -38,7 +38,7 @@ local function CheckTaskmasterWin(ply) if #activeTasksList == 0 then ply:SetProperty("TaskmasterShouldWin", true) local message = "All tasks complete!" - if taskmaster_wins_with_others then + if taskmaster_wins_with_others:GetBool() then message = message .. " You will win at the end of the round." end ply:QueueMessage(MSG_PRINTBOTH, message, nil, "tskTaskComplete") From fb35f6ec6313a1908acb63785dc469ed6fba5db0 Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 25 Aug 2025 12:55:08 -0400 Subject: [PATCH 114/115] Fixed broken doc header --- docs/api/hooks.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/hooks.html b/docs/api/hooks.html index f4027a8bc..181f4ed97 100644 --- a/docs/api/hooks.html +++ b/docs/api/hooks.html @@ -308,7 +308,7 @@

TTTDetectiveCalledToBody(ply, owner, rag) +

TTTDetectiveCalledToBody(ply, owner, rag)  

Called when a player calls a detective to a player ragdoll.
Realm: Server
From 09a281bbf8edb51db694de0dc979518eaceca237 Mon Sep 17 00:00:00 2001 From: Malivil Date: Mon, 25 Aug 2025 13:01:43 -0400 Subject: [PATCH 115/115] Added Taskmaster to release notes --- RELEASE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index 660d507f0..83e9d9892 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -3,6 +3,9 @@ ## 2.3.5 (Beta) **Released:** +### Additions +- Added new independent role: Taskmaster + ### Developer - Added `TTTDetectiveCalledToBody` hook which is called when a player calls a detective to a body - Changed `SYNC` methods to not clear values that are already `nil`