Page 1 of 31 12311 ... LastLast
Results 1 to 10 of 303
  1. #1

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

    VERSION: 0.8p3/R5. Compiled but not tested. If you try this out, post your feedback in this thread.

    See post #10 below for the !surrender version.

    Do you want to enforce a "no camping of deployments" rule on your Conquest or Rush server, but can't babysit 24 hours a day? How about giving your players a vote if their deployment gets camped and they get can't get out?

    This limit implements a voting system for Conquest and Rush maps when there are a minimum number of players on the server (default 16) and there are enough tickets left in the round (default 10%, e.g., on a 300 ticket map, both teams have more than 30 tickets left) and that the gap between winning and losing team tickets is large enough (default 50 tickets). Players on the losing team may vote to kill everyone on the camping team by typing:

    !votecamp

    or

    !vote camp

    One vote per player per round. If more than a set percentage of the losing team votes (default is 50%), the winning/camping team is nuked: each and every player is killed. This gives the camped team a chance to break out. Since the kills are admin kills, they do not count against the kill count stats for the camping team. All that happens is that they have to respawn and get back in position. The winning team can't vote, any votes they make are ignored. Winning/losing is determined by ticket count.

    Each team only gets to vote once per round -- if a team succeeds at completing a vote, subsequent votes are ignored for the rest of the round. If the losing team gets trapped in their deployment more than once, they deserve to be pwned. The vote only lasts for a certain number of minutes (defined by the timeout variable in the code, 5 minutes by default). If insufficient votes are cast before the timeout expires, the vote is cancelled. The same team may try to start a vote again if they wish.



    See Post #10 below for a variation of this limit that allows the losing team to vote to end the current round.

    See Post #101 below for a variation of this limit that adds a !cancelvote command for admins.

    See Post #169 below for a variation of this limit that adds a second admin.kill (second nuke) when a nuked player tries to spawn. Effectively the same as a double nuke for one successful vote.

    See Post #210 below for a variation of this limit that makes the command be !votenuke and that adds a series of countdown messages before the team is nuked.

    See Post #261 below for an additional limit that sends chat and yell messages every 60 seconds (you can change) about the status of the vote.







    RECOMMENDED: Inform your players about the vote system by adding scrolling/spambot chat, adding to your on-demand !rules command, or something similar.

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

    Set first_check to this Expression:

    Only use one of the following choices, BF3 or BF4.

    BF3

    Code:
    (Regex.Match(server.Gamemode, @"(Conquest|Rush)").Success)
    BF4

    Code:
    (Regex.Match(server.Gamemode, @"(Conquest|Rush|Domination)").Success)

    This second_check works for either BF3 or BF4:

    Set second_check to this Code:

    Code:
    /* VERSION 0.9.15/R6 */
    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 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*camp", RegexOptions.IgnoreCase);
    
    /* Bail out if not a proper vote */
    
    if (!campMatch.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;
    }
    
    /* 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 vote camp 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 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(kCamp)) player.RoundData.setBool(kCamp, true);
    
    if (level >= 2) plugin.ConsoleWrite("^b[VoteCamp]^n " + player.FullName + " voted to stop camping");
    
    msg = "You voted to stop the other team from camping your deployment";
    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[VoteCamp]^n vote timer started");
    }
    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[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[VoteCamp]^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[VoteCamp]^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 == -1 || team1.Faction > 2) ? 0 : team1.Faction;
        int f2 = (team2.Faction == -1 || 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[VoteCamp]^n " + msg);
        return false;
    }
    
    /* Punish the campers */
    
    msg = "Vote succeeded: " + campers + " team is being nuked for camping your deployment! Break out now!";
    plugin.SendTeamMessage(losing, msg);
    plugin.SendGlobalMessage(msg, 15);
    if (level >= 2) plugin.ConsoleWrite("^b[VoteCamp]^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[VoteCamp]^n killing " + nuke.FullName);
    }
    
    /* Losing team only gets to do this once */
    
    server.RoundData.setBool(key, true);
    
    return false;
    Keywords: vote, nuke, kill, team, camping, base rape, anti-camping, anti-base raping

    R6 - added BF4 faction names
    R5 - added level 3 debugging
    R4 - changed determination of losing team to be based on tickets instead of points
    R3 - added minTicketPercent and minTicketGap variables so that vote is enabled only if there are enough tickets left in the round and enough of a gap between the winning and losing teams, respectively
    R2 - added minPlayers variable so that vote is enabled only when a minimum number of players are on the server
    R1 - original version
    Last edited by PapaCharlie9; 05-04-2015 at 17:28. Reason: Updated with post #261
    Don't send me private messages (PMs) unless you really need privacy, like your game server password. If you just have a question or need help, post in one of the threads. It's extra work for me to answer questions and give help in private messages and no one else gets the benefit of the answer.

  2. #2
    HINT: Since the vote is check only when a !votecamp command is sent, players on the losing team should pay attention to players quitting from the server. If players quit from their side, the voting goal reduces proportionally, but it is checked only after a command. So players on the losing team who are still on the server should type !votecamp, even if they have already voted, to force the limit to recheck the voting goal.

    For example, if the losing side starts with 32 players, 17 votes are needed to trigger the nuke of the winning team. Let's say 15 players have voted. Two more votes are needed. However, 4 players who haven't voted on the losing team leave the server. That cuts the vote goal down to 15, 50% of 28 is 14 + 1. The vote will succeed and the punishment will happen, but only if some player on the losing team types !votecamp again.
    Don't send me private messages (PMs) unless you really need privacy, like your game server password. If you just have a question or need help, post in one of the threads. It's extra work for me to answer questions and give help in private messages and no one else gets the benefit of the answer.

  3. #3
    @papa
    LOL this is just cute enough to try. Interesting idea but also starts with the premiss we are dealing with fair and mature adults.
    Potential problems:
    1- Nuking team when base rape is not occuring. (may just want to advance and capture a flag {eg. metro usa side losing and wants to capture B} by nuking RU team they can capture and advance to ticket booth)

    A- Is there a way for IL to know if all flags are owned or lost?

    2- Nuking team when too few players to justify nuking. ( I cant see a server starting or just having 8-10 players (4vs4 - 5vs5) being raped unless they are not interested in advancing )

    A- There could be a minimum player count before nuke vote is enabled or actionable. (atleast the option for server owners to adjust. {eg. min player count 20, ie.10vs10 }

  4. #4
    Quote Originally Posted by Learning-Curve View Post
    @papa
    LOL this is just cute enough to try. Interesting idea but also starts with the premiss we are dealing with fair and mature adults.
    Potential problems:
    1- Nuking team when base rape is not occuring. (may just want to advance and capture a flag {eg. metro usa side losing and wants to capture B} by nuking RU team they can capture and advance to ticket booth)

    A- Is there a way for IL to know if all flags are owned or lost?

    2- Nuking team when too few players to justify nuking. ( I cant see a server starting or just having 8-10 players (4vs4 - 5vs5) being raped unless they are not interested in advancing )

    A- There could be a minimum player count before nuke vote is enabled or actionable. (atleast the option for server owners to adjust. {eg. min player count 20, ie.10vs10 }
    Good feedback. I added the minimum player count, excellent suggestion.

    No plugin knows how many flags are capped, it's not in the protocol. Yes, this can be abused, but note that it can only be abused once per team per round, so it's self-limiting and balanced. If one team nukes the other as an abuse, the other team can retaliate in kind if they end up losing in points.
    Last edited by PapaCharlie9; 03-06-2012 at 19:12.
    Don't send me private messages (PMs) unless you really need privacy, like your game server password. If you just have a question or need help, post in one of the threads. It's extra work for me to answer questions and give help in private messages and no one else gets the benefit of the answer.

  5. #5
    Procon Plugin Tester
    Join Date
    Apr 2010
    Location
    Finland
    Posts
    133
    Papa, heres my req.: Is it possible to edit this so it will launch voting for ending the round. Like that it would be public command like !endvote or something.
    ]

  6. #6
    Procon Plugin Tester
    Join Date
    Nov 2011
    Posts
    472
    Excellent idea! While we usually do not nuke, this is one aspect that can really kill a server.

    I haven't tested it yet, but do have a couple of suggestions:

    Do NOT nuke if under XX tickets are left. (keep from nuking with only a few tickets left or round is about to end - conquest).
    ONLY nuke if XX ticket difference (I really don't want to allow nuking if there is only a 10 ticket difference).

    Keep up the good work. I always look forward to seeing your posts / improvements.

  7. #7
    May I ask where to download, I want to try this plug-in

  8. #8
    Procon Plugin Tester
    Join Date
    Apr 2010
    Location
    Finland
    Posts
    133
    Quote Originally Posted by superman50 View Post
    May I ask where to download, I want to try this plug-in
    You have to download and install this plugin for porocn http://www.phogue.net/forumvb/showth...%28beta-BF3%29 (read description and info).
    Then you have to insert code provided in this thread into that plugin.
    First it could look lilbit hard, but its not, once u get a hang of it.
    ]

  9. #9
    Quote Originally Posted by superman50 View Post
    May I ask where to download, I want to try this plug-in
    Watch the video at the link Lumpy provided, it shows how to add a limit.
    Don't send me private messages (PMs) unless you really need privacy, like your game server password. If you just have a question or need help, post in one of the threads. It's extra work for me to answer questions and give help in private messages and no one else gets the benefit of the answer.

  10. #10

    THIS VERSION ENDS THE ROUND WITH !surrender INSTEAD OF NUKING

    Quote Originally Posted by LumpyNutZ View Post
    Papa, heres my req.: Is it possible to edit this so it will launch voting for ending the round. Like that it would be public command like !endvote or something.
    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 (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;
        voters = (losing == 1) ? factionNames[f1] : factionNames[f2];
        otherVoters = (losing == 1) ? factionNames[f2] : factionNames[f1];
    }
    
    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
    Last edited by PapaCharlie9; 28-04-2014 at 17:17. Reason: R8: BF4 faction names
    Don't send me private messages (PMs) unless you really need privacy, like your game server password. If you just have a question or need help, post in one of the threads. It's extra work for me to answer questions and give help in private messages and no one else gets the benefit of the answer.

 

 

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •