v1.3.2: ручной телепорт игроков на спавны команды
- Добавлен TeleportToTeamSpawn (info_player_terrorist/counterterrorist) - ТТшник в 1vAll телепортируется на T-спавн (было: CS_RespawnPlayer оставлял живого игрока на CT-спавне) - После 1vAll команды восстанавливаются физически через Timer_FinalTeamRestore
This commit is contained in:
@@ -97,10 +97,14 @@ addons/sourcemod/logs/custom_rounds.log
|
|||||||
|
|
||||||
## Версия
|
## Версия
|
||||||
|
|
||||||
`1.3.1` — Автор: deidara.dev
|
`1.3.2` — Автор: deidara.dev
|
||||||
|
|
||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
|
- **1.3.2**
|
||||||
|
- Фикс: ТТшник в режиме 1 vs All теперь гарантированно телепортируется на T-спавн (раньше `CS_RespawnPlayer` в CSGO мог оставить уже-живого игрока на CT-спавне, что ломало возможность покупки)
|
||||||
|
- Фикс: после окончания 1vAll команды восстанавливаются физически — добавлен `Timer_FinalTeamRestore`, который телепортирует игроков на спавны их исходных команд
|
||||||
|
- Добавлен хелпер `TeleportToTeamSpawn` (использует `info_player_terrorist` / `info_player_counterterrorist` энтити)
|
||||||
- **1.3.1**
|
- **1.3.1**
|
||||||
- Фикс компиляции: `CSRoundEnd_RoundDraw` → `CSRoundEnd_Draw` (правильное имя константы в `cstrike.inc`)
|
- Фикс компиляции: `CSRoundEnd_RoundDraw` → `CSRoundEnd_Draw` (правильное имя константы в `cstrike.inc`)
|
||||||
- **1.3.0**
|
- **1.3.0**
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public Plugin myinfo =
|
|||||||
name = "ArcaneGame Custom Rounds Core",
|
name = "ArcaneGame Custom Rounds Core",
|
||||||
author = "deidara.dev",
|
author = "deidara.dev",
|
||||||
description = "Core plugin for custom rounds with AG Coin integration",
|
description = "Core plugin for custom rounds with AG Coin integration",
|
||||||
version = "1.3.1",
|
version = "1.3.2",
|
||||||
url = "https://deidara.dev"
|
url = "https://deidara.dev"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -618,7 +618,9 @@ public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast)
|
|||||||
|
|
||||||
ResetAllPlayerStats();
|
ResetAllPlayerStats();
|
||||||
|
|
||||||
// Восстанавливаем команды после предыдущего 1vAll (до спавна игроков)
|
// Восстанавливаем команды после предыдущего 1vAll
|
||||||
|
// CS_SwitchTeam меняем сразу (чтобы спавн использовал нужную команду),
|
||||||
|
// а телепорт делаем через таймер после того как игроки заспавнились
|
||||||
if (g_PendingTeamRestore)
|
if (g_PendingTeamRestore)
|
||||||
{
|
{
|
||||||
for (int i = 1; i <= MaxClients; i++)
|
for (int i = 1; i <= MaxClients; i++)
|
||||||
@@ -632,10 +634,11 @@ public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast)
|
|||||||
{
|
{
|
||||||
CS_SwitchTeam(i, g_OriginalTeam[i]);
|
CS_SwitchTeam(i, g_OriginalTeam[i]);
|
||||||
}
|
}
|
||||||
g_OriginalTeam[i] = 0;
|
|
||||||
}
|
}
|
||||||
g_PendingTeamRestore = false;
|
|
||||||
g_OneVsAllTUserId = 0;
|
// Через 0.4с телепортируем всех на спавны их исходных команд
|
||||||
|
// (к этому моменту CSGO уже отработает игровой спавн)
|
||||||
|
CreateTimer(0.4, Timer_FinalTeamRestore, _, TIMER_FLAG_NO_MAPCHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_PendingRound != CR_None)
|
if (g_PendingRound != CR_None)
|
||||||
@@ -921,6 +924,18 @@ public Action Timer_OneVsAll_ApplyLoadouts(Handle timer, any tUserId)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int targetTeam = (i == chosenT) ? CS_TEAM_T : CS_TEAM_CT;
|
||||||
|
|
||||||
|
// Гарантированно убеждаемся что игрок на правильной команде
|
||||||
|
if (GetClientTeam(i) != targetTeam)
|
||||||
|
{
|
||||||
|
CS_SwitchTeam(i, targetTeam);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Принудительно телепортируем на спавн нужной команды
|
||||||
|
// (CS_RespawnPlayer в CSGO не переносит уже живого игрока)
|
||||||
|
TeleportToTeamSpawn(i, targetTeam);
|
||||||
|
|
||||||
StripPlayerWeapons(i);
|
StripPlayerWeapons(i);
|
||||||
GivePlayerItem(i, "weapon_knife");
|
GivePlayerItem(i, "weapon_knife");
|
||||||
|
|
||||||
@@ -954,6 +969,44 @@ public Action Timer_OneVsAll_ApplyLoadouts(Handle timer, any tUserId)
|
|||||||
return Plugin_Stop;
|
return Plugin_Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Action Timer_FinalTeamRestore(Handle timer)
|
||||||
|
{
|
||||||
|
if (!g_PendingTeamRestore)
|
||||||
|
{
|
||||||
|
return Plugin_Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i <= MaxClients; i++)
|
||||||
|
{
|
||||||
|
if (!IsClientInGame(i) || IsFakeClient(i))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (g_OriginalTeam[i] < CS_TEAM_T)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Дополнительная проверка команды
|
||||||
|
if (GetClientTeam(i) != g_OriginalTeam[i])
|
||||||
|
{
|
||||||
|
CS_SwitchTeam(i, g_OriginalTeam[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Телепортируем на спавн исходной команды если игрок жив
|
||||||
|
if (IsPlayerAlive(i))
|
||||||
|
{
|
||||||
|
TeleportToTeamSpawn(i, g_OriginalTeam[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_OriginalTeam[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_PendingTeamRestore = false;
|
||||||
|
g_OneVsAllTUserId = 0;
|
||||||
|
return Plugin_Stop;
|
||||||
|
}
|
||||||
|
|
||||||
int ResolveOneVsAllTarget()
|
int ResolveOneVsAllTarget()
|
||||||
{
|
{
|
||||||
// 1) Если админ выбрал конкретного — пробуем его
|
// 1) Если админ выбрал конкретного — пробуем его
|
||||||
@@ -998,6 +1051,58 @@ int CountActivePlayers()
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Телепортирует игрока на случайный спавн нужной команды.
|
||||||
|
// CS_RespawnPlayer в CSGO не всегда переносит уже живого игрока, поэтому делаем это вручную.
|
||||||
|
bool TeleportToTeamSpawn(int client, int team)
|
||||||
|
{
|
||||||
|
if (!IsClientInGame(client) || !IsPlayerAlive(client))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (team != CS_TEAM_T && team != CS_TEAM_CT)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char classname[64];
|
||||||
|
if (team == CS_TEAM_T)
|
||||||
|
{
|
||||||
|
strcopy(classname, sizeof(classname), "info_player_terrorist");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcopy(classname, sizeof(classname), "info_player_counterterrorist");
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawns[128];
|
||||||
|
int count = 0;
|
||||||
|
int ent = -1;
|
||||||
|
while ((ent = FindEntityByClassname(ent, classname)) != -1 && count < sizeof(spawns))
|
||||||
|
{
|
||||||
|
// Пропускаем отключённые spawn points (если у энтити есть такой проп)
|
||||||
|
if (HasEntProp(ent, Prop_Data, "m_bDisabled") && GetEntProp(ent, Prop_Data, "m_bDisabled") != 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
spawns[count++] = ent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawnEnt = spawns[GetRandomInt(0, count - 1)];
|
||||||
|
|
||||||
|
float pos[3], ang[3];
|
||||||
|
GetEntPropVector(spawnEnt, Prop_Data, "m_vecAbsOrigin", pos);
|
||||||
|
GetEntPropVector(spawnEnt, Prop_Data, "m_angRotation", ang);
|
||||||
|
|
||||||
|
float zeroVel[3];
|
||||||
|
TeleportEntity(client, pos, ang, zeroVel);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public Action Timer_ApplyModeToClient(Handle timer, any userid)
|
public Action Timer_ApplyModeToClient(Handle timer, any userid)
|
||||||
{
|
{
|
||||||
int client = GetClientOfUserId(userid);
|
int client = GetClientOfUserId(userid);
|
||||||
|
|||||||
Reference in New Issue
Block a user