mirror of
https://github.com/edgegamers/Jailbreak.git
synced 2025-12-06 04:42:57 -08:00
Compare commits
310 Commits
4.6.0
...
6900848ef9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6900848ef9 | ||
|
|
b8beac3d14 | ||
|
|
4bde4e8f0a | ||
|
|
1cf95f1b3d | ||
|
|
2182c22e44 | ||
|
|
a2dd074403 | ||
|
|
faeec955f8 | ||
|
|
4e94f724e9 | ||
|
|
b89f2c1b60 | ||
|
|
400a5171a7 | ||
|
|
edd6dfdab6 | ||
|
|
8bdfff38e5 | ||
|
|
d5f8c80b0d | ||
|
|
6bc0395768 | ||
|
|
a4b5394e0b | ||
|
|
1434b42e79 | ||
|
|
6d01e2e58d | ||
|
|
4de90e6ae9 | ||
|
|
981025facd | ||
|
|
2c50333446 | ||
|
|
d2db34b509 | ||
|
|
53e75cdc22 | ||
|
|
0cb7f833dc | ||
|
|
5fdefd67ee | ||
|
|
04c383916c | ||
|
|
b78b05c73f | ||
|
|
54e9262b56 | ||
|
|
4f121106f9 | ||
|
|
d57cefaad2 | ||
|
|
d91cede2a8 | ||
|
|
588b9748c4 | ||
|
|
8ba25a410e | ||
|
|
7a60ff7c6d | ||
|
|
74e20acfe3 | ||
|
|
900e79401f | ||
|
|
a40a0841ea | ||
|
|
b165823621 | ||
|
|
19215e2695 | ||
|
|
c5d050c226 | ||
|
|
5957833e81 | ||
|
|
cecf3cec04 | ||
|
|
94db4d7252 | ||
|
|
af623b2ea5 | ||
|
|
b4aeb9b8ee | ||
|
|
5213241dfc | ||
|
|
ec45ba581f | ||
|
|
a832e43230 | ||
|
|
3ec269eef0 | ||
|
|
5a6e1a56c3 | ||
|
|
9a5acc5926 | ||
|
|
8f556329cb | ||
|
|
ee12f527eb | ||
|
|
5d42dacf43 | ||
|
|
e7e799abb3 | ||
|
|
b2f2411b1b | ||
|
|
9cba0c155d | ||
|
|
6844272ba2 | ||
|
|
dcc4da4ac5 | ||
|
|
144f879562 | ||
|
|
6ec15da3cf | ||
|
|
0d0453cfe6 | ||
|
|
66d5d245de | ||
|
|
df599050f2 | ||
|
|
96bc068494 | ||
|
|
39c6ad6270 | ||
|
|
8f942383c6 | ||
|
|
7dd822b6de | ||
|
|
33c4389fcf | ||
|
|
587d64fcf5 | ||
|
|
4b412dcc7b | ||
|
|
b5603fafbc | ||
|
|
4df6446b18 | ||
|
|
8851e27004 | ||
|
|
ece5e9bb35 | ||
|
|
19f240d918 | ||
|
|
d7f1149317 | ||
|
|
bda2fd7a43 | ||
|
|
fc8b7f0cff | ||
|
|
75094be9cf | ||
|
|
22e9e45811 | ||
|
|
6a804dd2a5 | ||
|
|
9e69f774ce | ||
|
|
963bb85c28 | ||
|
|
cccf2c41e7 | ||
|
|
a4a50e6a6d | ||
|
|
31ada4a226 | ||
|
|
310606f37f | ||
|
|
f0b96663bc | ||
|
|
5a98918f71 | ||
|
|
8f370df230 | ||
|
|
97381652ec | ||
|
|
f010bce92c | ||
|
|
d8996efb41 | ||
|
|
11b527d9fc | ||
|
|
888906fc3a | ||
|
|
c9083a3630 | ||
|
|
e75baccdd0 | ||
|
|
ef74889949 | ||
|
|
ce27b3ad45 | ||
|
|
169f9883ae | ||
|
|
5ce074f0b1 | ||
|
|
274319e95f | ||
|
|
dc49770716 | ||
|
|
5972950f78 | ||
|
|
aad9263123 | ||
|
|
43926f8ec4 | ||
|
|
4fb8e5c599 | ||
|
|
74505b647d | ||
|
|
9cf357a522 | ||
|
|
3d9283993e | ||
|
|
bec433f05c | ||
|
|
6961fa9c81 | ||
|
|
537744712d | ||
|
|
37f6cccecf | ||
|
|
34fcf653c8 | ||
|
|
da31614dec | ||
|
|
a24963cb17 | ||
|
|
d2e048f3d8 | ||
|
|
51f87a9c08 | ||
|
|
9067a09b03 | ||
|
|
921613ab65 | ||
|
|
7ec893ddda | ||
|
|
3406fff706 | ||
|
|
d2c945bf43 | ||
|
|
7e5e4bca29 | ||
|
|
fd43b750a7 | ||
|
|
064f0eb51a | ||
|
|
8e8a22194e | ||
|
|
2a062b0a7e | ||
|
|
3f1d50d584 | ||
|
|
9ce8893aa0 | ||
|
|
c37c2d3b0d | ||
|
|
2952e98bfa | ||
|
|
c9fc1f444c | ||
|
|
3d677fb679 | ||
|
|
0e591ebe79 | ||
|
|
12b58160c1 | ||
|
|
7650556948 | ||
|
|
6cf980bd14 | ||
|
|
e06b8c4623 | ||
|
|
ec6606f800 | ||
|
|
f072f392fe | ||
|
|
9bd1668e06 | ||
|
|
c58e9a033e | ||
|
|
b34d984ffb | ||
|
|
12f8fa7819 | ||
|
|
3510375c4a | ||
|
|
7688fa67d9 | ||
|
|
cc7b21286a | ||
|
|
7b8a6c514b | ||
|
|
f9be61e62d | ||
|
|
9ef36aa97e | ||
|
|
4482291c44 | ||
|
|
4413de9933 | ||
|
|
fe42cd41dd | ||
|
|
2744ca54c0 | ||
|
|
0936f57f2a | ||
|
|
c155e3e720 | ||
|
|
c70cad0614 | ||
|
|
f029049302 | ||
|
|
1938ba65ab | ||
|
|
80f1cf8802 | ||
|
|
3aad5eba3c | ||
|
|
2b47b10afb | ||
|
|
95bd6a0ff2 | ||
|
|
17acc5f174 | ||
|
|
1cddf43798 | ||
|
|
00ab901022 | ||
|
|
4bf9924ddb | ||
|
|
294d761cf8 | ||
|
|
cc206db226 | ||
|
|
51365a3526 | ||
|
|
8ce1556711 | ||
|
|
1845621483 | ||
|
|
b4df6302b6 | ||
|
|
37adbf1853 | ||
|
|
8bed3fd086 | ||
|
|
5d6cef55de | ||
|
|
b95c386eb9 | ||
|
|
1c9603e276 | ||
|
|
7cf0e194be | ||
|
|
65101d7490 | ||
|
|
58185c09ad | ||
|
|
a5a5809a34 | ||
|
|
8e2e8ea73d | ||
|
|
d24f6d8b47 | ||
|
|
e3b34685ec | ||
|
|
2403ace85b | ||
|
|
0d9e830e11 | ||
|
|
dcdd504d05 | ||
|
|
472ccf01b8 | ||
|
|
a28eb746a8 | ||
|
|
0041d36bad | ||
|
|
0682427979 | ||
|
|
b7cf0af6c1 | ||
|
|
3f307dcd03 | ||
|
|
5223db8e39 | ||
|
|
c49580800d | ||
|
|
4d5ad8dca3 | ||
|
|
97faee0977 | ||
|
|
38d0a0f8ab | ||
|
|
e7b8b5c28c | ||
|
|
45a71a9755 | ||
|
|
3666814699 | ||
|
|
c8403dec59 | ||
|
|
3b80d551ca | ||
|
|
1b032b2506 | ||
|
|
132c94b058 | ||
|
|
ba4eccd49e | ||
|
|
21a22acd1f | ||
|
|
6c2ab5e89c | ||
|
|
ddd4402ac5 | ||
|
|
cdeb71f48e | ||
|
|
5b6b6fe011 | ||
|
|
70e8efd2d8 | ||
|
|
f34e6df4d3 | ||
|
|
5450024a86 | ||
|
|
7fc91cc95c | ||
|
|
9351c38efb | ||
|
|
a428bd6886 | ||
|
|
a3a4da7307 | ||
|
|
5fb5b31c87 | ||
|
|
0b091692cb | ||
|
|
45976f0232 | ||
|
|
9ec911addf | ||
|
|
9c15b87400 | ||
|
|
73d01ea772 | ||
|
|
09d5cd9129 | ||
|
|
1afa53718a | ||
|
|
6cc534e3a4 | ||
|
|
49e5dd4c81 | ||
|
|
d9152a5870 | ||
|
|
3f2e334b44 | ||
|
|
cdaad4542a | ||
|
|
3b2f6d6961 | ||
|
|
eaeb490797 | ||
|
|
41646ec179 | ||
|
|
326d1b7300 | ||
|
|
8ba575ed3a | ||
|
|
590fbdf3fb | ||
|
|
8a76c0824e | ||
|
|
a1bc5dd5ae | ||
|
|
65bf3eafd6 | ||
|
|
81064bf9bf | ||
|
|
e249eba1ce | ||
|
|
6c8619f073 | ||
|
|
c571f925e0 | ||
|
|
c7ba9c0300 | ||
|
|
9a8047f79a | ||
|
|
9ebbdf2c6d | ||
|
|
fb12732dc9 | ||
|
|
ba24da2350 | ||
|
|
e9324127df | ||
|
|
ae444a7fce | ||
|
|
90163b1778 | ||
|
|
79819ce617 | ||
|
|
ec904a5788 | ||
|
|
7a70740fcb | ||
|
|
8ea19a62df | ||
|
|
d0ec40f7aa | ||
|
|
19ee8c2e62 | ||
|
|
d8a76d6162 | ||
|
|
9e16e50d98 | ||
|
|
b987887974 | ||
|
|
840f8f6af2 | ||
|
|
1010a57b28 | ||
|
|
08359231b3 | ||
|
|
ba9dcdbcc8 | ||
|
|
d61a35a023 | ||
|
|
96aa9bfc9c | ||
|
|
2a254b683b | ||
|
|
e95d9f99c2 | ||
|
|
b42d9403d1 | ||
|
|
b764694c89 | ||
|
|
71a6507975 | ||
|
|
8591cf14f6 | ||
|
|
073c101ce4 | ||
|
|
fb062b06e2 | ||
|
|
23110b2256 | ||
|
|
5613d0119e | ||
|
|
03e7a39ad9 | ||
|
|
cf7760d13b | ||
|
|
b5f279fdce | ||
|
|
dcda1e9ecb | ||
|
|
652b274e5b | ||
|
|
5ab57ea659 | ||
|
|
311eda12cc | ||
|
|
3c785657cc | ||
|
|
fc9366baeb | ||
|
|
9474bf3584 | ||
|
|
36cad95a1d | ||
|
|
983a76497c | ||
|
|
da08d2dbf7 | ||
|
|
088b46374d | ||
|
|
19fa0ef1ca | ||
|
|
1272fc4203 | ||
|
|
1afcf3f0eb | ||
|
|
e36f2d2162 | ||
|
|
120c5cc532 | ||
|
|
34993a2bae | ||
|
|
6d584a846a | ||
|
|
2a027b62b6 | ||
|
|
76c1527158 | ||
|
|
136c74abb0 | ||
|
|
2f6f5c7cf3 | ||
|
|
8921871955 | ||
|
|
81a6d99612 | ||
|
|
4cc2426852 | ||
|
|
ade62e7283 | ||
|
|
dc2ccf13f3 |
6
.github/workflows/nightly.yml
vendored
6
.github/workflows/nightly.yml
vendored
@@ -3,7 +3,11 @@
|
||||
|
||||
name: Nightlies
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '15 0 * * 3' # Every Wednesday at 00:15 UTC
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
BIN
.gitignore
vendored
BIN
.gitignore
vendored
Binary file not shown.
@@ -9,8 +9,8 @@ public class CoinflipLocale : LastRequestLocale, ILRCFLocale {
|
||||
public IView FailedToChooseInTime(bool choice) {
|
||||
return new SimpleView {
|
||||
PREFIX,
|
||||
"You failed to choose in time, defaulting to" + ChatColors.Green,
|
||||
choice ? "Heads" : "Tails"
|
||||
"You failed to choose in time, defaulting to",
|
||||
$"{ChatColors.Green} {(choice ? "Heads" : "Tails")}{ChatColors.Grey}."
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,17 +18,16 @@ public class CoinflipLocale : LastRequestLocale, ILRCFLocale {
|
||||
return new SimpleView {
|
||||
PREFIX,
|
||||
guard,
|
||||
"chose" + ChatColors.Green,
|
||||
choice ? "Heads" : "Tails",
|
||||
ChatColors.Default + ", flipping..."
|
||||
"chose",
|
||||
$" {ChatColors.Green}{(choice ? "Heads" : "Tails")}{ChatColors.Grey}, flipping..."
|
||||
};
|
||||
}
|
||||
|
||||
public IView CoinLandsOn(bool heads) {
|
||||
return new SimpleView {
|
||||
PREFIX,
|
||||
"The coin landed on" + ChatColors.Green,
|
||||
heads ? "Heads" : "Tails" + ChatColors.White + "."
|
||||
"The coin landed on",
|
||||
$" {ChatColors.Green}{(heads ? "Heads" : "Tails")}{ChatColors.Grey}."
|
||||
};
|
||||
}
|
||||
}
|
||||
13
lang/Jailbreak.English/LastRequest/GunTossLocale.cs
Normal file
13
lang/Jailbreak.English/LastRequest/GunTossLocale.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using Jailbreak.Formatting.Base;
|
||||
using Jailbreak.Formatting.Views.LastRequest;
|
||||
|
||||
namespace Jailbreak.English.LastRequest;
|
||||
|
||||
public class GunTossLocale : LastRequestLocale, ILRGunTossLocale {
|
||||
public IView PlayerThrewGunDistance(CCSPlayerController player, float dist) {
|
||||
return new SimpleView {
|
||||
{ PREFIX, player, "threw their gun", dist, "units." }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ public class LastRequestLocale : ILRLocale,
|
||||
}
|
||||
|
||||
public IView LastRequestNotEnabled() {
|
||||
return new SimpleView { { PREFIX, "Last Request is not enabled." } };
|
||||
return new SimpleView { PREFIX, "Last Request is not enabled." };
|
||||
}
|
||||
|
||||
public IView InvalidLastRequest(string query) {
|
||||
@@ -132,14 +132,24 @@ public class LastRequestLocale : ILRLocale,
|
||||
};
|
||||
|
||||
public IView LastRequestRebel(CCSPlayerController player, int tHealth) {
|
||||
return new SimpleView { PREFIX, player, $"{ChatColors.LightRed}has decided to {ChatColors.DarkRed}LR Rebel {ChatColors.LightRed}with", tHealth, $"{ChatColors.LightRed}HP!"};
|
||||
}
|
||||
|
||||
return new SimpleView {
|
||||
PREFIX,
|
||||
player,
|
||||
$"{ChatColors.LightRed}has decided to {ChatColors.DarkRed}LR Rebel {ChatColors.LightRed}with",
|
||||
tHealth,
|
||||
$"{ChatColors.LightRed}HP!"
|
||||
};
|
||||
}
|
||||
|
||||
public IView LastRequestRebelDisabled() {
|
||||
return new SimpleView { PREFIX, "Rebelling during last request is disabled." };
|
||||
}
|
||||
|
||||
return new SimpleView {
|
||||
PREFIX, "Rebelling during last request is disabled."
|
||||
};
|
||||
}
|
||||
|
||||
public IView CannotLastRequestRebelCt() {
|
||||
return new SimpleView { PREFIX, "You cannot rebel as a CT during the last request." };
|
||||
return new SimpleView {
|
||||
PREFIX, "You cannot rebel as a CT during the last request."
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -39,41 +39,30 @@ public class WardenPeaceLocale : IWardenPeaceLocale,
|
||||
}
|
||||
|
||||
public IView UnmutedGuards
|
||||
=> new SimpleView {
|
||||
{ PREFIX, $"{ChatColors.Blue}Guards {ChatColors.Grey}were unmuted." }
|
||||
};
|
||||
=> new SimpleView { PREFIX, CsTeam.CounterTerrorist, "were unmuted." };
|
||||
|
||||
public IView UnmutedPrisoners
|
||||
=> new SimpleView {
|
||||
{
|
||||
PREFIX, $"{ChatColors.LightRed}Prisoners {ChatColors.Grey}were unmuted."
|
||||
}
|
||||
};
|
||||
=> new SimpleView { PREFIX, CsTeam.Terrorist, "were unmuted." };
|
||||
|
||||
public IView MuteReminder
|
||||
=> new SimpleView {
|
||||
{ PREFIX, ChatColors.Red + "You are currently muted." }
|
||||
};
|
||||
=> new SimpleView { PREFIX, ChatColors.Red + "You are currently muted." };
|
||||
|
||||
public IView PeaceReminder
|
||||
=> new SimpleView {
|
||||
{
|
||||
PREFIX,
|
||||
$"Peace is currently active. {ChatColors.Red}You should only be talking if absolutely necessary!"
|
||||
}
|
||||
PREFIX,
|
||||
$"Peace is currently active. {ChatColors.Red}You should only be talking if absolutely necessary!"
|
||||
};
|
||||
|
||||
public IView DeadReminder
|
||||
=> new SimpleView {
|
||||
{ PREFIX, $"{ChatColors.Red}You are dead and cannot speak." }
|
||||
PREFIX, $"{ChatColors.Red}You are dead and cannot speak."
|
||||
};
|
||||
|
||||
public IView AdminDeadReminder
|
||||
=> new SimpleView {
|
||||
{
|
||||
PREFIX, "You are dead.",
|
||||
$"{ChatColors.Red}You should only be talking if absolutely necessary!"
|
||||
}
|
||||
PREFIX,
|
||||
"You are dead.",
|
||||
$"{ChatColors.Red}You should only be talking if absolutely necessary!"
|
||||
};
|
||||
|
||||
public IView PeaceActive
|
||||
|
||||
26
lang/Jailbreak.English/SpecialDay/FogDayLocale.cs
Normal file
26
lang/Jailbreak.English/SpecialDay/FogDayLocale.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Jailbreak.Formatting.Base;
|
||||
|
||||
namespace Jailbreak.English.SpecialDay;
|
||||
|
||||
public class FogDayLocale() : SoloDayLocale("Fog War",
|
||||
"A heavy fog is creeping in...", "Your visibility will be gone soon.",
|
||||
"Fog expands periodically — Stay alert.") {
|
||||
|
||||
public IView FogComingIn() {
|
||||
return new SimpleView {
|
||||
PREFIX,
|
||||
"Fog's rolling in!",
|
||||
"Match Starts in 15 seconds."
|
||||
};
|
||||
}
|
||||
|
||||
public IView FogExpandsIn(int seconds) {
|
||||
if (seconds == 0) return new SimpleView { PREFIX, "Fog is expanding." };
|
||||
return new SimpleView {
|
||||
PREFIX,
|
||||
"Fog will start expanding in",
|
||||
seconds,
|
||||
"second" + (seconds == 1 ? "" : "s")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -48,4 +48,10 @@ public class SDLocale : ISDLocale, ILanguage<Formatting.Languages.English> {
|
||||
"second" + (maxTime == 1 ? "" : "s") + " of round start."
|
||||
};
|
||||
}
|
||||
|
||||
public IView CannotCallDay(string reason) {
|
||||
return new SimpleView {
|
||||
PREFIX, "You cannot call this special day:", ChatColors.Red + reason
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace Jailbreak.English.SpecialDay;
|
||||
public class SpeedrunDayLocale() : SoloDayLocale("Speedrunners",
|
||||
$"Follow the {ChatColors.Blue}blue{ChatColors.Default} player!",
|
||||
"They will run to a spot on the map.",
|
||||
$"Each round, the {ChatColors.Red}slowest players{ChatColors.Default} to reach the target will be eliminated."),
|
||||
$"Each round, the {ChatColors.Red}slowest players{ChatColors.Grey} to reach the target will be eliminated."),
|
||||
ISpeedDayLocale {
|
||||
public IView RoundEnded
|
||||
=> new SimpleView {
|
||||
|
||||
@@ -16,6 +16,9 @@ public class WardenLocale : IWardenLocale,
|
||||
Plain = false, Panorama = false, Chat = true
|
||||
};
|
||||
|
||||
public static readonly FormatObject COMMAND_STANDS =
|
||||
new HiddenFormatObject($"The previous command stands for 10 seconds.");
|
||||
|
||||
public IView PickingShortly
|
||||
=> new SimpleView {
|
||||
PREFIX,
|
||||
@@ -28,13 +31,25 @@ public class WardenLocale : IWardenLocale,
|
||||
$"No one in queue. Next guard to {ChatColors.BlueGrey}!warden{ChatColors.Grey} will become warden."
|
||||
};
|
||||
|
||||
public IView NowFreeday
|
||||
=> new SimpleView {
|
||||
PREFIX,
|
||||
$"It is now a freeday! CTs must pursue {ChatColors.BlueGrey}!warden{ChatColors.Grey}."
|
||||
};
|
||||
|
||||
public IView WardenLeft
|
||||
=> new SimpleView { PREFIX, "The warden left the game." };
|
||||
=> new SimpleView { PREFIX, "The warden left the game.", COMMAND_STANDS };
|
||||
|
||||
public IView WardenDied
|
||||
=> new SimpleView {
|
||||
PREFIX,
|
||||
$"The warden {ChatColors.Red}died{ChatColors.Grey}. CTs must pursue {ChatColors.BlueGrey}!warden{ChatColors.Grey}."
|
||||
{
|
||||
PREFIX,
|
||||
$"The warden {ChatColors.Red}died{ChatColors.Grey}. It is a freeday!"
|
||||
},
|
||||
SimpleView.NEWLINE, {
|
||||
PREFIX,
|
||||
$"CTs must pursue {ChatColors.BlueGrey}!warden{ChatColors.Grey}."
|
||||
}
|
||||
};
|
||||
|
||||
public IView BecomeNextWarden
|
||||
@@ -63,13 +78,22 @@ public class WardenLocale : IWardenLocale,
|
||||
=> new SimpleView {
|
||||
PREFIX, "The fire command failed for some unknown reason..."
|
||||
};
|
||||
|
||||
public IView TogglingNotEnabled
|
||||
=> new SimpleView {
|
||||
PREFIX, "Toggling Auto-Warden is not supported on this server."
|
||||
};
|
||||
|
||||
public IView PassWarden(CCSPlayerController player) {
|
||||
return new SimpleView { PREFIX, player, "resigned from warden." };
|
||||
return new SimpleView {
|
||||
PREFIX, player, "resigned from warden.", COMMAND_STANDS
|
||||
};
|
||||
}
|
||||
|
||||
public IView FireWarden(CCSPlayerController player) {
|
||||
return new SimpleView { PREFIX, player, "was fired from warden." };
|
||||
return new SimpleView {
|
||||
PREFIX, player, "was fired from warden.", COMMAND_STANDS
|
||||
};
|
||||
}
|
||||
|
||||
public IView
|
||||
@@ -79,14 +103,15 @@ public class WardenLocale : IWardenLocale,
|
||||
admin,
|
||||
"fired",
|
||||
player,
|
||||
"from warden."
|
||||
"from warden.",
|
||||
COMMAND_STANDS
|
||||
};
|
||||
}
|
||||
|
||||
public IView NewWarden(CCSPlayerController player) {
|
||||
return new SimpleView { PREFIX, player, "is now the warden." };
|
||||
}
|
||||
|
||||
|
||||
public IView CurrentWarden(CCSPlayerController? player) {
|
||||
return player is not null ?
|
||||
new SimpleView { PREFIX, "The warden is", player, "." } :
|
||||
@@ -101,4 +126,25 @@ public class WardenLocale : IWardenLocale,
|
||||
PREFIX, player, "was fired and is no longer the warden."
|
||||
};
|
||||
}
|
||||
|
||||
public IView MarkerPlaced(string marker) {
|
||||
return new SimpleView {
|
||||
PREFIX, $"{marker}{ChatColors.Grey} marker placed."
|
||||
};
|
||||
}
|
||||
|
||||
public IView MarkerRemoved(string marker) {
|
||||
return new SimpleView {
|
||||
PREFIX, $"{marker}{ChatColors.Grey} marker removed."
|
||||
};
|
||||
}
|
||||
|
||||
public IView AutoWardenToggled(bool enabled) {
|
||||
return new SimpleView {
|
||||
PREFIX,
|
||||
ChatColors.Grey + "You",
|
||||
enabled ? ChatColors.Green + "enabled" : ChatColors.Red + "disabled",
|
||||
ChatColors.Grey + "Auto-Warden."
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -68,17 +68,11 @@ public abstract class AbstractEnumCommand<T>(IServiceProvider provider,
|
||||
var gang = await gangs.GetGang(player.GangId.Value)
|
||||
?? throw new GangNotFoundException(player.GangId.Value);
|
||||
|
||||
var (success, data) =
|
||||
await gangStats.GetForGang<T>(player.GangId.Value, statId);
|
||||
|
||||
if (!success) data = def;
|
||||
|
||||
T equipped;
|
||||
var (_, tmp) = await playerStats.GetForPlayer<T>(player.Steam, statId);
|
||||
equipped = tmp;
|
||||
var data = await gangStats.GetForGang<T>(player.GangId.Value, statId);
|
||||
var tmp = await playerStats.GetForPlayer<T>(player.Steam, statId);
|
||||
|
||||
if (info.Args.Length == 1) {
|
||||
openMenu(executor, data, equipped);
|
||||
openMenu(executor, data, tmp);
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -113,13 +107,15 @@ public abstract class AbstractEnumCommand<T>(IServiceProvider provider,
|
||||
|
||||
if (gangChat != null)
|
||||
await gangChat.SendGangChat(player, gang,
|
||||
localizer.Get(MSG.PERK_PURCHASED, $"{title} ({formatItem(val)})"));
|
||||
localizer.Get(MSG.PERK_PURCHASED,
|
||||
player.Name ?? player.Steam.ToString(),
|
||||
$"{title} ({formatItem(val)})"));
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
await playerStats.SetForPlayer(executor, statId, val);
|
||||
executor.PrintToChat(
|
||||
$"{localizer.Get(MSG.PREFIX)}Set your {title} to {formatItem(val)}.");
|
||||
$"{localizer.Get(MSG.PREFIX)}Set your {ChatColors.BlueGrey}{title} to {ChatColors.LightBlue}{formatItem(val)}.");
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public abstract class AbstractEnumMenu<T>(IServiceProvider provider, T data,
|
||||
T item) {
|
||||
if (item.Equals((T)(object)0))
|
||||
return Task.FromResult(
|
||||
$" {ChatColors.DarkBlue}Gang Perks: {ChatColors.LightBlue}{title}\n {ChatColors.Grey}{desc}");
|
||||
$" {ChatColors.DarkBlue}Gang Perks: {ChatColors.LightBlue}{title}\\n {ChatColors.Grey}{desc}");
|
||||
|
||||
if (item.Equals(equipped))
|
||||
return Task.FromResult(
|
||||
|
||||
@@ -52,7 +52,7 @@ public class BasicPerkMenu(IServiceProvider provider, IPerk perk)
|
||||
$" {ChatColors.DarkBlue}Gang Perk: {ChatColors.Blue}{perk.Name}";
|
||||
var items = new List<string>();
|
||||
if (perk.Description != null)
|
||||
title += $"\n {ChatColors.LightBlue}{perk.Description}";
|
||||
title += $"\\n {ChatColors.LightBlue}{perk.Description}";
|
||||
items.Add(title);
|
||||
if (cost != null) {
|
||||
var color = await economy.CanAfford(player, cost.Value) ?
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace Gangs.BaseImpl.Stats;
|
||||
|
||||
public class LGStat : BaseStat<LGData> {
|
||||
public const string STAT_ID = "jb_lg_stat";
|
||||
public override string StatId => STAT_ID;
|
||||
public override string Name => "LGs";
|
||||
public override string? Description => "LGs reached";
|
||||
public override string Description => "LGs reached";
|
||||
public override LGData? Value { get; set; }
|
||||
}
|
||||
|
||||
@@ -13,6 +15,7 @@ public class LGData {
|
||||
public int TLgs { get; set; }
|
||||
|
||||
public override string ToString() {
|
||||
return $"CT/T Last Guards: {CtLgs}/{TLgs}";
|
||||
return
|
||||
$"{ChatColors.Blue}CT{ChatColors.Grey}/{ChatColors.Red}T {ChatColors.BlueGrey}Last Guards: {ChatColors.Blue}{CtLgs}{ChatColors.White}/{ChatColors.Red}{TLgs}";
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace Gangs.BaseImpl.Stats;
|
||||
|
||||
public class LRStat : BaseStat<LRData> {
|
||||
public const string STAT_ID = "jb_lr_stat";
|
||||
public override string StatId => STAT_ID;
|
||||
public override string Name => "LRs";
|
||||
public override string? Description => "LRs reached";
|
||||
public override string Description => "LRs reached";
|
||||
public override LRData? Value { get; set; }
|
||||
}
|
||||
|
||||
@@ -17,6 +19,8 @@ public class LRData {
|
||||
public int TLrsWon { get; set; }
|
||||
|
||||
public override string ToString() {
|
||||
return $"CT/T LRs, CT/T LR Wins: {CtLrs}/{TLrs} {CTLrsWon}/{TLrsWon}";
|
||||
return
|
||||
$"{ChatColors.Blue}CT{ChatColors.Grey}/{ChatColors.Red}T {ChatColors.BlueGrey}LRs: {ChatColors.Blue}{CtLrs}{ChatColors.White}/{ChatColors.Red}{TLrs}\\n"
|
||||
+ $"{ChatColors.Blue}CT{ChatColors.Grey}/{ChatColors.Red}T {ChatColors.BlueGrey}LR Wins: {ChatColors.Blue}{CTLrsWon}{ChatColors.White}/{ChatColors.Red}{TLrsWon}";
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace Gangs.BaseImpl.Stats;
|
||||
|
||||
public class WardenStat : BaseStat<WardenData> {
|
||||
public const string STAT_ID = "jb_warden_stat";
|
||||
public override string StatId => STAT_ID;
|
||||
public override string Name => "Guard";
|
||||
public override string? Description => "Stats revolving CT specific info";
|
||||
public override string Description => "Stats revolving CT specific info";
|
||||
public override WardenData? Value { get; set; }
|
||||
}
|
||||
|
||||
@@ -16,10 +18,17 @@ public class WardenData {
|
||||
public int WardenDeathsAsGuard { get; set; }
|
||||
|
||||
public override string ToString() {
|
||||
return $"WardenData:\n" + $" Times Wardened: {TimesWardened}\n"
|
||||
+ $" Warden Deaths: {WardenDeaths}\n"
|
||||
+ $" Wardens Killed: {WardensKilled}\n"
|
||||
+ $" Guard Deaths as Warden: {GuardDeathsAsWarden}\n"
|
||||
+ $" Warden Deaths as Guard: {WardenDeathsAsGuard}";
|
||||
var result =
|
||||
$"{ChatColors.BlueGrey}Times Wardened: {ChatColors.Yellow}{TimesWardened}\\n";
|
||||
|
||||
result +=
|
||||
$"{ChatColors.BlueGrey}Warden {ChatColors.LightBlue}Deaths{ChatColors.BlueGrey}: {ChatColors.Yellow}{WardenDeaths}\\n";
|
||||
result +=
|
||||
$"{ChatColors.BlueGrey}Wardens {ChatColors.LightRed}Killed{ChatColors.BlueGrey}: {ChatColors.Yellow}{WardensKilled}\\n";
|
||||
result +=
|
||||
$"{ChatColors.BlueGrey}Guard {ChatColors.LightRed}Deaths{ChatColors.BlueGrey} as Warden: {ChatColors.Yellow}{GuardDeathsAsWarden}\\n";
|
||||
result +=
|
||||
$"{ChatColors.BlueGrey}Warden {ChatColors.LightRed}Deaths{ChatColors.BlueGrey} as Guard: {ChatColors.Yellow}{WardenDeathsAsGuard}";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -60,10 +60,8 @@ public class BombIconCommand(IServiceProvider provider) : ICommand {
|
||||
var gang = await gangs.GetGang(player.GangId.Value)
|
||||
?? throw new GangNotFoundException(player.GangId.Value);
|
||||
|
||||
var (success, data) =
|
||||
await gangStats.GetForGang<BombPerkData>(gang, BombPerk.STAT_ID);
|
||||
|
||||
if (!success || data == null) data = new BombPerkData();
|
||||
var data = await gangStats.GetForGang<BombPerkData>(gang, BombPerk.STAT_ID)
|
||||
?? new BombPerkData();
|
||||
|
||||
if (info.ArgCount == 1) {
|
||||
var menu = new BombIconMenu(provider, data);
|
||||
|
||||
@@ -35,10 +35,9 @@ public class BombPerk(IServiceProvider provider)
|
||||
public override async Task<IMenu?> GetMenu(IGangPlayer player) {
|
||||
Debug.Assert(player.GangId != null, "player.GangId != null");
|
||||
|
||||
var (success, data) =
|
||||
await gangStats.GetForGang<BombPerkData>(player.GangId.Value, STAT_ID);
|
||||
|
||||
if (!success || data == null) data = new BombPerkData();
|
||||
var data =
|
||||
await gangStats.GetForGang<BombPerkData>(player.GangId.Value, STAT_ID)
|
||||
?? new BombPerkData();
|
||||
|
||||
return new BombIconMenu(Provider, data);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<ProjectReference Include="..\Gangs.SpecialDayColorPerk\Gangs.SpecialDayColorPerk.csproj"/>
|
||||
<ProjectReference Include="..\Gangs.SpecialIconPerk\Gangs.SpecialIconPerk.csproj"/>
|
||||
<ProjectReference Include="..\Gangs.WardenIconPerk\Gangs.WardenIconPerk.csproj"/>
|
||||
<ProjectReference Include="..\Gangs.WardenPaintColorPerk\Gangs.WardenPaintColorPerk.csproj" />
|
||||
<ProjectReference Include="..\Gangs.WardenPaintColorPerk\Gangs.WardenPaintColorPerk.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -26,7 +26,7 @@ public class GangsInit : IPluginBehavior {
|
||||
|
||||
_ = new BombIconBootstrap(services);
|
||||
_ = new SDColorBootstrap(services);
|
||||
_ = new CellsPerkBootstrap(services);
|
||||
// _ = new CellsPerkBootstrap(services);
|
||||
_ = new LRColorBootstrap(services);
|
||||
_ = new WardenIconBootstrap(services);
|
||||
_ = new SpecialIconBootstrap(services);
|
||||
|
||||
@@ -24,18 +24,14 @@ public class CellsPerk(IServiceProvider provider) : BasePerk<int>(provider) {
|
||||
public override string StatId => STAT_ID;
|
||||
public override string Name => "Hide in Cells";
|
||||
|
||||
public override string? Description
|
||||
public override string Description
|
||||
=> "# of gang members that can hide in cells without being detected";
|
||||
|
||||
public override int Value { get; set; }
|
||||
|
||||
public override async Task<int?> GetCost(IGangPlayer player) {
|
||||
if (player.GangId == null || player.GangRank == null) return null;
|
||||
var (success, cells) =
|
||||
await gangStats.GetForGang<int>(player.GangId.Value, StatId);
|
||||
|
||||
if (!success) cells = 0;
|
||||
|
||||
var cells = await gangStats.GetForGang<int>(player.GangId.Value, StatId);
|
||||
return getCostFor(cells + 1);
|
||||
}
|
||||
|
||||
@@ -47,9 +43,7 @@ public class CellsPerk(IServiceProvider provider) : BasePerk<int>(provider) {
|
||||
|
||||
public override async Task OnPurchase(IGangPlayer player) {
|
||||
if (player.GangId == null || player.GangRank == null) return;
|
||||
var (success, cells) =
|
||||
await gangStats.GetForGang<int>(player.GangId.Value, StatId);
|
||||
if (!success) cells = 1;
|
||||
var cells = await gangStats.GetForGang<int>(player.GangId.Value, StatId);
|
||||
cells++;
|
||||
await gangStats.SetForGang(player.GangId.Value, StatId, cells);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public class LRColorPerk(IServiceProvider provider)
|
||||
public const string STAT_ID = "jb_lr_color";
|
||||
|
||||
public const string DESC =
|
||||
"Pick the color of you and your partner during your LRs\nConflicting colors are resolved by gang rank";
|
||||
"Pick the color of you and your partner during your LRs\\nConflicting colors are resolved by gang rank";
|
||||
|
||||
private readonly IGangStatManager gangStats =
|
||||
provider.GetRequiredService<IGangStatManager>();
|
||||
@@ -24,7 +24,7 @@ public class LRColorPerk(IServiceProvider provider)
|
||||
public override string StatId => STAT_ID;
|
||||
public override string Name => "LR Colors";
|
||||
|
||||
public override string? Description => DESC;
|
||||
public override string Description => DESC;
|
||||
|
||||
public override LRColor Value { get; set; } = LRColor.DEFAULT;
|
||||
|
||||
@@ -38,10 +38,9 @@ public class LRColorPerk(IServiceProvider provider)
|
||||
|
||||
public override async Task<IMenu?> GetMenu(IGangPlayer player) {
|
||||
Debug.Assert(player.GangId != null, "player.GangId != null");
|
||||
var (success, data) =
|
||||
var data =
|
||||
await gangStats.GetForGang<LRColor>(player.GangId.Value, STAT_ID);
|
||||
if (!success) data = LRColor.DEFAULT;
|
||||
var (_, equipped) =
|
||||
var equipped =
|
||||
await playerStats.GetForPlayer<LRColor>(player.Steam, STAT_ID);
|
||||
return new LRColorMenu(Provider, data, equipped);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.260"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="GangsAPI">
|
||||
<HintPath>..\..\public\Jailbreak.Public\Mixin\GangsAPI.dll</HintPath>
|
||||
|
||||
@@ -63,10 +63,9 @@ public class SDColorCommand(IServiceProvider provider) : ICommand {
|
||||
var gang = await gangs.GetGang(player.GangId.Value)
|
||||
?? throw new GangNotFoundException(player.GangId.Value);
|
||||
|
||||
var (success, data) =
|
||||
await gangStats.GetForGang<SDColorData>(gang, SDColorPerk.STAT_ID);
|
||||
|
||||
if (!success || data == null) data = new SDColorData();
|
||||
var data =
|
||||
await gangStats.GetForGang<SDColorData>(gang, SDColorPerk.STAT_ID)
|
||||
?? new SDColorData();
|
||||
|
||||
if (info.ArgCount == 1) {
|
||||
var menu = new SDColorMenu(provider, data);
|
||||
@@ -120,7 +119,7 @@ public class SDColorCommand(IServiceProvider provider) : ICommand {
|
||||
}
|
||||
|
||||
data.Equipped = color;
|
||||
await gangStats.SetForGang(gang, BombPerk.STAT_ID, data);
|
||||
await gangStats.SetForGang(gang, SDColorPerk.STAT_ID, data);
|
||||
|
||||
if (gangChat == null) return CommandResult.SUCCESS;
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Gangs.BaseImpl;
|
||||
using Gangs.BaseImpl.Extensions;
|
||||
using GangsAPI.Data;
|
||||
using GangsAPI.Extensions;
|
||||
using GangsAPI.Menu;
|
||||
using GangsAPI.Services.Commands;
|
||||
using Jailbreak.Public.Mod.Rainbow;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Gangs.SpecialDayColorPerk;
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ public class SDColorPerk(IServiceProvider provider)
|
||||
|
||||
public override async Task<IMenu?> GetMenu(IGangPlayer player) {
|
||||
Debug.Assert(player.GangId != null, "player.GangId != null");
|
||||
var (success, data) =
|
||||
await gangStats.GetForGang<SDColorData>(player.GangId.Value, STAT_ID);
|
||||
if (!success || data == null) data = new SDColorData();
|
||||
var data =
|
||||
await gangStats.GetForGang<SDColorData>(player.GangId.Value, STAT_ID)
|
||||
?? new SDColorData();
|
||||
return new SDColorMenu(Provider, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Gangs.SpecialIconPerk;
|
||||
public class SpecialIconMenu(IServiceProvider provider, SpecialIcon data,
|
||||
SpecialIcon equipped) : AbstractEnumMenu<SpecialIcon>(provider, data,
|
||||
equipped, "css_sticon", "ST Icon",
|
||||
new SpecialIconPerk(provider).Description ?? "") {
|
||||
new SpecialIconPerk(provider).Description) {
|
||||
override protected int getCost(SpecialIcon item) { return item.GetCost(); }
|
||||
|
||||
override protected List<SpecialIcon> getValues() {
|
||||
|
||||
@@ -21,7 +21,7 @@ public class SpecialIconPerk(IServiceProvider provider)
|
||||
public override string StatId => STAT_ID;
|
||||
public override string Name => "ST Icon";
|
||||
|
||||
public override string? Description
|
||||
public override string Description
|
||||
=> "Change the icon that appears above your head as ST";
|
||||
|
||||
public override SpecialIcon Value { get; set; } = SpecialIcon.DEFAULT;
|
||||
@@ -36,10 +36,9 @@ public class SpecialIconPerk(IServiceProvider provider)
|
||||
|
||||
public override async Task<IMenu?> GetMenu(IGangPlayer player) {
|
||||
Debug.Assert(player.GangId != null, "player.GangId != null");
|
||||
var (success, data) =
|
||||
var data =
|
||||
await gangStats.GetForGang<SpecialIcon>(player.GangId.Value, STAT_ID);
|
||||
if (!success) data = SpecialIcon.DEFAULT;
|
||||
var (_, equipped) =
|
||||
var equipped =
|
||||
await playerStats.GetForPlayer<SpecialIcon>(player.Steam, STAT_ID);
|
||||
return new SpecialIconMenu(Provider, data, equipped);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,6 @@ public class WardenIconMenu(IServiceProvider provider, WardenIcon data,
|
||||
}
|
||||
|
||||
override protected string formatItem(WardenIcon item) {
|
||||
return $"{item.GetIcon()} ({item.ToString().ToTitleCase()}";
|
||||
return $"{item.GetIcon()} ({item.ToString().ToTitleCase()})";
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public class WardenIconPerk(IServiceProvider provider)
|
||||
public override string StatId => STAT_ID;
|
||||
public override string Name => "Warden Icon";
|
||||
|
||||
public override string? Description => DESC;
|
||||
public override string Description => DESC;
|
||||
|
||||
public override WardenIcon Value { get; set; } = WardenIcon.DEFAULT;
|
||||
|
||||
@@ -38,10 +38,9 @@ public class WardenIconPerk(IServiceProvider provider)
|
||||
|
||||
public override async Task<IMenu?> GetMenu(IGangPlayer player) {
|
||||
Debug.Assert(player.GangId != null, "player.GangId != null");
|
||||
var (success, data) =
|
||||
var data =
|
||||
await gangStats.GetForGang<WardenIcon>(player.GangId.Value, STAT_ID);
|
||||
if (!success) data = WardenIcon.DEFAULT;
|
||||
var (_, equipped) =
|
||||
var equipped =
|
||||
await playerStats.GetForPlayer<WardenIcon>(player.Steam, STAT_ID);
|
||||
return new WardenIconMenu(Provider, data, equipped);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Gangs.BaseImpl\Gangs.BaseImpl.csproj" />
|
||||
<ProjectReference Include="..\Gangs.BaseImpl\Gangs.BaseImpl.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="GangsAPI">
|
||||
<HintPath>..\..\public\Jailbreak.Public\Mixin\GangsAPI.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="GangsAPI">
|
||||
<HintPath>..\..\public\Jailbreak.Public\Mixin\GangsAPI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -10,18 +10,20 @@ namespace WardenPaintColorPerk;
|
||||
|
||||
public class WardenPaintColorPerk(IServiceProvider provider)
|
||||
: BasePerk<WardenPaintColor>(provider) {
|
||||
public const string STAT_ID = "jb_wardenpaintcolor";
|
||||
public const string DESC = "Change the color of your warden paint!";
|
||||
|
||||
private readonly IGangStatManager gangStats =
|
||||
provider.GetRequiredService<IGangStatManager>();
|
||||
|
||||
private readonly IPlayerStatManager playerStats =
|
||||
provider.GetRequiredService<IPlayerStatManager>();
|
||||
|
||||
public const string STAT_ID = "jb_wardenpaintcolor";
|
||||
public const string DESC = "Change the color of your warden paint!";
|
||||
|
||||
public override string StatId => STAT_ID;
|
||||
public override string Name => "Paint Color";
|
||||
public override string? Description => DESC;
|
||||
public override string Description => DESC;
|
||||
|
||||
public override WardenPaintColor Value { get; set; }
|
||||
|
||||
public override Task<int?> GetCost(IGangPlayer player) {
|
||||
return Task.FromResult<int?>(null);
|
||||
@@ -33,14 +35,11 @@ public class WardenPaintColorPerk(IServiceProvider provider)
|
||||
|
||||
public override async Task<IMenu?> GetMenu(IGangPlayer player) {
|
||||
Debug.Assert(player.GangId != null, "player.GangId != null");
|
||||
var (success, data) =
|
||||
var data =
|
||||
await gangStats.GetForGang<WardenPaintColor>(player.GangId.Value,
|
||||
STAT_ID);
|
||||
if (!success) data = WardenPaintColor.DEFAULT;
|
||||
var (_, equipped) =
|
||||
var equipped =
|
||||
await playerStats.GetForPlayer<WardenPaintColor>(player.Steam, STAT_ID);
|
||||
return new WardenPaintColorMenu(Provider, data, equipped);
|
||||
}
|
||||
|
||||
public override WardenPaintColor Value { get; set; }
|
||||
}
|
||||
@@ -13,10 +13,11 @@ public class DebugZone(IServiceProvider services, BasePlugin plugin)
|
||||
private readonly IDictionary<ulong, ITypedZoneCreator> creators =
|
||||
new Dictionary<ulong, ITypedZoneCreator>();
|
||||
|
||||
private readonly IZoneFactory? factory = services.GetService<IZoneFactory>();
|
||||
private readonly IZoneFactory factory =
|
||||
services.GetRequiredService<IZoneFactory>();
|
||||
|
||||
private readonly IZoneManager? zoneManager =
|
||||
services.GetService<IZoneManager>();
|
||||
private readonly IZoneManager zoneManager =
|
||||
services.GetRequiredService<IZoneManager>();
|
||||
|
||||
public override void OnCommand(CCSPlayerController? executor,
|
||||
WrappedInfo info) {
|
||||
@@ -27,11 +28,6 @@ public class DebugZone(IServiceProvider services, BasePlugin plugin)
|
||||
return;
|
||||
}
|
||||
|
||||
if (factory == null || zoneManager == null) {
|
||||
info.ReplyToCommand("Zone factory or manager not found");
|
||||
return;
|
||||
}
|
||||
|
||||
var position = executor.PlayerPawn.Value.AbsOrigin;
|
||||
|
||||
if (info.ArgCount <= 1) {
|
||||
@@ -65,9 +61,9 @@ public class DebugZone(IServiceProvider services, BasePlugin plugin)
|
||||
executor.PrintToChat(
|
||||
$"Zone created. Area: {zone.GetArea()} Center: {zone.CalculateCenterPoint()}");
|
||||
executor.PrintToChat("Pushing zone...");
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
await zoneManager.PushZone(zone, creator.Type);
|
||||
Server.NextFrame(() => {
|
||||
await Server.NextFrameAsync(() => {
|
||||
executor.PrintToChat($"Successfully created {creator.Type} zone");
|
||||
creator.Dispose();
|
||||
creators.Remove(executor.SteamID);
|
||||
@@ -90,25 +86,23 @@ public class DebugZone(IServiceProvider services, BasePlugin plugin)
|
||||
}
|
||||
|
||||
if (zoneCount == 0) {
|
||||
if (specifiedType.HasValue)
|
||||
info.ReplyToCommand($"No {specifiedType} zones found");
|
||||
else
|
||||
info.ReplyToCommand("No zones found");
|
||||
info.ReplyToCommand(specifiedType.HasValue ?
|
||||
$"No {specifiedType} zones found" :
|
||||
"No zones found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (specifiedType.HasValue)
|
||||
info.ReplyToCommand($"Showing {zoneCount} {specifiedType} zones");
|
||||
else
|
||||
info.ReplyToCommand($"Showing {zoneCount} zones");
|
||||
info.ReplyToCommand(specifiedType.HasValue ?
|
||||
$"Showing {zoneCount} {specifiedType} zones" :
|
||||
$"Showing {zoneCount} zones");
|
||||
return;
|
||||
case "remove":
|
||||
case "delete":
|
||||
var toDelete = getUniqueZone(executor, specifiedType);
|
||||
if (toDelete == null) return;
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
await zoneManager.DeleteZone(toDelete.Value.Item1.Id, map);
|
||||
Server.NextFrame(() => {
|
||||
await Server.NextFrameAsync(() => {
|
||||
executor.PrintToChat("Deleted zone #" + toDelete.Value.Item1.Id);
|
||||
});
|
||||
});
|
||||
@@ -119,22 +113,22 @@ public class DebugZone(IServiceProvider services, BasePlugin plugin)
|
||||
if (innerPair == null) return;
|
||||
var innerZone = innerPair.Value.Item1;
|
||||
innerZone.AddPoint(position);
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
await zoneManager.DeleteZone(innerZone.Id, map);
|
||||
await zoneManager.PushZoneWithID(innerZone, innerPair.Value.Item2,
|
||||
map);
|
||||
Server.NextFrame(() => {
|
||||
await Server.NextFrameAsync(() => {
|
||||
info.ReplyToCommand("Added point to zone #" + innerZone.Id);
|
||||
});
|
||||
});
|
||||
return;
|
||||
case "reload":
|
||||
case "refresh":
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
await zoneManager.LoadZones(Server.MapName);
|
||||
var count = (await zoneManager.GetAllZones()).SelectMany(e => e.Value)
|
||||
.Count();
|
||||
Server.NextFrame(() => {
|
||||
await Server.NextFrameAsync(() => {
|
||||
executor.PrintToChat($"Reloaded {count} zones");
|
||||
});
|
||||
});
|
||||
@@ -185,15 +179,14 @@ public class DebugZone(IServiceProvider services, BasePlugin plugin)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
|
||||
var toRemove = new List<IZone>();
|
||||
foreach (var spawn in spawns)
|
||||
if (doNotTeleport.Any(d
|
||||
=> d.IsInsideZone(spawn.CalculateCenterPoint())))
|
||||
toRemove.Add(spawn);
|
||||
var toRemove = spawns.Where(spawn
|
||||
=> doNotTeleport.Any(
|
||||
d => d.IsInsideZone(spawn.CalculateCenterPoint())))
|
||||
.ToList();
|
||||
|
||||
info.ReplyToCommand("Removing " + toRemove.Count
|
||||
+ " auto-generated zones");
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
foreach (var z in toRemove) await zoneManager.DeleteZone(z.Id, map);
|
||||
});
|
||||
return;
|
||||
@@ -215,13 +208,14 @@ public class DebugZone(IServiceProvider services, BasePlugin plugin)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
|
||||
Server.NextFrameAsync(async () => {
|
||||
// Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
var copy = zones.ToList();
|
||||
|
||||
foreach (var zone in copy)
|
||||
await zoneManager.DeleteZone(zone.Id, Server.MapName);
|
||||
|
||||
Server.NextFrame(()
|
||||
await Server.NextFrameAsync(()
|
||||
=> attemptBeginCreation(executor, specifiedType.Value));
|
||||
});
|
||||
|
||||
@@ -273,8 +267,8 @@ public class DebugZone(IServiceProvider services, BasePlugin plugin)
|
||||
}
|
||||
}
|
||||
|
||||
private void
|
||||
attemptBeginCreation(CCSPlayerController executor, ZoneType type) {
|
||||
private void attemptBeginCreation(CCSPlayerController executor,
|
||||
ZoneType type) {
|
||||
if (creators.ContainsKey(executor.SteamID)) {
|
||||
executor.PrintToChat("You are already creating a zone");
|
||||
return;
|
||||
@@ -285,9 +279,10 @@ public class DebugZone(IServiceProvider services, BasePlugin plugin)
|
||||
var zone =
|
||||
factory.CreateZone([executor.PlayerPawn.Value.AbsOrigin!.Clone()]);
|
||||
zone.Draw(plugin, type.GetColor(), 1f);
|
||||
Server.NextFrameAsync(async () => {
|
||||
// Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
await zoneManager.PushZone(zone, type);
|
||||
Server.NextFrame(() => {
|
||||
await Server.NextFrameAsync(() => {
|
||||
executor.PrintToChat("Successfully created a single point zone");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,12 +30,12 @@ public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager,
|
||||
"If true, the LG will be forced lower health if calculated");
|
||||
|
||||
public static readonly FakeConVar<double> CV_GUARD_HEALTH_RATIO = new(
|
||||
"css_jb_lg_ct_hp_ratio", "Ratio of CT : T Health", 0.6,
|
||||
"css_jb_lg_ct_hp_ratio", "Ratio of CT : T Health", 0.7,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<double>(0.00001, 10));
|
||||
|
||||
public static readonly FakeConVar<int> CV_LG_BASE_ROUND_TIME =
|
||||
new("css_jb_lg_time_base",
|
||||
"Round time to set when LG is activated, 0 to disable", 60);
|
||||
"Round time to set when LG is activated, 0 to disable", 30);
|
||||
|
||||
public static readonly FakeConVar<int> CV_LG_KILL_BONUS_TIME =
|
||||
new("css_jb_lg_time_per_kill",
|
||||
@@ -43,7 +43,7 @@ public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager,
|
||||
|
||||
public static readonly FakeConVar<int> CV_LG_MAX_TIME =
|
||||
new("css_jb_lg_time_max",
|
||||
"Max round time to give the LG regardless of bonuses", 120);
|
||||
"Max round time to give the LG regardless of bonuses", 90);
|
||||
|
||||
public static readonly FakeConVar<int> CV_LG_PER_PRISONER_TIME =
|
||||
new("css_jb_lg_time_per_prisoner",
|
||||
@@ -86,9 +86,9 @@ public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager,
|
||||
.ToList();
|
||||
Task.Run(async () => {
|
||||
foreach (var wrapper in players) {
|
||||
var (success, stat) =
|
||||
await gangStats.GetForPlayer<LGData>(wrapper, LGStat.STAT_ID);
|
||||
if (!success || stat == null) stat = new LGData();
|
||||
var stat =
|
||||
await gangStats.GetForPlayer<LGData>(wrapper, LGStat.STAT_ID)
|
||||
?? new LGData();
|
||||
if (wrapper.Team == CsTeam.CounterTerrorist)
|
||||
stat.CtLgs++;
|
||||
else
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\public\Jailbreak.Formatting\Jailbreak.Formatting.csproj"/>
|
||||
<ProjectReference Include="..\..\public\Jailbreak.Public\Jailbreak.Public.csproj"/>
|
||||
<ProjectReference Include="..\..\public\Jailbreak.Validator\Jailbreak.Validator.csproj" />
|
||||
<ProjectReference Include="..\..\public\Jailbreak.Validator\Jailbreak.Validator.csproj"/>
|
||||
<ProjectReference Include="..\Gangs.BaseImpl\Gangs.BaseImpl.csproj"/>
|
||||
<ProjectReference Include="..\Gangs.LastRequestColorPerk\Gangs.LastRequestColorPerk.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -13,7 +13,8 @@ using Jailbreak.Public.Mod.LastRequest.Enums;
|
||||
|
||||
namespace Jailbreak.LastRequest;
|
||||
|
||||
public class LastRequestCommand(ILastRequestManager lastRequestManager, ILastRequestRebelManager lastRequestRebelManager, ILRLocale messages,
|
||||
public class LastRequestCommand(ILastRequestManager lastRequestManager,
|
||||
ILastRequestRebelManager lastRequestRebelManager, ILRLocale messages,
|
||||
IGenericCmdLocale generic, ILastRequestFactory factory) : IPluginBehavior {
|
||||
private LastRequestMenuSelector? menuSelector;
|
||||
private LastRequestPlayerSelector? playerSelector;
|
||||
@@ -52,7 +53,8 @@ public class LastRequestCommand(ILastRequestManager lastRequestManager, ILastReq
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastRequestManager.IsInLR(executor) || lastRequestRebelManager.IsInLRRebelling(executor.Slot)) {
|
||||
if (lastRequestManager.IsInLR(executor)
|
||||
|| lastRequestRebelManager.IsInLRRebelling(executor.Slot)) {
|
||||
messages.CannotLR("You are already in an LR").ToChat(executor);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ public static class LastRequestExtension {
|
||||
collection.AddPluginBehavior<ILastRequestManager, LastRequestManager>();
|
||||
collection.AddPluginBehavior<LastRequestCommand>();
|
||||
collection.AddPluginBehavior<EndRaceCommand>();
|
||||
collection.AddPluginBehavior<ILastRequestRebelManager, LastRequestRebelManager>();
|
||||
collection
|
||||
.AddPluginBehavior<ILastRequestRebelManager, LastRequestRebelManager>();
|
||||
collection.AddPluginBehavior<LastRequestRebelCommand>();
|
||||
}
|
||||
}
|
||||
@@ -17,15 +17,16 @@ public class LastRequestFactory(ILastRequestManager manager,
|
||||
CCSPlayerController guard, LRType type) {
|
||||
return type switch {
|
||||
LRType.KNIFE_FIGHT => new KnifeFight(plugin, services, prisoner, guard),
|
||||
LRType.GUN_TOSS => new GunToss(plugin, manager, prisoner, guard),
|
||||
LRType.NO_SCOPE => new NoScope(plugin, services, prisoner, guard),
|
||||
LRType.GUN_TOSS =>
|
||||
new GunToss(plugin, manager, services, prisoner, guard),
|
||||
LRType.NO_SCOPE => new NoScope(plugin, services, prisoner, guard),
|
||||
LRType.SHOT_FOR_SHOT => new BulletForBullet(plugin, services, prisoner,
|
||||
guard, false),
|
||||
LRType.ROCK_PAPER_SCISSORS => new RockPaperScissors(plugin, services,
|
||||
prisoner, guard),
|
||||
LRType.COINFLIP => new Coinflip(plugin, services, prisoner, guard),
|
||||
LRType.RACE => new Race(plugin, manager, prisoner, guard,
|
||||
services.GetRequiredService<ILRRaceLocale>()),
|
||||
// LRType.RACE => new Race(plugin, manager, prisoner, guard,
|
||||
// services.GetRequiredService<ILRRaceLocale>()),
|
||||
LRType.MAG_FOR_MAG => new BulletForBullet(plugin, services, prisoner,
|
||||
guard, true),
|
||||
_ => throw new ArgumentException("Invalid last request type: " + type,
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using System.Drawing;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Cvars.Validators;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Gangs.BaseImpl.Extensions;
|
||||
@@ -23,7 +26,9 @@ using Jailbreak.Public.Mod.LastRequest;
|
||||
using Jailbreak.Public.Mod.LastRequest.Enums;
|
||||
using Jailbreak.Public.Mod.Rainbow;
|
||||
using Jailbreak.Public.Mod.Rebel;
|
||||
using Jailbreak.Public.Mod.Weapon;
|
||||
using Jailbreak.Public.Utils;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using MStatsShared;
|
||||
@@ -38,7 +43,7 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
|
||||
public static readonly FakeConVar<int> CV_LR_BONUS_TIME =
|
||||
new("css_jb_lr_time_per_lr",
|
||||
"Additional round time to add per LR completion", 30);
|
||||
"Additional round time to add per LR completion", 20);
|
||||
|
||||
public static readonly FakeConVar<int> CV_LR_GUARD_TIME =
|
||||
new("css_jb_lr_time_per_guard", "Additional round time to add per guard");
|
||||
@@ -51,42 +56,51 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
new("css_jb_min_players_for_credits",
|
||||
"Minimum number of players to start giving credits out", 5);
|
||||
|
||||
public static readonly FakeConVar<int> CV_MAX_TIME_FOR_LR =
|
||||
new("css_jb_max_time_for_lr", "Maximum round time during LR", 60);
|
||||
|
||||
private readonly IRainbowColorizer rainbowColorizer =
|
||||
provider.GetRequiredService<IRainbowColorizer>();
|
||||
|
||||
private ILastRequestFactory? factory;
|
||||
public bool IsLREnabledForRound { get; set; } = true;
|
||||
|
||||
public bool ShouldBlockDamage(CCSPlayerController player,
|
||||
CCSPlayerController? attacker, EventPlayerHurt @event) {
|
||||
public bool ShouldBlockDamage(CCSPlayerController victim,
|
||||
CCSPlayerController? attacker) {
|
||||
if (!IsLREnabled) return false;
|
||||
|
||||
if (attacker == null || !attacker.IsReal()) return false;
|
||||
|
||||
var playerLR = ((ILastRequestManager)this).GetActiveLR(player);
|
||||
var victimLR = ((ILastRequestManager)this).GetActiveLR(victim);
|
||||
var attackerLR = ((ILastRequestManager)this).GetActiveLR(attacker);
|
||||
|
||||
if (playerLR == null && attackerLR == null)
|
||||
if (victimLR == null && attackerLR == null)
|
||||
// Neither of them is in an LR
|
||||
return false;
|
||||
|
||||
if (playerLR == null != (attackerLR == null)) {
|
||||
if (victimLR == null != (attackerLR == null)) {
|
||||
// One of them is in an LR
|
||||
messages.DamageBlockedInsideLastRequest.ToCenter(attacker);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Both of them are in LR, verify they're in same LR
|
||||
if (playerLR == null) return false;
|
||||
if (victimLR == null) return false;
|
||||
|
||||
if (playerLR.Prisoner.Equals(attacker) || playerLR.Guard.Equals(attacker))
|
||||
// Same LR, allow damage
|
||||
if (victimLR.Prisoner.Slot == attacker.Slot
|
||||
|| victimLR.Guard.Slot == attacker.Slot)
|
||||
// The person attacking is the victim's LR participant, allow damage
|
||||
return false;
|
||||
|
||||
messages.DamageBlockedNotInSameLR.ToCenter(attacker);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsLREnabled { get; set; }
|
||||
|
||||
public IList<AbstractLastRequest> ActiveLRs { get; } =
|
||||
new List<AbstractLastRequest>();
|
||||
|
||||
public void Start(BasePlugin basePlugin) {
|
||||
factory = provider.GetRequiredService<ILastRequestFactory>();
|
||||
|
||||
@@ -94,12 +108,21 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
|
||||
var stats = API.Gangs.Services.GetService<IStatManager>();
|
||||
stats?.Stats.Add(new LRStat());
|
||||
|
||||
basePlugin.RegisterListener<Listeners.OnEntityParentChanged>(OnDrop);
|
||||
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage,
|
||||
HookMode.Pre);
|
||||
VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Hook(OnCanAcquire,
|
||||
HookMode.Pre);
|
||||
}
|
||||
|
||||
public bool IsLREnabled { get; set; }
|
||||
public void Dispose() {
|
||||
VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Unhook(OnCanAcquire,
|
||||
HookMode.Pre);
|
||||
|
||||
public IList<AbstractLastRequest> ActiveLRs { get; } =
|
||||
new List<AbstractLastRequest>();
|
||||
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamage,
|
||||
HookMode.Pre);
|
||||
}
|
||||
|
||||
public void DisableLR() { IsLREnabled = false; }
|
||||
|
||||
@@ -135,9 +158,9 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
var playerStatMgr = API.Gangs.Services.GetService<IPlayerStatManager>();
|
||||
if (playerStatMgr != null)
|
||||
Task.Run(async () => {
|
||||
var (success, stat) =
|
||||
await playerStatMgr.GetForPlayer<LRData>(wrapper, LRStat.STAT_ID);
|
||||
if (stat == null || !success) stat = new LRData();
|
||||
var stat =
|
||||
await playerStatMgr.GetForPlayer<LRData>(wrapper, LRStat.STAT_ID)
|
||||
?? new LRData();
|
||||
if (wrapper.Team == CsTeam.Terrorist)
|
||||
stat.TLrs++;
|
||||
else
|
||||
@@ -202,7 +225,8 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
rainbowColorizer.StopRainbow(lr.Prisoner);
|
||||
rainbowColorizer.StopRainbow(lr.Guard);
|
||||
if (result is LRResult.GUARD_WIN or LRResult.PRISONER_WIN) {
|
||||
RoundUtil.AddTimeRemaining(CV_LR_BONUS_TIME.Value);
|
||||
// RoundUtil.AddTimeRemaining(CV_LR_BONUS_TIME.Value);
|
||||
addRoundTimeCapped(CV_LR_BONUS_TIME.Value, CV_MAX_TIME_FOR_LR.Value);
|
||||
messages.LastRequestDecided(lr, result).ToAllChat();
|
||||
|
||||
var wrapper =
|
||||
@@ -228,6 +252,49 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnDrop(CEntityInstance entity, CEntityInstance newparent) {
|
||||
if (!entity.IsValid) return;
|
||||
if (!Tag.WEAPONS.Contains(entity.DesignerName)
|
||||
&& !Tag.UTILITY.Contains(entity.DesignerName))
|
||||
return;
|
||||
|
||||
var weapon = Utilities.GetEntityFromIndex<CCSWeaponBase>((int)entity.Index);
|
||||
var owner = weapon?.PrevOwner.Get()?.OriginalController.Get();
|
||||
|
||||
if (owner == null || weapon == null || !weapon.IsValid) return;
|
||||
|
||||
var lr = ((ILastRequestManager)this).GetActiveLR(owner);
|
||||
if (lr == null) return;
|
||||
|
||||
if (newparent.IsValid) return;
|
||||
|
||||
var color = owner.Team == CsTeam.CounterTerrorist ? Color.Blue : Color.Red;
|
||||
weapon.SetColor(color);
|
||||
|
||||
if (lr is not IDropListener listener) return;
|
||||
listener.OnWeaponDrop(owner, weapon);
|
||||
}
|
||||
|
||||
private HookResult OnCanAcquire(DynamicHook hook) {
|
||||
if (ActiveLRs.Count == 0) return HookResult.Continue;
|
||||
var player = hook.GetParam<CCSPlayer_ItemServices>(0)
|
||||
.Pawn.Value.Controller.Value?.As<CCSPlayerController>();
|
||||
var data = VirtualFunctions.GetCSWeaponDataFromKey.Invoke(-1,
|
||||
hook.GetParam<CEconItemView>(1).ItemDefinitionIndex.ToString());
|
||||
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
|
||||
var method = hook.GetParam<AcquireMethod>(2);
|
||||
if (method != AcquireMethod.PickUp) return HookResult.Continue;
|
||||
|
||||
if (ActiveLRs.Any(lr => lr.PreventEquip(player, data))) {
|
||||
hook.SetReturn(AcquireResult.NotAllowedByMode);
|
||||
return HookResult.Handled;
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private async Task colorForLR(PlayerWrapper a, PlayerWrapper b) {
|
||||
var playerStats = API.Gangs?.Services.GetService<IPlayerStatManager>();
|
||||
var gangStats = API.Gangs?.Services.GetService<IGangStatManager>();
|
||||
@@ -236,46 +303,29 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
if (playerStats == null || localizer == null || gangs == null
|
||||
|| gangStats == null)
|
||||
return;
|
||||
var (aSuccess, aData) =
|
||||
await playerStats.GetForPlayer<LRColor>(a, LRColorPerk.STAT_ID);
|
||||
var (bSuccess, bData) =
|
||||
await playerStats.GetForPlayer<LRColor>(b, LRColorPerk.STAT_ID);
|
||||
|
||||
if (!aSuccess) aData = LRColor.DEFAULT;
|
||||
if (!bSuccess) bData = LRColor.DEFAULT;
|
||||
var aData = await playerStats.GetForPlayer<LRColor>(a, LRColorPerk.STAT_ID);
|
||||
var bData = await playerStats.GetForPlayer<LRColor>(b, LRColorPerk.STAT_ID);
|
||||
|
||||
LRColor? toApply = null;
|
||||
PlayerWrapper? higher = null;
|
||||
if (aSuccess && bSuccess) {
|
||||
higher = await getHigherPlayer(a, b);
|
||||
toApply = higher.Steam == a.Steam ? aData : bData;
|
||||
} else if (aSuccess) {
|
||||
toApply = aData;
|
||||
higher = a;
|
||||
} else if (bSuccess) {
|
||||
toApply = bData;
|
||||
higher = b;
|
||||
}
|
||||
|
||||
if (toApply == null || higher == null) return;
|
||||
higher = await getHigherPlayer(a, b);
|
||||
if (toApply == null) return;
|
||||
if (a.Player == null || b.Player == null) return;
|
||||
|
||||
var higherGang = await gangs.GetGang(higher.Steam);
|
||||
if (higherGang == null) return;
|
||||
|
||||
var (gangSuccess, gData) =
|
||||
var gData =
|
||||
await gangStats.GetForGang<LRColor>(higherGang, LRColorPerk.STAT_ID);
|
||||
|
||||
if (!gangSuccess) return;
|
||||
if ((gData & toApply.Value) == 0) return;
|
||||
|
||||
var color = toApply.Value.GetColor();
|
||||
|
||||
if (color == null) { // Player picked random, but we need to pick
|
||||
// the random from their GANG's colors
|
||||
var (success, gangData) =
|
||||
var gangData =
|
||||
await playerStats.GetForPlayer<LRColor>(higher, LRColorPerk.STAT_ID);
|
||||
if (!success) return;
|
||||
color = gangData.PickRandomColor();
|
||||
}
|
||||
|
||||
@@ -382,9 +432,8 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
private async Task<LRData?> getStat(PlayerWrapper player) {
|
||||
var stats = API.Gangs?.Services.GetService<IPlayerStatManager>();
|
||||
if (stats == null) return null;
|
||||
var (success, data) =
|
||||
await stats.GetForPlayer<LRData>(player, LRStat.STAT_ID);
|
||||
if (!success || data == null) data = new LRData();
|
||||
var data = await stats.GetForPlayer<LRData>(player, LRStat.STAT_ID)
|
||||
?? new LRData();
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -393,10 +442,38 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
return Utilities.GetPlayers().Count >= CV_MIN_PLAYERS_FOR_CREDITS.Value;
|
||||
}
|
||||
|
||||
[GameEventHandler(HookMode.Pre)]
|
||||
public HookResult OnTakeDamage(EventPlayerHurt @event, GameEventInfo info) {
|
||||
IDamageBlocker damageBlockerHandler = this;
|
||||
return damageBlockerHandler.BlockUserDamage(@event, info);
|
||||
private HookResult OnTakeDamage(DynamicHook hook) {
|
||||
var playerPawn = hook.GetParam<CCSPlayerPawn>(0);
|
||||
var info = hook.GetParam<CTakeDamageInfo>(1);
|
||||
|
||||
var player = playerPawn.Controller.Value?.As<CCSPlayerController>();
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
|
||||
var attackerPawn = info.Attacker.Value?.As<CCSPlayerPawn>();
|
||||
var attacker = attackerPawn?.As<CCSPlayerController>();
|
||||
|
||||
if (attacker == null || !attacker.IsValid) return HookResult.Continue;
|
||||
|
||||
return ((IDamageBlocker)this).ShouldBlockDamage(player, attacker) ?
|
||||
HookResult.Handled :
|
||||
HookResult.Continue;
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
[GameEventHandler]
|
||||
public HookResult OnTakeDamage(EventPlayerHurt ev, GameEventInfo info) {
|
||||
var player = ev.Userid;
|
||||
var attacker = ev.Attacker;
|
||||
if (player == null || !player.IsReal()) return HookResult.Continue;
|
||||
if (!ShouldBlockDamage(player, attacker)) return HookResult.Continue;
|
||||
if (player.PlayerPawn.IsValid) {
|
||||
var playerPawn = player.PlayerPawn.Value!;
|
||||
playerPawn.Health = playerPawn.LastHealth;
|
||||
}
|
||||
|
||||
info.DontBroadcast = false;
|
||||
ev.DmgArmor = ev.DmgHealth = 0;
|
||||
return HookResult.Handled;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
@@ -414,6 +491,10 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
IsLREnabled = false;
|
||||
foreach (var player in Utilities.GetPlayers())
|
||||
MenuManager.CloseActiveMenu(player);
|
||||
|
||||
foreach (var lr in ActiveLRs.ToList())
|
||||
EndLastRequest(lr, LRResult.TIMED_OUT);
|
||||
ActiveLRs.Clear();
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
@@ -423,11 +504,9 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
if (player == null || !player.IsReal() || RoundUtil.IsWarmup())
|
||||
return HookResult.Continue;
|
||||
|
||||
if (IsLREnabled) {
|
||||
// Handle active LRs
|
||||
var activeLr = ((ILastRequestManager)this).GetActiveLR(player);
|
||||
if (activeLr == null || activeLr.State == LRState.COMPLETED)
|
||||
return HookResult.Continue;
|
||||
// Handle active LRs
|
||||
var activeLr = ((ILastRequestManager)this).GetActiveLR(player);
|
||||
if (activeLr != null && activeLr.State != LRState.COMPLETED) {
|
||||
var isPrisoner = activeLr.Prisoner.Slot == player.Slot;
|
||||
EndLastRequest(activeLr,
|
||||
isPrisoner ? LRResult.GUARD_WIN : LRResult.PRISONER_WIN);
|
||||
@@ -489,4 +568,10 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
|
||||
if (!player.PawnIsAlive) return false;
|
||||
return player.Team == CsTeam.Terrorist;
|
||||
}
|
||||
|
||||
private void addRoundTimeCapped(int time, int max) {
|
||||
var timeleft = RoundUtil.GetTimeRemaining();
|
||||
if (timeleft + time > max) time = max - timeleft;
|
||||
RoundUtil.AddTimeRemaining(time);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.LastRequest;
|
||||
@@ -13,6 +15,30 @@ namespace Jailbreak.LastRequest;
|
||||
public class LastRequestRebelCommand(ILastRequestManager lastRequestManager,
|
||||
ILastRequestRebelManager lastRequestRebelManager, ILRLocale messages)
|
||||
: IPluginBehavior {
|
||||
private readonly Dictionary<int, int> rebellerHealths = [];
|
||||
|
||||
public void Start(BasePlugin basePlugin) {
|
||||
basePlugin.RegisterListener<Listeners.OnEntityParentChanged>(OnDrop);
|
||||
}
|
||||
|
||||
private void OnDrop(CEntityInstance entity, CEntityInstance newparent) {
|
||||
if (!entity.IsValid || !Tag.WEAPONS.Contains(entity.DesignerName)) return;
|
||||
|
||||
var weapon = Utilities.GetEntityFromIndex<CCSWeaponBase>((int)entity.Index);
|
||||
if (weapon == null
|
||||
|| weapon.PrevOwner.Get()?.OriginalController.Get() == null)
|
||||
return;
|
||||
|
||||
var owner = weapon.PrevOwner.Get()?.OriginalController.Get();
|
||||
if (owner == null || newparent.IsValid) return;
|
||||
|
||||
if (!rebellerHealths.TryGetValue(owner.Slot, out var hp)) return;
|
||||
if (owner.Pawn.Value != null)
|
||||
owner.SetHealth(Math.Min(hp, owner.Pawn.Value.Health));
|
||||
|
||||
rebellerHealths.Remove(owner.Slot);
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_rebel", "Rebel during last request as a prisoner")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
public void Command_Rebel(CCSPlayerController? rebeller, CommandInfo info) {
|
||||
@@ -32,17 +58,30 @@ public class LastRequestRebelCommand(ILastRequestManager lastRequestManager,
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastRequestManager.IsInLR(rebeller) || lastRequestRebelManager.IsInLRRebelling(rebeller.Slot)) {
|
||||
if (lastRequestManager.IsInLR(rebeller)
|
||||
|| lastRequestRebelManager.IsInLRRebelling(rebeller.Slot)) {
|
||||
messages.CannotLR("You are already in an LR").ToChat(rebeller);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Utilities.GetPlayers()
|
||||
.Count(p
|
||||
=> p.IsReal() && p is { PawnIsAlive: true, Team: CsTeam.Terrorist })
|
||||
> 1) {
|
||||
messages.CannotLR("You must be the last alive to !rebel")
|
||||
.ToChat(rebeller);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rebeller.Pawn.Value != null)
|
||||
rebellerHealths[rebeller.Slot] = rebeller.Pawn.Value.Health;
|
||||
lastRequestRebelManager.StartLRRebelling(rebeller);
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) {
|
||||
lastRequestRebelManager.ClearLRRebelling();
|
||||
rebellerHealths.Clear();
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,13 @@ using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Cvars.Validators;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
using Jailbreak.Public.Mod.LastRequest;
|
||||
using Jailbreak.Public.Mod.Rebel;
|
||||
using Jailbreak.Validator;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.LastRequest;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.LastRequest;
|
||||
using Jailbreak.Public.Mod.Rebel;
|
||||
using Jailbreak.Validator;
|
||||
|
||||
namespace Jailbreak.LastRequest;
|
||||
|
||||
@@ -27,42 +27,44 @@ public class LastRequestRebelManager(IRebelService rebelService,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<int>(1, 1000));
|
||||
|
||||
public static readonly FakeConVar<double> CV_T_HEALTH_RATIO = new(
|
||||
"css_jb_rebel_t_hp_ratio", "Ratio of T : CT Health", 0.5,
|
||||
"css_jb_rebel_t_hp_ratio", "Ratio of T : CT Health", 0.7,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<double>(0.00001, 10));
|
||||
|
||||
public static readonly FakeConVar<int> CV_MAX_T_HEALTH =
|
||||
new("css_jb_rebel_t_max_hp", "Max HP that the rebeller can have otherwise",
|
||||
125, ConVarFlags.FCVAR_NONE, new RangeValidator<int>(1, 1000));
|
||||
800, ConVarFlags.FCVAR_NONE, new RangeValidator<int>(1, 1000));
|
||||
|
||||
public HashSet<int> PlayersLRRebelling { get; } = [];
|
||||
|
||||
public void StartLRRebelling(CCSPlayerController player) {
|
||||
MenuManager.CloseActiveMenu(player);
|
||||
|
||||
var calculatedHealth = CalculateHealth();
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
var updatedHealth = Math.Min(CV_MAX_T_HEALTH.Value, Math.Max(calculatedHealth, playerPawn?.Health ?? 0));
|
||||
|
||||
player.SetHealth(updatedHealth);
|
||||
messages.LastRequestRebel(player, updatedHealth).ToAllChat();
|
||||
AddLRRebelling(player.Slot);
|
||||
var hp = getHealthForPlayer(player);
|
||||
messages.LastRequestRebel(player, hp).ToAllChat();
|
||||
rebelService.MarkRebel(player);
|
||||
|
||||
((ILastRequestRebelManager)this).AddLRRebelling(player.Slot);
|
||||
|
||||
player.SetHealth(hp);
|
||||
player.RemoveWeapons();
|
||||
player.GiveNamedItem(CV_REBEL_WEAPON.Value);
|
||||
player.GiveNamedItem("weapon_knife");
|
||||
}
|
||||
|
||||
public bool IsInLRRebelling(int playerSlot) {
|
||||
return PlayersLRRebelling.Contains(playerSlot);
|
||||
private int getHealthForPlayer(CCSPlayerController player) {
|
||||
var hpRatio = getHealthForRatio();
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
if (playerPawn == null) return 101;
|
||||
|
||||
// If player's HP is already higher than the ratio, don't lower it
|
||||
hpRatio = Math.Max(hpRatio, playerPawn.Health);
|
||||
|
||||
// Make sure the player's health is within the bounds
|
||||
hpRatio = Math.Min(hpRatio, CV_MAX_T_HEALTH.Value);
|
||||
|
||||
return hpRatio;
|
||||
}
|
||||
|
||||
public void AddLRRebelling(int playerSlot) {
|
||||
PlayersLRRebelling.Add(playerSlot);
|
||||
}
|
||||
|
||||
public void ClearLRRebelling() { PlayersLRRebelling.Clear(); }
|
||||
|
||||
public int CalculateHealth() {
|
||||
private int getHealthForRatio() {
|
||||
var aliveCounterTerrorists = Utilities.GetPlayers()
|
||||
.Where(plr => plr is { PawnIsAlive: true, Team: CsTeam.CounterTerrorist })
|
||||
.ToList();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
@@ -12,7 +11,10 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Jailbreak.LastRequest.LastRequests;
|
||||
|
||||
public class BulletForBullet : TeleportingRequest {
|
||||
public class BulletForBullet(BasePlugin plugin, IServiceProvider provider,
|
||||
CCSPlayerController prisoner, CCSPlayerController guard, bool magForMag)
|
||||
: TeleportingRequest(plugin,
|
||||
provider.GetRequiredService<ILastRequestManager>(), prisoner, guard) {
|
||||
private const string weaponName = "weapon_deagle";
|
||||
|
||||
public static readonly FakeConVar<bool> KILL_BY_HEALTH = new(
|
||||
@@ -20,26 +22,19 @@ public class BulletForBullet : TeleportingRequest {
|
||||
"If true, the player with the lowest health will die after 60 seconds.",
|
||||
true);
|
||||
|
||||
private readonly ChatMenu chatMenu;
|
||||
private readonly bool magForMag;
|
||||
private readonly ILRB4BLocale msg;
|
||||
private readonly ChatMenu chatMenu =
|
||||
new(magForMag ? "Mag for Mag" : "Shot for Shot");
|
||||
|
||||
private readonly ILRB4BLocale msg =
|
||||
provider.GetRequiredService<ILRB4BLocale>();
|
||||
|
||||
private int? whosShot, magSize;
|
||||
|
||||
public BulletForBullet(BasePlugin plugin, IServiceProvider provider,
|
||||
CCSPlayerController prisoner, CCSPlayerController guard,
|
||||
bool magForMag) : base(plugin,
|
||||
provider.GetRequiredService<ILastRequestManager>(), prisoner, guard) {
|
||||
this.magForMag = magForMag;
|
||||
chatMenu = new ChatMenu(magForMag ? "Mag for Mag" : "Shot for Shot");
|
||||
|
||||
msg = provider.GetRequiredService<ILRB4BLocale>();
|
||||
}
|
||||
|
||||
public override LRType Type
|
||||
=> magForMag ? LRType.MAG_FOR_MAG : LRType.SHOT_FOR_SHOT;
|
||||
|
||||
public override void Setup() {
|
||||
Plugin.RegisterEventHandler<EventBulletImpact>(OnPlayerShoot);
|
||||
Plugin.RegisterEventHandler<EventWeaponFire>(OnWeaponFire);
|
||||
|
||||
Prisoner.RemoveWeapons();
|
||||
Guard.RemoveWeapons();
|
||||
@@ -100,8 +95,7 @@ public class BulletForBullet : TeleportingRequest {
|
||||
}, TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
private HookResult OnPlayerShoot(EventBulletImpact @event,
|
||||
GameEventInfo info) {
|
||||
private HookResult OnWeaponFire(EventWeaponFire @event, GameEventInfo info) {
|
||||
if (State != LRState.ACTIVE) return HookResult.Continue;
|
||||
|
||||
var player = @event.Userid;
|
||||
@@ -120,16 +114,30 @@ public class BulletForBullet : TeleportingRequest {
|
||||
var bullets = player.GetWeaponBase(weaponName)?.Clip1 ?? 1;
|
||||
if (bullets > 1) return HookResult.Continue;
|
||||
|
||||
Server.NextFrame(() => {
|
||||
var opponent = player.Slot == Prisoner.Slot ? Guard : Prisoner;
|
||||
whosShot = opponent.Slot;
|
||||
opponent.GetWeaponBase(weaponName)?.SetAmmo(magSize.Value, 0);
|
||||
});
|
||||
var opponent = player.Slot == Prisoner.Slot ? Guard : Prisoner;
|
||||
whosShot = opponent.Slot;
|
||||
opponent.GetWeaponBase(weaponName)?.SetAmmo(magSize.Value, 0);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
public override void OnEnd(LRResult result) {
|
||||
Plugin.DeregisterEventHandler<EventBulletImpact>(OnPlayerShoot);
|
||||
Plugin.DeregisterEventHandler<EventWeaponFire>(OnWeaponFire);
|
||||
State = LRState.COMPLETED;
|
||||
|
||||
switch (result) {
|
||||
case LRResult.GUARD_WIN when Guard.IsValid:
|
||||
Guard.GiveNamedItem("weapon_knife");
|
||||
break;
|
||||
case LRResult.PRISONER_WIN when Prisoner.IsValid:
|
||||
Prisoner.GiveNamedItem("weapon_knife");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool PreventEquip(CCSPlayerController player,
|
||||
CCSWeaponBaseVData weapon) {
|
||||
if (State == LRState.PENDING) return false;
|
||||
if (player != Prisoner && player != Guard) return false;
|
||||
return !weapon.Name.Contains("knife") && !weapon.Name.Contains("bayonet");
|
||||
}
|
||||
}
|
||||
@@ -86,4 +86,9 @@ public class Coinflip : AbstractLastRequest {
|
||||
else
|
||||
Prisoner.Pawn.Value?.CommitSuicide(false, true);
|
||||
}
|
||||
|
||||
public override bool PreventEquip(CCSPlayerController player,
|
||||
CCSWeaponBaseVData weapon) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,77 @@
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.LastRequest;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.Draw;
|
||||
using Jailbreak.Public.Mod.LastRequest;
|
||||
using Jailbreak.Public.Mod.LastRequest.Enums;
|
||||
using Jailbreak.Public.Mod.Weapon;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
|
||||
|
||||
namespace Jailbreak.LastRequest.LastRequests;
|
||||
|
||||
public class GunToss(BasePlugin plugin, ILastRequestManager manager,
|
||||
CCSPlayerController prisoner, CCSPlayerController guard)
|
||||
: TeleportingRequest(plugin, manager, prisoner, guard) {
|
||||
IServiceProvider provider, CCSPlayerController prisoner,
|
||||
CCSPlayerController guard)
|
||||
: TeleportingRequest(plugin, manager, prisoner, guard), IDropListener {
|
||||
/// <summary>
|
||||
/// Null if no one has thrown a gun yet, negative if only one has thrown a gun,
|
||||
/// Positive if both have thrown a gun.
|
||||
/// </summary>
|
||||
private int? bothThrewTick;
|
||||
|
||||
private bool guardTossed, prisonerTossed;
|
||||
private CCSWeaponBase? prisonerWeapon, guardWeapon;
|
||||
public override LRType Type => LRType.GUN_TOSS;
|
||||
|
||||
public void OnWeaponDrop(CCSPlayerController player, CCSWeaponBase weapon) {
|
||||
if (bothThrewTick > 0) return;
|
||||
if (State != LRState.ACTIVE || !player.IsValid) return;
|
||||
|
||||
bothThrewTick = bothThrewTick switch {
|
||||
null => -Server.TickCount,
|
||||
< 0 => Server.TickCount,
|
||||
_ => bothThrewTick
|
||||
};
|
||||
|
||||
if (player == Prisoner) {
|
||||
prisonerTossed = true;
|
||||
prisonerWeapon = weapon;
|
||||
}
|
||||
|
||||
if (player == Guard) {
|
||||
guardTossed = true;
|
||||
guardWeapon = weapon;
|
||||
}
|
||||
|
||||
if (prisonerTossed && guardTossed) bothThrewTick = Server.TickCount;
|
||||
|
||||
if (bothThrewTick > 0)
|
||||
Plugin.AddTimer(5, () => {
|
||||
if (State != LRState.ACTIVE || !Guard.IsValid || !Guard.Pawn.IsValid) return;
|
||||
Guard.SetHealth(Math.Min(Guard.Pawn.Value!.Health, 100));
|
||||
Guard.SetArmor(Math.Min(Guard.PawnArmor, 100));
|
||||
});
|
||||
}
|
||||
|
||||
public override void Setup() {
|
||||
base.Setup();
|
||||
|
||||
Prisoner.RemoveWeapons();
|
||||
Guard.RemoveWeapons();
|
||||
|
||||
Server.NextFrame(() => {
|
||||
if (!Guard.IsValid) return;
|
||||
|
||||
Guard.SetHealth(500);
|
||||
Guard.SetArmor(500);
|
||||
});
|
||||
|
||||
Plugin.AddTimer(3, Execute);
|
||||
}
|
||||
@@ -23,8 +81,35 @@ public class GunToss(BasePlugin plugin, ILastRequestManager manager,
|
||||
Guard.GiveNamedItem("weapon_knife");
|
||||
Prisoner.GiveNamedItem("weapon_deagle");
|
||||
Guard.GiveNamedItem("weapon_deagle");
|
||||
State = LRState.ACTIVE;
|
||||
Prisoner.GetWeaponBase("weapon_deagle").SetAmmo(0, 7);
|
||||
|
||||
Server.RunOnTick(Server.TickCount + 16, () => State = LRState.ACTIVE);
|
||||
}
|
||||
|
||||
public override void OnEnd(LRResult result) { State = LRState.COMPLETED; }
|
||||
|
||||
public override bool PreventEquip(CCSPlayerController player,
|
||||
CCSWeaponBaseVData weapon) {
|
||||
if (State != LRState.ACTIVE) return false;
|
||||
|
||||
if (player.Slot != Prisoner.Slot && player.Slot != Guard.Slot) {
|
||||
if (weapon.Name != "weapon_deagle") return false;
|
||||
var guardGunDist = guardWeapon == null ?
|
||||
float.MaxValue :
|
||||
guardWeapon.AbsOrigin!.DistanceSquared(
|
||||
Guard.PlayerPawn.Value!.AbsOrigin!);
|
||||
|
||||
var prisonerGunDist = prisonerWeapon == null ?
|
||||
float.MaxValue :
|
||||
prisonerWeapon.AbsOrigin!.DistanceSquared(Prisoner.PlayerPawn.Value!
|
||||
.AbsOrigin!);
|
||||
|
||||
var dist = Math.Min(guardGunDist, prisonerGunDist);
|
||||
return dist < 16500;
|
||||
}
|
||||
|
||||
if (bothThrewTick is null or < 0) return true;
|
||||
var time = Server.TickCount - bothThrewTick.Value;
|
||||
return time < 64 * 4;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ public class KnifeFight(BasePlugin plugin, IServiceProvider provider,
|
||||
public override LRType Type => LRType.KNIFE_FIGHT;
|
||||
|
||||
public override void Execute() {
|
||||
Prisoner.RemoveWeapons();
|
||||
Guard.RemoveWeapons();
|
||||
Prisoner.GiveNamedItem("weapon_knife");
|
||||
Guard.GiveNamedItem("weapon_knife");
|
||||
State = LRState.ACTIVE;
|
||||
|
||||
@@ -74,4 +74,11 @@ public class NoScope(BasePlugin plugin, IServiceProvider provider,
|
||||
winner.GiveNamedItem("weapon_knife");
|
||||
winner.GiveNamedItem("weapon_ak47");
|
||||
}
|
||||
|
||||
public override bool PreventEquip(CCSPlayerController player,
|
||||
CCSWeaponBaseVData weapon) {
|
||||
if (State == LRState.PENDING) return false;
|
||||
if (player != Prisoner && player != Guard) return false;
|
||||
return !weapon.Name.Contains("knife") && !weapon.Name.Contains("bayonet");
|
||||
}
|
||||
}
|
||||
@@ -26,20 +26,9 @@ public class Race(BasePlugin plugin, ILastRequestManager manager,
|
||||
base.Setup();
|
||||
|
||||
Prisoner.RemoveWeapons();
|
||||
|
||||
Guard.RemoveWeapons();
|
||||
Plugin.AddTimer(1, () => {
|
||||
if (State != LRState.PENDING) return;
|
||||
Guard.GiveNamedItem("weapon_knife");
|
||||
});
|
||||
|
||||
Plugin.AddTimer(3, () => {
|
||||
if (State != LRState.PENDING) return;
|
||||
Prisoner.GiveNamedItem("weapon_knife");
|
||||
});
|
||||
|
||||
messages.EndRaceInstruction.ToChat(Prisoner);
|
||||
|
||||
messages.RaceStartingMessage(Prisoner).ToChat(Guard);
|
||||
|
||||
startLocation = Prisoner.Pawn.Value?.AbsOrigin?.Clone();
|
||||
@@ -48,12 +37,12 @@ public class Race(BasePlugin plugin, ILastRequestManager manager,
|
||||
start = new BeamCircle(Plugin, startLocation, 20, 16);
|
||||
start.SetColor(Color.Aqua);
|
||||
start.Draw();
|
||||
|
||||
if (Guard.Pawn.Value != null) Guard.Pawn.Value.TakesDamage = false;
|
||||
}
|
||||
|
||||
// Called when the prisoner types !endrace
|
||||
public override void Execute() {
|
||||
State = LRState.ACTIVE;
|
||||
|
||||
endLocation = Prisoner.Pawn.Value?.AbsOrigin?.Clone();
|
||||
|
||||
if (endLocation == null) return;
|
||||
@@ -64,6 +53,8 @@ public class Race(BasePlugin plugin, ILastRequestManager manager,
|
||||
Prisoner.Pawn.Value?.Teleport(startLocation);
|
||||
Guard.Pawn.Value?.Teleport(startLocation);
|
||||
|
||||
if (Prisoner.Pawn.Value != null) Prisoner.Pawn.Value.TakesDamage = false;
|
||||
|
||||
Guard.Freeze();
|
||||
Prisoner.Freeze();
|
||||
|
||||
@@ -78,6 +69,11 @@ public class Race(BasePlugin plugin, ILastRequestManager manager,
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
if (!Prisoner.IsValid || !Guard.IsValid) {
|
||||
Manager.EndLastRequest(this, LRResult.INTERRUPTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Prisoner.AbsOrigin == null || Guard.AbsOrigin == null) return;
|
||||
var requiredDistance = getRequiredDistance();
|
||||
var requiredDistanceSqured = MathF.Pow(requiredDistance, 2);
|
||||
@@ -109,6 +105,8 @@ public class Race(BasePlugin plugin, ILastRequestManager manager,
|
||||
|
||||
public override void OnEnd(LRResult result) {
|
||||
State = LRState.COMPLETED;
|
||||
if (Prisoner.Pawn.Value != null) Prisoner.Pawn.Value.TakesDamage = true;
|
||||
if (Guard.Pawn.Value != null) Guard.Pawn.Value.TakesDamage = true;
|
||||
switch (result) {
|
||||
case LRResult.GUARD_WIN:
|
||||
Prisoner.Pawn.Value?.CommitSuicide(false, true);
|
||||
|
||||
@@ -99,4 +99,9 @@ public class RockPaperScissors : AbstractLastRequest {
|
||||
|
||||
msg.Results(Guard, Prisoner, guardChoice, prisonerChoice).ToAllChat();
|
||||
}
|
||||
|
||||
public override bool PreventEquip(CCSPlayerController player,
|
||||
CCSWeaponBaseVData weapon) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -33,25 +33,30 @@ public class LogDamageListeners : IPluginBehavior {
|
||||
var health = @event.DmgHealth;
|
||||
|
||||
if (isWorld) {
|
||||
if (health > 0)
|
||||
logs.Append("The world hurt", logs.Player(player),
|
||||
$"for {health} damage");
|
||||
else
|
||||
logs.Append("The world killed", logs.Player(player));
|
||||
logs.Append("The world hurt", logs.Player(player),
|
||||
$"for {health} damage");
|
||||
} else {
|
||||
if (attacker == null) {
|
||||
logs.Append(logs.Player(player), "was hurt by an unknown source",
|
||||
$"for {health} damage");
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
if (health > 0)
|
||||
logs.Append(logs.Player(attacker), "hurt", logs.Player(player),
|
||||
$"for {health} damage");
|
||||
else
|
||||
logs.Append(logs.Player(attacker), "killed", logs.Player(player));
|
||||
logs.Append(logs.Player(attacker!), "hurt", logs.Player(player),
|
||||
$"for {health} damage");
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) {
|
||||
var player = @event.Userid;
|
||||
if (player == null || !player.IsReal()) return HookResult.Continue;
|
||||
var attacker = @event.Attacker;
|
||||
|
||||
var isWorld = attacker == null || !attacker.IsReal();
|
||||
|
||||
if (isWorld) {
|
||||
logs.Append("The world killed", logs.Player(player));
|
||||
} else {
|
||||
logs.Append(logs.Player(attacker!), "killed", logs.Player(player));
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,15 @@ public class MuteSystem(IServiceProvider provider)
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnDeath(EventPlayerDeath @event, GameEventInfo info) {
|
||||
var player = @event.Userid;
|
||||
if (player == null || !player.IsReal()) return HookResult.Continue;
|
||||
|
||||
mute(player);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private void unmuteGuards() {
|
||||
foreach (var player in Utilities.GetPlayers()
|
||||
.Where(player => player is {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using System.Collections.Concurrent;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
@@ -17,20 +18,27 @@ namespace Jailbreak.RTD;
|
||||
|
||||
public class AutoRTD(IRTDRewarder rewarder, IAutoRTDLocale locale,
|
||||
IRTDLocale rtdLocale, IGenericCmdLocale generic) : IPluginBehavior {
|
||||
private static readonly Dictionary<ulong, bool> cachedCookies = new();
|
||||
private static readonly ConcurrentDictionary<ulong, bool> cachedCookies = new();
|
||||
|
||||
public static readonly FakeConVar<string> CV_AUTORTD_FLAG =
|
||||
new("css_autortd_flag", "Permission flag required to enable auto-RTD",
|
||||
"@ego/dssilver");
|
||||
|
||||
private BasePlugin plugin = null!;
|
||||
private ICookie? cookie;
|
||||
|
||||
public void Start(BasePlugin basePlugin) {
|
||||
Server.NextFrameAsync(async () => {
|
||||
if (API.Actain != null)
|
||||
cookie = await API.Actain.getCookieService()
|
||||
.RegClientCookie("jb_rtd_auto");
|
||||
});
|
||||
plugin = basePlugin;
|
||||
|
||||
TryLoadCookie();
|
||||
basePlugin.RegisterListener<Listeners.OnMapStart>(OnMapStart);
|
||||
}
|
||||
|
||||
private void OnMapStart(string mapname) {
|
||||
// Attempt to load the cookie OnMapStart if it fails to load on plugin start
|
||||
// This can happen if the MAUL plugin is loaded *after* this plugin
|
||||
if (cookie == null) TryLoadCookie();
|
||||
else plugin.RemoveListener<Listeners.OnMapStart>(OnMapStart);
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
@@ -46,7 +54,7 @@ public class AutoRTD(IRTDRewarder rewarder, IAutoRTDLocale locale,
|
||||
.Where(player => !rewarder.HasReward(player))) {
|
||||
var steam = player.SteamID;
|
||||
if (!cachedCookies.ContainsKey(steam))
|
||||
Server.NextFrameAsync(async () => await populateCache(player, steam));
|
||||
Task.Run(async () => await populateCache(player, steam));
|
||||
|
||||
if (cachedCookies.TryGetValue(player.SteamID, out var value) && value)
|
||||
player.ExecuteClientCommandFromServer("css_rtd");
|
||||
@@ -56,22 +64,11 @@ public class AutoRTD(IRTDRewarder rewarder, IAutoRTDLocale locale,
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private async Task populateCache(CCSPlayerController player, ulong steam) {
|
||||
if (cookie == null) return;
|
||||
var val = await cookie.Get(steam);
|
||||
cachedCookies[steam] = val is null or "Y";
|
||||
if (!cachedCookies[steam]) return;
|
||||
await Server.NextFrameAsync(() => {
|
||||
if (!player.IsValid) return;
|
||||
player.ExecuteClientCommandFromServer("css_rtd");
|
||||
});
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_autortd")]
|
||||
public void Command_AutoRTD(CCSPlayerController? executor, CommandInfo info) {
|
||||
if (executor == null) return;
|
||||
|
||||
if (!RTDCommand.CV_RTD_ENABLED.Value) {
|
||||
if (RTDCommand.CV_RTD_ENABLED.Value == -1) {
|
||||
rtdLocale.RollingDisabled().ToChat(executor);
|
||||
return;
|
||||
}
|
||||
@@ -87,7 +84,7 @@ public class AutoRTD(IRTDRewarder rewarder, IAutoRTDLocale locale,
|
||||
}
|
||||
|
||||
var steam = executor.SteamID;
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
var value = await cookie.Get(steam);
|
||||
var enable = value is not (null or "Y");
|
||||
await cookie.Set(steam, enable ? "Y" : "N");
|
||||
@@ -98,4 +95,23 @@ public class AutoRTD(IRTDRewarder rewarder, IAutoRTDLocale locale,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void TryLoadCookie() {
|
||||
Task.Run(async () => {
|
||||
if (API.Actain != null)
|
||||
cookie = await API.Actain.getCookieService()
|
||||
.RegClientCookie("jb_rtd_auto");
|
||||
});
|
||||
}
|
||||
|
||||
private async Task populateCache(CCSPlayerController player, ulong steam) {
|
||||
if (cookie == null) return;
|
||||
var val = await cookie.Get(steam);
|
||||
cachedCookies[steam] = val is null or "Y";
|
||||
if (!cachedCookies[steam]) return;
|
||||
await Server.NextFrameAsync(() => {
|
||||
if (!player.IsValid) return;
|
||||
player.ExecuteClientCommandFromServer("css_rtd");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views;
|
||||
using Jailbreak.Formatting.Views.RTD;
|
||||
@@ -14,8 +16,9 @@ namespace Jailbreak.RTD;
|
||||
|
||||
public class RTDCommand(IRTDRewarder rewarder, IRewardGenerator generator,
|
||||
IRTDLocale locale, IGenericCmdLocale generic) : IPluginBehavior {
|
||||
public static readonly FakeConVar<bool> CV_RTD_ENABLED =
|
||||
new("css_jb_rtd_enabled", "Whether to allow dice rolling", true);
|
||||
public static readonly FakeConVar<int> CV_RTD_ENABLED =
|
||||
new("css_jb_rtd_minplayers",
|
||||
"Minimum amount of players to enable rolling the dice", 3);
|
||||
|
||||
private bool inBetweenRounds;
|
||||
|
||||
@@ -31,15 +34,18 @@ public class RTDCommand(IRTDRewarder rewarder, IRewardGenerator generator,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bypass && !CV_RTD_ENABLED.Value) {
|
||||
locale.RollingDisabled().ToChat(executor);
|
||||
return;
|
||||
}
|
||||
var count = Utilities.GetPlayers().Count(p => p.Team > CsTeam.Spectator);
|
||||
|
||||
if (!bypass && !inBetweenRounds && !RoundUtil.IsWarmup()
|
||||
&& executor.PawnIsAlive) {
|
||||
locale.CannotRollYet().ToChat(executor);
|
||||
return;
|
||||
if (!bypass) {
|
||||
if (count < CV_RTD_ENABLED.Value) {
|
||||
locale.RollingDisabled().ToChat(executor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inBetweenRounds && !RoundUtil.IsWarmup() && executor.PawnIsAlive) {
|
||||
locale.CannotRollYet().ToChat(executor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var reward = generator.GenerateReward(executor);
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Jailbreak.RTD;
|
||||
public class RewardGenerator(IC4Service bomb, IWardenSelectionService warden,
|
||||
IRTDLocale locale, IServiceProvider provider)
|
||||
: IPluginBehavior, IRewardGenerator {
|
||||
private const float PROB_LOTTERY = 1 / 3000f;
|
||||
private const float PROB_LOTTERY = 1 / 5000f;
|
||||
private const float PROB_EXTREMELY_LOW = 1 / 800f;
|
||||
private const float PROB_VERY_LOW = 1 / 100f;
|
||||
private const float PROB_LOW = 1 / 20f;
|
||||
@@ -43,55 +43,58 @@ public class RewardGenerator(IC4Service bomb, IWardenSelectionService warden,
|
||||
(new WeaponReward("weapon_decoy"), PROB_OFTEN),
|
||||
(new HPReward(110), PROB_OFTEN), (new ArmorReward(15), PROB_OFTEN),
|
||||
(new CreditReward(-10, locale), PROB_VERY_OFTEN),
|
||||
(new CreditReward(5, locale), PROB_MEDIUM),
|
||||
|
||||
// Medium
|
||||
(new CreditReward(1, locale), PROB_MEDIUM),
|
||||
(new CreditReward(2, locale), PROB_MEDIUM),
|
||||
(new CreditReward(3, locale), PROB_MEDIUM),
|
||||
(new CreditReward(10, locale), PROB_MEDIUM),
|
||||
(new CreditReward(25, locale), PROB_MEDIUM),
|
||||
(new WeaponReward("weapon_flashbang"), PROB_MEDIUM),
|
||||
(new WeaponReward("weapon_hegrenade"), PROB_MEDIUM),
|
||||
(new WeaponReward("weapon_smokegrenade"), PROB_MEDIUM),
|
||||
(new WeaponReward("weapon_molotov"), PROB_MEDIUM),
|
||||
(new WeaponReward("weapon_taser"), PROB_MEDIUM),
|
||||
(new CannotUseReward(basePlugin, WeaponType.UTILITY), PROB_MEDIUM),
|
||||
(new HPReward(150), PROB_MEDIUM), (new HPReward(50), PROB_MEDIUM),
|
||||
(new ArmorReward(150), PROB_MEDIUM),
|
||||
(new GuaranteedWardenReward(warden), PROB_MEDIUM),
|
||||
(new WeaponReward("weapon_g3sg1", CsTeam.CounterTerrorist), PROB_MEDIUM),
|
||||
(new CreditReward(5, locale), PROB_MEDIUM),
|
||||
(new WeaponReward("weapon_g3sg1", CsTeam.CounterTerrorist),
|
||||
PROB_MEDIUM / 2),
|
||||
|
||||
// Low
|
||||
(new ChatSpyReward(basePlugin), PROB_LOW),
|
||||
(new AmmoWeaponReward("weapon_glock", 0, 0), PROB_LOW),
|
||||
(new ChatSpyReward(basePlugin), PROB_LOW * 1.5f),
|
||||
(new ColorReward(Color.FromArgb(0, 255, 0), true), PROB_LOW),
|
||||
(new ColorReward(Color.FromArgb(255, 0, 0), true), PROB_LOW),
|
||||
// (new ColorReward(Color.FromArgb(255, 0, 0), true), PROB_LOW),
|
||||
(new CannotUseReward(basePlugin, WeaponType.GRENADE), PROB_LOW),
|
||||
(new CannotScope(basePlugin), PROB_LOW),
|
||||
(new CannotRightKnife(basePlugin), PROB_LOW),
|
||||
(new TransparentReward(), PROB_LOW),
|
||||
(new AmmoWeaponReward("weapon_glock", 2, 0), PROB_LOW),
|
||||
(new AmmoWeaponReward("weapon_negev", 0, 5), PROB_LOW),
|
||||
(new CannotUseReward(basePlugin, WeaponType.SNIPERS), PROB_LOW),
|
||||
(new CannotUseReward(basePlugin, WeaponType.HEAVY), PROB_LOW),
|
||||
(new TransparentReward(), PROB_LOW / 2),
|
||||
(new AmmoWeaponReward("weapon_glock", 2, 0), PROB_LOW / 2),
|
||||
(new AmmoWeaponReward("weapon_negev", 0, 6), PROB_LOW / 2),
|
||||
(new CreditReward(50, locale), PROB_LOW), (new HPReward(1), PROB_LOW / 2),
|
||||
|
||||
// Very low
|
||||
(new FakeBombReward(), PROB_VERY_LOW * 2),
|
||||
(new CannotLeftKnife(basePlugin), PROB_VERY_LOW),
|
||||
(new NoWeaponReward(), PROB_VERY_LOW),
|
||||
(new AmmoWeaponReward("weapon_deagle", 1, 0), PROB_VERY_LOW),
|
||||
(new CannotUseReward(basePlugin, WeaponType.SMGS), PROB_VERY_LOW),
|
||||
(new CannotUseReward(basePlugin, WeaponType.PISTOLS), PROB_VERY_LOW),
|
||||
(new CannotUseReward(basePlugin, WeaponType.RIFLES), PROB_VERY_LOW),
|
||||
(new RandomTeleportReward(provider.GetService<IZoneManager>()),
|
||||
PROB_VERY_LOW),
|
||||
(new BombReward(bomb), PROB_VERY_LOW),
|
||||
(new CannotUseReward(basePlugin, WeaponType.UTILITY), PROB_VERY_LOW),
|
||||
(new CreditReward(-100, locale), PROB_VERY_LOW),
|
||||
(new CreditReward(500, locale), PROB_VERY_LOW),
|
||||
(new AmmoWeaponReward("weapon_awp", 1, 0), PROB_VERY_LOW / 2),
|
||||
(new AmmoWeaponReward("weapon_deagle", 1, 0), PROB_VERY_LOW / 2),
|
||||
(new AmmoWeaponReward("weapon_awp", 1, 0), PROB_VERY_LOW / 4),
|
||||
|
||||
// Extremely low
|
||||
(new CannotUseReward(basePlugin, WeaponType.KNIVES), PROB_EXTREMELY_LOW),
|
||||
(new CannotUseReward(basePlugin, WeaponType.GUNS), PROB_EXTREMELY_LOW),
|
||||
(new AmmoWeaponReward("weapon_awp", 3, 0), PROB_EXTREMELY_LOW),
|
||||
(new WeaponReward("weapon_glock"), PROB_EXTREMELY_LOW),
|
||||
(new CannotUseReward(basePlugin, WeaponType.GUNS), PROB_EXTREMELY_LOW),
|
||||
(new CreditReward(1000, locale), PROB_EXTREMELY_LOW),
|
||||
(new CreditReward(-5000, locale), PROB_EXTREMELY_LOW / 2),
|
||||
|
||||
|
||||
@@ -15,6 +15,11 @@ public class AmmoWeaponReward : WeaponReward {
|
||||
this.secondary = secondary;
|
||||
}
|
||||
|
||||
public override string Name
|
||||
=> primary + secondary == 0 ?
|
||||
$"Toy {weapon.GetFriendlyWeaponName()}" :
|
||||
$"{weapon.GetFriendlyWeaponName()} ({primary}/{secondary})";
|
||||
|
||||
public override bool GrantReward(CCSPlayerController player) {
|
||||
player.GiveNamedItem(weapon);
|
||||
player.GetWeaponBase(weapon).SetAmmo(primary, secondary);
|
||||
|
||||
@@ -6,8 +6,6 @@ namespace Jailbreak.RTD.Rewards;
|
||||
|
||||
public class CannotRightKnife(BasePlugin plugin)
|
||||
: AbstractOnTickReward(plugin) {
|
||||
private readonly HashSet<int> blockedPlayerIDs = [];
|
||||
|
||||
public override string Name => "Cannot Right-Knife";
|
||||
|
||||
public override string Description
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
using System.Collections.Immutable;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.RTD;
|
||||
|
||||
namespace Jailbreak.RTD.Rewards;
|
||||
|
||||
public class CannotUseReward : AbstractOnTickReward {
|
||||
public class CannotUseReward : IRTDReward {
|
||||
private readonly HashSet<int> blockedIDs = [];
|
||||
private readonly ImmutableHashSet<string> blockedWeapons;
|
||||
|
||||
public CannotUseReward(BasePlugin plugin, WeaponType blocked) : this(plugin,
|
||||
@@ -13,29 +17,54 @@ public class CannotUseReward : AbstractOnTickReward {
|
||||
NameShort = blocked.ToString().ToTitleCase();
|
||||
}
|
||||
|
||||
public CannotUseReward(BasePlugin plugin, params string[] weapons) : base(
|
||||
plugin) {
|
||||
public CannotUseReward(BasePlugin plugin, params string[] weapons) {
|
||||
blockedWeapons = weapons.ToImmutableHashSet();
|
||||
NameShort = string.Join(", ",
|
||||
blockedWeapons.Select(s => s.GetFriendlyWeaponName()));
|
||||
VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Hook(OnCanAcquire,
|
||||
HookMode.Pre);
|
||||
plugin.RegisterEventHandler<EventRoundEnd>(OnRoundEnd);
|
||||
}
|
||||
|
||||
public override string Name => $"Cannot Use {NameShort}";
|
||||
public string NameShort { get; }
|
||||
|
||||
public override string Description
|
||||
public string Name => $"Cannot Use {NameShort}";
|
||||
|
||||
public string Description
|
||||
=> $"You will not be able to use {NameShort} next round.";
|
||||
|
||||
override protected void tick(CCSPlayerController player) {
|
||||
if (!player.IsReal()) return;
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid) return;
|
||||
var weaponServices = pawn.WeaponServices;
|
||||
if (weaponServices == null) return;
|
||||
var activeWeapon = weaponServices.ActiveWeapon.Value;
|
||||
if (activeWeapon == null || !activeWeapon.IsValid) return;
|
||||
if (!blockedWeapons.Contains(activeWeapon.DesignerName)) return;
|
||||
activeWeapon.NextPrimaryAttackTick = Server.TickCount + 500;
|
||||
activeWeapon.NextSecondaryAttackTick = Server.TickCount + 500;
|
||||
public bool GrantReward(CCSPlayerController player) {
|
||||
if (player.UserId == null) return false;
|
||||
blockedIDs.Add(player.UserId.Value);
|
||||
|
||||
if (blockedWeapons.Any(w => w.Contains("knife") || w.Contains("bayonet")))
|
||||
player.RemoveWeapons();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) {
|
||||
blockedIDs.Clear();
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private HookResult OnCanAcquire(DynamicHook hook) {
|
||||
var player = hook.GetParam<CCSPlayer_ItemServices>(0)
|
||||
.Pawn.Value.Controller.Value?.As<CCSPlayerController>();
|
||||
var data = VirtualFunctions.GetCSWeaponDataFromKey.Invoke(-1,
|
||||
hook.GetParam<CEconItemView>(1).ItemDefinitionIndex.ToString());
|
||||
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
|
||||
var method = hook.GetParam<AcquireMethod>(2);
|
||||
if (method != AcquireMethod.PickUp) return HookResult.Continue;
|
||||
|
||||
if (player.UserId == null || !blockedIDs.Contains(player.UserId.Value))
|
||||
return HookResult.Continue;
|
||||
|
||||
if (!blockedWeapons.Contains(data.Name)) return HookResult.Continue;
|
||||
|
||||
hook.SetReturn(AcquireResult.NotAllowedByMode);
|
||||
return HookResult.Handled;
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,17 @@ using Jailbreak.Formatting.Views;
|
||||
using Jailbreak.Public;
|
||||
using Jailbreak.Public.Behaviors;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.LastRequest;
|
||||
using Jailbreak.Public.Mod.Rebel;
|
||||
using Jailbreak.Public.Utils;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MStatsShared;
|
||||
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
|
||||
|
||||
namespace Jailbreak.Rebel.C4Bomb;
|
||||
|
||||
public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
|
||||
: IPluginBehavior, IC4Service {
|
||||
public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService,
|
||||
IServiceProvider provider) : IPluginBehavior, IC4Service {
|
||||
public static readonly FakeConVar<bool> CV_GIVE_BOMB = new("css_jb_c4_give",
|
||||
"Whether to give a random prisoner a bomb at the beginning of the round.",
|
||||
true);
|
||||
@@ -40,17 +43,11 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
|
||||
new RangeValidator<float>(0, 10000));
|
||||
|
||||
private readonly Dictionary<CC4, C4Metadata> bombs = new();
|
||||
|
||||
private readonly Dictionary<ulong, string> cachedBombIcons = new();
|
||||
|
||||
// EmitSound(CBaseEntity* pEnt, const char* sSoundName, int nPitch, float flVolume, float flDelay)
|
||||
private readonly MemoryFunctionVoid<CBaseEntity, string, int, float, float>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
CBaseEntity_EmitSoundParamsLinux = new(
|
||||
"48 B8 ? ? ? ? ? ? ? ? 55 48 89 E5 41 55 41 54 49 89 FC 53 48 89 F3"); // LINUX ONLY.
|
||||
private int roundStart = 0;
|
||||
|
||||
private readonly Dictionary<int, int> deathToKiller = new();
|
||||
|
||||
private bool giveNextRound = true;
|
||||
|
||||
private BasePlugin? plugin;
|
||||
@@ -76,14 +73,13 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
|
||||
API.Stats?.PushStat(new ServerStat("JB_BOMB_ATTEMPT",
|
||||
$"{pos.X:F2} {pos.Y:F2} {pos.Z:F2}"));
|
||||
|
||||
tryEmitSound(player, "jb.jihad", 1, 1f, 0f);
|
||||
|
||||
bombs[bombEntity].IsDetonating = true;
|
||||
|
||||
rebelService.MarkRebel(player);
|
||||
|
||||
Server.RunOnTick(Server.TickCount + (int)(64 * delay),
|
||||
() => detonate(player, bombEntity));
|
||||
player.EmitSound("jb.jihad");
|
||||
}
|
||||
|
||||
public void TryGiveC4ToRandomTerrorist() {
|
||||
@@ -109,18 +105,21 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
|
||||
|
||||
public void Start(BasePlugin basePlugin) {
|
||||
plugin = basePlugin;
|
||||
plugin.RegisterListener<Listeners.OnTick>(playerUseC4ListenerCallback);
|
||||
plugin.RegisterListener<Listeners.OnPlayerButtonsChanged>(
|
||||
playerButtonsChanged);
|
||||
}
|
||||
|
||||
private void playerUseC4ListenerCallback() {
|
||||
private void playerButtonsChanged(CCSPlayerController player,
|
||||
PlayerButtons pressed, PlayerButtons released) {
|
||||
if ((pressed & PlayerButtons.Use) == 0) return;
|
||||
|
||||
foreach (var (bomb, meta) in bombs) {
|
||||
if (!bomb.IsValid) continue;
|
||||
if (meta.IsDetonating) continue;
|
||||
if (!bomb.IsValid || meta.IsDetonating) continue;
|
||||
|
||||
var bombCarrier = bomb.OwnerEntity.Value?.As<CCSPlayerPawn>()
|
||||
.Controller.Value?.As<CCSPlayerController>();
|
||||
if (bombCarrier == null || !bombCarrier.IsValid
|
||||
|| (bombCarrier.Buttons & PlayerButtons.Use) == 0)
|
||||
|| bombCarrier.Slot != player.Slot)
|
||||
continue;
|
||||
|
||||
var activeWeapon = bombCarrier.PlayerPawn.Value?.WeaponServices
|
||||
@@ -135,6 +134,7 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) {
|
||||
roundStart = Server.TickCount;
|
||||
ClearActiveC4s();
|
||||
refreshBombIcons();
|
||||
|
||||
@@ -172,11 +172,11 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
|
||||
continue;
|
||||
}
|
||||
|
||||
var (success, data) =
|
||||
var data =
|
||||
await gangStats.GetForGang<BombPerkData>(gangPlayer.GangId.Value,
|
||||
BombPerk.STAT_ID);
|
||||
|
||||
if (!success || data == null || data.Equipped == 0)
|
||||
if (data == null || data.Equipped == 0)
|
||||
cachedGangBombIcons[gangPlayer.GangId.Value] = "";
|
||||
else
|
||||
cachedGangBombIcons[gangPlayer.GangId.Value] =
|
||||
@@ -229,27 +229,24 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
|
||||
|
||||
private void detonate(CCSPlayerController player, CC4 bomb) {
|
||||
if (!player.IsValid || !player.IsReal() || !player.PawnIsAlive) {
|
||||
bombs.TryGetValue(bomb, out _);
|
||||
if (bomb.IsValid) bomb.Remove();
|
||||
bombs.Remove(bomb);
|
||||
return;
|
||||
}
|
||||
|
||||
tryEmitSound(player, "jb.jihadExplosion", 1, 1f, 0f);
|
||||
var particleSystemEntity =
|
||||
Utilities.CreateEntityByName<CParticleSystem>("info_particle_system")!;
|
||||
particleSystemEntity.EffectName =
|
||||
"particles/explosions_fx/explosion_c4_500.vpcf";
|
||||
particleSystemEntity.StartActive = true;
|
||||
|
||||
particleSystemEntity.Teleport(player.PlayerPawn.Value!.AbsOrigin!,
|
||||
new QAngle(), new Vector());
|
||||
particleSystemEntity.DispatchSpawn();
|
||||
if (Server.TickCount - roundStart < CV_C4_DELAY.Value * 64) return;
|
||||
|
||||
var killed = 0;
|
||||
/* Calculate damage here, only applies to alive CTs. */
|
||||
var lrs = provider.GetRequiredService<ILastRequestManager>();
|
||||
foreach (var ct in Utilities.GetPlayers()
|
||||
.Where(p => p is { Team: CsTeam.CounterTerrorist, PawnIsAlive: true })) {
|
||||
var lr = lrs.GetActiveLR(ct);
|
||||
if (lr != null) {
|
||||
var otherLr = lrs.GetActiveLR(player);
|
||||
if (otherLr == null || otherLr != lr) continue;
|
||||
}
|
||||
|
||||
var distanceFromBomb =
|
||||
ct.PlayerPawn.Value!.AbsOrigin!.Distance(player.PlayerPawn.Value
|
||||
.AbsOrigin!);
|
||||
@@ -269,6 +266,10 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
|
||||
}
|
||||
}
|
||||
|
||||
// If they didn't have the C4 make sure to remove it.
|
||||
player.CommitSuicide(true, true);
|
||||
bombs.Remove(bomb);
|
||||
|
||||
if (API.Gangs != null && killed > 0) {
|
||||
var eco = API.Gangs.Services.GetService<IEcoManager>();
|
||||
if (eco != null) {
|
||||
@@ -278,17 +279,18 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
|
||||
}
|
||||
}
|
||||
|
||||
player.EmitSound("jb.jihadExplosion");
|
||||
var particleSystemEntity =
|
||||
Utilities.CreateEntityByName<CParticleSystem>("info_particle_system")!;
|
||||
particleSystemEntity.EffectName =
|
||||
"particles/explosions_fx/explosion_c4_500.vpcf";
|
||||
particleSystemEntity.StartActive = true;
|
||||
|
||||
particleSystemEntity.Teleport(player.PlayerPawn.Value!.AbsOrigin!,
|
||||
new QAngle(), new Vector());
|
||||
particleSystemEntity.DispatchSpawn();
|
||||
|
||||
API.Stats?.PushStat(new ServerStat("JB_BOMB_EXPLODED", killed.ToString()));
|
||||
|
||||
// If they didn't have the C4 make sure to remove it.
|
||||
player.CommitSuicide(true, true);
|
||||
bombs.Remove(bomb);
|
||||
}
|
||||
|
||||
private void tryEmitSound(CBaseEntity entity, string soundEventName,
|
||||
int pitch, float volume, float delay) {
|
||||
CBaseEntity_EmitSoundParamsLinux.Invoke(entity, soundEventName, pitch,
|
||||
volume, delay);
|
||||
}
|
||||
|
||||
private class C4Metadata(bool isDetonating) {
|
||||
|
||||
@@ -7,6 +7,7 @@ using Jailbreak.LastRequest;
|
||||
using Jailbreak.Public;
|
||||
using Jailbreak.Public.Behaviors;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.LastGuard;
|
||||
using Jailbreak.Public.Mod.LastRequest;
|
||||
using Jailbreak.Public.Mod.Rebel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -14,7 +15,8 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
namespace Jailbreak.Rebel;
|
||||
|
||||
public class RebelListener(IRebelService rebelService,
|
||||
ILastRequestManager lastRequestManager) : IPluginBehavior {
|
||||
ILastRequestManager lastRequestManager, ILastGuardService lastGuard)
|
||||
: IPluginBehavior {
|
||||
private readonly Dictionary<int, int> weaponScores = [];
|
||||
|
||||
[GameEventHandler]
|
||||
@@ -65,13 +67,16 @@ public class RebelListener(IRebelService rebelService,
|
||||
var attacker = ev.Attacker;
|
||||
if (attacker == null || !attacker.IsValid || attacker.IsBot)
|
||||
return HookResult.Continue;
|
||||
|
||||
// Do not give player credits if they suicided
|
||||
if (player.SteamID == attacker.SteamID) return HookResult.Continue;
|
||||
|
||||
var eco = API.Gangs?.Services.GetService<IEcoManager>();
|
||||
if (eco == null) return HookResult.Continue;
|
||||
|
||||
var wrapper = new PlayerWrapper(attacker);
|
||||
if (!weaponScores.TryGetValue(player.Slot, out var weaponScore))
|
||||
weaponScore = 5;
|
||||
weaponScore = lastGuard.IsLastGuardActive ? 2 : 5;
|
||||
|
||||
Task.Run(async ()
|
||||
=> await eco.Grant(wrapper, weaponScore, true, "Rebel Kill"));
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,31 +1,22 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.SpecialDay;
|
||||
using Jailbreak.Formatting.Views.Warden;
|
||||
using Jailbreak.Public.Behaviors;
|
||||
using Jailbreak.Public.Mod.SpecialDay;
|
||||
using Jailbreak.Public.Mod.SpecialDay.Enums;
|
||||
using Jailbreak.Public.Mod.Warden;
|
||||
using Jailbreak.Public.Utils;
|
||||
using Jailbreak.SpecialDay.SpecialDays;
|
||||
|
||||
namespace Jailbreak.SpecialDay;
|
||||
|
||||
public class SpecialDayCommand(IWardenService warden,
|
||||
ISpecialDayFactory factory, IWardenLocale wardenMsg, ISDLocale sdMsg,
|
||||
public class SpecialDayCommand(ISpecialDayFactory factory, ISDLocale sdMsg,
|
||||
ISpecialDayManager sd) : IPluginBehavior {
|
||||
public static readonly FakeConVar<int> CV_ROUNDS_BETWEEN_SD = new(
|
||||
"css_jb_sd_round_cooldown", "Rounds between special days", 4);
|
||||
|
||||
public static readonly FakeConVar<int> CV_MAX_ELAPSED_TIME = new(
|
||||
"css_jb_sd_max_elapsed_time",
|
||||
"Max time elapsed in a round to be able to call a special day", 30);
|
||||
"css_jb_sd_round_cooldown", "Rounds between special days", 5);
|
||||
|
||||
private SpecialDayMenuSelector menuSelector = null!;
|
||||
private BasePlugin plugin = null!;
|
||||
@@ -52,36 +43,6 @@ public class SpecialDayCommand(IWardenService warden,
|
||||
return;
|
||||
}
|
||||
|
||||
if (executor != null
|
||||
&& !AdminManager.PlayerHasPermissions(executor, "@css/rcon")) {
|
||||
if (!warden.IsWarden(executor) || RoundUtil.IsWarmup()) {
|
||||
wardenMsg.NotWarden.ToChat(executor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sd.IsSDRunning) {
|
||||
// SD is already running
|
||||
if (sd.CurrentSD is ISpecialDayMessageProvider messaged)
|
||||
sdMsg.SpecialDayRunning(messaged.Locale.Name).ToChat(executor);
|
||||
else
|
||||
sdMsg.SpecialDayRunning(sd.CurrentSD?.Type.ToString() ?? "Unknown")
|
||||
.ToChat(executor);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var roundsToNext = sd.RoundsSinceLastSD - CV_ROUNDS_BETWEEN_SD.Value;
|
||||
if (roundsToNext < 0) {
|
||||
sdMsg.SpecialDayCooldown(Math.Abs(roundsToNext)).ToChat(executor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RoundUtil.GetTimeElapsed() > CV_MAX_ELAPSED_TIME.Value) {
|
||||
sdMsg.TooLateForSpecialDay(CV_MAX_ELAPSED_TIME.Value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (info.ArgCount == 1) {
|
||||
if (executor == null) {
|
||||
Server.PrintToConsole("css_sd [SD]");
|
||||
@@ -100,6 +61,8 @@ public class SpecialDayCommand(IWardenService warden,
|
||||
return;
|
||||
}
|
||||
|
||||
var canStart = sd.CanStartSpecialDay(type.Value, executor);
|
||||
if (!canStart) return;
|
||||
sd.InitiateSpecialDay(type.Value);
|
||||
}
|
||||
}
|
||||
@@ -12,18 +12,22 @@ public class SpecialDayFactory(IServiceProvider provider) : ISpecialDayFactory {
|
||||
|
||||
public AbstractSpecialDay CreateSpecialDay(SDType type) {
|
||||
return type switch {
|
||||
SDType.BHOP => new BHopDay(plugin, provider),
|
||||
SDType.CUSTOM => new CustomDay(plugin, provider),
|
||||
SDType.FFA => new FFADay(plugin, provider),
|
||||
SDType.GUNGAME => new GunGameDay(plugin, provider),
|
||||
SDType.HNS => new HideAndSeekDay(plugin, provider),
|
||||
SDType.INFECTION => new InfectionDay(plugin, provider),
|
||||
SDType.NOSCOPE => new NoScopeDay(plugin, provider),
|
||||
SDType.OITC => new OneInTheChamberDay(plugin, provider),
|
||||
SDType.SPEEDRUN => new SpeedrunDay(plugin, provider),
|
||||
SDType.TELEPORT => new TeleportDay(plugin, provider),
|
||||
SDType.WARDAY => new WardayDay(plugin, provider),
|
||||
_ => throw new NotImplementedException()
|
||||
SDType.BHOP => new BHopDay(plugin, provider),
|
||||
SDType.CUSTOM => new CustomDay(plugin, provider),
|
||||
SDType.FFA => new FFADay(plugin, provider),
|
||||
SDType.FOG => new FogDay(plugin, provider),
|
||||
SDType.GUNGAME => new GunGameDay(plugin, provider),
|
||||
SDType.GHOST => new GhostDay(plugin, provider),
|
||||
SDType.HE => new HEDay(plugin, provider),
|
||||
SDType.HNS => new HideAndSeekDay(plugin, provider),
|
||||
SDType.INFECTION => new InfectionDay(plugin, provider),
|
||||
SDType.NOSCOPE => new NoScopeDay(plugin, provider),
|
||||
SDType.OITC => new OneInTheChamberDay(plugin, provider),
|
||||
//SDType.ROCKETJUMP => new RocketJumpDay(plugin, provider),
|
||||
SDType.SPEEDRUN => new SpeedrunDay(plugin, provider),
|
||||
SDType.TELEPORT => new TeleportDay(plugin, provider),
|
||||
SDType.WARDAY => new WardayDay(plugin, provider),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Gangs.BaseImpl.Extensions;
|
||||
using Gangs.SpecialDayColorPerk;
|
||||
@@ -8,11 +10,14 @@ using GangsAPI.Data;
|
||||
using GangsAPI.Services.Gang;
|
||||
using GangsAPI.Services.Player;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.SpecialDay;
|
||||
using Jailbreak.Formatting.Views.Warden;
|
||||
using Jailbreak.Public;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.Rainbow;
|
||||
using Jailbreak.Public.Mod.SpecialDay;
|
||||
using Jailbreak.Public.Mod.SpecialDay.Enums;
|
||||
using Jailbreak.Public.Mod.Warden;
|
||||
using Jailbreak.Public.Utils;
|
||||
using Jailbreak.SpecialDay.SpecialDays;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -21,7 +26,15 @@ using MStatsShared;
|
||||
namespace Jailbreak.SpecialDay;
|
||||
|
||||
public class SpecialDayManager(ISpecialDayFactory factory,
|
||||
IServiceProvider provider) : ISpecialDayManager {
|
||||
IServiceProvider provider, IWardenLocale wardenMsg, ISDLocale locale)
|
||||
: ISpecialDayManager {
|
||||
public static readonly FakeConVar<int> CV_MAX_ELAPSED_TIME = new(
|
||||
"css_jb_sd_max_elapsed_time",
|
||||
"Max time elapsed in a round to be able to call a special day", 30);
|
||||
|
||||
public static readonly FakeConVar<int> CV_ROUNDS_BETWEEN_SD = new(
|
||||
"css_jb_sd_round_cooldown", "Rounds between special days", 5);
|
||||
|
||||
private readonly IRainbowColorizer colorizer =
|
||||
provider.GetRequiredService<IRainbowColorizer>();
|
||||
|
||||
@@ -29,6 +42,51 @@ public class SpecialDayManager(ISpecialDayFactory factory,
|
||||
public AbstractSpecialDay? CurrentSD { get; private set; }
|
||||
public int RoundsSinceLastSD { get; set; }
|
||||
|
||||
public bool CanStartSpecialDay(SDType type, CCSPlayerController? player,
|
||||
bool print = true) {
|
||||
var warden = provider.GetRequiredService<IWardenService>();
|
||||
if (!AdminManager.PlayerHasPermissions(player, "@css/rcon")) {
|
||||
if (!warden.IsWarden(player) || RoundUtil.IsWarmup()) {
|
||||
if (print) wardenMsg.NotWarden.ToChat(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsSDRunning) {
|
||||
if (CurrentSD is ISpecialDayMessageProvider messaged) {
|
||||
if (print)
|
||||
locale.SpecialDayRunning(messaged.Locale.Name).ToChat(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (print)
|
||||
locale.SpecialDayRunning(CurrentSD?.Type.ToString() ?? "Unknown")
|
||||
.ToChat(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
var roundsToNext = RoundsSinceLastSD - CV_ROUNDS_BETWEEN_SD.Value;
|
||||
if (roundsToNext < 0) {
|
||||
if (print)
|
||||
locale.SpecialDayCooldown(Math.Abs(roundsToNext)).ToChat(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RoundUtil.GetTimeElapsed() > CV_MAX_ELAPSED_TIME.Value) {
|
||||
if (print)
|
||||
locale.TooLateForSpecialDay(CV_MAX_ELAPSED_TIME.Value).ToChat(player);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var denyReason = type.CanCall(player);
|
||||
|
||||
if (denyReason == null
|
||||
|| AdminManager.PlayerHasPermissions(player, "@css/root"))
|
||||
return true;
|
||||
if (print) locale.CannotCallDay(denyReason).ToChat(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool InitiateSpecialDay(SDType type) {
|
||||
API.Stats?.PushStat(new ServerStat("JB_SPECIALDAY", type.ToString()));
|
||||
RoundsSinceLastSD = 0;
|
||||
@@ -56,9 +114,9 @@ public class SpecialDayManager(ISpecialDayFactory factory,
|
||||
var gangPlayer = await players.GetPlayer(wrapper.Steam);
|
||||
if (gangPlayer?.GangId == null) return;
|
||||
var gangId = gangPlayer.GangId.Value;
|
||||
var (success, data) =
|
||||
var data =
|
||||
await gangStats.GetForGang<SDColorData>(gangId, SDColorPerk.STAT_ID);
|
||||
if (!success || data == null) continue;
|
||||
if (data == null) continue;
|
||||
|
||||
var col = data.Equipped.GetColor() ?? data.Unlocked.PickRandom();
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public class BHopDay(BasePlugin plugin, IServiceProvider provider)
|
||||
public override SpecialDaySettings Settings => new BHopSettings();
|
||||
|
||||
public ISDInstanceLocale Locale
|
||||
=> new TeamDayLocale("Bunny Hop Day",
|
||||
=> new TeamDayLocale("Bunny Hop",
|
||||
"Auto-Bunny hopping is on, otherwise normal day!");
|
||||
|
||||
public override void Setup() {
|
||||
@@ -27,6 +27,7 @@ public class BHopDay(BasePlugin plugin, IServiceProvider provider)
|
||||
AllowLastRequests = true;
|
||||
AllowRebels = true;
|
||||
OpenCells = false;
|
||||
RespawnPlayers = false;
|
||||
|
||||
ConVarValues["sv_enablebunnyhopping"] = true;
|
||||
ConVarValues["sv_autobunnyhopping"] = true;
|
||||
|
||||
@@ -15,7 +15,8 @@ public class CustomDay(BasePlugin plugin, IServiceProvider provider)
|
||||
StripToKnife = false,
|
||||
AllowLastRequests = true,
|
||||
AllowRebels = true,
|
||||
OpenCells = false
|
||||
OpenCells = false,
|
||||
RespawnPlayers = false
|
||||
};
|
||||
|
||||
public ISDInstanceLocale Locale
|
||||
|
||||
206
mod/Jailbreak.SpecialDay/SpecialDays/FogDay.cs
Normal file
206
mod/Jailbreak.SpecialDay/SpecialDays/FogDay.cs
Normal file
@@ -0,0 +1,206 @@
|
||||
using System.Drawing;
|
||||
using System.Runtime.CompilerServices;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using Jailbreak.English.SpecialDay;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.SpecialDay;
|
||||
using Jailbreak.Public.Mod.SpecialDay;
|
||||
using Jailbreak.Public.Mod.SpecialDay.Enums;
|
||||
|
||||
namespace Jailbreak.SpecialDay.SpecialDays;
|
||||
|
||||
public class FogDay(BasePlugin plugin, IServiceProvider provider)
|
||||
: AbstractSpecialDay(plugin, provider), ISpecialDayMessageProvider {
|
||||
public override SDType Type => SDType.FOG;
|
||||
private FogDayLocale Msg => (FogDayLocale)Locale;
|
||||
public ISDInstanceLocale Locale => new FogDayLocale();
|
||||
public override SpecialDaySettings Settings => new FogSettings();
|
||||
|
||||
private CFogController? fogController;
|
||||
private nint originalSkyMat;
|
||||
private nint originalSkyMatLighting;
|
||||
private CEnvSky? skyEntity;
|
||||
|
||||
private float targetFogEnd = 2000f;
|
||||
private float fogStepPerTick;
|
||||
private bool shouldGrowFog;
|
||||
|
||||
public override void Setup() {
|
||||
Plugin.RegisterListener<Listeners.OnTick>(onTick);
|
||||
Plugin.RegisterEventHandler<EventPlayerDeath>(onDeath);
|
||||
|
||||
cacheOriginalSky();
|
||||
|
||||
setFog(true);
|
||||
setSky(true);
|
||||
|
||||
Timers[20] += () => Locale.BeginsIn(20).ToAllChat();
|
||||
Timers[25] += () => {
|
||||
Msg.FogComingIn().ToAllChat();
|
||||
setTargetFogDistance(300, 10);
|
||||
};
|
||||
Timers[30] += () => Msg.BeginsIn(10).ToAllChat();
|
||||
Timers[35] += () => Msg.BeginsIn(5).ToAllChat();
|
||||
Timers[40] += () => {
|
||||
Execute();
|
||||
Msg.BeginsIn(0).ToAllChat();
|
||||
};
|
||||
Timers[97] += () => Msg.FogExpandsIn(3).ToAllChat();
|
||||
Timers[98] += () => Msg.FogExpandsIn(2).ToAllChat();
|
||||
Timers[99] += () => Msg.FogExpandsIn(1).ToAllChat();
|
||||
Timers[100] += () => {
|
||||
setTargetFogDistance(3000, 180);
|
||||
Msg.FogExpandsIn(0).ToAllChat();
|
||||
};
|
||||
|
||||
base.Setup();
|
||||
}
|
||||
|
||||
|
||||
private unsafe void setSky(bool set) {
|
||||
if (skyEntity == null) return;
|
||||
|
||||
var mat = set ? nint.Zero : originalSkyMat;
|
||||
var matLit = set ? nint.Zero : originalSkyMatLighting;
|
||||
|
||||
Unsafe.Write((void*)skyEntity.SkyMaterial.Handle, mat);
|
||||
Unsafe.Write((void*)skyEntity.SkyMaterialLightingOnly.Handle, matLit);
|
||||
|
||||
Utilities.SetStateChanged(skyEntity, "CEnvSky", "m_hSkyMaterial");
|
||||
Utilities.SetStateChanged(skyEntity, "CEnvSky",
|
||||
"m_hSkyMaterialLightingOnly");
|
||||
|
||||
skyEntity.BrightnessScale = 1.0f;
|
||||
Utilities.SetStateChanged(skyEntity, "CEnvSky", "m_flBrightnessScale");
|
||||
}
|
||||
|
||||
private void setFog(bool set) {
|
||||
if (!set) {
|
||||
fogController?.Remove();
|
||||
fogController = null;
|
||||
return;
|
||||
}
|
||||
|
||||
fogController ??=
|
||||
Utilities.CreateEntityByName<CFogController>("env_fog_controller");
|
||||
fogController?.DispatchSpawn();
|
||||
|
||||
if (fogController == null) return;
|
||||
|
||||
var fog = fogController.Fog;
|
||||
fog.Enable = true;
|
||||
fog.Blend = true;
|
||||
fog.ColorPrimary = Color.Black;
|
||||
fog.Exponent = 0.1f;
|
||||
fog.Maxdensity = 1f;
|
||||
fog.Start = 0;
|
||||
fog.End = targetFogEnd;
|
||||
fog.Farz = targetFogEnd * 1.04f;
|
||||
|
||||
foreach (var field in new[] {
|
||||
"colorPrimary", "start", "end", "farz", "maxdensity", "exponent",
|
||||
"enable", "blend",
|
||||
}) {
|
||||
Utilities.SetStateChanged(fogController, "CFogController", "m_fog",
|
||||
Schema.GetSchemaOffset("fogparams_t", field));
|
||||
}
|
||||
|
||||
var vis = Utilities
|
||||
.FindAllEntitiesByDesignerName<CPlayerVisibility>("env_player_visibility")
|
||||
.FirstOrDefault();
|
||||
if (vis != null) {
|
||||
vis.FogMaxDensityMultiplier = 1f;
|
||||
Utilities.SetStateChanged(vis, "CPlayerVisibility",
|
||||
"m_flFogMaxDensityMultiplier");
|
||||
}
|
||||
|
||||
foreach (var pawn in Utilities.GetPlayers()
|
||||
.Select(p => p.Pawn.Value)
|
||||
.OfType<CBasePlayerPawn>())
|
||||
pawn.AcceptInput("SetFogController", activator: fogController,
|
||||
value: "!activator");
|
||||
}
|
||||
|
||||
private void onTick() {
|
||||
if (!shouldGrowFog || fogController == null) return;
|
||||
|
||||
var fog = fogController.Fog;
|
||||
|
||||
if (Math.Abs(fog.End - targetFogEnd) < Math.Abs(fogStepPerTick)) {
|
||||
fog.End = targetFogEnd;
|
||||
fog.Farz = targetFogEnd * 1.04f;
|
||||
shouldGrowFog = false;
|
||||
} else {
|
||||
fog.End += fogStepPerTick;
|
||||
fog.Farz = fog.End + 10f;
|
||||
}
|
||||
|
||||
Utilities.SetStateChanged(fogController, "CFogController", "m_fog",
|
||||
Schema.GetSchemaOffset("fogparams_t", "end"));
|
||||
Utilities.SetStateChanged(fogController, "CFogController", "m_fog",
|
||||
Schema.GetSchemaOffset("fogparams_t", "farz"));
|
||||
}
|
||||
|
||||
private HookResult onDeath(EventPlayerDeath @event, GameEventInfo info) {
|
||||
var pawn = @event.Userid?.PlayerPawn.Value;
|
||||
if (pawn == null) return HookResult.Continue;
|
||||
|
||||
Server.NextFrame(() => {
|
||||
pawn.AcceptInput("SetFogController", activator: fogController,
|
||||
value: "!activator");
|
||||
});
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
override protected HookResult OnEnd(EventRoundEnd @event,
|
||||
GameEventInfo info) {
|
||||
setSky(false);
|
||||
setFog(false);
|
||||
|
||||
if (fogController != null) fogController.Remove();
|
||||
|
||||
Plugin.RemoveListener<Listeners.OnTick>(onTick);
|
||||
Plugin.DeregisterEventHandler<EventPlayerDeath>(onDeath);
|
||||
|
||||
return base.OnEnd(@event, info);
|
||||
}
|
||||
|
||||
private unsafe void cacheOriginalSky() {
|
||||
skyEntity = Utilities.FindAllEntitiesByDesignerName<CEnvSky>("env_sky")
|
||||
.FirstOrDefault();
|
||||
if (skyEntity == null) return;
|
||||
|
||||
originalSkyMat = Unsafe.Read<nint>((void*)skyEntity.SkyMaterial.Handle);
|
||||
originalSkyMatLighting =
|
||||
Unsafe.Read<nint>((void*)skyEntity.SkyMaterialLightingOnly.Handle);
|
||||
}
|
||||
|
||||
private void setTargetFogDistance(int distance, float durationInSeconds) {
|
||||
if (fogController == null) return;
|
||||
|
||||
var currentEnd = fogController.Fog.End;
|
||||
var totalTicks = durationInSeconds * 64f;
|
||||
fogStepPerTick = (distance - currentEnd) / totalTicks;
|
||||
targetFogEnd = distance;
|
||||
shouldGrowFog = true;
|
||||
}
|
||||
|
||||
public class FogSettings : SpecialDaySettings {
|
||||
private readonly Random rng;
|
||||
|
||||
public FogSettings() {
|
||||
TTeleport = TeleportType.ARMORY;
|
||||
CtTeleport = TeleportType.ARMORY;
|
||||
OpenCells = true;
|
||||
StripToKnife = false;
|
||||
rng = new Random();
|
||||
WithFriendlyFire();
|
||||
}
|
||||
|
||||
public override float FreezeTime(CCSPlayerController player) {
|
||||
return rng.NextSingle() * 5 + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
153
mod/Jailbreak.SpecialDay/SpecialDays/GhostDay.cs
Normal file
153
mod/Jailbreak.SpecialDay/SpecialDays/GhostDay.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.English.SpecialDay;
|
||||
using Jailbreak.Formatting.Views.SpecialDay;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.SpecialDay;
|
||||
using Jailbreak.Public.Mod.SpecialDay.Enums;
|
||||
using Jailbreak.Public.Utils;
|
||||
using Jailbreak.Validator;
|
||||
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
|
||||
|
||||
namespace Jailbreak.SpecialDay.SpecialDays;
|
||||
|
||||
public class GhostDay(BasePlugin plugin, IServiceProvider provider)
|
||||
: FFADay(plugin, provider), ISpecialDayMessageProvider {
|
||||
public static readonly FakeConVar<float> CV_VISIBLE_DURATION = new(
|
||||
"css_jb_sd_ghost_visible_duration",
|
||||
"Amount of time players spend visible per cycle", 5f,
|
||||
ConVarFlags.FCVAR_NONE, new NonZeroRangeValidator<float>(1f, 30f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_INVISIBLE_DURATION = new(
|
||||
"css_jb_sd_ghost_invisible_duration",
|
||||
"Amount of time players spend invisible per cycle", 5f,
|
||||
ConVarFlags.FCVAR_NONE, new NonZeroRangeValidator<float>(1f, 30f));
|
||||
|
||||
private static readonly
|
||||
MemoryFunctionVoid<nint, nint, int, nint, nint, nint, int, bool>
|
||||
CHECK_TRANSMIT = new(GameData.GetSignature("CheckTransmit"));
|
||||
|
||||
private static readonly int CHECK_TRANSMIT_PLAYER_SLOT_CACHE =
|
||||
GameData.GetOffset("CheckTransmitPlayerSlot");
|
||||
|
||||
private static float CycleDuration
|
||||
=> CV_VISIBLE_DURATION.Value + CV_INVISIBLE_DURATION.Value;
|
||||
private bool allPlayersVisible;
|
||||
private float timeElapsed;
|
||||
private Timer? ghostTimer;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CCheckTransmitInfo
|
||||
{
|
||||
public CFixedBitVecBase m_pTransmitEntity;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public readonly unsafe struct CFixedBitVecBase
|
||||
{
|
||||
private const int LOG2_BITS_PER_INT = 5;
|
||||
private const int MAX_EDICT_BITS = 14;
|
||||
private const int BITS_PER_INT = 32;
|
||||
private const int MAX_EDICTS = 1 << MAX_EDICT_BITS;
|
||||
|
||||
private readonly uint* m_Ints;
|
||||
|
||||
public void Clear(int bitNum)
|
||||
{
|
||||
if (bitNum is < 0 or >= MAX_EDICTS)
|
||||
return;
|
||||
|
||||
var pInt = m_Ints + (bitNum >> LOG2_BITS_PER_INT);
|
||||
*pInt &= ~(uint)(1 << (bitNum & BITS_PER_INT - 1));
|
||||
}
|
||||
}
|
||||
public override SDType Type => SDType.GHOST;
|
||||
public override ISDInstanceLocale Locale
|
||||
=> new SoloDayLocale("Ghost War",
|
||||
"Now you see me… now you don’t! Fight through flickering visibility!");
|
||||
public override SpecialDaySettings Settings => new GhostSettings();
|
||||
|
||||
public override void Setup() {
|
||||
CHECK_TRANSMIT.Hook(onTransmit, HookMode.Post);
|
||||
Server.NextFrameAsync(() => setVisibility(false));
|
||||
base.Setup();
|
||||
}
|
||||
|
||||
public override void Execute() {
|
||||
base.Execute();
|
||||
|
||||
timeElapsed = 0f;
|
||||
setVisibility(true);
|
||||
|
||||
ghostTimer = Plugin.AddTimer(1f, () => {
|
||||
timeElapsed += 1f;
|
||||
|
||||
var mod = timeElapsed % CycleDuration;
|
||||
|
||||
var shouldBeVisible = mod < CV_VISIBLE_DURATION.Value;
|
||||
var timeLeft = (int)((shouldBeVisible ?
|
||||
CV_VISIBLE_DURATION.Value : CycleDuration) - mod);
|
||||
|
||||
if (shouldBeVisible != allPlayersVisible)
|
||||
setVisibility(shouldBeVisible);
|
||||
|
||||
foreach (var player in PlayerUtil.GetAlive()
|
||||
.Where(p => p.IsValid))
|
||||
player.PrintToCenter($"{(allPlayersVisible
|
||||
? "Visible" : "Hidden")} for: {timeLeft}s");
|
||||
}, TimerFlags.REPEAT);
|
||||
}
|
||||
|
||||
private unsafe HookResult onTransmit(DynamicHook hook) {
|
||||
if (allPlayersVisible) return HookResult.Continue;
|
||||
|
||||
var ppInfoList = (nint*)hook.GetParam<nint>(1);
|
||||
var infoCount = hook.GetParam<int>(2);
|
||||
|
||||
var players = Utilities.GetPlayers()
|
||||
.Where(p => p is { IsValid: true, PawnIsAlive: true })
|
||||
.ToList();
|
||||
|
||||
for (var i = 0; i < infoCount; i++) {
|
||||
var pInfo = ppInfoList[i];
|
||||
var slot = *(byte*)(pInfo + CHECK_TRANSMIT_PLAYER_SLOT_CACHE);
|
||||
var player = Utilities.GetPlayerFromSlot(slot);
|
||||
if (player == null || !player.IsValid) continue;
|
||||
|
||||
var info = Marshal.PtrToStructure<CCheckTransmitInfo>(pInfo);
|
||||
|
||||
foreach (var target in
|
||||
players.Where(target => target.Index != player.Index)) {
|
||||
info.m_pTransmitEntity.Clear((int)target.PlayerPawn.Value.Index);
|
||||
}
|
||||
}
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
override protected HookResult OnEnd(EventRoundEnd ev, GameEventInfo info) {
|
||||
ghostTimer?.Kill();
|
||||
CHECK_TRANSMIT.Unhook(onTransmit, HookMode.Post);
|
||||
return base.OnEnd(ev, info);
|
||||
}
|
||||
|
||||
private void setVisibility(bool state) {
|
||||
allPlayersVisible = state;
|
||||
Server.ExecuteCommand($"mp_footsteps_serverside {(state ? "1" : "0")}");
|
||||
if (state) EnableDamage(); else DisableDamage();
|
||||
foreach (var player in PlayerUtil.GetAlive()) {
|
||||
player.ExecuteClientCommand(
|
||||
$"play {(state ? "\"sounds/buttons/bell1.vsnd\"" : "\"sounds/ui/counter_beep.vsnd\"")}");
|
||||
}
|
||||
}
|
||||
|
||||
public class GhostSettings : FFASettings {
|
||||
public GhostSettings() {
|
||||
ConVarValues["mp_footsteps_serverside"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.English.SpecialDay;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
@@ -116,12 +118,13 @@ public class GunGameDay(BasePlugin plugin, IServiceProvider provider)
|
||||
var attacker = @event.Attacker;
|
||||
info.DontBroadcast = true;
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
int playerIndex;
|
||||
if (!progressions.TryGetValue(player.Slot, out playerIndex))
|
||||
if (!progressions.TryGetValue(player.Slot, out var playerIndex))
|
||||
playerIndex = 0;
|
||||
if (attacker == null || !attacker.IsValid) return HookResult.Continue;
|
||||
if (attacker.Slot == player.Slot) return HookResult.Continue;
|
||||
|
||||
@event.FireEventToClient(attacker);
|
||||
|
||||
var attackerProgress =
|
||||
progressions.TryGetValue(attacker.Slot, out var attackerIndex) ?
|
||||
attackerIndex :
|
||||
@@ -135,6 +138,9 @@ public class GunGameDay(BasePlugin plugin, IServiceProvider provider)
|
||||
p.RemoveWeapons();
|
||||
}
|
||||
|
||||
VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Unhook(
|
||||
OnCanAcquire, HookMode.Pre);
|
||||
|
||||
attacker.SetSpeed(2f);
|
||||
attacker.RemoveWeapons();
|
||||
attacker.GiveNamedItem("weapon_negev");
|
||||
@@ -147,7 +153,6 @@ public class GunGameDay(BasePlugin plugin, IServiceProvider provider)
|
||||
RoundUtil.SetTimeRemaining(Math.Min(RoundUtil.GetTimeRemaining(), 30));
|
||||
|
||||
Plugin.DeregisterEventHandler<EventPlayerDeath>(OnDeath, HookMode.Pre);
|
||||
Plugin.RemoveListener<Listeners.OnTick>(OnTick);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
@@ -185,14 +190,17 @@ public class GunGameDay(BasePlugin plugin, IServiceProvider provider)
|
||||
return result;
|
||||
}
|
||||
|
||||
override protected void OnTick() {
|
||||
foreach (var player in PlayerUtil.GetAlive()) {
|
||||
var weapons = allowedWeapons(player);
|
||||
disableWeapon(player, weapons);
|
||||
}
|
||||
}
|
||||
override protected HookResult OnCanAcquire(DynamicHook hook) {
|
||||
var player = hook.GetParam<CCSPlayer_ItemServices>(0)
|
||||
.Pawn.Value.Controller.Value?.As<CCSPlayerController>();
|
||||
var data = VirtualFunctions.GetCSWeaponDataFromKey.Invoke(-1,
|
||||
hook.GetParam<CEconItemView>(1).ItemDefinitionIndex.ToString());
|
||||
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
|
||||
var method = hook.GetParam<AcquireMethod>(2);
|
||||
if (method != AcquireMethod.PickUp) return HookResult.Continue;
|
||||
|
||||
private ISet<string> allowedWeapons(CCSPlayerController player) {
|
||||
var progress = progressions.TryGetValue(player.Slot, out var index) ?
|
||||
index :
|
||||
0;
|
||||
@@ -206,21 +214,10 @@ public class GunGameDay(BasePlugin plugin, IServiceProvider provider)
|
||||
if (Tag.PISTOLS.Contains(weapon))
|
||||
allowed = allowed.Union(Tag.PISTOLS).ToHashSet();
|
||||
|
||||
return allowed.Union(Tag.UTILITY).ToHashSet();
|
||||
}
|
||||
if (allowed.Contains(data.Name)) return HookResult.Continue;
|
||||
|
||||
private void disableWeapon(CCSPlayerController player,
|
||||
ICollection<string> allowed) {
|
||||
if (!player.IsReal()) return;
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid) return;
|
||||
var weaponServices = pawn.WeaponServices;
|
||||
if (weaponServices == null) return;
|
||||
var activeWeapon = weaponServices.ActiveWeapon.Value;
|
||||
if (activeWeapon == null || !activeWeapon.IsValid) return;
|
||||
if (allowed.Contains(activeWeapon.DesignerName)) return;
|
||||
activeWeapon.NextSecondaryAttackTick = Server.TickCount + 500;
|
||||
activeWeapon.NextPrimaryAttackTick = Server.TickCount + 500;
|
||||
hook.SetReturn(AcquireResult.NotAllowedByMode);
|
||||
return HookResult.Handled;
|
||||
}
|
||||
|
||||
public class GunGameSettings : SpecialDaySettings {
|
||||
@@ -230,7 +227,6 @@ public class GunGameDay(BasePlugin plugin, IServiceProvider provider)
|
||||
FreezePlayers = false;
|
||||
ConVarValues["mp_respawn_immunitytime"] = 5.0f;
|
||||
ConVarValues["mp_death_drop_gun"] = 0;
|
||||
RestrictWeapons = true;
|
||||
WithFriendlyFire();
|
||||
WithRespawns();
|
||||
}
|
||||
|
||||
66
mod/Jailbreak.SpecialDay/SpecialDays/HEDay.cs
Normal file
66
mod/Jailbreak.SpecialDay/SpecialDays/HEDay.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using Jailbreak.English.SpecialDay;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.SpecialDay;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.SpecialDay;
|
||||
using Jailbreak.Public.Mod.SpecialDay.Enums;
|
||||
using Jailbreak.Public.Utils;
|
||||
|
||||
namespace Jailbreak.SpecialDay.SpecialDays;
|
||||
|
||||
public class HEDay(BasePlugin plugin, IServiceProvider provider)
|
||||
: AbstractSpecialDay(plugin, provider), ISpecialDayMessageProvider {
|
||||
public override SDType Type => SDType.HE;
|
||||
public override SpecialDaySettings Settings => new HESettings();
|
||||
|
||||
public ISDInstanceLocale Locale
|
||||
=> new SoloDayLocale("HE Only",
|
||||
"Grenades Only—No guns. Fight against everyone else. No Camping!");
|
||||
|
||||
public override void Setup() {
|
||||
Plugin.RegisterEventHandler<EventGrenadeThrown>(onThrow);
|
||||
Timers[10] += () => Locale.BeginsIn(10).ToAllChat();
|
||||
Timers[15] += () => Locale.BeginsIn(5).ToAllChat();
|
||||
Timers[20] += Execute;
|
||||
|
||||
base.Setup();
|
||||
}
|
||||
|
||||
public override void Execute() {
|
||||
foreach (var player in PlayerUtil.GetAlive())
|
||||
player.GiveNamedItem("weapon_hegrenade");
|
||||
base.Execute();
|
||||
Locale.BeginsIn(0).ToAllChat();
|
||||
}
|
||||
|
||||
private HookResult onThrow(EventGrenadeThrown @event, GameEventInfo info) {
|
||||
var player = @event.Userid;
|
||||
if (player == null || !player.IsReal() || !player.PawnIsAlive)
|
||||
return HookResult.Continue;
|
||||
player.GiveNamedItem("weapon_hegrenade");
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
override protected HookResult
|
||||
OnEnd(EventRoundEnd @event, GameEventInfo info) {
|
||||
var result = base.OnEnd(@event, info);
|
||||
Plugin.DeregisterEventHandler<EventGrenadeThrown>(onThrow);
|
||||
return result;
|
||||
}
|
||||
|
||||
public class HESettings : SpecialDaySettings {
|
||||
public HESettings() {
|
||||
CtTeleport = TeleportType.RANDOM;
|
||||
TTeleport = TeleportType.RANDOM;
|
||||
StripToKnife = true;
|
||||
WithFriendlyFire();
|
||||
}
|
||||
|
||||
public override float FreezeTime(CCSPlayerController player) { return 1; }
|
||||
|
||||
public override ISet<string>? AllowedWeapons(CCSPlayerController player) {
|
||||
return new HashSet<string> {"weapon_hegrenade"};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,10 @@ using Jailbreak.Formatting.Base;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.SpecialDay;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.LastRequest;
|
||||
using Jailbreak.Public.Mod.SpecialDay;
|
||||
using Jailbreak.Public.Mod.SpecialDay.Enums;
|
||||
using Jailbreak.Public.Utils;
|
||||
using Jailbreak.Validator;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Jailbreak.SpecialDay.SpecialDays;
|
||||
|
||||
@@ -145,24 +143,12 @@ public class HideAndSeekDay(BasePlugin plugin, IServiceProvider provider)
|
||||
foreach (var ct in PlayerUtil.FromTeam(HiderTeam.Value)) ct.SetSpeed(1);
|
||||
}
|
||||
|
||||
override protected void OnTick() {
|
||||
var lr = Provider.GetService<ILastRequestManager>();
|
||||
if (lr == null) {
|
||||
base.OnTick();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lr.IsLREnabled) return;
|
||||
base.OnTick();
|
||||
}
|
||||
|
||||
public class HnsSettings : SpecialDaySettings {
|
||||
private readonly ISet<string>? cachedGuardWeapons, cachedPrisonerWeapons;
|
||||
|
||||
public HnsSettings() {
|
||||
AllowLastRequests = true;
|
||||
TTeleport = TeleportType.ARMORY;
|
||||
CtTeleport = TeleportType.ARMORY;
|
||||
TTeleport = TeleportType.ARMORY;
|
||||
CtTeleport = TeleportType.ARMORY;
|
||||
|
||||
cachedGuardWeapons = CV_GUARD_WEAPONS.Value.Split(",").ToHashSet();
|
||||
cachedPrisonerWeapons = CV_PRISONER_WEAPONS.Value.Split(",").ToHashSet();
|
||||
@@ -188,5 +174,9 @@ public class HideAndSeekDay(BasePlugin plugin, IServiceProvider provider)
|
||||
cachedPrisonerWeapons :
|
||||
cachedGuardWeapons;
|
||||
}
|
||||
|
||||
public override float FreezeTime(CCSPlayerController player) {
|
||||
return player.Team == CsTeam.CounterTerrorist ? 3 : 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Jailbreak.SpecialDay.SpecialDays;
|
||||
public class InfectionDay(BasePlugin plugin, IServiceProvider provider)
|
||||
: AbstractArmoryRestrictedDay(plugin, provider, CsTeam.CounterTerrorist),
|
||||
ISpecialDayMessageProvider {
|
||||
private readonly ICollection<int> swappedPrisoners = new HashSet<int>();
|
||||
private readonly ICollection< CCSPlayerController> swappedPrisoners = new HashSet<CCSPlayerController>();
|
||||
|
||||
public override SDType Type => SDType.INFECTION;
|
||||
|
||||
@@ -74,7 +74,7 @@ public class InfectionDay(BasePlugin plugin, IServiceProvider provider)
|
||||
target.PlayerPawn.Value!.AbsOrigin!.Clone() :
|
||||
pos;
|
||||
|
||||
swappedPrisoners.Add(player.Slot);
|
||||
swappedPrisoners.Add(player);
|
||||
if (!player.IsValid) return HookResult.Continue;
|
||||
|
||||
msg.YouWereInfectedMessage(
|
||||
@@ -107,7 +107,7 @@ public class InfectionDay(BasePlugin plugin, IServiceProvider provider)
|
||||
var hp = Settings.InitialHealth(player);
|
||||
if (hp != -1) Plugin.AddTimer(0.1f, () => { player.SetHealth(hp); });
|
||||
|
||||
var color = swappedPrisoners.Contains(player.Slot) ?
|
||||
var color = swappedPrisoners.Contains(player) ?
|
||||
Color.DarkOliveGreen :
|
||||
Color.ForestGreen;
|
||||
player.SetColor(color);
|
||||
@@ -120,29 +120,25 @@ public class InfectionDay(BasePlugin plugin, IServiceProvider provider)
|
||||
Plugin.DeregisterEventHandler<EventPlayerDeath>(onPlayerDeath);
|
||||
Plugin.DeregisterEventHandler<EventPlayerSpawn>(onRespawn);
|
||||
|
||||
Plugin.AddTimer(0.5f, () => {
|
||||
foreach (var index in swappedPrisoners) {
|
||||
var player = Utilities.GetPlayerFromSlot(index);
|
||||
if (player == null || !player.IsValid) continue;
|
||||
player.SwitchTeam(CsTeam.Terrorist);
|
||||
}
|
||||
});
|
||||
foreach (var player in swappedPrisoners) {
|
||||
if (!player.IsValid) continue;
|
||||
player.SwitchTeam(CsTeam.Terrorist);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public class InfectionSettings : SpecialDaySettings {
|
||||
public InfectionSettings() {
|
||||
CtTeleport = TeleportType.ARMORY;
|
||||
TTeleport = TeleportType.RANDOM;
|
||||
RestrictWeapons = true;
|
||||
CtTeleport = TeleportType.ARMORY;
|
||||
TTeleport = TeleportType.RANDOM;
|
||||
|
||||
WithRespawns(CsTeam.CounterTerrorist);
|
||||
}
|
||||
|
||||
public override ISet<string>? AllowedWeapons(CCSPlayerController player) {
|
||||
return player.Team == CsTeam.CounterTerrorist ?
|
||||
Tag.UTILITY.Union(Tag.PISTOLS).ToHashSet() :
|
||||
Tag.UTILITY.Union(Tag.KNIVES).Union(Tag.PISTOLS).ToHashSet() :
|
||||
null;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,5 +109,11 @@ public class NoScopeDay(BasePlugin plugin, IServiceProvider provider)
|
||||
}
|
||||
|
||||
public override float FreezeTime(CCSPlayerController player) { return 1; }
|
||||
|
||||
public override ISet<string>? AllowedWeapons(CCSPlayerController player) {
|
||||
return CV_WEAPON_WHITELIST.Value.Length == 0 ?
|
||||
null :
|
||||
CV_WEAPON_WHITELIST.Value.Split(",").ToHashSet();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider)
|
||||
"Additional (non-ammo restricted) weapons to give for the day",
|
||||
"weapon_knife", ConVarFlags.FCVAR_NONE, new ItemValidator());
|
||||
|
||||
private bool started;
|
||||
public override SDType Type => SDType.OITC;
|
||||
|
||||
public override SpecialDaySettings Settings => new OitcSettings();
|
||||
@@ -37,13 +36,11 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider)
|
||||
Timers[15] += () => Locale.BeginsIn(5).ToAllChat();
|
||||
Timers[20] += Execute;
|
||||
base.Setup();
|
||||
Plugin.RegisterEventHandler<EventItemPickup>(OnPickup);
|
||||
Plugin.RegisterEventHandler<EventPlayerHurt>(OnPlayerDamage);
|
||||
Plugin.RegisterEventHandler<EventPlayerDeath>(OnPlayerDeath);
|
||||
}
|
||||
|
||||
public override void Execute() {
|
||||
base.Execute();
|
||||
Locale.BeginsIn(0).ToAllChat();
|
||||
|
||||
foreach (var player in PlayerUtil.GetAlive()) {
|
||||
@@ -56,16 +53,7 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider)
|
||||
}
|
||||
}
|
||||
|
||||
started = true;
|
||||
}
|
||||
|
||||
protected HookResult OnPickup(EventItemPickup @event, GameEventInfo info) {
|
||||
if (!started) return HookResult.Continue;
|
||||
|
||||
var player = @event.Userid;
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
player.RemoveWeapons();
|
||||
return HookResult.Continue;
|
||||
base.Execute();
|
||||
}
|
||||
|
||||
private HookResult
|
||||
@@ -89,7 +77,6 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider)
|
||||
OnEnd(EventRoundEnd @event, GameEventInfo info) {
|
||||
Plugin.DeregisterEventHandler<EventPlayerHurt>(OnPlayerDamage);
|
||||
Plugin.DeregisterEventHandler<EventPlayerDeath>(OnPlayerDeath);
|
||||
Plugin.DeregisterEventHandler<EventItemPickup>(OnPickup);
|
||||
return base.OnEnd(@event, info);
|
||||
}
|
||||
|
||||
@@ -103,9 +90,7 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider)
|
||||
}
|
||||
|
||||
public override ISet<string> AllowedWeapons(CCSPlayerController player) {
|
||||
return new HashSet<string> {
|
||||
CV_WEAPON.Value, CV_ADDITIONAL_WEAPON.Value
|
||||
};
|
||||
return new HashSet<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
321
mod/Jailbreak.SpecialDay/SpecialDays/RocketJumpDay.cs
Normal file
321
mod/Jailbreak.SpecialDay/SpecialDays/RocketJumpDay.cs
Normal file
@@ -0,0 +1,321 @@
|
||||
using System.Numerics;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Cvars.Validators;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.UserMessages;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.English.SpecialDay;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.SpecialDay;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.SpecialDay;
|
||||
using Jailbreak.Public.Mod.SpecialDay.Enums;
|
||||
using Jailbreak.Public.Utils;
|
||||
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
|
||||
|
||||
namespace Jailbreak.SpecialDay.SpecialDays;
|
||||
public class RocketJumpDay(BasePlugin plugin, IServiceProvider provider)
|
||||
: AbstractSpecialDay(plugin, provider), ISpecialDayMessageProvider {
|
||||
public static readonly FakeConVar<float> CV_BULLET_SPEED = new(
|
||||
"css_jb_rj_bullet_speed", "Speed of the projectile bullet.", 1250.0f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(100f, 5000f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_MAX_DISTANCE = new(
|
||||
"css_jb_rj_max_distance", "Max distance to apply rocketjump.", 160.0f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(1f, 1000f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_CLOSE_JUMP_DISTANCE = new(
|
||||
"css_jb_rj_close_jump_distance",
|
||||
"Max distance that causes a full force jump.", 37.0f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(1f, 1000f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_JUMP_FORCE_MAIN = new(
|
||||
"css_jb_rj_jump_force_main", "Base jump push strength.", 270.0f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(0f, 2000f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_JUMP_FORCE_UP = new(
|
||||
"css_jb_rj_jump_force_up", "Vertical boost on rocketjump.", 8.0f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(0f, 500f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_JUMP_FORCE_FORWARD = new(
|
||||
"css_jb_rj_jump_force_forward", "Forward scale on rocketjump.", 1.2f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(0f, 10f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_JUMP_FORCE_BACKWARD = new(
|
||||
"css_jb_rj_jump_force_backward", "Backward scale on rocketjump.", 1.25f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(0f, 10f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_RUN_FORCE_MAIN = new(
|
||||
"css_jb_rj_run_force_main", "Extra boost if running.", 0.8f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(0f, 10f));
|
||||
|
||||
public static readonly FakeConVar<bool> CV_PROJ_INHERIT_PLAYER_VELOCITY = new(
|
||||
"css_jb_rj_proj_inherit_player_velocity",
|
||||
"Whether the projectile inherits player velocity. "
|
||||
+ "True allows for easier rocket jumps at the cost of 'funky' shot paths when trying to shoot a player");
|
||||
|
||||
public static readonly FakeConVar<float> CV_PROJ_DAMAGE = new(
|
||||
"css_jb_rj_proj_damage", "The damage caused by projectile explosion", 65f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(1f, 200f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_PROJ_DAMAGE_RADIUS = new(
|
||||
"css_jb_rj_proj_damage_radius",
|
||||
"The radius of the explosion caused by projectile", 225f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(1f, 1000f));
|
||||
|
||||
public static readonly FakeConVar<float> CV_PROJ_GRAVITY = new(
|
||||
"css_jb_rj_proj_gravity", "The gravity of the projectile.", 0.001f,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<float>(0.001f, 2000f));
|
||||
|
||||
private const int GE_FIRE_BULLETS_ID = 452;
|
||||
|
||||
// Thank you https://github.com/ipsvn/cs2-Rocketjump/tree/master
|
||||
private readonly MemoryFunctionVoid<nint, nint> touch =
|
||||
new("55 48 89 E5 41 54 49 89 F4 53 48 8B 87");
|
||||
|
||||
private readonly HashSet<CCSPlayerPawn> jumping = [];
|
||||
private Dictionary<ulong, float> nextNova = new();
|
||||
|
||||
public override SDType Type => SDType.ROCKETJUMP;
|
||||
public override SpecialDaySettings Settings => new RocketJumpSettings();
|
||||
|
||||
public ISDInstanceLocale Locale
|
||||
=> new SoloDayLocale("Rocket Jump",
|
||||
"Your shotgun is now an RPG that fires grenades! "
|
||||
+ "Shoot the ground to launch! " + "Mid-air knives Insta-kill!");
|
||||
|
||||
public override void Setup() {
|
||||
Plugin.HookUserMessage(GE_FIRE_BULLETS_ID, fireBulletsUmHook);
|
||||
touch.Hook(CBaseEntity_Touch, HookMode.Pre);
|
||||
Plugin.RegisterEventHandler<EventWeaponFire>(onWeaponFire);
|
||||
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(onHurt, HookMode.Pre);
|
||||
Plugin.RegisterListener<Listeners.OnTick>(onTick);
|
||||
|
||||
Timers[10] += () => Locale.BeginsIn(10).ToAllChat();
|
||||
Timers[15] += () => Locale.BeginsIn(5).ToAllChat();
|
||||
Timers[20] += () => {
|
||||
Execute();
|
||||
Locale.BeginsIn(0).ToAllChat();
|
||||
};
|
||||
|
||||
base.Setup();
|
||||
}
|
||||
|
||||
public override void Execute() {
|
||||
foreach (var player in PlayerUtil.GetAlive()) {
|
||||
player.RemoveWeapons();
|
||||
player.SetArmor(0);
|
||||
player.GiveNamedItem("weapon_knife");
|
||||
player.GiveNamedItem("weapon_nova");
|
||||
}
|
||||
base.Execute();
|
||||
}
|
||||
|
||||
override protected HookResult OnEnd(EventRoundEnd ev, GameEventInfo info) {
|
||||
Plugin.UnhookUserMessage(GE_FIRE_BULLETS_ID, fireBulletsUmHook);
|
||||
touch.Unhook(CBaseEntity_Touch, HookMode.Pre);
|
||||
Plugin.DeregisterEventHandler<EventWeaponFire>(onWeaponFire);
|
||||
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(onHurt, HookMode.Pre);
|
||||
Plugin.RemoveListener<Listeners.OnTick>(onTick);
|
||||
|
||||
// Delay to avoid mutation during hook execution
|
||||
Server.NextFrameAsync(() => { jumping.Clear(); });
|
||||
|
||||
return base.OnEnd(ev, info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears recipients of the Nova bullet pellets to hide it from everyone.
|
||||
/// Give cleaner shot effect and removes unecessary rendering
|
||||
/// </summary>
|
||||
private HookResult fireBulletsUmHook(UserMessage um) {
|
||||
um.Recipients.Clear();
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles when the grenade touches something.
|
||||
/// Triggers a rocket jump for its owner if nearby.
|
||||
/// Uses CHEGrenadeProjectile for built-in AoE, visibility, and raycast-like behavior.
|
||||
/// This is prefered b/c using a raycast would require custom logic for:
|
||||
/// -Damage radius simulation, Entity filtering, Visual/audio, feedback Manual hit registration
|
||||
/// </summary>
|
||||
private HookResult CBaseEntity_Touch(DynamicHook hook) {
|
||||
var projectile = hook.GetParam<CHEGrenadeProjectile>(0);
|
||||
if (projectile.DesignerName != "hegrenade_projectile")
|
||||
return HookResult.Continue;
|
||||
|
||||
var owner = projectile.OwnerEntity.Value?.As<CCSPlayerPawn>();
|
||||
if (owner == null || owner.DesignerName != "player")
|
||||
return HookResult.Continue;
|
||||
|
||||
var bulletOrigin = projectile.AbsOrigin;
|
||||
var pawnOrigin = owner.AbsOrigin;
|
||||
if (bulletOrigin == null || pawnOrigin == null) return HookResult.Continue;
|
||||
|
||||
var eyeOrigin = owner.GetEyeOrigin();
|
||||
var distance = Vector3.Distance(bulletOrigin.ToVec3(), pawnOrigin.ToVec3());
|
||||
|
||||
projectile.DetonateTime = 0f;
|
||||
doJump(owner, distance, bulletOrigin.ToVec3(), eyeOrigin);
|
||||
|
||||
return HookResult.Handled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detects Nova shots and spawns a grenade projectile in the direction the player is aiming.
|
||||
/// </summary>
|
||||
private HookResult onWeaponFire(EventWeaponFire @event, GameEventInfo info) {
|
||||
var controller = @event.Userid;
|
||||
if (controller == null) return HookResult.Continue;
|
||||
|
||||
var weapon = @event.Weapon;
|
||||
if (weapon != "weapon_nova") return HookResult.Continue;
|
||||
|
||||
var sid = controller.SteamID;
|
||||
var now = Server.CurrentTime;
|
||||
|
||||
if (nextNova.TryGetValue(sid, out var next) && now < next)
|
||||
return HookResult.Continue;
|
||||
|
||||
nextNova[sid] = now + 0.82f;
|
||||
|
||||
var pawn = controller.PlayerPawn.Value;
|
||||
var origin = pawn?.AbsOrigin;
|
||||
if (pawn == null || origin == null) return HookResult.Continue;
|
||||
pawn.GetEyeForward(10.0f, out var forwardDir, out var targetPos);
|
||||
|
||||
var realBulletVelocity = forwardDir * CV_BULLET_SPEED.Value;
|
||||
var addedBulletVelocity = CV_PROJ_INHERIT_PLAYER_VELOCITY.Value ?
|
||||
pawn.AbsVelocity.ToVec3() + realBulletVelocity :
|
||||
realBulletVelocity;
|
||||
shootBullet(controller, targetPos, addedBulletVelocity,
|
||||
new Vector3(origin.X, origin.Y, (float)(origin.Z + 64.09)));
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes knife hits lethal only if the attacker is airborne via rocket jump.
|
||||
/// Nullifies Nova Pellet Damage
|
||||
/// Passes Grenades Per Usual
|
||||
/// </summary>
|
||||
private HookResult onHurt(DynamicHook hook) {
|
||||
var info = hook.GetParam<CTakeDamageInfo>(1);
|
||||
var attacker = info.Attacker.Value?.As<CCSPlayerPawn>();
|
||||
var weaponName = info.Ability.Value?.As<CCSWeaponBase>().VData?.Name;
|
||||
|
||||
if (attacker == null || weaponName == null) return HookResult.Continue;
|
||||
|
||||
if (weaponName.Contains("grenade")) return HookResult.Continue;
|
||||
|
||||
if (!weaponName.Contains("knife") && !weaponName.Contains("bayonet"))
|
||||
return HookResult.Handled;
|
||||
|
||||
if (jumping.Contains(attacker)) info.Damage = 200f;
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Continuously removes players from the "jumping" list once they land.
|
||||
/// </summary>
|
||||
private void onTick() {
|
||||
foreach (var player in jumping.Where(p => p.OnGroundLastTick).ToList())
|
||||
jumping.Remove(player);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns and launches a CHEGrenadeProjectile with explosive properties like radius and damage.
|
||||
/// </summary>
|
||||
private void shootBullet(CCSPlayerController controller, Vector3 origin,
|
||||
Vector3 velocity, Vector3 angle) {
|
||||
var pawn = controller.PlayerPawn.Value;
|
||||
if (pawn == null) return;
|
||||
|
||||
var projectile =
|
||||
Utilities
|
||||
.CreateEntityByName<CHEGrenadeProjectile>("hegrenade_projectile");
|
||||
if (projectile == null) return;
|
||||
|
||||
projectile.OwnerEntity.Raw = pawn.EntityHandle.Raw;
|
||||
projectile.Damage = CV_PROJ_DAMAGE.Value;
|
||||
projectile.DmgRadius = CV_PROJ_DAMAGE_RADIUS.Value;
|
||||
projectile.DispatchSpawn();
|
||||
projectile.AcceptInput("InitializeSpawnFromWorld", pawn, pawn);
|
||||
Schema.SetSchemaValue(projectile.Handle, "CBaseGrenade", "m_hThrower",
|
||||
pawn.EntityHandle.Raw);
|
||||
projectile.GravityScale = CV_PROJ_GRAVITY.Value;
|
||||
projectile.DetonateTime = 9999f;
|
||||
|
||||
// Set transform BY VALUE (no unsafe pointers)
|
||||
var pos = new Vector(origin.X, origin.Y, origin.Z);
|
||||
var vel = new Vector(velocity.X, velocity.Y, velocity.Z);
|
||||
var ang = new QAngle(angle.X, angle.Y, angle.Z);
|
||||
|
||||
projectile.Teleport(pos, ang, vel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates and applies rocket jump force based on distance and direction.
|
||||
/// Combines player velocity with a directional push, scaled by angle and proximity.
|
||||
/// Adds upward force and modifies Z for vertical boost.
|
||||
/// </summary>
|
||||
private void doJump(CCSPlayerPawn pawn, float distance, Vector3 bulletOrigin,
|
||||
Vector3 pawnOrigin) {
|
||||
if (distance >= CV_MAX_DISTANCE.Value) return;
|
||||
|
||||
var down = false;
|
||||
var direction = Vector3.Normalize(pawnOrigin - bulletOrigin);
|
||||
if (direction.Z < 0) down = true;
|
||||
|
||||
var pawnVelocity = pawn.AbsVelocity;
|
||||
var movementDir =
|
||||
Vector3.Normalize(new Vector3(pawnVelocity.X, pawnVelocity.Y, 0));
|
||||
|
||||
var dot = Vector3.Dot(direction, movementDir);
|
||||
var scale = dot >= 0 ?
|
||||
CV_JUMP_FORCE_FORWARD.Value :
|
||||
CV_JUMP_FORCE_BACKWARD.Value;
|
||||
|
||||
var velocity = direction * CV_JUMP_FORCE_MAIN.Value;
|
||||
var totalVelocity = (pawnVelocity.ToVec3() + velocity) * scale;
|
||||
pawnVelocity.Z = 0.0f;
|
||||
totalVelocity.Z = 0.0f;
|
||||
|
||||
if (pawn.OnGroundLastTick) totalVelocity *= CV_RUN_FORCE_MAIN.Value;
|
||||
|
||||
var forceUp = CV_JUMP_FORCE_UP.Value * (CV_MAX_DISTANCE.Value - distance);
|
||||
if (distance > CV_CLOSE_JUMP_DISTANCE.Value)
|
||||
if (totalVelocity.Z > 0.0f)
|
||||
totalVelocity.Z = 1000.0f + forceUp;
|
||||
else
|
||||
totalVelocity.Z += forceUp;
|
||||
else
|
||||
totalVelocity.Z += forceUp / 1.37f;
|
||||
if (down) velocity.Z *= -1.0f;
|
||||
unsafe { pawn.Teleport(null, null, new Vector((nint)(&totalVelocity))); }
|
||||
|
||||
jumping.Add(pawn);
|
||||
}
|
||||
|
||||
public class RocketJumpSettings : SpecialDaySettings {
|
||||
public RocketJumpSettings() {
|
||||
CtTeleport = TeleportType.RANDOM;
|
||||
TTeleport = TeleportType.RANDOM;
|
||||
StripToKnife = true;
|
||||
WithFriendlyFire();
|
||||
|
||||
ConVarValues["sv_infinite_ammo"] = 1;
|
||||
ConVarValues["mp_death_drop_gun"] = 0;
|
||||
ConVarValues["ff_damage_reduction_grenade_self"] = 0f;
|
||||
ConVarValues["sv_falldamage_scale"] = 0f;
|
||||
}
|
||||
|
||||
public override float FreezeTime(CCSPlayerController player) { return 1; }
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Cvars.Validators;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.English.SpecialDay;
|
||||
@@ -28,7 +29,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider)
|
||||
|
||||
public static readonly FakeConVar<int> CV_INITIAL_SPEEDRUN_TIME =
|
||||
new("css_jb_speedrun_initial_time",
|
||||
"Duration in seconds to grant the speedrunner", 30);
|
||||
"Duration in seconds to grant the speedrunner", 20);
|
||||
|
||||
public static readonly FakeConVar<int> CV_FIRST_ROUND_FREEZE =
|
||||
new("css_jb_speedrun_first_round_freeze",
|
||||
@@ -122,9 +123,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider)
|
||||
generics = Provider.GetRequiredService<IGenericCmdLocale>();
|
||||
|
||||
foreach (var player in Utilities.GetPlayers()
|
||||
.Where(p => p is {
|
||||
PawnIsAlive: false, Team: CsTeam.Terrorist or CsTeam.CounterTerrorist
|
||||
}))
|
||||
.Where(p => p is { Team: CsTeam.Terrorist or CsTeam.CounterTerrorist }))
|
||||
player.Respawn();
|
||||
|
||||
speedrunner = getRunner();
|
||||
@@ -666,7 +665,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider)
|
||||
|
||||
if (aliveCount <= CV_MAX_PLAYERS_TO_FINISH.Value) {
|
||||
if (finishTimestampList.Count == 0) {
|
||||
generics.Error("No slowest times found").ToAllChat();
|
||||
panic("No slowest times found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -700,6 +699,9 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider)
|
||||
|
||||
if (CV_WINNER_DAMAGEABLE.Value) EnableDamage(winner);
|
||||
|
||||
VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Unhook(
|
||||
OnCanAcquire, HookMode.Pre);
|
||||
|
||||
foreach (var weapon in CV_LOSERS_WEAPONS.Value.Split(','))
|
||||
foreach (var loser in losers)
|
||||
loser.GiveNamedItem(weapon);
|
||||
@@ -708,7 +710,6 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider)
|
||||
winner.GiveNamedItem(weapon);
|
||||
|
||||
Plugin.RemoveListener<Listeners.OnTick>(checkFinishers);
|
||||
Plugin.RemoveListener<Listeners.OnTick>(OnTick);
|
||||
RoundUtil.SetTimeRemaining(Math.Min(timeToSet, CV_WIN_TIME_MAX.Value));
|
||||
Server.ExecuteCommand("mp_ignore_round_win_conditions 0");
|
||||
return;
|
||||
@@ -780,15 +781,13 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider)
|
||||
|
||||
private int getEliminations(int players) {
|
||||
return players switch {
|
||||
<= 3 => 1,
|
||||
<= 4 => 2,
|
||||
<= 6 => 2,
|
||||
<= 4 => 1,
|
||||
<= 8 => 3,
|
||||
<= 12 => 3,
|
||||
<= 20 => 6,
|
||||
<= 12 => 4,
|
||||
<= 20 => 5,
|
||||
<= 35 => 8,
|
||||
<= 40 => 10,
|
||||
<= 64 => 12,
|
||||
<= 64 => 15,
|
||||
_ => players / 5
|
||||
};
|
||||
}
|
||||
@@ -828,7 +827,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider)
|
||||
TTeleport = TeleportType.RANDOM_STACKED;
|
||||
StripToKnife = true;
|
||||
ConVarValues["mp_ignore_round_win_conditions"] = true;
|
||||
if (new Random().Next(5) == 0) WithAutoBhop();
|
||||
if (new Random().Next(3) == 0) WithAutoBhop();
|
||||
WithFriendlyFire();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public class WardayDay(BasePlugin plugin, IServiceProvider provider)
|
||||
}
|
||||
|
||||
public override float FreezeTime(CCSPlayerController player) {
|
||||
return player.Team == CsTeam.CounterTerrorist ? 3 : 5;
|
||||
return player.Team == CsTeam.CounterTerrorist ? 3 : 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
160
mod/Jailbreak.Warden/Commands/CountdownCommandBehavior.cs
Normal file
160
mod/Jailbreak.Warden/Commands/CountdownCommandBehavior.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views;
|
||||
using Jailbreak.Formatting.Views.Warden;
|
||||
using Jailbreak.Public.Behaviors;
|
||||
using Jailbreak.Public.Mod.Mute;
|
||||
using Jailbreak.Public.Mod.Warden;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using Jailbreak.Formatting.Base;
|
||||
using Jailbreak.Formatting.Core;
|
||||
using Jailbreak.Formatting.Objects;
|
||||
|
||||
public class CountdownCommandBehavior(IWardenService warden, IMuteService mute,
|
||||
IWardenLocale wardenLocale, IGenericCmdLocale generics) : IPluginBehavior {
|
||||
|
||||
public static readonly FakeConVar<int> CV_WARDEN_MAX_COUNTDOWN =
|
||||
new("css_jb_warden_countdown_max",
|
||||
"The maximum duration for a countdown", 15);
|
||||
|
||||
public static readonly FakeConVar<int> CV_WARDEN_MIN_COUNTDOWN =
|
||||
new("css_jb_warden_countdown_min",
|
||||
"The minimum duration for a countdown", 3);
|
||||
|
||||
public static readonly FakeConVar<int> CV_WARDEN_DEFAULT_COUNTDOWN =
|
||||
new("css_jb_warden_countdown_default",
|
||||
"The default duration for a countdown", 5);
|
||||
|
||||
private DateTime lastCountdown = DateTime.MinValue;
|
||||
private int countdownDuration;
|
||||
|
||||
[ConsoleCommand("css_countdown",
|
||||
"Invokes a countdown "
|
||||
+ "that will display in chat and notify Ts when to go (for a game or to follow a command) "
|
||||
+ "If no duration is provided it will default to 5 seconds. "
|
||||
+ "Maximum duration of 15 seconds. Minimum duration of 3 seconds.")]
|
||||
|
||||
public void Command_Countdown(CCSPlayerController? executor, CommandInfo command) {
|
||||
// Set duration of countdown
|
||||
countdownDuration = CV_WARDEN_DEFAULT_COUNTDOWN.Value;
|
||||
|
||||
// Ensure countdown duration is within acceptable range
|
||||
if (command.ArgCount == 2) {
|
||||
if (!int.TryParse(command.GetArg(1), out countdownDuration)) {
|
||||
generics.InvalidParameter(command.GetArg(1), "number");
|
||||
command.ReplyToCommand("Expected a number parameter.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (countdownDuration <= 0) {
|
||||
generics.InvalidParameter(command.GetArg(1), "number greater than 0");
|
||||
command.ReplyToCommand("Expected a number greater than 0.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (countdownDuration < CV_WARDEN_MIN_COUNTDOWN.Value) {
|
||||
generics.InvalidParameter(command.GetArg(1),
|
||||
$"number greater than or equal to {CV_WARDEN_MIN_COUNTDOWN.Value}");
|
||||
command.ReplyToCommand($"Expected a number greater than or equal to {CV_WARDEN_MIN_COUNTDOWN.Value}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (countdownDuration > CV_WARDEN_MAX_COUNTDOWN.Value) {
|
||||
generics.InvalidParameter(command.GetArg(1),
|
||||
$"number less than or equal to {CV_WARDEN_MAX_COUNTDOWN.Value}");
|
||||
command.ReplyToCommand($"Expected a number less than or equal to {CV_WARDEN_MAX_COUNTDOWN.Value}");
|
||||
return;
|
||||
}
|
||||
//
|
||||
|
||||
// Check perm and enact peace
|
||||
bool success = PermCheckAndEnactPeace(executor);
|
||||
if (!success) return;
|
||||
|
||||
// Inform players of countdown
|
||||
StartCountDown(countdownDuration);
|
||||
|
||||
// Create callbacks each second less than 5 or divisible by 5 to notify players of countdown time remaining / completion of countdown
|
||||
for (int i = countdownDuration; i > 0; --i) {
|
||||
int current = i; // lambda capture
|
||||
|
||||
if (current <= 5 || current % 5 == 0) {
|
||||
Server.RunOnTick(Server.TickCount + (64 * (countdownDuration - current)),
|
||||
() => PrintCountdownToPlayers(current));
|
||||
}
|
||||
}
|
||||
Server.RunOnTick(Server.TickCount + (64 * countdownDuration), () => PrintGoToPlayers());
|
||||
}
|
||||
|
||||
// Is this okay?
|
||||
// Feels like bad encapsulation
|
||||
private static readonly FormatObject PREFIX =
|
||||
new HiddenFormatObject($" {ChatColors.DarkBlue}Countdown>") {
|
||||
Plain = false, Panorama = false, Chat = true
|
||||
};
|
||||
|
||||
private void StartCountDown(int duration) {
|
||||
new SimpleView { PREFIX, $"A {duration} second countdown has begun!" }.ToAllChat();
|
||||
}
|
||||
|
||||
private void PrintCountdownToPlayers(int seconds) {
|
||||
new SimpleView { PREFIX, seconds.ToString() }.ToAllChat();
|
||||
|
||||
// var players = Utilities.GetPlayers();
|
||||
// foreach (var player in players) {
|
||||
// player.ExecuteClientCommand("play buttons\\blip1");
|
||||
// }
|
||||
}
|
||||
|
||||
private void PrintGoToPlayers() {
|
||||
new SimpleView { PREFIX, "GO! GO! GO!" }.ToAllChat();
|
||||
|
||||
// var players = Utilities.GetPlayers();
|
||||
// foreach (var player in players) {
|
||||
// player.ExecuteClientCommand("play \\sounds\\vo\\agents\\balkan\\radio_letsgo01.vsnd_c");
|
||||
// }
|
||||
}
|
||||
//
|
||||
|
||||
// Check permissions and attempt to enact a period of peace for players to focus on the countdown
|
||||
private bool PermCheckAndEnactPeace(CCSPlayerController? executor) {
|
||||
var fromWarden = executor != null && warden.IsWarden(executor);
|
||||
|
||||
if (executor == null
|
||||
|| AdminManager.PlayerHasPermissions(executor, "@css/cheats")) {
|
||||
// Server console or a high-admin is invoking the peace period, bypass cooldown
|
||||
mute.PeaceMute(MuteReason.ADMIN);
|
||||
lastCountdown = DateTime.Now;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!fromWarden
|
||||
&& AdminManager.PlayerHasPermissions(executor, "@css/chat")) {
|
||||
mute.PeaceMute(MuteReason.ADMIN);
|
||||
lastCountdown = DateTime.Now;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DateTime.Now - lastCountdown < TimeSpan.FromSeconds(60)) {
|
||||
generics.CommandOnCooldown(lastCountdown.AddSeconds(60))
|
||||
.ToChat(executor);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fromWarden) {
|
||||
mute.PeaceMute(fromWarden ? MuteReason.WARDEN_INVOKED : MuteReason.ADMIN);
|
||||
lastCountdown = DateTime.Now;
|
||||
return true;
|
||||
} else {
|
||||
wardenLocale.NotWarden.ToChat(executor);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -16,19 +16,11 @@ public class SoccerCommandBehavior(IWardenService warden,
|
||||
new("css_jb_max_soccers",
|
||||
"The maximum number of soccer balls that the warden can spawn", 3);
|
||||
|
||||
private int soccers;
|
||||
|
||||
public void Start(BasePlugin basePlugin) {
|
||||
basePlugin.RegisterListener<Listeners.OnServerPrecacheResources>(manifest
|
||||
=> {
|
||||
manifest.AddResource(
|
||||
"models/props/de_dust/hr_dust/dust_soccerball/dust_soccer_ball001.vmdl");
|
||||
});
|
||||
}
|
||||
private int soccerBalls;
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) {
|
||||
soccers = 0;
|
||||
soccerBalls = 0;
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
@@ -42,7 +34,7 @@ public class SoccerCommandBehavior(IWardenService warden,
|
||||
return;
|
||||
}
|
||||
|
||||
if (soccers >= CV_MAX_SOCCERS.Value) {
|
||||
if (soccerBalls >= CV_MAX_SOCCERS.Value) {
|
||||
locale.TooManySoccers.ToChat(player);
|
||||
return;
|
||||
}
|
||||
@@ -66,6 +58,6 @@ public class SoccerCommandBehavior(IWardenService warden,
|
||||
ball.Teleport(loc);
|
||||
locale.SoccerSpawned.ToAllChat();
|
||||
ball.DispatchSpawn();
|
||||
soccers++;
|
||||
soccerBalls++;
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,12 @@ public class SpecialTreatmentCommandsBehavior(IWardenService warden,
|
||||
// TODO: Pop up menu of prisoners to toggle ST for
|
||||
return;
|
||||
|
||||
// FIXME: Remove after @aim is fixed in CSS
|
||||
if (command.ArgByIndex(1).ToLower().Contains("@aim")) {
|
||||
command.ReplyToCommand("@aim is currently not supported due to a bug in CSS.");
|
||||
return;
|
||||
}
|
||||
|
||||
var targets = command.GetArgTargetResult(1);
|
||||
var eligible = targets
|
||||
.Where(p => p is { Team: CsTeam.Terrorist, PawnIsAlive: true })
|
||||
|
||||
@@ -28,17 +28,15 @@ public class SpecialIconBehavior(ITextSpawner spawner)
|
||||
|
||||
if (playerStats == null) return SpecialIcon.DEFAULT.GetIcon();
|
||||
|
||||
var (success, icon) =
|
||||
var icon =
|
||||
await playerStats.GetForPlayer<SpecialIcon>(player,
|
||||
SpecialIconPerk.STAT_ID);
|
||||
|
||||
if (!success) icon = SpecialIcon.DEFAULT;
|
||||
|
||||
if (gangStats == null || players == null) return icon.GetIcon();
|
||||
|
||||
var gangPlayer = await players.GetPlayer(player.Steam);
|
||||
if (gangPlayer?.GangId == null) return SpecialIcon.DEFAULT.GetIcon();
|
||||
var (_, available) =
|
||||
var available =
|
||||
await gangStats.GetForGang<SpecialIcon>(gangPlayer.GangId.Value,
|
||||
SpecialIconPerk.STAT_ID);
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
public static readonly FakeConVar<bool> CV_WARDEN_AUTO_SNITCH =
|
||||
new("css_jb_warden_auto_snitch",
|
||||
"True to broadcast how many prisoners were in cells when they auto-open",
|
||||
true);
|
||||
false);
|
||||
|
||||
public static readonly FakeConVar<int> CV_WARDEN_HEALTH =
|
||||
new("css_jb_warden_hp", "HP for the warden", 125, ConVarFlags.FCVAR_NONE,
|
||||
@@ -106,7 +106,7 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
|
||||
private BasePlugin parent = null!;
|
||||
private PreWardenStats? preWardenStats;
|
||||
private Timer? unblueTimer, openCellsTimer;
|
||||
private Timer? unblueTimer, openCellsTimer, passFreedayTimer;
|
||||
|
||||
public void Start(BasePlugin basePlugin) {
|
||||
parent = basePlugin;
|
||||
@@ -152,7 +152,8 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
|
||||
if (API.Actain != null) {
|
||||
var steam = Warden.SteamID;
|
||||
Server.NextFrameAsync(async () => {
|
||||
// Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
oldTag = await API.Actain.getTagService().GetTag(steam);
|
||||
oldTagColor = await API.Actain.getTagService().GetTagColor(steam);
|
||||
await Server.NextFrameAsync(() => {
|
||||
@@ -169,10 +170,9 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
var stats = API.Gangs.Services.GetService<IPlayerStatManager>();
|
||||
if (stats != null)
|
||||
Task.Run(async () => {
|
||||
var (success, stat) =
|
||||
await stats.GetForPlayer<WardenData>(wrapper, WardenStat.STAT_ID);
|
||||
|
||||
if (!success || stat == null) stat = new WardenData();
|
||||
var stat =
|
||||
await stats.GetForPlayer<WardenData>(wrapper, WardenStat.STAT_ID)
|
||||
?? new WardenData();
|
||||
|
||||
stat.TimesWardened++;
|
||||
await stats.SetForPlayer(wrapper, WardenStat.STAT_ID, stat);
|
||||
@@ -187,6 +187,8 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
logs.Append(logs.Player(Warden), "is now the warden.");
|
||||
|
||||
unblueTimer = parent.AddTimer(3, unmarkPrisonersBlue);
|
||||
passFreedayTimer
|
||||
?.Kill(); // If a warden is assigned, cancel the 10s freeday timer on pass
|
||||
mute.PeaceMute(firstWarden ?
|
||||
MuteReason.INITIAL_WARDEN :
|
||||
MuteReason.WARDEN_TAKEN);
|
||||
@@ -239,6 +241,11 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
|
||||
HasWarden = false;
|
||||
|
||||
if (isPass) { // If passing, start the timer to announce freeday
|
||||
passFreedayTimer =
|
||||
parent.AddTimer(10, () => { locale.NowFreeday.ToAllChat(); });
|
||||
}
|
||||
|
||||
if (Warden != null && Warden.Pawn.Value != null) {
|
||||
Warden.Clan = "";
|
||||
Warden.SetColor(Color.White);
|
||||
@@ -297,9 +304,8 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
var stats = API.Gangs?.Services.GetService<IPlayerStatManager>();
|
||||
if (stats == null) return;
|
||||
|
||||
var (success, stat) =
|
||||
await stats.GetForPlayer<WardenData>(player, WardenStat.STAT_ID);
|
||||
if (!success || stat == null) stat = new WardenData();
|
||||
var stat = await stats.GetForPlayer<WardenData>(player, WardenStat.STAT_ID)
|
||||
?? new WardenData();
|
||||
stat.WardenDeaths++;
|
||||
|
||||
await stats.SetForPlayer(player, WardenStat.STAT_ID, stat);
|
||||
@@ -355,10 +361,9 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
var stats = API.Gangs?.Services.GetService<IPlayerStatManager>();
|
||||
if (stats == null) return;
|
||||
await Task.Run(async () => {
|
||||
var (success, stat) =
|
||||
await stats.GetForPlayer<WardenData>(attacker, WardenStat.STAT_ID);
|
||||
|
||||
if (!success || stat == null) stat = new WardenData();
|
||||
var stat =
|
||||
await stats.GetForPlayer<WardenData>(attacker, WardenStat.STAT_ID)
|
||||
?? new WardenData();
|
||||
|
||||
stat.WardensKilled++;
|
||||
await stats.SetForPlayer(attacker, WardenStat.STAT_ID, stat);
|
||||
@@ -370,10 +375,8 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
var stats = API.Gangs?.Services.GetService<IPlayerStatManager>();
|
||||
if (stats == null) return;
|
||||
|
||||
var (success, stat) =
|
||||
await stats.GetForPlayer<WardenData>(player, WardenStat.STAT_ID);
|
||||
|
||||
if (!success || stat == null) stat = new WardenData();
|
||||
var stat = await stats.GetForPlayer<WardenData>(player, WardenStat.STAT_ID)
|
||||
?? new WardenData();
|
||||
|
||||
if (isWarden)
|
||||
// The warden let a guard die
|
||||
@@ -392,7 +395,7 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
|
||||
if (API.Actain != null) {
|
||||
var steam = player.SteamID;
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
if ("[WARDEN]" != await API.Actain.getTagService().GetTag(steam))
|
||||
return;
|
||||
Server.NextFrame(() => {
|
||||
@@ -424,8 +427,6 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
$"play sounds/{CV_WARDEN_SOUND_KILLED.Value}");
|
||||
}
|
||||
|
||||
locale.BecomeNextWarden.ToAllChat();
|
||||
|
||||
unblueTimer
|
||||
?.Kill(); // If the warden dies withing 3 seconds of becoming warden, we need to cancel the unblue timer
|
||||
markPrisonersBlue();
|
||||
@@ -596,9 +597,8 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
|
||||
var gangId = gangPlayer?.GangId;
|
||||
if (gangId == null) continue;
|
||||
|
||||
var (success, cells) =
|
||||
var cells =
|
||||
await gangStats.GetForGang<int>(gangId.Value, CellsPerk.STAT_ID);
|
||||
if (!success) cells = 0;
|
||||
|
||||
gangMembers.TryGetValue(gangId.Value, out var count);
|
||||
gangMembers[gangId.Value] = ++count;
|
||||
|
||||
@@ -28,17 +28,15 @@ public class WardenIconBehavior(ITextSpawner spawner)
|
||||
|
||||
if (playerStats == null) return WardenIcon.DEFAULT.GetIcon();
|
||||
|
||||
var (success, icon) =
|
||||
var icon =
|
||||
await playerStats.GetForPlayer<WardenIcon>(player,
|
||||
WardenIconPerk.STAT_ID);
|
||||
|
||||
if (!success) icon = WardenIcon.DEFAULT;
|
||||
|
||||
if (gangStats == null || players == null) return icon.GetIcon();
|
||||
|
||||
var gangPlayer = await players.GetPlayer(player.Steam);
|
||||
if (gangPlayer?.GangId == null) return WardenIcon.DEFAULT.GetIcon();
|
||||
var (_, available) =
|
||||
var available =
|
||||
await gangStats.GetForGang<WardenIcon>(gangPlayer.GangId.Value,
|
||||
WardenIconPerk.STAT_ID);
|
||||
|
||||
|
||||
@@ -4,15 +4,16 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\public\Jailbreak.Formatting\Jailbreak.Formatting.csproj"/>
|
||||
<ProjectReference Include="..\..\public\Jailbreak.Public\Jailbreak.Public.csproj"/>
|
||||
<ProjectReference Include="..\Gangs.CellsPerk\Gangs.CellsPerk.csproj"/>
|
||||
<ProjectReference Include="..\Gangs.SpecialIconPerk\Gangs.SpecialIconPerk.csproj"/>
|
||||
<ProjectReference Include="..\Gangs.WardenIconPerk\Gangs.WardenIconPerk.csproj"/>
|
||||
<ProjectReference Include="..\Jailbreak.Zones\Jailbreak.Zones.csproj"/>
|
||||
<ProjectReference Include="..\..\public\Jailbreak.Formatting\Jailbreak.Formatting.csproj" />
|
||||
<ProjectReference Include="..\..\public\Jailbreak.Public\Jailbreak.Public.csproj" />
|
||||
<ProjectReference Include="..\Gangs.CellsPerk\Gangs.CellsPerk.csproj" />
|
||||
<ProjectReference Include="..\Gangs.SpecialIconPerk\Gangs.SpecialIconPerk.csproj" />
|
||||
<ProjectReference Include="..\Gangs.WardenIconPerk\Gangs.WardenIconPerk.csproj" />
|
||||
<ProjectReference Include="..\Jailbreak.Zones\Jailbreak.Zones.csproj" />
|
||||
<ProjectReference Include="..\Gangs.WardenPaintColorPerk\Gangs.WardenPaintColorPerk.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -28,4 +29,9 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CS2ScreenMenuAPI" Version="2.6.0" />
|
||||
<PackageReference Include="CS2TraceRay" Version="1.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,18 +1,31 @@
|
||||
using System.Drawing;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using CS2ScreenMenuAPI;
|
||||
using CS2ScreenMenuAPI.Enums;
|
||||
using CS2ScreenMenuAPI.Internal;
|
||||
using CS2TraceRay.Class;
|
||||
using CS2TraceRay.Enum;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views.Warden;
|
||||
using Jailbreak.Public;
|
||||
using Jailbreak.Public.Behaviors;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.Draw;
|
||||
using Jailbreak.Public.Mod.Warden;
|
||||
using Jailbreak.Warden.Paint;
|
||||
using MStatsShared;
|
||||
using PostSelectAction = CS2ScreenMenuAPI.Enums.PostSelectAction;
|
||||
|
||||
namespace Jailbreak.Warden.Markers;
|
||||
|
||||
public class WardenMarkerBehavior(IWardenService warden)
|
||||
public class WardenMarkerBehavior(IWardenService warden, IWardenLocale locale)
|
||||
: IPluginBehavior, IMarkerService {
|
||||
public static readonly FakeConVar<float> CV_MAX_RADIUS = new(
|
||||
"css_jb_warden_marker_max_radius", "Maximum radius for warden marker", 360);
|
||||
@@ -24,20 +37,138 @@ public class WardenMarkerBehavior(IWardenService warden)
|
||||
"css_jb_warden_resize_time", "Milliseconds to wait for resizing marker",
|
||||
800);
|
||||
|
||||
// private Vector? MarkerPosition;
|
||||
private BeamCircle[] markers = [];
|
||||
private BeamCircle tmpMarker = null!;
|
||||
|
||||
private readonly string[] markerNames = [
|
||||
ChatColors.Red + "Red", ChatColors.Green + "Green",
|
||||
ChatColors.Blue + "Blue", ChatColors.Purple + "Purple"
|
||||
];
|
||||
|
||||
private BeamCircle? marker;
|
||||
private long placementTime;
|
||||
|
||||
public Vector? MarkerPosition { get; private set; }
|
||||
|
||||
public float radius { get; private set; }
|
||||
// private float radius;
|
||||
private bool activelyPlacing, removedMarker;
|
||||
|
||||
private ScreenMenu menu = null!;
|
||||
private BasePlugin plugin = null!;
|
||||
|
||||
public void Start(BasePlugin basePlugin) {
|
||||
marker = new BeamCircle(basePlugin, new Vector(), CV_MIN_RADIUS.Value,
|
||||
(int)Math.PI * 15);
|
||||
plugin = basePlugin;
|
||||
tmpMarker = new BeamCircle(basePlugin, new Vector(), CV_MIN_RADIUS.Value,
|
||||
10);
|
||||
markers = [
|
||||
new BeamCircle(basePlugin, new Vector(), CV_MIN_RADIUS.Value, 10),
|
||||
new BeamCircle(basePlugin, new Vector(), CV_MIN_RADIUS.Value, 10),
|
||||
new BeamCircle(basePlugin, new Vector(), CV_MIN_RADIUS.Value, 10),
|
||||
new BeamCircle(basePlugin, new Vector(), CV_MIN_RADIUS.Value, 10)
|
||||
];
|
||||
|
||||
markers[0].SetColor(Color.Red);
|
||||
markers[1].SetColor(Color.Green);
|
||||
markers[2].SetColor(Color.Blue);
|
||||
markers[3].SetColor(Color.Purple);
|
||||
|
||||
menu = new ScreenMenu("Markers", basePlugin) {
|
||||
PostSelectAction = PostSelectAction.Close,
|
||||
MenuType = MenuType.KeyPress,
|
||||
PositionX = -8.5f
|
||||
};
|
||||
|
||||
menu.AddOption("Red", (_, _) => placeMarker(0));
|
||||
menu.AddOption("Green", (_, _) => placeMarker(1));
|
||||
menu.AddOption("Blue", (_, _) => placeMarker(2));
|
||||
menu.AddOption("Purple", (_, _) => placeMarker(3));
|
||||
|
||||
basePlugin.AddCommandListener("player_ping", CommandListener_PlayerPing);
|
||||
// basePlugin.AddTimer(0.1f, OnTick, TimerFlags.REPEAT);
|
||||
}
|
||||
|
||||
private void placeMarker(int index) {
|
||||
if (MarkerPosition == null) return;
|
||||
var marker = markers[index];
|
||||
marker.Move(MarkerPosition);
|
||||
marker.SetRadius(radius);
|
||||
marker.Update();
|
||||
tmpMarker.SetRadius(1);
|
||||
tmpMarker.Move(MarkerPosition);
|
||||
tmpMarker.Update();
|
||||
|
||||
MarkerPosition = null;
|
||||
locale.MarkerPlaced(markerNames[index]).ToAllChat();
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnSpawn(EventPlayerSpawn spawn, GameEventInfo info) {
|
||||
if (spawn.Userid == null || !spawn.Userid.IsValid)
|
||||
return HookResult.Continue;
|
||||
SetBinds(spawn.Userid);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private void OnTick() {
|
||||
if (!warden.HasWarden) return;
|
||||
|
||||
if (warden.Warden == null || !warden.Warden.IsReal()) return;
|
||||
if ((warden.Warden.Buttons & PlayerButtons.Attack2) == 0) {
|
||||
if (activelyPlacing && !removedMarker) {
|
||||
MenuAPI.CloseActiveMenu(warden.Warden);
|
||||
Server.NextFrame(() => MenuAPI.OpenMenu(plugin, warden.Warden, menu));
|
||||
}
|
||||
|
||||
activelyPlacing = false;
|
||||
removedMarker = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var weapon = warden.Warden.Pawn.Value?.WeaponServices?.ActiveWeapon.Value
|
||||
?.DesignerName;
|
||||
if (weapon != null && Tag.SNIPERS.Contains(weapon)
|
||||
|| weapon == "weapon_sg556")
|
||||
return;
|
||||
|
||||
var trace =
|
||||
warden.Warden.GetGameTraceByEyePosition(TraceMask.MaskSolid, Contents.Solid,
|
||||
warden.Warden);
|
||||
if (trace == null) return;
|
||||
|
||||
var position = trace.Value.Position.ToCsVector();
|
||||
|
||||
if (!activelyPlacing) {
|
||||
for (var i = 0; i < markers.Length; i++) {
|
||||
var marker = markers[i];
|
||||
var dist = marker.Position.DistanceSquared(position);
|
||||
if (!(dist < MathF.Pow(marker.Radius, 2))) continue;
|
||||
marker.SetRadius(0);
|
||||
marker.Update();
|
||||
locale.MarkerRemoved(markerNames[i]).ToAllChat();
|
||||
removedMarker = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedMarker) return;
|
||||
|
||||
if (MarkerPosition == null || !activelyPlacing) {
|
||||
tmpMarker.SetRadius(CV_MIN_RADIUS.Value);
|
||||
tmpMarker.Move(position);
|
||||
tmpMarker.Update();
|
||||
MarkerPosition = position;
|
||||
activelyPlacing = true;
|
||||
placementTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
API.Stats?.PushStat(new ServerStat("JB_MARKER",
|
||||
$"{position.X:F2} {position.Y:F2} {position.Z:F2}"));
|
||||
radius = CV_MIN_RADIUS.Value;
|
||||
return;
|
||||
}
|
||||
|
||||
var distance = MarkerPosition.Distance(position);
|
||||
distance = Math.Clamp(distance, CV_MIN_RADIUS.Value, CV_MAX_RADIUS.Value);
|
||||
|
||||
radius = distance;
|
||||
tmpMarker.SetRadius(distance);
|
||||
tmpMarker.Update();
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
@@ -55,13 +186,13 @@ public class WardenMarkerBehavior(IWardenService warden)
|
||||
if (distance <= CV_MAX_RADIUS.Value * 1.3) {
|
||||
distance = Math.Clamp(distance, CV_MIN_RADIUS.Value,
|
||||
CV_MAX_RADIUS.Value);
|
||||
marker?.SetRadius(distance);
|
||||
marker?.Update();
|
||||
tmpMarker?.SetRadius(distance);
|
||||
tmpMarker?.Update();
|
||||
radius = distance;
|
||||
return HookResult.Handled;
|
||||
}
|
||||
} else if (distance <= radius) {
|
||||
marker?.Remove();
|
||||
tmpMarker?.Remove();
|
||||
return HookResult.Handled;
|
||||
}
|
||||
}
|
||||
@@ -72,9 +203,9 @@ public class WardenMarkerBehavior(IWardenService warden)
|
||||
|
||||
API.Stats?.PushStat(new ServerStat("JB_MARKER",
|
||||
$"{vec.X:F2} {vec.Y:F2} {vec.Z:F2}"));
|
||||
marker?.Move(vec);
|
||||
marker?.SetRadius(radius);
|
||||
marker?.Update();
|
||||
tmpMarker?.Move(vec);
|
||||
tmpMarker?.SetRadius(radius);
|
||||
tmpMarker?.Update();
|
||||
return HookResult.Handled;
|
||||
}
|
||||
|
||||
@@ -82,4 +213,9 @@ public class WardenMarkerBehavior(IWardenService warden)
|
||||
CommandInfo info) {
|
||||
return warden.IsWarden(player) ? HookResult.Continue : HookResult.Handled;
|
||||
}
|
||||
|
||||
public static void SetBinds(CCSPlayerController player) {
|
||||
for (var i = 0; i < 10; i++)
|
||||
player.ExecuteClientCommand($"echo test | bind {i} \"slot{i};css_{i}\"");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using CS2TraceRay.Class;
|
||||
using CS2TraceRay.Enum;
|
||||
using GangsAPI.Data;
|
||||
using GangsAPI.Services.Gang;
|
||||
using GangsAPI.Services.Player;
|
||||
@@ -14,19 +17,19 @@ using Jailbreak.Public.Mod.Rainbow;
|
||||
using Jailbreak.Public.Mod.Warden;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WardenPaintColorPerk;
|
||||
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
|
||||
|
||||
namespace Jailbreak.Warden.Paint;
|
||||
|
||||
public class WardenPaintBehavior(IWardenService wardenService,
|
||||
IServiceProvider provider) : IPluginBehavior {
|
||||
private Vector? lastPosition;
|
||||
private BasePlugin? parent;
|
||||
|
||||
private IRainbowColorizer? colorizer =
|
||||
private readonly IRainbowColorizer? colorizer =
|
||||
provider.GetService<IRainbowColorizer>();
|
||||
|
||||
private WardenPaintColor?[] colors = new WardenPaintColor?[65];
|
||||
private bool[] fetched = new bool[65];
|
||||
private Vector? lastPosition;
|
||||
private BasePlugin? parent;
|
||||
|
||||
public void Start(BasePlugin basePlugin) {
|
||||
parent = basePlugin;
|
||||
@@ -48,8 +51,12 @@ public class WardenPaintBehavior(IWardenService wardenService,
|
||||
|
||||
if ((warden.Buttons & PlayerButtons.Use) == 0) return;
|
||||
|
||||
var position = findFloorIntersection(warden);
|
||||
if (position == null) return;
|
||||
var trace =
|
||||
warden.GetGameTraceByEyePosition(TraceMask.MaskSolid, Contents.TouchAll,
|
||||
warden);
|
||||
if (trace == null) return;
|
||||
|
||||
var position = trace.Value.Position.ToCsVector();
|
||||
|
||||
var start = lastPosition ?? position;
|
||||
start = start.Clone();
|
||||
@@ -67,6 +74,7 @@ public class WardenPaintBehavior(IWardenService wardenService,
|
||||
var color = getColor(warden);
|
||||
var line = new BeamLine(parent, start.Clone(), position.Clone());
|
||||
line.SetColor(color);
|
||||
line.SetWidth(1.5f);
|
||||
line.Draw(30);
|
||||
}
|
||||
|
||||
@@ -106,11 +114,8 @@ public class WardenPaintBehavior(IWardenService wardenService,
|
||||
|| gangStats == null)
|
||||
return WardenPaintColor.DEFAULT;
|
||||
|
||||
var (success, playerColors) =
|
||||
await playerStats.GetForPlayer<WardenPaintColor>(player.Steam,
|
||||
WardenPaintColorPerk.WardenPaintColorPerk.STAT_ID);
|
||||
|
||||
if (!success) return WardenPaintColor.DEFAULT;
|
||||
var playerColors = await playerStats.GetForPlayer<WardenPaintColor>(
|
||||
player.Steam, WardenPaintColorPerk.WardenPaintColorPerk.STAT_ID);
|
||||
|
||||
var gangPlayer = await players.GetPlayer(player.Steam);
|
||||
|
||||
@@ -119,7 +124,7 @@ public class WardenPaintBehavior(IWardenService wardenService,
|
||||
var gang = await gangs.GetGang(gangPlayer.GangId.Value);
|
||||
if (gang == null) return WardenPaintColor.DEFAULT;
|
||||
|
||||
var (_, available) = await gangStats.GetForGang<WardenPaintColor>(gang,
|
||||
var available = await gangStats.GetForGang<WardenPaintColor>(gang,
|
||||
WardenPaintColorPerk.WardenPaintColorPerk.STAT_ID);
|
||||
|
||||
if (playerColors == WardenPaintColor.RANDOM)
|
||||
@@ -127,60 +132,4 @@ public class WardenPaintBehavior(IWardenService wardenService,
|
||||
|
||||
return playerColors & available;
|
||||
}
|
||||
|
||||
private Vector? findFloorIntersection(CCSPlayerController player) {
|
||||
if (player.Pawn.Value == null || player.PlayerPawn.Value == null)
|
||||
return null;
|
||||
var pawn = player.Pawn.Value;
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid || !playerPawn.IsValid
|
||||
|| pawn.CameraServices == null)
|
||||
return null;
|
||||
if (pawn.AbsOrigin == null) return null;
|
||||
|
||||
var camera = pawn.CameraServices;
|
||||
var cameraOrigin = new Vector(pawn.AbsOrigin!.X, pawn.AbsOrigin!.Y,
|
||||
pawn.AbsOrigin!.Z + camera.OldPlayerViewOffsetZ);
|
||||
var eyeAngle = player.PlayerPawn.Value.EyeAngles;
|
||||
|
||||
var pitch = Math.PI / 180 * eyeAngle.X;
|
||||
var yaw = Math.PI / 180 * eyeAngle.Y;
|
||||
|
||||
// get direction vector from angles
|
||||
var eyeVector = new Vector((float)(Math.Cos(yaw) * Math.Cos(pitch)),
|
||||
(float)(Math.Sin(yaw) * Math.Cos(pitch)), (float)-Math.Sin(pitch));
|
||||
|
||||
return findFloorIntersection(cameraOrigin, eyeVector,
|
||||
new Vector(eyeAngle.X, eyeAngle.Y, eyeAngle.Z), pawn.AbsOrigin.Z);
|
||||
}
|
||||
|
||||
private Vector? findFloorIntersection(Vector start, Vector worldAngles,
|
||||
Vector rotationAngles, float z) {
|
||||
var pitch =
|
||||
rotationAngles
|
||||
.X; // 90 = straight down, -90 = straight up, 0 = straight ahead
|
||||
// normalize so 0 = straight down, 180 = straight up, 90 = straight ahead
|
||||
pitch = 90 - pitch;
|
||||
if (pitch >= 90) return null;
|
||||
|
||||
// var angleA = ToRadians(90);
|
||||
var sideB = start.Z - z;
|
||||
var angleC = toRadians(pitch);
|
||||
|
||||
|
||||
var angleB = 180 - 90 - pitch;
|
||||
var sideA = sideB * MathF.Sin(toRadians(90)) / MathF.Sin(toRadians(angleB));
|
||||
var sideC = MathF.Sqrt(sideB * sideB + sideA * sideA
|
||||
- 2 * sideB * sideA * MathF.Cos(angleC));
|
||||
|
||||
var destination = start.Clone();
|
||||
destination.X += worldAngles.X * sideC;
|
||||
destination.Y += worldAngles.Y * sideC;
|
||||
destination.Z = z;
|
||||
return destination;
|
||||
}
|
||||
|
||||
private static float toRadians(float angle) {
|
||||
return (float)(Math.PI / 180) * angle;
|
||||
}
|
||||
}
|
||||
121
mod/Jailbreak.Warden/Selection/AutoWarden.cs
Normal file
121
mod/Jailbreak.Warden/Selection/AutoWarden.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System.Collections.Concurrent;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Jailbreak.Formatting.Extensions;
|
||||
using Jailbreak.Formatting.Views;
|
||||
using Jailbreak.Formatting.Views.Warden;
|
||||
using Jailbreak.Public;
|
||||
using Jailbreak.Public.Behaviors;
|
||||
using Jailbreak.Public.Extensions;
|
||||
using Jailbreak.Public.Mod.Warden;
|
||||
using MAULActainShared.plugin.models;
|
||||
|
||||
namespace Jailbreak.Warden.Selection;
|
||||
|
||||
public class AutoWarden(IWardenSelectionService selectionService,
|
||||
IWardenLocale locale, IGenericCmdLocale generic) : IPluginBehavior {
|
||||
|
||||
private static readonly ConcurrentDictionary<ulong, bool> CACHED_COOKIES = new();
|
||||
|
||||
private static readonly FakeConVar<string> CV_AUTOWARDEN_FLAG =
|
||||
new("css_autowarden_flag", "Permission flag required to enable auto-Warden",
|
||||
"@ego/dssilver");
|
||||
private static readonly FakeConVar<float> CV_AUTOWARDEN_DELAY_INTERVAL =
|
||||
new("css_autowarden_delay_interval", "The amount of time in seconds to wait after round start to queue users with auto-warden enabled for warden",
|
||||
5f);
|
||||
|
||||
private BasePlugin plugin = null!;
|
||||
private ICookie? cookie;
|
||||
|
||||
public void Start(BasePlugin basePlugin) {
|
||||
plugin = basePlugin;
|
||||
|
||||
TryLoadCookie();
|
||||
basePlugin.RegisterListener<Listeners.OnMapStart>(OnMapStart);
|
||||
basePlugin.RegisterEventHandler<EventRoundPoststart>(OnRoundStart);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
private void OnMapStart(string mapname) {
|
||||
// Attempt to load the cookie OnMapStart if it fails to load on plugin start
|
||||
// This can happen if the MAUL plugin is loaded *after* this plugin
|
||||
if (cookie == null) TryLoadCookie();
|
||||
else plugin.RemoveListener<Listeners.OnMapStart>(OnMapStart);
|
||||
}
|
||||
|
||||
private HookResult OnRoundStart(EventRoundPoststart @event, GameEventInfo info) {
|
||||
plugin.AddTimer(CV_AUTOWARDEN_DELAY_INTERVAL.Value, () => {
|
||||
foreach (var player in Utilities.GetPlayers()
|
||||
.Where(p => p.Team == CsTeam.CounterTerrorist
|
||||
&& p.IsReal()
|
||||
&& p.PawnIsAlive
|
||||
&& AdminManager.PlayerHasPermissions(p, CV_AUTOWARDEN_FLAG.Value))) {
|
||||
|
||||
if (player.PlayerPawn.Value == null
|
||||
|| !player.PlayerPawn.Value.HasMovedSinceSpawn)
|
||||
continue;
|
||||
|
||||
var steam = player.SteamID;
|
||||
if (!CACHED_COOKIES.ContainsKey(steam))
|
||||
Task.Run(async () => await populateCache(player, steam));
|
||||
|
||||
if (!CACHED_COOKIES.TryGetValue(steam, out var value) || !value)
|
||||
continue;
|
||||
selectionService.TryEnter(player);
|
||||
locale.JoinRaffle.ToChat(player);
|
||||
}
|
||||
});
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_aw")]
|
||||
[ConsoleCommand("css_autowarden")]
|
||||
public void Command_AutoWarden(CCSPlayerController? player, CommandInfo info) {
|
||||
if (player == null) return;
|
||||
if (!AdminManager.PlayerHasPermissions(player, CV_AUTOWARDEN_FLAG.Value)) {
|
||||
generic.NoPermissionMessage(CV_AUTOWARDEN_FLAG.Value).ToChat(player);
|
||||
return;
|
||||
}
|
||||
if (cookie == null) { locale.TogglingNotEnabled.ToChat(player); return; }
|
||||
|
||||
var steam = player.SteamID;
|
||||
Task.Run(async () => {
|
||||
var cur = await cookie.Get(steam);
|
||||
var enable = cur != "Y";
|
||||
await cookie.Set(steam, enable ? "Y" : "N");
|
||||
await Server.NextFrameAsync(() => {
|
||||
if (!player.IsValid) return;
|
||||
locale.AutoWardenToggled(enable).ToChat(player);
|
||||
CACHED_COOKIES[steam] = enable;
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void TryLoadCookie() {
|
||||
Task.Run(async () => {
|
||||
if (API.Actain != null)
|
||||
cookie = await API.Actain.getCookieService()
|
||||
.RegClientCookie("jb_warden_auto");
|
||||
});
|
||||
}
|
||||
|
||||
private async Task populateCache(CCSPlayerController player, ulong steam) {
|
||||
if (cookie == null) return;
|
||||
var val = await cookie.Get(steam);
|
||||
var enabled = val == "Y";
|
||||
CACHED_COOKIES[steam] = enabled;
|
||||
if (!enabled) return;
|
||||
await Server.NextFrameAsync(() => {
|
||||
if (!player.IsValid) return;
|
||||
selectionService.TryEnter(player);
|
||||
locale.JoinRaffle.ToChat(player);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -16,27 +16,20 @@ public class SpecialTreatmentBehavior(IPlayerStateFactory factory,
|
||||
IWardenSTLocale notifications, IServiceProvider provider)
|
||||
: IPluginBehavior, ISpecialTreatmentService {
|
||||
private readonly ISpecialIcon? iconer = provider.GetService<ISpecialIcon>();
|
||||
|
||||
private readonly IPlayerState<SpecialTreatmentState> sts =
|
||||
factory.Round<SpecialTreatmentState>();
|
||||
|
||||
private IRebelService rebel = null!;
|
||||
|
||||
public void Start(BasePlugin basePlugin, bool hotreload) {
|
||||
rebel = provider.GetRequiredService<IRebelService>();
|
||||
}
|
||||
|
||||
private readonly IPlayerState<SpecialTreatmentState> sts =
|
||||
factory.Round<SpecialTreatmentState>();
|
||||
|
||||
public bool IsSpecialTreatment(CCSPlayerController player) {
|
||||
return sts.Get(player).HasSpecialTreatment;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnDeath(EventPlayerDeath ev, GameEventInfo info) {
|
||||
if (ev.Userid == null || !ev.Userid.IsValid) return HookResult.Continue;
|
||||
Revoke(ev.Userid, false);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
public void Grant(CCSPlayerController player) {
|
||||
// Player is already granted ST
|
||||
if (IsSpecialTreatment(player)) return;
|
||||
@@ -71,6 +64,14 @@ public class SpecialTreatmentBehavior(IPlayerStateFactory factory,
|
||||
iconer?.RemoveSpecialIcon(player);
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnDeath(EventPlayerDeath ev, GameEventInfo info) {
|
||||
if (ev.Userid == null || !ev.Userid.IsValid) return HookResult.Continue;
|
||||
Revoke(ev.Userid, false);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private void setSpecialColor(CCSPlayerController player, bool hasSt) {
|
||||
if (!player.IsValid || player.Pawn.Value == null) return;
|
||||
|
||||
|
||||
@@ -23,10 +23,11 @@ public static class WardenServiceExtension {
|
||||
serviceCollection.AddPluginBehavior<IWardenIcon, WardenIconBehavior>();
|
||||
serviceCollection.AddPluginBehavior<ISpecialIcon, SpecialIconBehavior>();
|
||||
serviceCollection.AddPluginBehavior<CountCommandsBehavior>();
|
||||
|
||||
serviceCollection.AddPluginBehavior<AutoWarden>();
|
||||
|
||||
serviceCollection.AddPluginBehavior<SpecialTreatmentCommandsBehavior>();
|
||||
serviceCollection.AddPluginBehavior<PeaceCommandsBehavior>();
|
||||
serviceCollection.AddPluginBehavior<CountdownCommandBehavior>();
|
||||
serviceCollection.AddPluginBehavior<WardenCommandsBehavior>();
|
||||
serviceCollection.AddPluginBehavior<RollCommandBehavior>();
|
||||
serviceCollection.AddPluginBehavior<ChickenCommandBehavior>();
|
||||
|
||||
@@ -102,7 +102,7 @@ public class RandomZoneGenerator(IZoneManager zoneManager, IZoneFactory factory,
|
||||
|
||||
var map = Server.MapName;
|
||||
zone.Id = nearestPoint.Id;
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
await zoneManager.DeleteZone(zone.Id, map);
|
||||
await zoneManager.PushZoneWithID(zone, ZoneType.SPAWN_AUTO, map);
|
||||
});
|
||||
@@ -112,7 +112,7 @@ public class RandomZoneGenerator(IZoneManager zoneManager, IZoneFactory factory,
|
||||
|
||||
var spawn = factory.CreateZone([pos]);
|
||||
autoSpawnPoints.Add(spawn);
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
await zoneManager.PushZone(spawn, ZoneType.SPAWN_AUTO, currentMap!);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ public class SqlZoneManager(IZoneFactory factory) : IZoneManager {
|
||||
}
|
||||
|
||||
private void OnMapStart(string mapname) {
|
||||
Server.NextFrameAsync(async () => {
|
||||
Task.Run(async () => {
|
||||
await createTable();
|
||||
await LoadZones(mapname);
|
||||
});
|
||||
|
||||
@@ -131,8 +131,13 @@ public static class ViewExtensions {
|
||||
}
|
||||
|
||||
public static IView ToChat(this IView view,
|
||||
params CCSPlayerController[] players) {
|
||||
foreach (var player in players) view.ToPlayerChat(player);
|
||||
params CCSPlayerController?[] players) {
|
||||
foreach (var player in players) {
|
||||
if (player == null)
|
||||
view.ToServerConsole();
|
||||
else
|
||||
view.ToPlayerChat(player);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using Jailbreak.Formatting.Base;
|
||||
|
||||
namespace Jailbreak.Formatting.Views.LastRequest;
|
||||
|
||||
public interface ILRGunTossLocale {
|
||||
public IView PlayerThrewGunDistance(CCSPlayerController player, float dist);
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public interface ILRLocale {
|
||||
public IView WinByHealth(CCSPlayerController player);
|
||||
public IView WinByReason(CCSPlayerController player, string reason);
|
||||
public IView Win(CCSPlayerController player);
|
||||
|
||||
|
||||
public IView LastRequestRebel(CCSPlayerController player, int tHealth);
|
||||
public IView LastRequestRebelDisabled();
|
||||
public IView CannotLastRequestRebelCt();
|
||||
|
||||
@@ -7,4 +7,5 @@ public interface ISDLocale {
|
||||
public IView InvalidSpecialDay(string name);
|
||||
public IView SpecialDayCooldown(int rounds);
|
||||
public IView TooLateForSpecialDay(int maxTime);
|
||||
public IView CannotCallDay(string reason);
|
||||
}
|
||||
@@ -8,6 +8,7 @@ namespace Jailbreak.Formatting.Views.Warden;
|
||||
public interface IWardenLocale {
|
||||
public IView PickingShortly { get; }
|
||||
public IView NoWardens { get; }
|
||||
public IView NowFreeday { get; }
|
||||
public IView WardenLeft { get; }
|
||||
public IView WardenDied { get; }
|
||||
public IView BecomeNextWarden { get; }
|
||||
@@ -17,6 +18,8 @@ public interface IWardenLocale {
|
||||
public IView FireCommandFailed { get; }
|
||||
|
||||
public IView CannotWardenDuringWarmup { get; }
|
||||
|
||||
public IView TogglingNotEnabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a view for when the specified player passes warden
|
||||
@@ -46,4 +49,10 @@ public interface IWardenLocale {
|
||||
|
||||
public IView FireWarden(CCSPlayerController player,
|
||||
CCSPlayerController admin);
|
||||
|
||||
public IView MarkerPlaced(string marker);
|
||||
|
||||
public IView MarkerRemoved(string marker);
|
||||
|
||||
IView AutoWardenToggled(bool enabled);
|
||||
}
|
||||
15
public/Jailbreak.Public/Extensions/CBaseEntityExtensions.cs
Normal file
15
public/Jailbreak.Public/Extensions/CBaseEntityExtensions.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Drawing;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace Jailbreak.Public.Extensions;
|
||||
|
||||
public static class CBaseEntityExtensions {
|
||||
public static void SetColor(this CBaseModelEntity? entity, Color color) {
|
||||
if (entity == null || !entity.IsValid) return;
|
||||
|
||||
entity.RenderMode = RenderMode_t.kRenderTransColor;
|
||||
entity.Render = color;
|
||||
Utilities.SetStateChanged(entity, "CBaseModelEntity", "m_clrRender");
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.UserMessages;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
|
||||
|
||||
namespace Jailbreak.Public.Extensions;
|
||||
|
||||
@@ -132,9 +134,10 @@ public static class PlayerExtensions {
|
||||
// TODO: Don't always override to allow other plugins to show legs.
|
||||
if (color.A == 255)
|
||||
color = Color.FromArgb(pawn.Render.A, color.R, color.G, color.B);
|
||||
pawn.RenderMode = RenderMode_t.kRenderTransColor;
|
||||
pawn.Render = color;
|
||||
Utilities.SetStateChanged(pawn, "CBaseModelEntity", "m_clrRender");
|
||||
// pawn.RenderMode = RenderMode_t.kRenderTransColor;
|
||||
// pawn.Render = color;
|
||||
// Utilities.SetStateChanged(pawn, "CBaseModelEntity", "m_clrRender");
|
||||
player.PlayerPawn.Value.SetColor(color);
|
||||
}
|
||||
|
||||
public static Color? GetColor(this CCSPlayerController player) {
|
||||
@@ -178,4 +181,31 @@ public static class PlayerExtensions {
|
||||
color.R | color.G << 8 | color.B << 16 | color.A << 24);
|
||||
fadeMsg.Send(player);
|
||||
}
|
||||
|
||||
public static Vector3 GetEyeOrigin(this CCSPlayerPawn pawn) {
|
||||
var origin = pawn.AbsOrigin;
|
||||
if (origin == null) return Vector3.Zero;
|
||||
|
||||
//return new Vector3(origin.X, origin.Y,
|
||||
//origin.Z + pawn.CameraServices?.OldPlayerViewOffsetZ ?? 0.0f);
|
||||
|
||||
return new Vector3(origin.X, origin.Y,
|
||||
origin.Z + 64.09f);
|
||||
}
|
||||
|
||||
public static void GetEyeForward(this CCSPlayerPawn pawn, float distance,
|
||||
out Vector3 forward, out Vector3 target) {
|
||||
if (pawn.AbsOrigin == null) {
|
||||
forward = default;
|
||||
target = default;
|
||||
return;
|
||||
}
|
||||
|
||||
var angles = new Vector3(pawn.AbsOrigin.X, pawn.AbsOrigin.Y,
|
||||
pawn.AbsOrigin.Z + 64.09f);
|
||||
angles.AngleVectors(out forward, out _, out _);
|
||||
|
||||
var eyeOrigin = pawn.GetEyeOrigin();
|
||||
target = eyeOrigin + forward * distance;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using System.Numerics;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
|
||||
|
||||
namespace Jailbreak.Public.Extensions;
|
||||
|
||||
@@ -14,7 +16,7 @@ public static class VectorExtensions {
|
||||
/// <param name="vector"></param>
|
||||
/// <param name="other"></param>
|
||||
/// <returns></returns>
|
||||
public static float Distance(this Vector vector, Vector other) {
|
||||
public static float Distance(this Vector? vector, Vector other) {
|
||||
return (float)Math.Sqrt(vector.DistanceSquared(other));
|
||||
}
|
||||
|
||||
@@ -24,7 +26,7 @@ public static class VectorExtensions {
|
||||
/// <param name="vector"></param>
|
||||
/// <param name="other"></param>
|
||||
/// <returns></returns>
|
||||
public static float DistanceSquared(this Vector vector, Vector other) {
|
||||
public static float DistanceSquared(this Vector? vector, Vector other) {
|
||||
return MathF.Pow(vector.X - other.X, 2) + MathF.Pow(vector.Y - other.Y, 2)
|
||||
+ MathF.Pow(vector.Z - other.Z, 2);
|
||||
}
|
||||
@@ -50,4 +52,46 @@ public static class VectorExtensions {
|
||||
HorizontalDistanceSquared(this Vector vector, Vector other) {
|
||||
return MathF.Pow(vector.X - other.X, 2) + MathF.Pow(vector.Y - other.Y, 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a CounterStrikeSharp Vector Into a Vector3 Class
|
||||
/// </summary>
|
||||
/// <param name="vector"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector3 ToVec3(this Vector vector) {
|
||||
return new Vector3(vector.X, vector.Y, vector.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Vector3 Into a CounterStrikeSharp Vector Class
|
||||
/// </summary>
|
||||
/// <param name="vec3"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector ToCsVector(this Vector3 vec3) {
|
||||
return new Vector(vec3.X, vec3.Y, vec3.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given angle vector (pitch, yaw, roll) into directional unit vectors:
|
||||
/// forward, right, and up.
|
||||
/// Useful for translating eye angles or view angles into world-space directions.
|
||||
/// Wraps the native `AngleVectors` call from the engine.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="forward"></param>
|
||||
/// <param name="right"></param>
|
||||
/// <param name="up"></param>
|
||||
public static void AngleVectors(this Vector3 input, out Vector3 forward,
|
||||
out Vector3 right, out Vector3 up) {
|
||||
Vector3 tmpForward, tmpRight, tmpUp;
|
||||
|
||||
unsafe {
|
||||
NativeAPI.AngleVectors((nint)(&input), (nint)(&tmpForward),
|
||||
(nint)(&tmpRight), (nint)(&tmpUp));
|
||||
}
|
||||
|
||||
forward = tmpForward;
|
||||
right = tmpRight;
|
||||
up = tmpUp;
|
||||
}
|
||||
}
|
||||
@@ -4,15 +4,16 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.260"/>
|
||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.330" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0"/>
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.5"/>
|
||||
<ProjectReference Include="..\Jailbreak.Tag\Jailbreak.Tag.csproj"/>
|
||||
<Reference Include="GangsAPI">
|
||||
<HintPath>Mixin\GangsAPI.dll</HintPath>
|
||||
<HintPath>./Mixin/GangsAPI.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MAULActainShared.dll">
|
||||
<HintPath>./Mixin/MAULActainShared.dll</HintPath>
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,4 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using Jailbreak.Public.Extensions;
|
||||
|
||||
namespace Jailbreak.Public.Mod.Damage;
|
||||
|
||||
@@ -8,23 +7,6 @@ namespace Jailbreak.Public.Mod.Damage;
|
||||
/// taking damage.
|
||||
/// </summary>
|
||||
public interface IDamageBlocker {
|
||||
HookResult BlockUserDamage(EventPlayerHurt @event, GameEventInfo _) {
|
||||
var player = @event.Userid;
|
||||
var attacker = @event.Attacker;
|
||||
if (player == null || !player.IsReal()) return HookResult.Continue;
|
||||
|
||||
if (!ShouldBlockDamage(player, attacker, @event))
|
||||
return HookResult.Continue;
|
||||
if (player.PlayerPawn.IsValid) {
|
||||
var playerPawn = player.PlayerPawn.Value!;
|
||||
playerPawn.Health = playerPawn.LastHealth;
|
||||
}
|
||||
|
||||
@event.DmgArmor = 0;
|
||||
@event.DmgHealth = 0;
|
||||
return HookResult.Stop;
|
||||
}
|
||||
|
||||
bool ShouldBlockDamage(CCSPlayerController victim,
|
||||
CCSPlayerController? attacker, EventPlayerHurt @event);
|
||||
CCSPlayerController? attacker);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user