Jump to content

Insane Limits V0.9/R6: Vote to nuke camping/base raping team, or !surrender (CQ/Rush)


ImportBot

Recommended Posts

Originally Posted by kcuestag*:

 

I currently use this latest version:

 

Code:

/* VERSION 0.9/R7 */
double percent = 35; // CUSTOMIZE: of losing team that has to vote
double timeout = 5.0; // CUSTOMIZE: number of minutes before vote times out
int minPlayers = 16; // CUSTOMIZE: minimum players to enable vote
double minTicketPercent = 10; // CUSTOMIZE: minimum ticket percentage remaining in the round
double minTicketGap = 20; // CUSTOMIZE: minimum ticket gap between winning and losing teams
int maxAttempts = 3; // CUSTOMIZE: maximum number of attempts

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);

/* 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!";
    ChatPlayer(player.Name);
    return false;
}

/* Bail out if ticket ratio isn't large enough */

double t1 = server.RemainTickets(1);
double t2 = server.RemainTickets(2);
if (Math.Abs(t1 - t2) < minTicketGap) {
    msg = "Ticket counts too close to hold a nuke vote!";
    ChatPlayer(player.Name);
    return false;
}

/* Bail out if voter is not on the losing team */

int losing = (t1 < t2) _ 1 : 2;

if (player.TeamId != losing) {
    msg = "You are not on the losing team!";
    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!";
    ChatPlayer(player.Name);
    return false;
}

/* Bail out if maxAttempts made */

