На сервера Метро и Взаперти, часто происходит базрейп (атака базы противника), что приводит к быстрому и не интересному концу раунда, так же к уходу многих игроков с сервера.
VOTENUKE (сброс бомбы на противника) даст возможность активировать игрокам голосование против команды, которая зажала их на базе.
Для этого, игроки, который оказались зажатыми на базе, должны ввести в чат !votenuke, на сервере в 64 человека, нужно 8-9 голосов !votenuke, и команду противника убьёт два раза, с периодичностью в 10-15 секунд, что даст возможность зажатой команде, прорваться со своей базы до точек.
Для этого можно использовать плагин Insane Limits, и следующий скрипт:
(как вводить лимит в Insane Limits показано здесь Insane limits )
Для этого потребуется создать два новых лимита, назовите первый к примеру Votenuke и установите limit_evaluation на OnAnyChat, первый скрипт Expression
второй скрипт Code
Теперь, создайте второй лимит, и назовите его Secon Nuke
Установите limit_evaluation на OnSpawn, а limit_first_check_code на Code и ввидите этот скрипт:
У вас, должна получиться следующая картина:
Таким образом, при успешном, начатом голосовании !votenuke, команду базрейперов убьёт два раза.
ОБНОВЛЕНИЕ: перевёл сообщения на русский язык!
установите limit_evaluation на OnAnyChat, первый скрипт Expression
Второй скрипт
Теперь, создайте второй лимит, и назовите его Secon Nuke
Установите limit_evaluation на OnSpawn, а limit_first_check_code на Code и ввидите этот скрипт:
VOTENUKE (сброс бомбы на противника) даст возможность активировать игрокам голосование против команды, которая зажала их на базе.
Для этого, игроки, который оказались зажатыми на базе, должны ввести в чат !votenuke, на сервере в 64 человека, нужно 8-9 голосов !votenuke, и команду противника убьёт два раза, с периодичностью в 10-15 секунд, что даст возможность зажатой команде, прорваться со своей базы до точек.
Для этого можно использовать плагин Insane Limits, и следующий скрипт:
(как вводить лимит в Insane Limits показано здесь Insane limits )
Для этого потребуется создать два новых лимита, назовите первый к примеру Votenuke и установите limit_evaluation на OnAnyChat, первый скрипт Expression
Код:
(Regex.Match(server.Gamemode, @"(Conquest|Rush|Domination)").Success)
Код:
/* VERSION 0.9/R8-yes-cancel */
double percent = 25; // CUSTOMIZE: of losing team that has to vote
double timeout = 6.0; // CUSTOMIZE: минут, до истечения голосования
int minPlayers = 16; // CUSTOMIZE: минимальное кол-во игроков для начала голосования
double minTicketPercent = 10; // CUSTOMIZE: минимальный процент тикетов до конца раунда
double minTicketGap = 20; // CUSTOMIZE: минимальная разница в тикетах между проигрывающей и выигрывающей командой
int maxAttempts = 3; // CUSTOMIZE: максимальное кол-во предупреждений
String kCamp = "votenuke";
String kOncePrefix = "votenuke_once_";
String kVoteTime = "votenuke_time";
String kAttemptsPrefix = "votenuke_attempts_";
int level = 2;
try {
level = Convert.ToInt32(plugin.getPluginVarValue("debug_level"));
} catch (Exception e) {}
String msg = "empty";
Action<String> ChatPlayer = delegate(String name) {
// closure bound to String msg
plugin.ServerCommand("admin.say", msg, "player", name);
plugin.PRoConChat("ADMIN to " + name + " > *** " + msg);
};
/* Parse the command */
Match campMatch = Regex.Match(player.LastChat, @"^\s*!vote\s*nuke", RegexOptions.IgnoreCase);
Match yesMatch = Regex.Match(player.LastChat, @"^\s*!yes", RegexOptions.IgnoreCase);
Match cancelMatch = Regex.Match(player.LastChat, @"^\s*!cancelvote", RegexOptions.IgnoreCase);
/* Check for admin cancel */
double t1 = server.RemainTickets(1);
double t2 = server.RemainTickets(2);
int losing = (t1 < t2) ? 1 : 2;
List<PlayerInfoInterface> losers = (losing == 1) ? team1.players : team2.players;
String keyAttempts = kAttemptsPrefix + losing;
int attempts = 0;
if (cancelMatch.Success) {
bool canKill = false;
bool canKick = false;
bool canBan = false;
bool canMove = false;
bool canChangeLevel = false;
if (plugin.CheckAccount(player.Name, out canKill, out canKick, out canBan, out canMove, out canChangeLevel)) {
if (canKick) {
plugin.SendGlobalMessage("votenuke has been cancelled!");
foreach (PlayerInfoInterface can in losers) {
// Erase the vote
if (can.RoundData.issetBool(kCamp)) can.RoundData.unsetBool(kCamp);
}
server.RoundData.unsetObject(kVoteTime);
/* Losing team only gets to try this vote maxAttempts */
attempts = 0;
if (server.RoundData.issetInt(keyAttempts)) attempts = server.RoundData.getInt(keyAttempts);
server.RoundData.setInt(keyAttempts, attempts + 1);
} else {
ChatPlayer("You are not authorized to use this command");
}
} else {
ChatPlayer("Nice try, but only admins can use that command");
}
return false;
}
/* Bail out if not a proper vote */
if (!campMatch.Success && !yesMatch.Success) return false;
/* Bail out if this player already voted */
if (player.RoundData.issetBool(kCamp)) {
msg = "You already voted on this votenuke attempt!";
ChatPlayer(player.Name);
return false;
}
/* Bail out if round about to end */
if (server.RemainTicketsPercent(1) < minTicketPercent || server.RemainTicketsPercent(2) < minTicketPercent) {
msg = "Round too close to ending to hold a nuke vote!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
/* Bail out if ticket ratio isn't large enough */
if (Math.Abs(t1 - t2) < minTicketGap) {
msg = "Ticket counts too close to hold a nuke vote!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
/* Bail out if voter is not on the losing team */
if (player.TeamId != losing) {
msg = "You are not on the losing team!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
/* Bail out if this team already completed a vote camp this round */
String key = kOncePrefix + losing;
if (server.RoundData.issetBool(key)) {
msg = "Your team already completed a nuke vote this round!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
/* Bail out if maxAttempts made */
if (server.RoundData.issetInt(keyAttempts)) {
attempts = server.RoundData.getInt(keyAttempts);
if (attempts >= maxAttempts) {
msg = "Your team already made " + maxAttempts + " attempts at nuking this round!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
}
/* Bail out if not enough players to enable vote */
if (server.PlayerCount < minPlayers) {
msg = "Not enough players to hold a nuke vote!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n " + player.FullName + " voted to nuke baserapers");
msg = "You voted to nuke the other team camping your base";
if (!yesMatch.Success) ChatPlayer(player.Name);
/* Tally the votes */
int votes = 0;
/* Start timer if a valid command */
if (!server.RoundData.issetObject(kVoteTime)) {
if (yesMatch.Success) {
return false;
}
server.RoundData.setObject(kVoteTime, DateTime.Now);
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n vote timer started");
}
DateTime started = (DateTime)server.RoundData.getObject(kVoteTime);
TimeSpan since = DateTime.Now.Subtract(started);
/* Count the vote in the voter's dictionary */
/* Votes are kept with the voter */
/* If the voter leaves, his votes are not counted */
if (!player.RoundData.issetBool(kCamp)) player.RoundData.setBool(kCamp, true);
/* Bail out if too much time has past */
if (since.TotalMinutes > timeout) {
msg = "The voting time has expired, the nuke vote is cancelled!";
plugin.SendGlobalMessage(msg);
plugin.SendGlobalYell(msg, 10);
if (level >= 2) plugin.ConsoleWrite("^b[VoteCamp]^n vote timeout expired");
foreach (PlayerInfoInterface can in losers) {
// Erase the vote
if (can.RoundData.issetBool(kCamp)) can.RoundData.unsetBool(kCamp);
}
server.RoundData.unsetObject(kVoteTime);
/* Losing team only gets to try this vote maxAttempts */
attempts = 0;
if (server.RoundData.issetInt(keyAttempts)) attempts = server.RoundData.getInt(keyAttempts);
server.RoundData.setInt(keyAttempts, attempts + 1);
return false;
}
/* Otherwise tally */
foreach(PlayerInfoInterface p in losers) {
if (p.RoundData.issetBool(kCamp)) votes++;
}
if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n loser votes = " + votes + " of " + losers.Count);
int needed = Convert.ToInt32(Math.Ceiling((double) losers.Count * (percent/100.0)));
int remain = needed - votes;
if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n needed = " + needed);
String campers = (losing == 1) ? "RU" : "US"; // BF3
String voters = (losing == 1) ? "US" : "RU"; // BF3
if (server.GameVersion == "BF4") {
String[] factionNames = new String[]{"US", "RU", "CN"};
int f1 = (team1.Faction < 0 || team1.Faction > 2) ? 0 : team1.Faction;
int f2 = (team2.Faction < 0 || team2.Faction > 2) ? 1 : team2.Faction;
campers = (losing == 1) ? factionNames[f2] : factionNames[f1];
voters = (losing == 1) ? factionNames[f1] : factionNames[f2];
}
if (remain > 0) {
msg = remain + " " + voters + " votes needed to punish " + campers + " team! " + Convert.ToInt32(Math.Ceiling(timeout - since.TotalMinutes)) + " mins left to vote!";
plugin.SendGlobalMessage(msg);
plugin.SendGlobalYell(msg, 8);
if (level >= 2) plugin.ConsoleWrite("^b[VoteNote]^n " + msg);
return false;
}
/* Punish the campers */
msg = "Vote succeeded: " + campers + " team is being nuked for camping your deployment! Break out now!";
plugin.SendGlobalMessage(msg);
plugin.SendGlobalYell(msg, 15);
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n " + msg);
List<PlayerInfoInterface> bad = (losing == 1) ? team2.players : team1.players;
foreach (PlayerInfoInterface nuke in bad) {
nuke.RoundData.setBool("NUKE TWICE", true);
plugin.KillPlayer(nuke.Name, 1);
if (level >= 3) plugin.ConsoleWrite("^b[VoteCamp]^n killing " + nuke.FullName);
}
/* Losing team only gets to do this once */
server.RoundData.setBool(key, true);
return false;
Теперь, создайте второй лимит, и назовите его Secon Nuke
Установите limit_evaluation на OnSpawn, а limit_first_check_code на Code и ввидите этот скрипт:
Код:
int level = 2;
try {
level = Convert.ToInt32(plugin.getPluginVarValue("debug_level"));
} catch (Exception e) {}
if (player.RoundData.issetBool("NUKE TWICE")) {
player.RoundData.unsetBool("NUKE TWICE");
plugin.SendPlayerMessage(player.Name, "You will be ADMIN KILLED one more time, then you can spawn again!");
plugin.KillPlayer(player.Name, 5);
if (level >= 3) plugin.ConsoleWrite("^b[VoteCamp]^n SECOND killing of " + player.FullName);
}
return false;
Таким образом, при успешном, начатом голосовании !votenuke, команду базрейперов убьёт два раза.
ОБНОВЛЕНИЕ: перевёл сообщения на русский язык!
установите limit_evaluation на OnAnyChat, первый скрипт Expression
Код:
(Regex.Match(server.Gamemode, @"(Conquest|Rush|Domination)").Success)
Второй скрипт
Код:
/* VERSION 0.9/R8-yes-cancel */
double percent = 25; // CUSTOMIZE: of losing team that has to vote
double timeout = 6.0; // CUSTOMIZE: минут, до истечения голосования
int minPlayers = 16; // CUSTOMIZE: минимальное кол-во игроков для начала голосования
double minTicketPercent = 10; // CUSTOMIZE: минимальный процент тикетов до конца раунда
double minTicketGap = 20; // CUSTOMIZE: минимальная разница в тикетах между проигрывающей и выигрывающей командой
int maxAttempts = 3; // CUSTOMIZE: максимальное кол-во предупреждений
String kCamp = "votenuke";
String kOncePrefix = "votenuke_once_";
String kVoteTime = "votenuke_time";
String kAttemptsPrefix = "votenuke_attempts_";
int level = 2;
try {
level = Convert.ToInt32(plugin.getPluginVarValue("debug_level"));
} catch (Exception e) {}
String msg = "empty";
Action<String> ChatPlayer = delegate(String name) {
// closure bound to String msg
plugin.ServerCommand("admin.say", msg, "player", name);
plugin.PRoConChat("ADMIN to " + name + " > *** " + msg);
};
/* Parse the command */
Match campMatch = Regex.Match(player.LastChat, @"^\s*!vote\s*nuke", RegexOptions.IgnoreCase);
Match yesMatch = Regex.Match(player.LastChat, @"^\s*!yes", RegexOptions.IgnoreCase);
Match cancelMatch = Regex.Match(player.LastChat, @"^\s*!cancelvote", RegexOptions.IgnoreCase);
/* Check for admin cancel */
double t1 = server.RemainTickets(1);
double t2 = server.RemainTickets(2);
int losing = (t1 < t2) ? 1 : 2;
List<PlayerInfoInterface> losers = (losing == 1) ? team1.players : team2.players;
String keyAttempts = kAttemptsPrefix + losing;
int attempts = 0;
if (cancelMatch.Success) {
bool canKill = false;
bool canKick = false;
bool canBan = false;
bool canMove = false;
bool canChangeLevel = false;
if (plugin.CheckAccount(player.Name, out canKill, out canKick, out canBan, out canMove, out canChangeLevel)) {
if (canKick) {
plugin.SendGlobalMessage("VOTENUK отменён!");
foreach (PlayerInfoInterface can in losers) {
// Erase the vote
if (can.RoundData.issetBool(kCamp)) can.RoundData.unsetBool(kCamp);
}
server.RoundData.unsetObject(kVoteTime);
/* Losing team only gets to try this vote maxAttempts */
attempts = 0;
if (server.RoundData.issetInt(keyAttempts)) attempts = server.RoundData.getInt(keyAttempts);
server.RoundData.setInt(keyAttempts, attempts + 1);
} else {
ChatPlayer("Вы не можете использовать эту команду");
}
} else {
ChatPlayer("Только админы могут использовать эту команду!");
}
return false;
}
/* Bail out if not a proper vote */
if (!campMatch.Success && !yesMatch.Success) return false;
/* Bail out if this player already voted */
if (player.RoundData.issetBool(kCamp)) {
msg = "Вы уже голосовали!";
ChatPlayer(player.Name);
return false;
}
/* Bail out if round about to end */
if (server.RemainTicketsPercent(1) < minTicketPercent || server.RemainTicketsPercent(2) < minTicketPercent) {
msg = "Round too close to ending to hold a nuke vote!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
/* Bail out if ticket ratio isn't large enough */
if (Math.Abs(t1 - t2) < minTicketGap) {
msg = "Нет требуемой разницы в тикетах, для сброса БОМБЫ! (Votenuke)";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
/* Bail out if voter is not on the losing team */
if (player.TeamId != losing) {
msg = "Вы не в проигрывающей команде!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
/* Bail out if this team already completed a vote camp this round */
String key = kOncePrefix + losing;
if (server.RoundData.issetBool(key)) {
msg = "Ваша команда уже использовала возможность сброса бомбы!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
/* Bail out if maxAttempts made */
if (server.RoundData.issetInt(keyAttempts)) {
attempts = server.RoundData.getInt(keyAttempts);
if (attempts >= maxAttempts) {
msg = "Вы уже использовали " + maxAttempts + " попыток VOTENUKE в этом раунде!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
}
/* Bail out if not enough players to enable vote */
if (server.PlayerCount < minPlayers) {
msg = "Не достаточно игроков, чтобы активировать СБРОС БОМБЫ!";
if (!yesMatch.Success) ChatPlayer(player.Name);
return false;
}
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n " + player.FullName + " voted to nuke baserapers");
msg = "Вы проголосовали за СБРОС БОМБЫ на вражескую команду!";
if (!yesMatch.Success) ChatPlayer(player.Name);
/* Tally the votes */
int votes = 0;
/* Start timer if a valid command */
if (!server.RoundData.issetObject(kVoteTime)) {
if (yesMatch.Success) {
return false;
}
server.RoundData.setObject(kVoteTime, DateTime.Now);
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n vote timer started");
}
DateTime started = (DateTime)server.RoundData.getObject(kVoteTime);
TimeSpan since = DateTime.Now.Subtract(started);
/* Count the vote in the voter's dictionary */
/* Votes are kept with the voter */
/* If the voter leaves, his votes are not counted */
if (!player.RoundData.issetBool(kCamp)) player.RoundData.setBool(kCamp, true);
/* Bail out if too much time has past */
if (since.TotalMinutes > timeout) {
msg = "Время голосования за СБРОС БОМБЫ (VOTENUKE) истекло!";
plugin.SendGlobalMessage(msg);
plugin.SendGlobalYell(msg, 10);
if (level >= 2) plugin.ConsoleWrite("^b[VoteCamp]^n vote timeout expired");
foreach (PlayerInfoInterface can in losers) {
// Erase the vote
if (can.RoundData.issetBool(kCamp)) can.RoundData.unsetBool(kCamp);
}
server.RoundData.unsetObject(kVoteTime);
/* Losing team only gets to try this vote maxAttempts */
attempts = 0;
if (server.RoundData.issetInt(keyAttempts)) attempts = server.RoundData.getInt(keyAttempts);
server.RoundData.setInt(keyAttempts, attempts + 1);
return false;
}
/* Otherwise tally */
foreach(PlayerInfoInterface p in losers) {
if (p.RoundData.issetBool(kCamp)) votes++;
}
if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n loser votes = " + votes + " of " + losers.Count);
int needed = Convert.ToInt32(Math.Ceiling((double) losers.Count * (percent/100.0)));
int remain = needed - votes;
if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n needed = " + needed);
String campers = (losing == 1) ? "RU" : "US"; // BF3
String voters = (losing == 1) ? "US" : "RU"; // BF3
if (server.GameVersion == "BF4") {
String[] factionNames = new String[]{"US", "RU", "CN"};
int f1 = (team1.Faction < 0 || team1.Faction > 2) ? 0 : team1.Faction;
int f2 = (team2.Faction < 0 || team2.Faction > 2) ? 1 : team2.Faction;
campers = (losing == 1) ? factionNames[f2] : factionNames[f1];
voters = (losing == 1) ? factionNames[f1] : factionNames[f2];
}
if (remain > 0) {
msg = remain + " " + voters + " ГОЛОСОВ ТРЕБУЕТСЯ, ЧТОБЫ СБРОСИТЬ БОМБУ НА КОМАНДУ " + campers + Convert.ToInt32(Math.Ceiling(timeout - since.TotalMinutes)) + " минут осталось!";
plugin.SendGlobalMessage(msg);
plugin.SendGlobalYell(msg, 8);
if (level >= 2) plugin.ConsoleWrite("^b[VoteNote]^n " + msg);
return false;
}
/* Punish the campers */
msg = "НА КОМАНДУ " + campers + " сброшена бомба! Прорывайтесь быстрее!";
plugin.SendGlobalMessage(msg);
plugin.SendGlobalYell(msg, 15);
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n " + msg);
List<PlayerInfoInterface> bad = (losing == 1) ? team2.players : team1.players;
foreach (PlayerInfoInterface nuke in bad) {
nuke.RoundData.setBool("NUKE TWICE", true);
plugin.KillPlayer(nuke.Name, 1);
if (level >= 3) plugin.ConsoleWrite("^b[VoteCamp]^n killing " + nuke.FullName);
}
/* Losing team only gets to do this once */
server.RoundData.setBool(key, true);
return false;
Теперь, создайте второй лимит, и назовите его Secon Nuke
Установите limit_evaluation на OnSpawn, а limit_first_check_code на Code и ввидите этот скрипт:
Код:
int level = 2;
try {
level = Convert.ToInt32(plugin.getPluginVarValue("debug_level"));
} catch (Exception e) {}
if (player.RoundData.issetBool("NUKE TWICE")) {
player.RoundData.unsetBool("NUKE TWICE");
plugin.SendPlayerMessage(player.Name, "Вы будете убиты ещё раз! Затем Вы сможете дислоцироваться!");
plugin.KillPlayer(player.Name, 5);
if (level >= 3) plugin.ConsoleWrite("^b[VoteCamp]^n SECOND killing of " + player.FullName);
}
return false;
Последнее редактирование: