Skip to content

Commit 46087e1

Browse files
Merge pull request #332 from shobhit-pathak/dev
0.8.13
2 parents 499e15e + 130e18c commit 46087e1

File tree

10 files changed

+81
-16
lines changed

10 files changed

+81
-16
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# MatchZy Changelog
22

3+
# 0.8.13
4+
5+
#### September 03, 2025
6+
7+
- Fixed coach bomb bug and updated CSS version.
8+
- Added `matchzy_demo_recording_enabled` convar to toggle demo recording.
9+
- Fixed the Map Winner Logic in MapWinner event
10+
- Fixed first Map Name in database stats
11+
312
# 0.8.12
413

514
#### August 25, 2025

Coach.cs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public void HandleCoaches()
122122
// Elevating coach before dropping the C4 to prevent it going inside the ground.
123123
AddTimer(0.05f, () =>
124124
{
125-
coach!.PlayerPawn.Value!.Teleport(new Vector(coachPosition.PlayerPosition.X, coachPosition.PlayerPosition.Y, coachPosition.PlayerPosition.Z + 20.0f), coachPosition.PlayerAngle, new Vector(0, 0, 0));
125+
// coach!.PlayerPawn.Value!.Teleport(new Vector(coachPosition.PlayerPosition.X, coachPosition.PlayerPosition.Y, coachPosition.PlayerPosition.Z + 20.0f), coachPosition.PlayerAngle, new Vector(0, 0, 0));
126126
HandleCoachWeapons(coach);
127127
coach!.PlayerPawn.Value.Teleport(newPosition.PlayerPosition, newPosition.PlayerAngle, new Vector(0, 0, 0));
128128
});
@@ -180,10 +180,36 @@ public void HandleCoaches()
180180
private void HandleCoachWeapons(CCSPlayerController coach)
181181
{
182182
if (!IsPlayerValid(coach)) return;
183-
DropWeaponByDesignerName(coach, "weapon_c4");
184183
coach.RemoveWeapons();
185184
}
186185

186+
/// <summary>
187+
/// Transfers bomb from coach to first available non-coach terrorist.
188+
/// </summary>
189+
public void TransferCoachBomb(CCSPlayerController coach) {
190+
if (coach.TeamNum != (int)CsTeam.Terrorist) return; // can't have bomb
191+
192+
// find bomb and new target
193+
var bomb = coach.PlayerPawn.Value!.WeaponServices!.MyWeapons
194+
.Where(w => w != null && w.IsValid && w.Value!.DesignerName == "weapon_c4")
195+
.FirstOrDefault();
196+
if (bomb == null || bomb.Value == null) return; // should never trigger
197+
198+
var target = Utilities.GetPlayers()
199+
.FirstOrDefault(
200+
p => IsPlayerValid(p)
201+
&& !reverseTeamSides["TERRORIST"].coach.Contains(p)
202+
&& p.TeamNum == (int)CsTeam.Terrorist
203+
&& p.PawnIsAlive
204+
);
205+
if (!IsPlayerValid(target)) return; // should never trigger
206+
207+
// transfer bomb
208+
Log($"[EventPlayerGivenC4 INFO] Transferred bomb from {coach.PlayerName} (Coach) to {target.PlayerName}.");
209+
bomb.Value!.Remove();
210+
target.GiveNamedItem("weapon_c4");
211+
}
212+
187213
public CsTeam GetCoachTeam(CCSPlayerController coach)
188214
{
189215
if (matchzyTeam1.coach.Contains(coach))
@@ -240,8 +266,6 @@ private void KillCoaches()
240266

241267
Position coachPosition = new(coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
242268
coach!.PlayerPawn.Value!.Teleport(new Vector(coachPosition.PlayerPosition.X, coachPosition.PlayerPosition.Y, coachPosition.PlayerPosition.Z + 20.0f), coachPosition.PlayerAngle, new Vector(0, 0, 0));
243-
// Dropping the C4 if it was picked up or passed to the coach.
244-
DropWeaponByDesignerName(coach, "weapon_c4");
245269
coach.PlayerPawn.Value!.CommitSuicide(explode: false, force: true);
246270
}
247271
Server.ExecuteCommand($"mp_suicide_penalty {suicidePenalty}; spec_freeze_time {specFreezeTime}; spec_freeze_time_lock {specFreezeTimeLock}; spec_freeze_deathanim_time {specFreezeDeathanim};");

ConfigConvars.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ public void MatchZyDemoNameFormat(CCSPlayerController? player, CommandInfo comma
125125
}
126126
}
127127