String keyAttempts = kAttemptsPrefix + losing;
int attempts = 0;
if (server.RoundData.issetInt(keyAttempts)) {
    attempts = server.RoundData.getInt(keyAttempts);
    if (attempts >= maxAttempts) {
        msg = "Your team already made " + maxAttempts + " attempts at nuking this round!";
        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!";
    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";
ChatPlayer(player.Name);

/* Tally the votes */

int votes = 0;
List<PlayerInfoInterface> losers = (losing == 1) _ team1.players : team2.players;

/* Bail out if too much time has past */

if (!server.RoundData.issetObject(kVoteTime)) {
        if (!campMatch.Success) {
            plugin.SendPlayerMessage(player.Name, "What are you voting !yes for_ Type !votenuke to start a vote.");
            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);

if (since.TotalMinutes > timeout) {
    msg = "The voting time has expired, the nuke vote is cancelled!";
    plugin.SendGlobalMessage(msg);
    plugin.ServerCommand("admin.yell", msg);
    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);
    
    //server.RoundData.setBool(key, true);

    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";
String voters = (losing == 1) _ "US" : "RU";
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.ServerCommand("admin.yell", 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.ServerCommand("admin.yell", msg, "30");
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n " + msg);

List<PlayerInfoInterface> bad = (losing == 1) _ team2.players : team1.players;
foreach (PlayerInfoInterface nuke in bad) {
    plugin.KillPlayer(nuke.Name, 1);
    if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n killing " + nuke.FullName);
}

/* Losing team only gets to do this once */

server.RoundData.setBool(key, true);

return false;
if I wanted to remove the !yes confirmation and only allow !votenuke so that I can use Votekick/Voteban, what would I need to remove?

 

Sorry for all the hassle.

* Restored post. It could be that the author is no longer active.
Link to comment
  • 4 weeks later...
  • Replies 306
  • Created
  • Last Reply

Originally Posted by Latimojo*:

 

NOTE: If you run votekick or other plugins that use !yes and !no, expect plugins to get confused.

 

Changes in red. Or you can just copy/paste the whole thing as a replacement.

 

Code:

/* VERSION 0.9/R6 */
double percent = 35; // CUSTOMIZE: of losing team that has to vote
double timeout = 5.0; // CUSTOMIZE: number of minutes before vote times out
int minPlayers = 16; // CUSTOMIZE: minimum players to enable vote
double minTicketPercent = 10; // CUSTOMIZE: minimum ticket percentage remaining in the round
double minTicketGap = 30; // CUSTOMIZE: minimum ticket gap between winning and losing teams

String kCamp = "votecamp";
String kOncePrefix = "votecamp_once_";
String kVoteTime = "votecamp_time";

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);

/* Bail out if not a proper vote */

if (!campMatch.Success && !yesMatch.Success) 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!";
	ChatPlayer(player.Name);
	return false;
}

/* Bail out if ticket ratio isn't large enough */

double t1 = server.RemainTickets(1);
double t2 = server.RemainTickets(2);
if (Math.Abs(t1 - t2) < minTicketGap) {
	msg = "Ticket counts too close to hold a nuke vote!";
	ChatPlayer(player.Name);
	return false;
}

/* Bail out if voter is not on the losing team */

int losing = (t1 < t2) _ 1 : 2;

if (player.TeamId != losing) {
	msg = "You are not on the losing team!";
	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!";
	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!";
	ChatPlayer(player.Name);
	return false;
}

// MOVED LINES TO LOWER, SEE BELOW

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";
ChatPlayer(player.Name);

/* Tally the votes */

int votes = 0;
List<PlayerInfoInterface> losers = (losing == 1) _ team1.players : team2.players;

/* Bail out if too much time has past */

if (!server.RoundData.issetObject(kVoteTime)) {
        if (!campMatch.Success) {
            plugin.SendPlayerMessage(player.Name, "What are you voting !yes for_ Type !votenuke to start a vote.");
            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);

if (since.TotalMinutes > timeout) {
	msg = "The voting time has expired, the nuke vote is cancelled!";
	plugin.SendGlobalMessage(msg);
	plugin.ServerCommand("admin.yell", msg);
	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 once per round */
	server.RoundData.setBool(key, true);

	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";
String voters = (losing == 1) _ "US" : "RU";
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.ServerCommand("admin.yell", 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.ServerCommand("admin.yell", msg, "30");
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n " + msg);

List<PlayerInfoInterface> bad = (losing == 1) _ team2.players : team1.players;
foreach (PlayerInfoInterface nuke in bad) {
	plugin.KillPlayer(nuke.Name, 1);
	if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n killing " + nuke.FullName);
}

/* Losing team only gets to do this once */

server.RoundData.setBool(key, true);

return false;
I see the different options to trigger the vote, but is there is "control" script that will prevent a second or third nuke prior to a predetermined amount of time instead of tickets?
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

I see the different options to trigger the vote, but is there is "control" script that will prevent a second or third nuke prior to a predetermined amount of time instead of tickets?

Each team is only allowed to successfully nuke once per round. The "count" is the line server.RoundData.setBool(key, true);
* Restored post. It could be that the author is no longer active.
Link to comment
  • 3 weeks later...

Originally Posted by txapollo243*:

 

I want to modify the plugin in order to display a message that lists the percentage of the players in the losing team that voted (either with yes or no) when the vote fails because not enough players have voted for it. Can someone point to me the lines where the plugin notifies the players that vote failed message because of insufficient "yes" votes?

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

I want to modify the plugin in order to display a message that lists the percentage of the players in the losing team that voted (either with yes or no) when the vote fails because not enough players have voted for it. Can someone point to me the lines where the plugin notifies the players that vote failed message because of insufficient "yes" votes?

Unfortunately, the way the code is structured, this can't be done. The check on a failed vote (time has run out) comes before the counting of votes. The only opportunity to send the message is when time is checked.

 

It mightbe possible to move the time check. I'm not sure if this will work, but you can try it. The line in red is the added line:

 

Code:

/* VERSION 0.9/R7 */
double percent = 35; // CUSTOMIZE: of losing team that has to vote
double timeout = 5.0; // CUSTOMIZE: number of minutes before vote times out
int minPlayers = 16; // CUSTOMIZE: minimum players to enable vote
double minTicketPercent = 10; // CUSTOMIZE: minimum ticket percentage remaining in the round
double minTicketGap = 20; // CUSTOMIZE: minimum ticket gap between winning and losing teams
int maxAttempts = 3; // CUSTOMIZE: maximum number of attempts

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);

/* 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!";
    ChatPlayer(player.Name);
    return false;
}

/* Bail out if ticket ratio isn't large enough */

double t1 = server.RemainTickets(1);
double t2 = server.RemainTickets(2);
if (Math.Abs(t1 - t2) < minTicketGap) {
    msg = "Ticket counts too close to hold a nuke vote!";
    ChatPlayer(player.Name);
    return false;
}

/* Bail out if voter is not on the losing team */

int losing = (t1 < t2) _ 1 : 2;

if (player.TeamId != losing) {
    msg = "You are not on the losing team!";
    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!";
    ChatPlayer(player.Name);
    return false;
}

/* Bail out if maxAttempts made */

String keyAttempts = kAttemptsPrefix + losing;
int attempts = 0;
if (server.RoundData.issetInt(keyAttempts)) {
    attempts = server.RoundData.getInt(keyAttempts);
    if (attempts >= maxAttempts) {
        msg = "Your team already made " + maxAttempts + " attempts at nuking this round!";
        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!";
    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";
ChatPlayer(player.Name);

/* Tally the votes */

int votes = 0;
List<PlayerInfoInterface> losers = (losing == 1) _ team1.players : team2.players;

/* Bail out if too much time has past */

if (!server.RoundData.issetObject(kVoteTime)) {
    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);

/* 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";
String voters = (losing == 1) _ "US" : "RU";

if (since.TotalMinutes > timeout) {
    msg = "Voting time has expired, only " + ((votes/needed)*100.0).ToString("F0") + "% voted, needed " + percent + "%";
    plugin.SendGlobalMessage(msg);
    plugin.ServerCommand("admin.yell", msg);
    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);
    
    //server.RoundData.setBool(key, true);

    return false;
}


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.ServerCommand("admin.yell", 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.ServerCommand("admin.yell", msg, "30");
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n " + msg);

List<PlayerInfoInterface> bad = (losing == 1) _ team2.players : team1.players;
foreach (PlayerInfoInterface nuke in bad) {
    plugin.KillPlayer(nuke.Name, 1);
    if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n killing " + nuke.FullName);
}

/* Losing team only gets to do this once */

server.RoundData.setBool(key, true);

return false;
* Restored post. It could be that the author is no longer active.
Link to comment
  • 2 weeks later...

Originally Posted by kcuestag*:

 

Hello PapaCharlie9,

 

I have two requests for my current version of the Limit:

 

1. Could you remove the !yes as a way of voting for Nuke? Too many conflicts with other plugins, although I do appreciate the fact you made this so I could try it out.

 

2. Any way you can do a command like !cancelvotenuke so that we can cancel the vote when people try to abuse it?

 

I'd really appreciate it, thanks in advance.

 

Here's the limit I'm using at the moment:

 

 

Code:

/* VERSION 0.9/R7 */
double percent = 35; // CUSTOMIZE: of losing team that has to vote
double timeout = 5.0; // CUSTOMIZE: number of minutes before vote times out
int minPlayers = 16; // CUSTOMIZE: minimum players to enable vote
double minTicketPercent = 10; // CUSTOMIZE: minimum ticket percentage remaining in the round
double minTicketGap = 20; // CUSTOMIZE: minimum ticket gap between winning and losing teams
int maxAttempts = 3; // CUSTOMIZE: maximum number of attempts

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);

/* 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!";
    ChatPlayer(player.Name);
    return false;
}

/* Bail out if ticket ratio isn't large enough */

double t1 = server.RemainTickets(1);
double t2 = server.RemainTickets(2);
if (Math.Abs(t1 - t2) < minTicketGap) {
    msg = "Ticket counts too close to hold a nuke vote!";
    ChatPlayer(player.Name);
    return false;
}

/* Bail out if voter is not on the losing team */

int losing = (t1 < t2) _ 1 : 2;

if (player.TeamId != losing) {
    msg = "You are not on the losing team!";
    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!";
    ChatPlayer(player.Name);
    return false;
}

/* Bail out if maxAttempts made */

String keyAttempts = kAttemptsPrefix + losing;
int attempts = 0;
if (server.RoundData.issetInt(keyAttempts)) {
    attempts = server.RoundData.getInt(keyAttempts);
    if (attempts >= maxAttempts) {
        msg = "Your team already made " + maxAttempts + " attempts at nuking this round!";
        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!";
    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";
ChatPlayer(player.Name);

/* Tally the votes */

int votes = 0;
List<PlayerInfoInterface> losers = (losing == 1) _ team1.players : team2.players;

/* Bail out if too much time has past */

if (!server.RoundData.issetObject(kVoteTime)) {
        if (!campMatch.Success) {
            plugin.SendPlayerMessage(player.Name, "What are you voting !yes for_ Type !votenuke to start a vote.");
            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);

if (since.TotalMinutes > timeout) {
    msg = "The voting time has expired, the nuke vote is cancelled!";
    plugin.SendGlobalMessage(msg);
    plugin.ServerCommand("admin.yell", msg);
    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);
    
    //server.RoundData.setBool(key, true);

    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";
String voters = (losing == 1) _ "US" : "RU";
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.ServerCommand("admin.yell", 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.ServerCommand("admin.yell", msg, "30");
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n " + msg);

List<PlayerInfoInterface> bad = (losing == 1) _ team2.players : team1.players;
foreach (PlayerInfoInterface nuke in bad) {
    plugin.KillPlayer(nuke.Name, 1);
    if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n killing " + nuke.FullName);
}

/* Losing team only gets to do this once */

server.RoundData.setBool(key, true);

return false;
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

This version still accepts !yes, but doesn't print any error messages if someone types !yes instead of !votenuke. Messages are printed if the !yes helps an on-going votenuke count, if the votenuke times out, or if a votenuke succeeds. Much fewer, but not zero, confusion or wrong messages this way.

 

I don't understand what you mean by abuse and I don't understand what kind of command you want or who "we" is exactly. If anyone can cancel a vote by a command, why have it?

 

Code:

/* VERSION 0.9/R7-yes */
double percent = 35; // CUSTOMIZE: of losing team that has to vote
double timeout = 5.0; // CUSTOMIZE: number of minutes before vote times out
int minPlayers = 16; // CUSTOMIZE: minimum players to enable vote
double minTicketPercent = 10; // CUSTOMIZE: minimum ticket percentage remaining in the round
double minTicketGap = 20; // CUSTOMIZE: minimum ticket gap between winning and losing teams
int maxAttempts = 3; // CUSTOMIZE: maximum number of attempts

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);

/* 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 */

double t1 = server.RemainTickets(1);
double t2 = server.RemainTickets(2);
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 */

int losing = (t1 < t2) _ 1 : 2;

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 */

String keyAttempts = kAttemptsPrefix + losing;
int attempts = 0;
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;
List<PlayerInfoInterface> losers = (losing == 1) _ team1.players : team2.players;

/* Bail out if too much time has past */

if (!server.RoundData.issetObject(kVoteTime)) {
        if (!campMatch.Success) {
            plugin.SendPlayerMessage(player.Name, "What are you voting !yes for_ Type !votenuke to start a vote.");
            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);

if (since.TotalMinutes > timeout) {
    msg = "The voting time has expired, the nuke vote is cancelled!";
    plugin.SendGlobalMessage(msg);
    plugin.ServerCommand("admin.yell", msg);
    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);
    
    //server.RoundData.setBool(key, true);

    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";
String voters = (losing == 1) _ "US" : "RU";
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.ServerCommand("admin.yell", 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.ServerCommand("admin.yell", msg, "30");
if (level >= 2) plugin.ConsoleWrite("^b[VoteNuke]^n " + msg);

List<PlayerInfoInterface> bad = (losing == 1) _ team2.players : team1.players;
foreach (PlayerInfoInterface nuke in bad) {
    plugin.KillPlayer(nuke.Name, 1);
    if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n killing " + nuke.FullName);
}

/* Losing team only gets to do this once */

server.RoundData.setBool(key, true);

return false;
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by kcuestag*:

 

I don't mean that anyone can cancel a vote, I want only ADMINS (With procon access or whatever) to be able to cancel a !votenuke.

 

Thanks for fixing the !yes error. :smile:

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

I don't mean that anyone can cancel a vote, I want only ADMINS (With procon access or whatever)

Okay, now we are getting somewhere. Just procon access or specific rights?

 

I can do that, but it is way easier for me if I can just use a clan tag, if that would be acceptable. If so, which tag?

 

I still want to understand what you mean by abuse, also.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by kcuestag*:

 

Sadly clan tag is not an option as we have some members with no admin privileges and I wouldn't like them having this one either. Would be nice that anyone who can use the Kick command (For example) could do this.

 

By abuse I mean some crying players who tend to just do !votenuke for fun even if their team has a flag or two, and sometimes it succeeds because other trolls follow his game.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

By abuse I mean some crying players who tend to just do !votenuke for fun even if their team has a flag or two, and sometimes it succeeds because other trolls follow his game.

Is the per-round max attempts limit not working? There is a team-wide counter that only allows 3 attempts at doing a votenuke. For the fourth and further the message, "Your team already made 3 attempts at nuking this round!" is sent to the player and the command is ignored. You can lower that value (maxAttempts) to 2 or 1 if you like.

 

In any case, this version has the !cancelvote command added.

 

Code:

/* VERSION 0.9/R8-yes-cancel */
double percent = 35; // CUSTOMIZE: of losing team that has to vote
double timeout = 5.0; // CUSTOMIZE: number of minutes before vote times out
int minPlayers = 16; // CUSTOMIZE: minimum players to enable vote
double minTicketPercent = 10; // CUSTOMIZE: minimum ticket percentage remaining in the round
double minTicketGap = 20; // CUSTOMIZE: minimum ticket gap between winning and losing teams
int maxAttempts = 3; // CUSTOMIZE: maximum number of attempts

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) {
    plugin.KillPlayer(nuke.Name, 1);
    if (level >= 3) plugin.ConsoleWrite("^b[VoteNuke]^n killing " + nuke.FullName);
}

/* Losing team only gets to do this once */

server.RoundData.setBool(key, true);

return false;
R8 - BF4 faction names
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by kcuestag*:

 

the per-round max attempt limit works just fine, what I mean is sometimes people try to do a !votenuke even when the round is balanced, just for trolling I guess...

 

And I wanted to be able to cancel the votes in case I see it again.

 

Thanks for adding that, who has privileges to use the !cancelvote ?

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by Blaze0075*:

 

Hey ineed your help to setup this:Keywords: vote, nuke, kill, team, camping, base rape, anti-camping, anti-base raping?

Were i write this keywords in script for base raped/anti-baseraping/camping___Jonas

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

the per-round max attempt limit works just fine, what I mean is sometimes people try to do a !votenuke even when the round is balanced, just for trolling I guess...

 

And I wanted to be able to cancel the votes in case I see it again.

 

Thanks for adding that, who has privileges to use the !cancelvote ?

Procon Admins with kick privilege.

 

Don't be afraid to read the code itself, often you can get the answers to your questions from the code. It's not always completely clear, but in this case, "if (canKick)" is pretty definitive.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by kcuestag*:

 

Procon Admins with kick privilege.

 

Don't be afraid to read the code itself, often you can get the answers to your questions from the code. It's not always completely clear, but in this case, "if (canKick)" is pretty definitive.

Thanks, I did check the code but didn't notice that part. :smile:
* Restored post. It could be that the author is no longer active.
Link to comment
  • 3 months later...

Originally Posted by XDE4TH*:

 

Has anyone tried this in Battlefield 4? If I use Insane Limits and set this up so that teams can surrender, should/will this still work?

 

If nobody knows I may try when I get off work and will report back.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

Has anyone tried this in Battlefield 4? If I use Insane Limits and set this up so that teams can surrender, should/will this still work?

 

If nobody knows I may try when I get off work and will report back.

I haven't tried it. Let us know what you find.

 

Some things that I know for sure will not work in BF4:

* All the yell messages won't work

* Team 1 will be called "US" and Team 2 will be called "RU", which will be wrong for most BF4 maps

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by jking54*:

 

I haven't tried it. Let us know what you find.

 

Some things that I know for sure will not work in BF4:

* All the yell messages won't work

* Team 1 will be called "US" and Team 2 will be called "RU", which will be wrong for most BF4 maps

I rather like this idea, who cares about yell for now, but where in the code can you change the US & RU, must be equivalents for BF4? In any event, US will be US but RU, CN etc.players will get the idea, I'd imagine.
* Restored post. It could be that the author is no longer active.
Link to comment
  • 3 weeks later...

Originally Posted by PapaCharlie9*:

 

anyone see if this works for BF4 yet? need it for my lockers server, its just like metro!

Give it a try, it should work. Only the yells won't work in BF4, everything else should work.

 

I'd recommend using the post #101 version, since it has the !cancelvote feature. Unless you really prefer the !surrender version in post #10.

 

EDIT: also the "RU" and "US" team names will be wrong for most BF4 maps, but that needs a Procon change to fix. You can find "US" in near the end of the code and change it to "Team 1" and "RU" in the code and change it to "Team 2" if you want.

* Restored post. It could be that the author is no longer active.
Link to comment
  • 2 months later...

Originally Posted by GaWebDev*:

 

Fanta did you get this set-up to your satisfaction on your lockers server? I'm also curious if it's been updated recently to account for yell now being functional in BF4 as well as the team names now rendering correctly on most plugin out-puts?

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

I've updated all versions (posts #1, #10, #101) for BF4 faction names. Yells should work with BF4 now also. Please pick up the new limit code. Make sure you use Insane Limits 0.9.15.0 or later.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by GaWebDev*:

 

I've updated all versions (posts #1, #10, #101) for BF4 faction names. Yells should work with BF4 now also. Please pick up the new limit code. Make sure you use Insane Limits 0.9.15.0 or later.

Thank you sir.
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by xFaNtASyGiRLx*:

 

Give this a try. Let me know if there are any compilation errors. Follow the steps in post #1, but use this code for second_check instead of the code in post #1.

 

Changes:

 

* !surrender or !votenext instead of !votecamp, as in vote to go to the next round -- losing team would use !surrender, winning team would use !votenext, though in truth, either team could use either command, they both do the same thing

 

* ends the round with the leading team getting the win

 

* either team may vote, not limited to the losing team

 

* a vote from the winning team counts only if there is a matching vote on the losing team, that is, the winning team can't unilaterally vote to end the round, they can only support the losing team's surrender

 

Set the limit to evaluate OnAnyChat. Set the Action to None.

 

Set first_check to this Expression:

 

Code:

(Regex.Match(server.Gamemode, @"(Conquest|Rush)").Success)
Set second_check to this Code:

 

Code:

/* VERSION 0.9.15/R8 - surrender */
double percent = 50; // CUSTOMIZE: of losing team that has to vote
double timeout = 5.0; // CUSTOMIZE: number of minutes before vote times out
int minPlayers = 16; // CUSTOMIZE: minimum players to enable vote
double minTicketPercent = 10; // CUSTOMIZE: minimum ticket percentage remaining in the round
double minTicketGap = 50; // CUSTOMIZE: minimum ticket gap between winning and losing teams

String kNext = "votenext";
String kVoteTime = "votenext_time";
String kNeeded = "votenext_needed";

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 nextMatch = Regex.Match(player.LastChat, @"^\s*[@!](_:surrender|vote\s*next)", RegexOptions.IgnoreCase);

/* Bail out if not a proper vote */

if (!nextMatch.Success) 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 vote!";
	ChatPlayer(player.Name);
	return false;
}

/* Bail out if ticket ratio isn't large enough */

double t1 = server.RemainTickets(1);
double t2 = server.RemainTickets(2);
if (Math.Abs(t1 - t2) < minTicketGap) {
	msg = "Ticket counts too close to hold a vote!";
	ChatPlayer(player.Name);
	return false;
}

/* Determine losing team by tickets */

int losing = (t1 < t2) _ 1 : 2;

/* Bail out if not enough players to enable vote */

if (server.PlayerCount < minPlayers) {
	msg = "Not enough players to hold a vote!";
	ChatPlayer(player.Name);
	return false;
}

/* 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(kNext)) {
	player.RoundData.setBool(kNext, true);
} else {
	msg = "You already voted!";
	ChatPlayer(player.Name);
	return false;
}

if (level >= 2) plugin.ConsoleWrite("^b[VoteNext]^n " + player.FullName + " voted to end the round");

msg = "You voted to end this round and start the next round!";
ChatPlayer(player.Name);

/* Tally the votes */

int votes = 0;
List<PlayerInfoInterface> losers = (losing == 1) _ team1.players : team2.players;
List<PlayerInfoInterface> winners = (losing == 1) _ team2.players : team1.players;

/* Bail out if too much time has past */

bool firstTime = false;

if (!server.RoundData.issetObject(kVoteTime)) {
	server.RoundData.setObject(kVoteTime, DateTime.Now);
	if (level >= 2) plugin.ConsoleWrite("^b[VoteNext]^n vote timer started");
	firstTime = true;
}
DateTime started = (DateTime)server.RoundData.getObject(kVoteTime);
TimeSpan since = DateTime.Now.Subtract(started);

if (since.TotalMinutes > timeout) {
	msg = "The voting time has expired, the vote is cancelled!";
	plugin.SendGlobalMessage(msg);
	plugin.SendGlobalYell(msg, 10);
	if (level >= 2) plugin.ConsoleWrite("^b[VoteNext]^n vote timeout expired");
	foreach (PlayerInfoInterface can in losers) {
		// Erase the vote
		if (can.RoundData.issetBool(kNext)) can.RoundData.unsetBool(kNext);
	}
	foreach (PlayerInfoInterface can in winners) {
		// Erase the vote
		if (can.RoundData.issetBool(kNext)) can.RoundData.unsetBool(kNext);
	}
	server.RoundData.unsetObject(kVoteTime);

	return false;
}

/* Otherwise tally */

foreach(PlayerInfoInterface p in losers) {
    if (p.RoundData.issetBool(kNext)) votes++;
}
if (level >= 3) plugin.ConsoleWrite("^b[VoteNext]^n loser votes = " + votes + " of " + losers.Count);

/* Votes on the winning side are counted as long as they are less than the votes on the losing side */

int losingVotes = votes;
int winningVotes = 0;
foreach(PlayerInfoInterface p in winners) {
    if (p.RoundData.issetBool(kNext)) {
        winningVotes++;
        if (winningVotes > losingVotes) break;
        ++votes;
    }
}

if (level >= 3) plugin.ConsoleWrite("^b[VoteNext]^n winner votes = " + winningVotes + " of " + winners.Count);

int needed = Convert.ToInt32(Math.Ceiling((double) losers.Count * (percent/100.0)));
if (server.RoundData.issetInt(kNeeded)) needed = Math.Min(needed, server.RoundData.getInt(kNeeded));
server.RoundData.setInt(kNeeded, needed);

int remain = needed - votes;

if (level >= 3) plugin.ConsoleWrite("^b[VoteNext]^n needed votes = " + needed);

String voters = (losing == 1) _ "US" : "RU";
String otherVoters = (losing == 1) _ "RU" : "US";

if (remain > 0) {
	if (firstTime) {
		msg = remain + " " + voters + " !surrender or " + otherVoters + " !votenext votes needed to end round with " + Convert.ToInt32(Math.Ceiling(timeout - since.TotalMinutes)) + " minutes left!";
	} else {
		msg = remain + " !surrender/!votenext needed to end round with " + Convert.ToInt32(Math.Ceiling(timeout - since.TotalMinutes)) + " mins left!";
	}
	plugin.SendGlobalMessage(msg);
	plugin.SendGlobalYell(msg, 8);
	if (level >= 2) plugin.ConsoleWrite("^b[VoteNext]^n " + msg);
	return false;
}

/* End the round */

String wteam = (losing == 1) _ "RU" : "US"; // 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;
    wteam = (losing == 1) _ factionNames[f2] : factionNames[f1];
}

msg = "Vote succeeded: round ends now, " + wteam + " team wins!";
plugin.SendGlobalMessage(msg);
plugin.SendGlobalYell(msg, 10);
if (level >= 2) plugin.ConsoleWrite("^b[VoteNext]^n " + msg);

String wid = (losing == 1) _ "2" : "1";

ThreadStart roundEnder = delegate {
    Thread.Sleep(10*1000);
    plugin.ServerCommand("mapList.endRound", wid);
};

Thread enderThread = new Thread(roundEnder);
enderThread.Start();
Thread.Sleep(10);

return false;
REVISIONS

 

R8: BF4 faction names

R7: enabled either @ or ! for surrender/votenext command

R6: Made needed be the minimum of calculated and last, improved the first message, stopped players from voting multiple times

tried it for bf4 and get these errors:

 

 

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 209, column: 33): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 209, column: 54): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 209, column: 79): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 210, column: 33): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 210, column: 54): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 210, column: 79): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

tried it for bf4 and get these errors:

 

 

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 209, column: 33): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 209, column: 54): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 209, column: 79): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 210, column: 33): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 210, column: 54): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

[15:37:43 30] [insane Limits] ERROR: (CS0117, line: 210, column: 79): 'PRoConEvents.TeamInfoInterface' does not contain a definition for 'Faction'

Requires Insane Limits 0.9.15.0 or later. You probably need to update.
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by xFaNtASyGiRLx*:

 

oh noes... I tried to update without backing up and the .15 newest version isn't appearing in my procon now.

 

where can I get the old one til I figure out whats conflicting? I need .14 i think

 

ughhh.. all my configs got reset

 

 

edit: whew! found a backup from dec 2013... panic mode = off.

 

but there is something with my plugins that conflict with other. I notice that when I tried installing ASP. I think its the auto messages plugin that makes other plugins stop working. I know I had to disable it for BF3 and just use spam bot.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by PapaCharlie9*:

 

oh noes... I tried to update without backing up and the .15 newest version isn't appearing in my procon now.

 

where can I get the old one til I figure out whats conflicting? I need .14 i think

 

ughhh.. all my configs got reset

 

 

edit: whew! found a backup from dec 2013... panic mode = off.

 

but there is something with my plugins that conflict with other. I notice that when I tried installing ASP. I think its the auto messages plugin that makes other plugins stop working. I know I had to disable it for BF3 and just use spam bot.

More and more plugins now require Procon 1.4.1.5 or later. Insane Limits certainly does. That's the usual reason that plugins "doesn't appear" after installation.
* Restored post. It could be that the author is no longer active.
Link to comment
  • 3 weeks later...