128+
[ConsoleCommand("matchzy_demo_recording_enabled", "Whether to automatically start demo recording when the match goes live. Default value: true")]
129+
public void MatchZyDemoRecordingEnabled(CCSPlayerController? player, CommandInfo command)
130+
{
131+
if (player != null) return;
132+
string args = command.ArgString;
133+
134+
isDemoRecordingEnabled = bool.TryParse(args, out bool isDemoRecordingEnabledValue) ? isDemoRecordingEnabledValue : args != "0" && isDemoRecordingEnabled;
135+
}
136+
128137
[ConsoleCommand("get5_demo_upload_url", "If defined, recorded demos will be uploaded to this URL once the map ends.")]
129138
[ConsoleCommand("matchzy_demo_upload_url", "If defined, recorded demos will be uploaded to this URL once the map ends.")]
130139
public void MatchZyDemoUploadURL(CCSPlayerController? player, CommandInfo command)

DatabaseStats.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,11 @@ FOREIGN KEY (mapnumber) REFERENCES matchzy_stats_maps (mapnumber)
229229
)");
230230
}
231231

232-
public long InitMatch(string team1name, string team2name, string serverIp, bool isMatchSetup, long liveMatchId, int mapNumber, string seriesType)
232+
public long InitMatch(string team1name, string team2name, string serverIp, bool isMatchSetup, long liveMatchId, int mapNumber, string seriesType, MatchConfig matchConfig)
233233
{
234234
try
235235
{
236-
string mapName = Server.MapName;
236+
string mapName = isMatchSetup ? matchConfig.Maplist[mapNumber] : Server.MapName;
237237
string dateTimeExpression = (connection is SqliteConnection) ? "datetime('now')" : "NOW()";
238238

239239
if (mapNumber == 0) {

DemoManagement.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,15 @@ public partial class MatchZy
2020
public string activeDemoFile = "";
2121

2222
public bool isDemoRecording = false;
23+
public bool isDemoRecordingEnabled = true;
2324

2425
public void StartDemoRecording()
2526
{
27+
if (!isDemoRecordingEnabled)
28+
{
29+
Log("[StartDemoRecording] Demo recording is disabled.");
30+
return;
31+
}
2632
if (isDemoRecording)
2733
{
2834
Log("[StartDemoRecording] Demo recording is already in progress.");

EventHandlers.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,9 @@ public HookResult EventRoundFreezeEndHandler(EventRoundFreezeEnd @event, GameEve
171171

172172
Position coachPosition = new(coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
173173
coach!.PlayerPawn.Value!.Teleport(new Vector(coachPosition.PlayerPosition.X, coachPosition.PlayerPosition.Y, coachPosition.PlayerPosition.Z + 20.0f), coachPosition.PlayerAngle, new Vector(0, 0, 0));
174-
// Dropping the C4 if it was picked up or passed to the coach.
175-
DropWeaponByDesignerName(coach, "weapon_c4");
176174
AddTimer(1.5f, () =>
177175
{
178176
coach!.PlayerPawn.Value!.Teleport(new Vector(coachPosition.PlayerPosition.X, coachPosition.PlayerPosition.Y, coachPosition.PlayerPosition.Z + 20.0f), coachPosition.PlayerAngle, new Vector(0, 0, 0));
179-
DropWeaponByDesignerName(coach, "weapon_c4");
180177
CsTeam oldTeam = GetCoachTeam(coach);
181178
coach.ChangeTeam(CsTeam.Spectator);
182179
AddTimer(0.01f, () => coach.ChangeTeam(oldTeam));
@@ -191,6 +188,23 @@ public HookResult EventRoundFreezeEndHandler(EventRoundFreezeEnd @event, GameEve
191188
}
192189
}
193190

191+
public HookResult EventPlayerGivenC4(EventPlayerGivenC4 @event, GameEventInfo info) {
192+
try {
193+
if (!matchStarted) return HookResult.Continue;
194+
if (@event.Userid == null) return HookResult.Continue;
195+
var recv = @event.Userid;
196+
197+
// check if coach
198+
var coaches = reverseTeamSides["TERRORIST"].coach;
199+
if (coaches.Contains(recv)) {
200+
TransferCoachBomb(recv);
201+
}
202+
} catch (Exception e) {
203+
Log($"[EventPlayerGivenC4 FATAL] An error occured: {e.Message}");
204+
}
205+
return HookResult.Continue;
206+
}
207+
194208
public void OnEntitySpawnedHandler(CEntityInstance entity)
195209
{
196210
try
@@ -274,7 +288,6 @@ public HookResult EventPlayerDeathPreHandler(EventPlayerDeath @event, GameEventI
274288
info.DontBroadcast = true;
275289
}
276290
}
277-
278291
return HookResult.Continue;
279292
}
280293
catch (Exception e)
@@ -323,7 +336,6 @@ public HookResult EventHegrenadeDetonateHandler(EventHegrenadeDetonate @event, G
323336
return HookResult.Continue;
324337
}
325338

326-
327339
public HookResult EventMolotovDetonateHandler(EventMolotovDetonate @event, GameEventInfo info)
328340
{
329341
if (!isPractice || isDryRun) return HookResult.Continue;

MatchZy.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ public partial class MatchZy : BasePlugin
1313
{
1414

1515
public override string ModuleName => "MatchZy";
16-
public override string ModuleVersion => "0.8.12";
16+
17+
public override string ModuleVersion => "0.8.13";
1718

1819
public override string ModuleAuthor => "WD- (https://github.com/shobhit-pathak/)";
1920

@@ -208,6 +209,7 @@ public override void Load(bool hotReload) {
208209
RegisterEventHandler<EventCsWinPanelMatch>(EventCsWinPanelMatchHandler);
209210
RegisterEventHandler<EventRoundStart>(EventRoundStartHandler);
210211
RegisterEventHandler<EventRoundFreezeEnd>(EventRoundFreezeEndHandler);
212+
RegisterEventHandler<EventPlayerGivenC4>(EventPlayerGivenC4);
211213
RegisterEventHandler<EventPlayerDeath>(EventPlayerDeathPreHandler, hookMode: HookMode.Pre);
212214
RegisterListener<Listeners.OnClientDisconnectPost>(playerSlot => {
213215
// May not be required, but just to be on safe side so that player data is properly updated in dictionaries

MatchZy.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.337">
10+
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.338">
1111
<PrivateAssets>none</PrivateAssets>
1212
<ExcludeAssets>runtime</ExcludeAssets>
1313
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

Utility.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ private void HandleMatchStart()
768768
HandleClanTags();
769769

770770
string seriesType = "BO" + matchConfig.NumMaps.ToString();
771-
liveMatchId = database.InitMatch(matchzyTeam1.teamName, matchzyTeam2.teamName, "-", isMatchSetup, liveMatchId, matchConfig.CurrentMapNumber, seriesType);
771+
liveMatchId = database.InitMatch(matchzyTeam1.teamName, matchzyTeam2.teamName, "-", isMatchSetup, liveMatchId, matchConfig.CurrentMapNumber, seriesType, matchConfig);
772772
SetupRoundBackupFile();
773773

774774
GetSpawns();
@@ -874,7 +874,7 @@ private void HandleMatchEnd()
874874
{
875875
MatchId = liveMatchId,
876876
MapNumber = currentMapNumber,
877-
Winner = new Winner(t1score > t2score && reverseTeamSides["CT"] == matchzyTeam1 ? "3" : "2", team1SeriesScore > team2SeriesScore ? "team1" : "team2"),
877+
Winner = new Winner(t1score > t2score && reverseTeamSides["CT"] == matchzyTeam1 ? "3" : "2", t1score > t2score ? "team1" : "team2"),
878878
StatsTeam1 = new MatchZyStatsTeam(matchzyTeam1.id, matchzyTeam1.teamName, team1SeriesScore, t1score, 0, 0, new List<StatsPlayer>()),
879879
StatsTeam2 = new MatchZyStatsTeam(matchzyTeam2.id, matchzyTeam2.teamName, team2SeriesScore, t2score, 0, 0, new List<StatsPlayer>())
880880
};
@@ -1739,7 +1739,7 @@ public bool IsTacticalTimeoutActive()
17391739

17401740
static string RemoveSpecialCharacters(string input)
17411741
{
1742-
Regex regex = new("[^a-zA-Z0-9 _-]");
1742+
Regex regex = new("[^\\p{L}0-9 _-]");
17431743
return regex.Replace(input, "");
17441744
}
17451745

cfg/MatchZy/config.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ matchzy_knife_enabled_default true
1313
// Minimum ready players required to start the match. If set to 0, all connected players have to ready-up to start the match. Default: 2
1414
matchzy_minimum_ready_required 2
1515

16+
// Whether to automatically start demo recording when the match goes live. Default value: true
17+
matchzy_demo_recording_enabled true
18+
1619
// Path of folder in which demos will be saved. If defined, it must not start with a slash and must end with a slash. Set to empty string to use the csgo root.
1720
// Example: matchzy_demo_path MatchZy/
1821
// A folder named MatchZy will be created in csgo folder if it does not exist and will store the recorded demos in it. Default value is MatchZy/ which means demos will be stored in MatchZy/

0 commit comments

Comments
 (0)