Originally Posted by PapaCharlie9*:

 

Thank you!!

 

The first link you gave is almost perfect, I think it will be fine now.

Now trying to setup it, is there no way i can only need like 4 votes instead of the percentage?

 

Thanks again :smile:.

Referring to the post #10 version above:

 

myrcon.net/...insane-limits-v09r6-vote-to-nuke-campingbase-raping-team-or-surrender#entry28837

 

Find this line of code in second_check:

 

Code:

int needed = Convert.ToInt32(Math.Ceiling((double) losers.Count * (percent/100.0)));
Delete that whole line and replace it with this:

 

Code:

int needed = Math.Min(losers.Count, 4);
That means the number of votes needed is either 4 or the number of players on the losing team, whichever is less.
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by Senshin*:

 

Thank you alot :smile:! (I am so happy this works)

I removed the old line and inserted the new one. Seems to work :smile:.

 

 

On last thing, is it possible to threat the winners and losers equal like everyone votes for the same? And the team with the most tickets wins standard.

So what I mean like make !surrender obsolete.

 

I am really sorry for the storm of questions but i am totally new in the world of servers.

And also, for now i can modify relative easy commands now in Insanelimits but how to make a function work, I really do not know that yet.

 

I understand if it is to much trouble.

 

EDIT:

I already managed to get !votenext to !voterestart as command, by only changing *next* in this line, is that also enough, it works but everywhere i see votenext standing?

I think its ok like this or am I missing something?

 

"Match nextMatch = Regex.Match(player.LastChat, @"^\s*[@!](_:surrender|vote\s*restart)", RegexOptions.IgnoreCase);"

* Restored post. It could be that the author is no longer active.
Link to comment

Archived

This topic is now archived and is closed to further replies.




  • Our picks

    • Game Server Hosting:

      We're happy to announce that EZRCON will branch out into the game server provider scene. This is a big step for us so please having patience if something doesn't go right in this area. Now, what makes us different compared to other providers? Well, we're going with the idea of having a scaleable server hosting and providing more control in how you set up your server. For example, in Minecraft, you have the ability to control how many CPU cores you wish your server to have access to, how much RAM you want to use, how much disk space you want to use. This type of control can't be offered in a single service package so you're able to configure a custom package the way you want it.

      You can see all the available games here. Currently, we have the following games available.

      Valheim (From $1.50 USD)


      Rust (From $3.20 USD)


      Minecraft (Basic) (From $4.00 USD)


      Call of Duty 4X (From $7.00 USD)


      OpenTTD (From $4.00 USD)


      Squad (From $9.00 USD)


      Insurgency: Sandstorm (From $6.40 USD)


      Changes to US-East:

      Starting in January 2022, we will be moving to a different provider that has better support, better infrastructure, and better connectivity. We've noticed that the connection/routes to this location are not ideal and it's been hard getting support to correct this. Our contract for our two servers ends in March/April respectively. If you currently have servers in this location you will be migrated over to the new provider. We'll have more details when the time comes closer to January. The new location for this change will be based out of Atlanta, GA. If you have any questions/concerns please open a ticket and we'll do our best to answer them.
      • 5 replies
    • Hello All,

      I wanted to give an update to how EZRCON is doing. As of today we have 56 active customers using the services offered. I'm glad its doing so well and it hasn't been 1 year yet. To those that have services with EZRCON, I hope the service is doing well and if not please let us know so that we can improve it where possible. We've done quite a few changes behind the scenes to improve the performance hopefully. 

      We'll be launching a new location for hosting procon layers in either Los Angeles, USA or Chicago, IL. Still being decided on where the placement should be but these two locations are not set in stone yet. We would like to get feedback on where we should have a new location for hosting the Procon Layers, which you can do by replying to this topic. A poll will be created where people can vote on which location they would like to see.

      We're also looking for some suggestions on what else you would like to see for hosting provider options. So please let us know your thoughts on this matter.
      • 4 replies
    • Added ability to disable the new API check for player country info


      Updated GeoIP database file


      Removed usage sending stats


      Added EZRCON ad banner



      If you are upgrading then you may need to add these two lines to your existing installation in the file procon.cfg. To enable these options just change False to True.

      procon.private.options.UseGeoIpFileOnly False
      procon.private.options.BlockRssFeedNews False



       
      • 2 replies
    • I wanted I let you know that I am starting to build out the foundation for the hosting services that I talked about here. The pricing model I was originally going for wasn't going to be suitable for how I want to build it. So instead I decided to offer each service as it's own product instead of a package deal. In the future, hopefully, I will be able to do this and offer discounts to those that choose it.

      Here is how the pricing is laid out for each service as well as information about each. This is as of 7/12/2020.

      Single MySQL database (up to 30 GB) is $10 USD per month.



      If you go over the 30 GB usage for the database then each additional gigabyte is charged at $0.10 USD each billing cycle. If you're under 30GB you don't need to worry about this.


      Databases are replicated across 3 zones (regions) for redundancy. One (1) on the east coast of the USA, One (1) in Frankfurt, and One (1) in Singapore. Depending on the demand, this would grow to more regions.


      Databases will also be backed up daily and retained for 7 days.




      Procon Layer will be $2 USD per month.


      Each layer will only allow one (1) game server connection. The reason behind this is for performance.


      Each layer will also come with all available plugins installed by default. This is to help facilitate faster deployments and get you up and running quickly.


      Each layer will automatically restart if Procon crashes. 


      Each layer will also automatically restart daily at midnight to make sure it stays in tip-top shape.


      Custom plugins can be installed by submitting a support ticket.




      Battlefield Admin Control Panel (BFACP) will be $5 USD per month


      As I am still working on building version 3 of the software, I will be installing the last version I did. Once I complete version 3 it will automatically be upgraded for you.





      All these services will be managed by me so you don't have to worry about the technical side of things to get up and going.

      If you would like to see how much it would cost for the services, I made a calculator that you can use. It can be found here https://ezrcon.com/calculator.html

       
      • 11 replies
    • I have pushed out a new minor release which updates the geodata pull (flags in the playerlisting). This should be way more accurate now. As always, please let me know if any problems show up.

       
      • 9 replies
×
×
  • Create New...

Important Information

Please review our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.