AdminMod.de
https://www.adminmod.de/

plugin pbt ?
https://www.adminmod.de/viewtopic.php?t=2727
Seite 1 von 1

Autor:  [BC]Daniel [ 27.04.2002, 20:20 ]
Betreff des Beitrags:  plugin pbt ?

kann mir wer sagen was das ding hier macht ????
und welchen befehl man dann eingeben muss wenn das plug in greift ?




hier die sma

/*

Ptahhotep's Team Balancer (PTB)
Version 1.4

File: plugin_cs_ptb.sma
Author: Ptahhotep (ptahhotep@planethalflife.com)
Testers: all the great guys at http://www.concarne.org
Date: 02/19/2002

Introduction
------------
PTB is an Adminmod plugin (http://www.adminmod.org).
LogD (http://logd.sourcforge.net) is required to run PTB.
PTB is a Counter-Strike (CS) specific plugin.

To run PTB with its default settings, simply compile it
for your operating system, include it into plugin.ini
and change the map on your CS server.

PTB detects situations, in which one team rules over the other.
It looks at the current team scores, current team win streaks
and the current team ratings and decides on actions with the
help of these values.

Features
--------
- team strength evaluation based on scores, streaks, kills, deaths and size
- announcement of team balance status once per round
- announcement of each WTJ (winning team joining/joiner) try
- prevention of WTJ
- display of WTJ count (per map)
- force into losing or smaller team for WTJ count 4
- log WTJ in wtj.log for WTJ count >= 4 (once per map)
- kick for WTJ count >= 10
- automatic dead only team switches - top winner against bottom loser
- automatic dead only team transfers - top winner to loser team
- overriden auto-join function, that is always choosing the right team
and prevents joining of the same or winning or bigger team
- display of PTB evaluation status
- lots of configuration options

Latest Changes
--------------
Version 1.4
+ FIXED: PTB didn't work the first time a player chooses a team
+ NEW: PTB sets team strength to team size, if team has no single kill yet
(fix for team inbalance in the first rounds of a map)
+ NEW: switching/transfering alive, if dead only is not possible repeatedly

Version 1.3
+ NEW: announcing team switch/transfer failures as typesay message
+ NEW: added "sayok" option
+ FIXED: completely reworked the options interface, which didn't work at all
+ WORKAROUND: retrying calculation for negative results on division of 2 positive numbers
+ REMOVED: command admin_ptb_stats no longer exists

Version 1.2a
+ FIXED: compile error with Adminmod 2.50.26 (plugin_connect syntax change in Adminmod?)

Version 1.2
+ NEW: display WTJ count
+ NEW: kick for WTJ count 10 or greater
+ NEW: force players into losing/smaller team for WTJ count > 3
+ NEW: save player name and WONID in wtj.log for WTJ count > 3
+ NEW: changed rating to incorporate team sizes
+ NEW: added switch dead only mode
+ NEW: added lots of configuration variables
+ NEW: added team advantage announcements
+ FIXED: trying to switch player that had already changed teams in the same round

Details
-------
The current team strength ist defined as sum of team kills
divided by sum if team deaths times players in the team
(strength = kills/deaths * players).

Example:

CT kills/deaths: 12/6 = 2
CT players: 3
CT strength: 2 * 3 = 6

T kills/deaths: 4/10 = 0.4
T players: 4
T strength: 0.4 * 4 = 1.6

The current team strength rating is calculated by dividing the team's
strength by the opposing team's strength (rating = ownStrength
/ opposingStrength).

Example (continued):

CT strength rating: 2/1.6 = 1.25

T strength rating: 1.6/2 = 0.8

For each team these criteria are checked:
- rating >= minRating (stronger team) and score > maxScoreDiff
- rating >= minRating (stronger team) and streak > maxStreak
- rating >= maxRating (stronger team) and more players
- rating >= maxRating (way stronger team)

If any TWO of these criteria match for a team, it is considered to
be the winning team and actions are taken as appropriate.

Note: Teams with a rating below minRating are considered as of equal
or very similar strength. If team strengths are very similar, streaks
and scores are ignored. As soon as a team gets noticibly stronger
than it's opposing team, scores, streaks and team size are checked.

Configuration
-------------
PTB Required Variable Settings:
allow_client_exec 1 - needed to switch players' teams
admin_balance_teams 0 - switch other team balancing methods off
mp_autoteambalance 0 - switch off inbuild CS team balancing
mp_limitteams 10 - enable any team size difference

PTB Commands:
admin_ptb - show PTB statistics (ACCESS_ALL)
admin_ptb on - enable all PTB functions
admin_ptb off - disable all PTB functions
admin_ptb status - show PTB status
admin_ptb kick on|off (default: on) - PTB kicking
admin_ptb switch on|off (default: on) - PTB team switching and transfers
admin_ptb announce on|off (default: on) - PTB announcements
admin_ptb sayok on|off (default: on) - PTB "no action required" message
admin_ptb limitjoin on|off (default: on) - PTB team join limitations
admin_ptb savewtj on|off (default: off) - PTB wtj.log writing
admin_ptb deadonly on|off (default: on) - switch dead only or alive, too
admin_ptb maxstreak <value> (default: 2) - maximum accepted team win streak
admin_ptb maxscore <value> (default: 2) - maximum accepted team score difference
admin_ptb maxrandom <value> (default: 3) - range of top/bottom players to choose from for switch/transfer
admin_ptb maxrating <value> (default: 2) - way stronger team, if rating >= maxrating
admin_ptb minrating <value> (default: 1.5) - stronger team, if rating >= minrating
(don't play with these, if you don't fully understand, what it means)

// SERVER VARIABLES ARE NOT WORKING ...
PTB Server Variables (only used as defaults when set in server.cfg or listenserver.cfg)
--------------------
admin_ptb_kick on|off (default: on) - PTB kicking
admin_ptb_switch on|off (default: on) - PTB team switching and transfers
admin_ptb_announce on|off (default: on) - PTB announcements
admin_ptb_sayok on|off (default: on) - PTB "no action required" message
admin_ptb_limitjoin on|off (default: on) - PTB team join limitations
admin_ptb_savewtj on|off (default: off) - PTB wtj.log writing
admin_ptb_deadonly on|off (default: on) - switch dead only or alive, too
admin_ptb_maxstreak <value> (default: 2) - maximum accepted team win streak
admin_ptb_maxscore <value> (default: 2) - maximum accepted team score difference
admin_ptb_maxrandom <value> (default: 3) - range of top/bottom players to choose from for switch/transfer
admin_ptb_maxrating <value> (default: 2) - way stronger team, if rating >= maxrating
admin_ptb_minrating <value> (default: 1.5) - stronger team, if rating >= minrating
(don't play with these, if you don't fully understand, what it means)
// SERVER VARIABLES ARE NOT WORKING ...

SUGGESTIONS & TODO
------------------
Ender - invent map type factors (de_, cs_, as_)

KNOWN BUGS
----------
- sometimes dividing 2 positive fixed numbers yields a negative number

*/

#pragma dynamic 32768

#include <core>
#include <console>
#include <string>
#include <admin>
#include <adminlib>
#include <fixed>

new STRING_VERSION[MAX_DATA_LENGTH] = "1.4";

#define ACCESS_BALANCE 32
#define ACCESS_CONSOLE 131072

#define TS 1
#define CTS 2
#define AUTO_TEAM 5

#define MAX_TEAM_SIZE 10
#define MAX_SCORE_DIFF 2
#define MAX_STREAK 2
#define MAX_RANDOM 3
new MIN_RATING[10] = "1.5";
new MAX_RATING[10] = "2";

// options
new option_kick = 1;
new option_switch = 1;
new option_announce = 1;
new option_sayok = 1;
new option_limitjoin = 1;
new option_savewtj = 0;
new option_deadonly = 1;
new option_maxstreak = 2;
new option_maxscore = 2;
new option_maxrandom = 3;
new fixed:option_maxrating;
new fixed:option_minrating;

new sortedTeams[3][MAX_PLAYERS + 1];

new nonDeadTeamCounts[3];
new sortedNonDeadTeams[3][MAX_PLAYERS + 1];

new kills[MAX_PLAYERS + 1] = { 0, ... };
new deaths[MAX_PLAYERS + 1] = { 0, ... };

new teamKills[3] = { 0, ... };
new teamDeaths[3] = { 0, ... };
new teamScores[3] = { 0, ... };
new winStreaks[3] = { 0, ... };

new wtConditions[3];
new winnerTeam = 0;
new loserTeam = 0;

new fixed:ctKD;
new fixed:tKD;
new fixed:ctStrength;
new fixed:tStrength;
new fixed:ctRating;
new fixed:tRating;

new isChoosingTeam[MAX_PLAYERS + 1];
new isBeingTransfered[MAX_PLAYERS + 1];
new playerTeam[MAX_PLAYERS + 1];
new switchedThisRound[MAX_PLAYERS + 1];
new wtjCount[MAX_PLAYERS + 1];
new teamCounts[3] = { 0, ... };

#define SWITCH_ALIVE_OVERRIDE 2
new couldNotSwitchCounter = 0;

/*
public admin_transfer(HLCommand, HLData, HLUserName, UserIndex) {
new Data[MAX_DATA_LENGTH];
convert_string(HLData, Data, MAX_DATA_LENGTH);
new i = strtonum(Data);
if (i >= 1 && i <= MAX_PLAYERS) transferPlayer(i);
}

public admin_spectator(HLCommand, HLData, HLUserName, UserIndex) {
new Data[MAX_DATA_LENGTH];
convert_string(HLData, Data, MAX_DATA_LENGTH);
new i = strtonum(Data);
if (i >= 1 && i <= MAX_PLAYERS) {
new Name[MAX_NAME_LENGTH];
playerinfo(i, Name, MAX_NAME_LENGTH);
execclient(Name, "chooseteam; menuselect 6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
}
}
*/

transferPlayer(player) {
//say("transferPlayer");

new Name[MAX_NAME_LENGTH];
playerinfo(player, Name, MAX_NAME_LENGTH);

if (playerTeam[player] == CTS || playerTeam[player] == TS) {
isBeingTransfered[player] = 1;
//say("Transferring Player:");
//say(Name);
if (playerTeam[player] == TS) {
execclient(Name, "chooseteam; menuselect 2; menuselect 5");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
}
else {
execclient(Name, "chooseteam; menuselect 1; menuselect 5");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
execclient(Name, "wait; wait; wait; slot6, wait; wait; wait; slot6");
}
}
else {
//say("Player Not In A Team:");
//say(Name);
}
}

act()
{
//say("act");
if (!option_switch) return;

say("PTB: Round ended, checking teams.");

checkTeamBalance();

if (winnerTeam != 0) {
sortTeam(CTS);
sortTeam(TS);

if (teamCounts[winnerTeam] <= teamCounts[loserTeam]) doSwitch();
else if (teamCounts[loserTeam] < teamCounts[winnerTeam]) doTransfer();

//new text[MAX_TEXT_LENGTH];
//snprintf(text, MAX_TEXT_LENGTH, "Winners: %d, Losers: %d", winners, losers);
//say(text);
}
}

createNonDeadTeam(theTeam) {
new Name[MAX_NAME_LENGTH];
new WonId;
new UserId;
new team;
new dead;

//say("createNonDeadTeam");
new n = 0;
for (new i = 0; i < teamCounts[theTeam]; ++i) {
if (0 == playerinfo(sortedTeams[theTeam], Name, MAX_NAME_LENGTH, WonId, UserId, team, dead)) {
//say("No playerinfo ...");
}
//snprintf(Name, MAX_NAME_LENGTH, "Index: %d, sortedTeamIndex: %d, dead: %d", i , sortedTeams[theTeam], dead);
//say(Name);
if (dead == 0) {
//say("player alive");
continue;
}
//say("player dead");
sortedNonDeadTeams[theTeam][n] = sortedTeams[theTeam];
++n;
}
nonDeadTeamCounts[theTeam] = n;
}

sortTeam(theTeam) {
//say("sortTeam");

// create list of players
new n = 0;
for (new i = 1; i <= MAX_PLAYERS; ++i) {
if (playerTeam != theTeam) continue;
sortedTeams[theTeam][n] = i;
++n;
}

// do a selection sort
new count = teamCounts[theTeam];
for (new i = count - 1; i > 0; --i) {
for (new k = i - 1; k >= 0; --k) {
// compare players
if (
(kills[sortedTeams[theTeam][k]] < kills[sortedTeams[theTeam]])
|| (
(kills[sortedTeams[theTeam][k]] == kills[sortedTeams[theTeam]])
&& (deaths[sortedTeams[theTeam][k]] > deaths[sortedTeams[theTeam]])
)
) {
// swap
new t;
t = sortedTeams[theTeam][k];
sortedTeams[theTeam][k] = sortedTeams[theTeam];
sortedTeams[theTeam] = t;
}
}
}
}

doSwitch() {
//say("doSwitch");
new text[MAX_TEXT_LENGTH];

//displayStatistics(true);

// don't switch, if at least one team is empty
if (teamCounts[winnerTeam] == 0 || teamCounts[loserTeam] == 0) {
text = "PTB: Can't switch players, need players in each team."
typesay(text, 5, 10, 255, 10);
say(text);
return;
}

// don't switch, if winner is alone (RULER!!!)
if (teamCounts[winnerTeam] == 1) {
text = "PTB: Won't switch players, only one player in winning team."
typesay(text, 5, 10, 255, 10);
say(text);
return;
}

// don't switch, if both teams are full
if (teamCounts[winnerTeam] == MAX_TEAM_SIZE && teamCounts[loserTeam] == MAX_TEAM_SIZE) {
text = "PTB: Can't switch players, both teams are full."
typesay(text, 5, 10, 255, 10);
say(text);
return;
}

new winner;
new loser;

if (!option_deadonly || couldNotSwitchCounter == SWITCH_ALIVE_OVERRIDE) {
// choose from random top or bottom x
new winnerIndex = random(min(teamCounts[winnerTeam] / 2, option_maxrandom));
new loserIndex = teamCounts[loserTeam] - random(min(teamCounts[loserTeam] / 2, option_maxrandom));
winner = sortedTeams[winnerTeam][winnerIndex];
loser = sortedTeams[loserTeam][loserIndex];
}
else {
//say("switch dead");
// choose best and worst dead players
createNonDeadTeam(winnerTeam);
createNonDeadTeam(loserTeam);
if (nonDeadTeamCounts[winnerTeam] == 0 || nonDeadTeamCounts[loserTeam] == 0) {
strcpy(text, "PTB: Can't switch players, need dead player in each team.", MAX_DATA_LENGTH);
++couldNotSwitchCounter;
if (couldNotSwitchCounter == SWITCH_ALIVE_OVERRIDE) {
say("PTB: Couldn't switch dead, switching alive.");
doSwitch();
return;
}
typesay(text, 5, 10, 255, 10);
say(text);
return;
}
winner = sortedNonDeadTeams[winnerTeam][0];
loser = sortedNonDeadTeams[loserTeam][nonDeadTeamCounts[loserTeam] - 1];
}

couldNotSwitchCounter = 0;

if (switchedThisRound[winner] || switchedThisRound[loser]) {
strcpy(text, "PTB: Can't switch players, player joined/changed this round already.", MAX_DATA_LENGTH);
typesay(text, 5, 10, 255, 10);
say(text);
return;
}

new winnerName[MAX_NAME_LENGTH];
new loserName[MAX_NAME_LENGTH];

//new debug[MAX_TEXT_LENGTH];
//snprintf(debug, MAX_TEXT_LENGTH, "Winner Index: %d", winnerIndex);
//say(debug);
//snprintf(debug, MAX_TEXT_LENGTH, "Loser Index: %d", loserIndex);
//say(debug);

playerinfo(winner, winnerName, MAX_NAME_LENGTH);
playerinfo(loser, loserName, MAX_NAME_LENGTH);

// if one team is full, first move the the player from the full team ...
if (teamCounts[winnerTeam] == MAX_TEAM_SIZE){
transferPlayer(winner);
transferPlayer(loser);
}
else {
transferPlayer(loser);
transferPlayer(winner);
}

strcpy(text, "PTB: Switching ", 80);
strcat(text, winnerName, 80);
strcat(text, " with ", 80);
strcat(text, loserName, 80);
strcat(text, ".", 80);
typesay(text, 5, 10, 255, 10);
say(text);
}

doTransfer() {
//say("doTransfer");
new text[MAX_TEXT_LENGTH];

if (teamCounts[winnerTeam] == 0) return;

//displayStatistics(true);

if (teamCounts[loserTeam] == MAX_TEAM_SIZE) {
strcpy(text, "PTB: Can't transfer player, losing team is full.", MAX_DATA_LENGTH);
typesay(text, 5, 10, 255, 10);
say(text);
return;
}

new winner;

if (!option_deadonly || couldNotSwitchCounter == SWITCH_ALIVE_OVERRIDE) {
// choose from random top x
new winnerIndex = random(min(teamCounts[winnerTeam] / 2, option_maxrandom));
winner = sortedTeams[winnerTeam][winnerIndex];
}
else {
// choose best dead player
createNonDeadTeam(winnerTeam);
if (nonDeadTeamCounts[winnerTeam] == 0) {
strcpy(text, "PTB: Can't transfer player, need dead player in winning team.", MAX_DATA_LENGTH);
++couldNotSwitchCounter;
if (couldNotSwitchCounter == SWITCH_ALIVE_OVERRIDE) {
say("PTB: Couldn't transfer dead, transfering alive.");
doTransfer();
return;
}
typesay(text, 5, 10, 255, 10);
say(text);
return;
}
winner = sortedNonDeadTeams[winnerTeam][0];
}

couldNotSwitchCounter = 0;

if (switchedThisRound[winner]) {
strcpy(text, "PTB: Can't transfer player, player joined/changed this round already.", MAX_DATA_LENGTH);
typesay(text, 5, 10, 255, 10);
say(text);
return;
}

new winnerName[MAX_NAME_LENGTH];

//new debug[MAX_TEXT_LENGTH];
//snprintf(debug, MAX_TEXT_LENGTH, "Winner Index: %d", winnerIndex);
//say(debug);

playerinfo(winner, winnerName, MAX_NAME_LENGTH);

transferPlayer(winner);

strcpy(text, "PTB: Transfering ", 80);
strcat(text, winnerName, 80);
strcat(text, " to the ", 80);
if (winnerTeam == CTS) strcat(text, "Ts", 80);
else if (winnerTeam == TS) strcat(text, "CTs", 80);
strcat(text, ".", 80);
typesay(text, 5, 10, 255, 10);
say(text);
}

checkTeamBalance() {
//say("Checking team balance ...");
new MAX_TRIES = 10;
new tries;

calcTeamScores();

ctKD = fixed(teamKills[CTS]);
if (teamDeaths[CTS] > 0) {
// workaround for negative results on dividing 2 positive numbers
tries = 0;
while (tries < MAX_TRIES) {
ctKD = fdiv(ctKD, fixed(teamDeaths[CTS]));
if (ctKD >= fixed(0)) break;
++tries;
}
}

tKD = fixed(teamKills[TS]);
if (teamDeaths[TS] > 0) {
// workaround for negative results on dividing 2 positive numbers
tries = 0;
while (tries < MAX_TRIES) {
tKD = fdiv(tKD, fixed(teamDeaths[TS]));
if (tKD >= fixed(0)) break;
++tries;
}
}

ctStrength = fixed(teamCounts[CTS]);
// workaround for match start team balancing
// this is making only team size count,
// as long as there is no single kill
if (ctKD != fixed(0)) ctStrength = fmul(ctKD, ctStrength);

tStrength = fixed(teamCounts[TS]);
// workaround for match start team balancing
// this is making only team size count,
// as long as there is no single kill
if (tKD != fixed(0)) tStrength = fmul(tKD, tStrength);

ctRating = ctStrength;
if (tStrength > fixed(0)) {
// workaround for negative results on dividing 2 positive numbers
tries = 0;
while (tries < MAX_TRIES) {
ctRating = fdiv(ctRating, tStrength);
if (ctRating >= fixed(0)) break;
++tries;
}
}

tRating = tStrength;
if (ctStrength > fixed(0)) {
// workaround for negative results on dividing 2 positive numbers
tries = 0;
while (tries < MAX_TRIES) {
tRating = fdiv(tRating, ctStrength);
if (tRating >= fixed(0)) break;
++tries;
}
}

wtConditions[TS] = 0;
wtConditions[CTS] = 0;

//new buffer[10];

// compare scores for unequal rating scores
if (teamScores[TS] - teamScores[CTS] > option_maxscore && tRating >= option_minrating) {
wtConditions[TS] = wtConditions[TS] + 1;
}
if (teamScores[CTS] - teamScores[TS] > option_maxscore && ctRating >= option_minrating) {
wtConditions[CTS] = wtConditions[CTS] + 1;
}

//say("// check streaks for unequal rating scores");
// check streaks for unequal rating scores
if (winStreaks[TS] > option_maxstreak && tRating >= option_minrating) {
wtConditions[TS] = wtConditions[TS] + 1;
}
if (winStreaks[CTS] > option_maxstreak && ctRating >= option_minrating) {
wtConditions[CTS] = wtConditions[CTS] + 1;
}

//say("// check ratings");
// check ratings
if (tRating >= option_maxrating) {
wtConditions[TS] = wtConditions[TS] + 1;
}
if (ctRating >= option_maxrating) {
wtConditions[CTS] = wtConditions[CTS] + 1;
}

//say("// check team sizes for unequal ratings");
// check team sizes for unequal ratings
if (teamCounts[TS] > teamCounts[CTS] && tRating >= option_minrating) {
wtConditions[TS] = wtConditions[TS] + 1;
}
if (teamCounts[CTS] > teamCounts[TS] && ctRating >= option_minrating) {
wtConditions[CTS] = wtConditions[CTS] + 1;
}

//say("// check conditions");
// check conditions
if (wtConditions[TS] >= 2) {
//say("TERRORISTS are the winning team ...");
winnerTeam = TS;
loserTeam = CTS;
}
else if (wtConditions[CTS] >= 2) {
//say("COUNTER-TERRORISTS are the winning team ...");
winnerTeam = CTS;
loserTeam = TS;
}
else {
winnerTeam = 0;
loserTeam = 0;
//if (wtConditions[CTS] > 0) say("COUNTER-TERRORIST team advantage ...");
//else if (wtConditions[TS] > 0) say("TERRORIST team advantage ...");
//else say("No winning team, no team advantage ...");
}
}

public ChoosingTeam(HLCommand, HLData, HLUserName, UserIndex) {
//say("ChoosingTeam");

isChoosingTeam[UserIndex] = 1;

return PLUGIN_CONTINUE;
}

public NotChoosingTeam(HLCommand, HLData, HLUserName, UserIndex) {
//say("NotChoosingTeam");

isChoosingTeam[UserIndex] = 0;

return PLUGIN_CONTINUE;
}

manageWtjFile(UserIndex) {
if (!option_savewtj) return;

//log("Trying to write wtj.log ....");

if (wtjCount[UserIndex] != 4) return;

//log("wtj.log should be written to now ....");

//new debug[MAX_DATA_LENGTH];
//snprintf(debug, MAX_DATA_LENGTH, "PTB manageWtjFile");
//log(debug);

new Time[MAX_DATA_LENGTH];
servertime(Time, MAX_DATA_LENGTH);

new Map[MAX_DATA_LENGTH];
currentmap(Map, MAX_DATA_LENGTH);

new Name[MAX_NAME_LENGTH];
new UserId;
new WonId;
playerinfo(UserIndex, Name, MAX_NAME_LENGTH, UserId, WonId);

new text[MAX_TEXT_LENGTH];
snprintf(text, MAX_TEXT_LENGTH, "%s %s <%d> %s", Time, Name, WonId, Map);

writefile("wtj.log", text);
}

public MenuSelect(HLCommand, HLData, HLUserName, UserIndex) {
//say("MenuSelect");

/*
new s[MAX_TEXT_LENGTH];
new d[MAX_DATA_LENGTH];
new n[MAX_NAME_LENGTH];
convert_string(HLData, d, MAX_DATA_LENGTH);
convert_string(HLUserName, n, MAX_DATA_LENGTH);
snprintf(s, MAX_TEXT_LENGTH, "%s (%d) selected menu %s (is choosing team: %d)", n, UserIndex, d, isChoosingTeam[UserIndex]);
say(s);
*/
if (!isChoosingTeam[UserIndex]) return PLUGIN_CONTINUE;

isChoosingTeam[UserIndex] = 0;

//if (UserIndex < 1) return PLUGIN_CONTINUE;
if (!option_limitjoin) return PLUGIN_CONTINUE;

if (isBeingTransfered[UserIndex]) {
//say("TRANSFER");
isBeingTransfered[UserIndex] = 0;
return PLUGIN_CONTINUE;
}
else {
//say("NO TRANSFER");
}

new Data[MAX_DATA_LENGTH];
new iNewTeam;

convert_string(HLData, Data, MAX_DATA_LENGTH);
iNewTeam = strtonum(Data);

new iOldTeam = playerTeam[UserIndex];

new Name[MAX_NAME_LENGTH];
playerinfo(UserIndex, Name, MAX_NAME_LENGTH);

// prevent unwanted rejoining of the same team ...
if (iNewTeam == playerTeam[UserIndex]) {
//say("Preventing rejoining of the same team.");
return PLUGIN_HANDLED;
}

checkTeamBalance();

//displayStatistics(true);

// debug
//snprintf(s, MAX_TEXT_LENGTH, "iOldTeam = %d, iNewTeam = %d, winnerTeam = %d, loserTeam = %d, CTS = %d, TS = %d, AUTO_TEAM = %d, #CTs = %d, #Ts = %d", iOldTeam, iNewTeam, winnerTeam, loserTeam, CTS, TS, AUTO_TEAM, teamCounts[CTS], teamCounts[TS]);
//say(s);

// check if player is trying to change teams
if ((iNewTeam == CTS || iNewTeam == TS) && (iOldTeam == CTS || iOldTeam == TS)) {
//say("Changing team directly.");
new opposingTeam = iNewTeam == CTS ? TS : CTS;
if (
teamCounts[iNewTeam] != 0
&& teamCounts[opposingTeam] < MAX_TEAM_SIZE
&& (
(winnerTeam != 0 && iNewTeam == winnerTeam)
|| (teamCounts[iNewTeam] >= teamCounts[opposingTeam])
)
) {
new text[MAX_TEXT_LENGTH];
wtjCount[UserIndex] += 1;
if (wtjCount[UserIndex] > 9 && option_kick) {
snprintf(text, 80, "PTB: Kicking %s for a WTJ count of %d).", Name, wtjCount[UserIndex]);
typesay(text, 5, 10, 255, 10);
say(text);
kick(Name);
return PLUGIN_HANDLED;
}
if (iNewTeam == CTS) {
snprintf(text, 80, "PTB: The CTs are strong enough, %s (WTJ count: %d).", Name, wtjCount[UserIndex]);
typesay(text, 5, 10, 10, 255);
}
else {
snprintf(text, 80, "PTB: The Ts are strong enough, %s (WTJ count: %d).", Name, wtjCount[UserIndex]);
typesay(text, 5, 255, 10, 10);
}
say(text);
return PLUGIN_HANDLED;
}
}
else if (iNewTeam == CTS || iNewTeam == TS) {
//say("Joining team directly.");
new opposingTeam = iNewTeam == CTS ? TS : CTS;
if (
teamCounts[iNewTeam] != 0
&& teamCounts[opposingTeam] < MAX_TEAM_SIZE
&& (
(winnerTeam != 0 && iNewTeam == winnerTeam) // && teamCounts[winnerTeam] >= teamCounts[opposingTeam])
|| (winnerTeam == 0 && teamCounts[iNewTeam] > teamCounts[opposingTeam])
)
) {
new text[MAX_TEXT_LENGTH];
wtjCount[UserIndex] += 1;
if (wtjCount[UserIndex] > 9 && option_kick) {
snprintf(text, 80, "PTB: Kicking %s for a WTJ count of %d).", Name, wtjCount[UserIndex]);
typesay(text, 5, 10, 255, 10);
say(text);
kick(Name);
return PLUGIN_HANDLED;
}
if (iNewTeam == CTS) {
if (wtjCount[UserIndex] > 3) {
manageWtjFile(UserIndex);
snprintf(text, 80, "PTB: Forcing %s to the Ts (WTJ count: %d).", Name, wtjCount[UserIndex]);
execclient(Name, "menuselect 1");
typesay(text, 5, 10, 255, 10);
}
else {
snprintf(text, 80, "PTB: The CTs are strong enough, %s (WTJ count: %d).", Name, wtjCount[UserIndex]);
typesay(text, 5, 10, 10, 255);
}
}
else {
if (wtjCount[UserIndex] > 3) {
manageWtjFile(UserIndex);
snprintf(text, 80, "PTB: Forcing %s to the CTs (WTJ count: %d).", Name, wtjCount[UserIndex]);
execclient(Name, "menuselect 2");
typesay(text, 5, 10, 255, 10);
}
else {
snprintf(text, 80, "PTB: The Ts are strong enough, %s (WTJ count: %d).", Name, wtjCount[UserIndex]);
typesay(text, 5, 255, 10, 10);
}
}
say(text);
return PLUGIN_HANDLED;
}
}
else if (iNewTeam == AUTO_TEAM && (iOldTeam == CTS || iOldTeam == TS)) {
//say("Changing team automatically.");

new opposingTeam = iOldTeam == CTS ? TS : CTS;
if (
teamCounts[opposingTeam] != 0
&& (
opposingTeam == MAX_TEAM_SIZE
|| (loserTeam != 0 && iOldTeam == loserTeam)
|| (loserTeam == 0 && teamCounts[iOldTeam] <= teamCounts[opposingTeam])
)
) {
//say("Aborting automatic team change.");
// debug
//new text[MAX_TEXT_LENGTH];
//snprintf(text, MAX_TEXT_LENGTH, "Aborting auto-joining team %d (winnerTeam = %d) teamCounts[iOldTeam] %d teamCounts[opposingTeam] %d", opposingTeam, winnerTeam, teamCounts[iOldTeam], teamCounts[opposingTeam]);
//say(text);

// close menu
return PLUGIN_HANDLED;
}

iNewTeam = opposingTeam;

// debug
//new text[MAX_TEXT_LENGTH];
//snprintf(text, MAX_TEXT_LENGTH, "Auto-joining team %d. (winnerTeam = %d)", iNewTeam, winnerTeam);
//say(text);

if (iNewTeam == CTS) execclient(Name, "menuselect 2");
else execclient(Name, "menuselect 1");

return PLUGIN_HANDLED;
}
else if (iNewTeam == AUTO_TEAM) {
//say("Joining team automatically.");

/* this is the "always smaller team" version
if (teamCounts[CTS] < teamCounts[TS] || teamCounts[TS] == MAX_TEAM_SIZE) iNewTeam = CTS;
else if (teamCounts[TS] < teamCounts[CTS] || teamCounts[CTS] == MAX_TEAM_SIZE) iNewTeam = TS;
// both teams have same size ...
else if (winnerTeam != 0 && teamCounts[loserTeam] < MAX_TEAM_SIZE) iNewTeam = loserTeam;
else if (teamCounts[TS] == MAX_TEAM_SIZE) iNewTeam = CTS;
else if (teamCounts[CTS] == MAX_TEAM_SIZE) iNewTeam = TS;
else iNewTeam = random(2) + 1;
*/

// this version prefers the losing team
if (winnerTeam != 0 && teamCounts[loserTeam] < MAX_TEAM_SIZE) iNewTeam = loserTeam;
else if (teamCounts[CTS] < teamCounts[TS] || teamCounts[TS] == MAX_TEAM_SIZE) iNewTeam = CTS;
else if (teamCounts[TS] < teamCounts[CTS] || teamCounts[CTS] == MAX_TEAM_SIZE) iNewTeam = TS;
// both teams have same size ...
else if (teamCounts[TS] == MAX_TEAM_SIZE) iNewTeam = CTS;
else if (teamCounts[CTS] == MAX_TEAM_SIZE) iNewTeam = TS;
else iNewTeam = random(2) + 1;

// debug
//new text[MAX_TEXT_LENGTH];
//snprintf(text, MAX_TEXT_LENGTH, "Auto-joining team %d. (winnerTeam = %d)", iNewTeam, winnerTeam);
//say(text);

if (iNewTeam == CTS) execclient(Name, "menuselect 2");
else execclient(Name, "menuselect 1");

return PLUGIN_HANDLED;
}

//say("Allow team join ...");

return PLUGIN_CONTINUE;
}

public ptb_teamaction(HLCommand, HLData, HLUserName, UserIndex)
{
//say("ptb_teamaction");

new params[MAX_DATA_LENGTH];
new team[MAX_DATA_LENGTH];
new action[MAX_DATA_LENGTH];

convert_string(HLData, params, MAX_DATA_LENGTH);

strbreak(params, team, action, MAX_DATA_LENGTH);

if(
strmatch(action, "CTs_Win", strlen("CTs_Win"))
|| strmatch(action, "Terrorists_Win", strlen("Terrorists_Win"))
|| strmatch(action, "Target_Bombed", strlen("Target_Bombed"))
) {
new scores[MAX_DATA_LENGTH];
new ctScore[MAX_DATA_LENGTH];
new tScore[MAX_DATA_LENGTH];
new skip[MAX_DATA_LENGTH];
new c;

strbreak(action, skip, scores, MAX_DATA_LENGTH);
strbreak(scores, ctScore, tScore, MAX_DATA_LENGTH);

c = strchr(ctScore, '#') + 1;
teamScores[CTS] = strtonum(ctScore[c]);

c = strchr(tScore, '#') + 1;
teamScores[TS] = strtonum(tScore[c]);

// count won rounds in a row
if (strmatch(action, "CTs_Win", strlen("CTs_Win"))) {
if (winStreaks[CTS] < 0) {
// reset counters
winStreaks[CTS] = 1;
winStreaks[TS] = -1;
}
else {
winStreaks[CTS] += 1;
winStreaks[TS] -= 1;
}
}
else {
if (winStreaks[TS] < 0) {
// reset counters
winStreaks[CTS] = -1;
winStreaks[TS] = 1;
}
else {
winStreaks[CTS] -= 1;
winStreaks[TS] += 1;
}
}
}

act();
// clear flags
for (new i = 1; i <= MAX_PLAYERS; ++i) switchedThisRound = false;

return PLUGIN_CONTINUE;
}

public ptb_worldaction(HLCommand, HLData, HLUserName, UserIndex) {
//say("ptb_worldaction");

new Data[MAX_DATA_LENGTH];
convert_string(HLData, Data, MAX_DATA_LENGTH);
//say(Data);

if (streq(Data, "Round_Start")) {
//set_timer("announceStatus", 15, 1);
announceStatus();
}

return PLUGIN_CONTINUE;
}

public ptb_teamselection(HLCommand, HLData, HLUserName, UserIndex) {
//say("ptb_teamselection");

//displayStatistics(true);

new data[MAX_DATA_LENGTH];
new sIndex[MAX_DATA_LENGTH];
new sTeam[MAX_DATA_LENGTH];
new i;
new team;

convert_string(HLData, data, MAX_DATA_LENGTH);
strsplit(data, " ", sIndex, MAX_DATA_LENGTH, sTeam, MAX_DATA_LENGTH);

//new debug[MAX_DATA_LENGTH];
//snprintf(debug, MAX_DATA_LENGTH, "PTB: ptb_teamselection: %s", data);
//log(debug);

if (streq(sTeam, "TERRORIST")) team = TS;
else if (streq(sTeam, "CT")) team = CTS;
else team = 0;

//if (team == 0) say("PTB: ptb_teamselection: Team is 0.");

i = strtonum(sIndex);

if (playerTeam[i] == TS || playerTeam[i] == CTS) teamCounts[playerTeam[i]] -= 1;
if (team == TS || team == CTS) teamCounts[team] += 1;

playerTeam[i] = team;

switchedThisRound[i] = true;

//say("ptb_teamselection");
//say(data);

//displayStatistics(true);

return PLUGIN_CONTINUE;
}

public ptb_kill(HLCommand, HLData, HLUserName, UserIndex)
{
//say("ptb_kill");

new iWinner;
new iLoser;
new idWinner[3];
new idLoser[3];
new data[MAX_DATA_LENGTH];
new name[MAX_NAME_LENGTH];

convert_string(HLData, data, MAX_DATA_LENGTH);

strsplit(data, " ", idWinner, 3, idLoser, 3);

iWinner = strtonum(idWinner);
iLoser = strtonum(idLoser);

if (!playerinfo(iWinner, name, MAX_NAME_LENGTH)) {
return PLUGIN_CONTINUE;
}

kills[iWinner] = kills[iWinner] + 1;
deaths[iLoser] = deaths[iLoser] + 1;

if (playerTeam[iWinner] != CTS && playerTeam[iWinner] != TS) log("PTB: Kill without team!");
if (playerTeam[iLoser] != CTS && playerTeam[iLoser] != TS) log("PTB: Death without team!");

return PLUGIN_CONTINUE;
}

calcTeamScores()
{
//say("calcTeamScores");

teamDeaths[CTS] = 0;
teamDeaths[TS] = 0;
teamKills[CTS] = 0;
teamKills[TS] = 0;

for (new i = 1; i <= MAX_PLAYERS; ++i) {
new team = playerTeam[i];
if (team == CTS || team == TS) {
teamKills[team] += kills[i];
teamDeaths[team] += deaths[i];
}
}

/*
new text[MAX_TEXT_LENGTH];
snprintf(text, MAX_TEXT_LENGTH, "CT Kill/Deaths: %d/%d", teamKills[CTS], teamDeaths[CTS]);
say(text);
snprintf(text, MAX_TEXT_LENGTH, "T Kill/Deaths: %d/%d", teamKills[TS], teamDeaths[TS]);
say(text);
*/

//say("calcTeamScores DONE");
}

announceStatus() {
//say("announceStatus");

if (!option_announce) return;

checkTeamBalance();

new text[MAX_TEXT_LENGTH];

if (winnerTeam == TS) {
snprintf(text, MAX_TEXT_LENGTH, "PTB: The COUNTER-TERRORIST team could use some support.");
typesay(text, 5, 10, 10, 255);
say("PTB: The COUNTER-TERRORIST team could use some support.");
}
else if (winnerTeam == CTS) {
snprintf(text, MAX_TEXT_LENGTH, "PTB: The TERRORIST team could use some support.");
typesay(text, 5, 255, 10, 10);
say("PTB: The TERRORIST team could use some support.");
}
else if (wtConditions[TS] > wtConditions[CTS]) {
snprintf(text, MAX_TEXT_LENGTH, "PTB: Observing TERRORIST team advantage.");
typesay(text, 5, 10, 10, 255);
say("PTB: Observing TERRORIST team advantage.");
}
else if (wtConditions[CTS] > wtConditions[TS]) {
snprintf(text, MAX_TEXT_LENGTH, "PTB: Observing COUNTER-TERRORIST team advantage.");
typesay(text, 5, 255, 10, 10);
say("PTB: Observing COUNTER-TERRORIST team advantage.");
}
else if (option_sayok) {
snprintf(text, MAX_TEXT_LENGTH, "PTB: Teams look fine, no action required.");
typesay(text, 5, 255, 255, 255);
say("PTB: Teams look fine, no action required.");
}

//displayStatistics();
}

public admin_ptb(HLCommand, HLData, HLUserName, UserIndex) {
new Data[MAX_DATA_LENGTH];
new Command[MAX_DATA_LENGTH];
new Argument[MAX_DATA_LENGTH];
new s[MAX_TEXT_LENGTH];

convert_string(HLData, Data, MAX_NAME_LENGTH);

strinit(Command);
strinit(Argument);

selfmessage("PTB: Ptahhotep's Team Balancer 1.4");
selfmessage("PTB: (ptahhotep@planethalflife.com)");

if (!strlen(Data)) {
displayStatistics();
}
else if (!access(ACCESS_BALANCE, "")) {
selfmessage("PTB: You are not allowed to use this command");
return PLUGIN_HANDLED;
}
else if (streq(Data, "on") || streq(Data, "1")) {
option_switch = 1;
option_announce = 1;
option_limitjoin = 1;
selfmessage("PTB: Enabled all PTB actions.");
return PLUGIN_HANDLED;
}
else if (streq(Data, "off") || streq(Data, "0")) {
option_switch = 0;
option_announce = 0;
option_limitjoin = 0;
selfmessage("PTB: Disabled all PTB actions.");
return PLUGIN_HANDLED;
}
else {
strsplit(Data, " ", Command, MAX_DATA_LENGTH, Argument, MAX_DATA_LENGTH);
}

if (streq(Command, "switch") && strlen(Argument)) option_switch = check_param(Argument);
if (streq(Command, "status") || streq(Command, "switch")) { if (option_switch) selfmessage("PTB: (switch) Team switching is ON."); else selfmessage("PTB: (switch) Team switching is OFF."); }

if (streq(Command, "announce") && strlen(Argument)) option_announce = check_param(Argument);
if (streq(Command, "status") || streq(Command, "announce")) { if (option_announce) selfmessage("PTB: (announce) Announcements are ON."); else selfmessage("PTB: (announce) Announcements are OFF."); }

if (streq(Command, "limitjoin") && strlen(Argument)) option_limitjoin = check_param(Argument);
if (streq(Command, "status") || streq(Command, "limitjoin")) { if (option_limitjoin) selfmessage("PTB: (limitjoin) WTJ prevention is ON."); else selfmessage("PTB: (limitjoin) WTJ prevention is OFF."); }

if (streq(Command, "kick") && strlen(Argument)) option_kick = check_param(Argument);
if (streq(Command, "status") || streq(Command, "kick")) { if (option_kick) selfmessage("PTB: (kick) Kicking is ON."); else selfmessage("PTB: (kick) Kicking is OFF."); }

if (streq(Command, "sayok") && strlen(Argument)) option_sayok = check_param(Argument);
if (streq(Command, "status") || streq(Command, "sayok")) { if (option_sayok) selfmessage("PTB: (sayok) ^"OK^" announcements are ON."); else selfmessage("PTB: (sayok) ^"OK^" announcements are OFF."); }

if (streq(Command, "savewtj") && strlen(Argument)) option_savewtj = check_param(Argument);
if (streq(Command, "status") || streq(Command, "savewtj")) { if (option_savewtj) selfmessage("PTB: (savewtj) Saving to wtj.txt is ON."); else selfmessage("PTB: (savewtj) Saving to wtj.txt is OFF."); }

if (streq(Command, "deadonly") && strlen(Argument)) option_deadonly = check_param(Argument);
if (streq(Command, "status") || streq(Command, "deadonly")) { if (option_deadonly) selfmessage("PTB: (deadonly) Switching dead only is ON."); else selfmessage("PTB: (deadonly) Switching dead only is OFF."); }

if (streq(Command, "maxstreak") && strlen(Argument)) {
option_maxstreak = strtonum(Argument);
if (option_maxstreak < 1) option_maxstreak = MAX_STREAK;
}
if (streq(Command, "status") || streq(Command, "maxstreak")) {
snprintf(s, MAX_TEXT_LENGTH, "PTB: (maxstreak) Maximum accepted win streak is %d.", option_maxstreak);
selfmessage(s);
}
if (streq(Command, "maxrandom") && strlen(Argument)) {
option_maxrandom = strtonum(Argument);
if (option_maxrandom < 1) option_maxrandom = MAX_RANDOM;
}
if (streq(Command, "status") || streq(Command, "maxrandom")) {
snprintf(s, MAX_TEXT_LENGTH, "PTB: (maxrandom) Maximum switch randomization is %d.", option_maxrandom);
selfmessage(s);
}

if (streq(Command, "maxrating") && strlen(Argument)) {
option_maxrating = fixedstr(Argument);
if (option_maxrating <= fixed(1)) option_maxrating = fixedstr(MAX_RATING);
}
if (streq(Command, "status") || streq(Command, "maxrating")) {
snprintf(s, MAX_TEXT_LENGTH, "PTB: (maxrating) Maximum strength rating is %d.%d.",
fround(option_maxrating, fround_floor),
fround(fmul(fixed(10), ffract(option_maxrating)), fround_floor)
);
selfmessage(s);
}
if (streq(Command, "minrating") && strlen(Argument)) {
option_minrating = fixedstr(Argument);
if (option_minrating <= fixed(1)) option_minrating = fixedstr(MIN_RATING);
}
if (streq(Command, "status") || streq(Command, "minrating")) {
snprintf(s, MAX_TEXT_LENGTH, "PTB: (minrating) Minimum strength rating is %d.%d.",
fround(option_minrating, fround_floor),
fround(fmul(fixed(10), ffract(option_minrating)), fround_floor)
);
selfmessage(s);
}

if (streq(Command, "status")) {
selfmessage("PTB: To change or view a single setting, type: ^"admin_ptb <setting> <^"on^"|^"off^"|value|^"^">");
}

return PLUGIN_HANDLED;
}

stock displayStatistics(toLog = false) {
//say("displayStatistics");

new text[MAX_TEXT_LENGTH];

// team sizes
snprintf(text, MAX_TEXT_LENGTH, "PTB: Team sizes: CTs %d, Ts %d", teamCounts[CTS], teamCounts[TS]);
if (toLog) log(text);
else selfmessage(text);

// team scores
snprintf(text, MAX_TEXT_LENGTH, "PTB: Team scores: CTs %d, Ts %d", teamScores[CTS], teamScores[TS]);
if (toLog) log(text);
else selfmessage(text);

// Kills:Deaths
snprintf(text, MAX_TEXT_LENGTH, "PTB: Team kills:deaths: CTs %d:%d, Ts %d:%d", teamKills[CTS], teamDeaths[CTS], teamKills[TS], teamDeaths[TS]);
if (toLog) log(text);
else selfmessage(text);

// Kills/Deaths
snprintf(text, MAX_TEXT_LENGTH, "PTB: Team kills/deaths: CTs %d.%d, Ts %d.%d",
fround(ctKD, fround_floor),
fround(fmul(fixed(100), ffract(ctKD)), fround_floor),
fround(tKD, fround_floor),
fround(fmul(fixed(100), ffract(tKD)), fround_floor)
);
if (toLog) log(text);
else selfmessage(text);

// strength
snprintf(text, MAX_TEXT_LENGTH, "PTB: Team strengths: CTs %d.%d, Ts %d.%d",
fround(ctStrength, fround_floor),
fround(fmul(fixed(100), ffract(ctStrength)),
fround_floor), fround(tStrength, fround_floor),
fround(fmul(fixed(100), ffract(tStrength)), fround_floor)
);
if (toLog) log(text);
else selfmessage(text);

// rating
snprintf(text, MAX_TEXT_LENGTH, "PTB: Team ratings: CTs %d.%d, Ts %d.%d",
fround(ctRating, fround_floor),
fround(fmul(fixed(100), ffract(ctRating)), fround_floor),
fround(tRating, fround_floor),
fround(fmul(fixed(100), ffract(tRating)), fround_floor)
);
if (toLog) log(text);
else selfmessage(text);

// won rounds
if (winStreaks[CTS] > 0) {
snprintf(text, MAX_TEXT_LENGTH, "PTB: Last %d round(s) won by CTs.", winStreaks[CTS]);
if (toLog) log(text);
else selfmessage(text);
}
else if (winStreaks[TS] > 0) {
snprintf(text, MAX_TEXT_LENGTH, "PTB: Last %d round(s) won by Ts.", winStreaks[TS]);
if (toLog) log(text);
else selfmessage(text);
}
}

/*
initVariables() {
// read the settings from server.cfg

new Argument[20];

get_serverinfo("admin_ptb_switch", Argument, 20);
if (strlen(Argument)) option_switch = check_param(Argument);

get_serverinfo("admin_ptb_announce", Argument, 20);
if (strlen(Argument)) option_announce = check_param(Argument);

get_serverinfo("admin_ptb_limitjoin", Argument, 20);
if (strlen(Argument)) option_limitjoin = check_param(Argument);

get_serverinfo("admin_ptb_kick", Argument, 20);
if (strlen(Argument)) option_kick = check_param(Argument);

get_serverinfo("admin_ptb_sayok", Argument, 20);
if (strlen(Argument)) option_sayok = check_param(Argument);

get_serverinfo("admin_ptb_savewtj", Argument, 20);
if (strlen(Argument)) option_savewtj = check_param(Argument);

get_serverinfo("admin_ptb_deadonly", Argument, 20);
if (strlen(Argument)) option_deadonly = check_param(Argument);

get_serverinfo("admin_ptb_maxstreak", Argument, 20);
if (strlen(Argument)) {
option_maxstreak = strtonum(Argument);
if (option_maxstreak < 1) option_maxstreak = MAX_STREAK;
}

get_serverinfo("admin_ptb_maxrandom", Argument, 20);
if (strlen(Argument)) {
option_maxrandom = strtonum(Argument);
if (option_maxrandom < 1) option_maxrandom = MAX_RANDOM;
}

get_serverinfo("admin_ptb_maxrating", Argument, 20);
if (strlen(Argument)) {
option_maxrating = fixedstr(Argument);
if (option_maxrating <= fixed(1)) option_maxrating = fixedstr(MAX_RATING);
}

get_serverinfo("admin_ptb_minrating", Argument, 20);
if (strlen(Argument)) {
option_minrating = fixedstr(Argument);
if (option_minrating <= fixed(1)) option_minrating = fixedstr(MIN_RATING);
}
}
*/

public plugin_connect(HLUserName, HLIP, UserIndex)
{
//say("plugin_connect");

if ((UserIndex >= 1) && (UserIndex <= MAX_PLAYERS)) {
kills[UserIndex] = 0;
deaths[UserIndex] = 0;
isChoosingTeam[UserIndex] = 1;
isBeingTransfered[UserIndex] = 0;
playerTeam[UserIndex] = 0;
switchedThisRound[UserIndex] = false;
wtjCount[UserIndex] = 0;
}
else {
say("PTB: Shouldn't get here, unexpected UserIndex.");
}
return PLUGIN_CONTINUE;
}

public plugin_disconnect(HLUserName, UserIndex)
{
//say("plugin_disconnect");

//new debug[MAX_DATA_LENGTH];
//snprintf(debug, MAX_DATA_LENGTH, "[DEBUG] PTB plugin_disconnect: %d %d", UserIndex, playerTeam[UserIndex]);
//log(debug);

if ((UserIndex >= 1) && (UserIndex <= MAX_PLAYERS)) {
kills[UserIndex] = 0;
deaths[UserIndex] = 0;
isChoosingTeam[UserIndex] = 0;
isBeingTransfered[UserIndex] = 0;
if (playerTeam[UserIndex] == TS || playerTeam[UserIndex] == CTS) {
teamCounts[playerTeam[UserIndex]] -= 1;
}
playerTeam[UserIndex] = 0;
switchedThisRound[UserIndex] = false;
wtjCount[UserIndex] = 0;
}
else {
say("PTB: Shouldn't get here, unexpected UserIndex.");
}

// redundant team size check
teamCounts[CTS] = 0;
teamCounts[TS] = 0;
teamCounts[0] = 0;
for (new i = 1; i <= MAX_PLAYERS; ++i) teamCounts[playerTeam[i]] += 1;

//displayStatistics(true);

return PLUGIN_CONTINUE;
}

public plugin_init()
{
//say("plugin_init");

//initVariables();

// must du this here
option_maxrating = fixedstr(MAX_RATING);
option_minrating = fixedstr(MIN_RATING);

plugin_registerinfo("PTB", "Ptahhotep's Team Balancer", STRING_VERSION);
plugin_registercmd("admin_ptb", "admin_ptb", ACCESS_ALL, "admin_ptb <^"on^" | ^"off^" | ^"status^" | ^"^">: Switch Ptahhotep's Team Balancer on or off, get status or statistics.");

//plugin_registercmd("admin_transfer", "admin_transfer", ACCESS_BALANCE);
//plugin_registercmd("admin_spectator", "admin_spectator", ACCESS_BALANCE);

plugin_registercmd("chooseteam", "ChoosingTeam", ACCESS_ALL);
plugin_registercmd("menuselect", "MenuSelect", ACCESS_ALL);
plugin_registercmd("radio", "NotChoosingTeam", ACCESS_ALL);
plugin_registercmd("buy", "NotChoosingTeam", ACCESS_ALL);
plugin_registercmd("buyequip", "NotChoosingTeam", ACCESS_ALL);
plugin_registercmd("showbriefing", "NotChoosingTeam", ACCESS_ALL);

plugin_registercmd("ptb_teamselection", "ptb_teamselection", ACCESS_CONSOLE);
plugin_registercmd("ptb_kill", "ptb_kill", ACCESS_CONSOLE);
plugin_registercmd("ptb_teamaction", "ptb_teamaction", ACCESS_CONSOLE);
plugin_registercmd("ptb_worldaction", "ptb_worldaction", ACCESS_CONSOLE);

exec("logd_reg 54 admin_command ptb_teamselection");
exec("logd_reg 57 admin_command ptb_kill");
exec("logd_reg 61 admin_command ptb_teamaction");
exec("logd_reg 62 admin_command ptb_worldaction");

return PLUGIN_CONTINUE;
}

Autor:  NIGHTMARE! [ 27.04.2002, 21:31 ]
Betreff des Beitrags: 

Code:
plugin_registerinfo("PTB", "Ptahhotep's Team Balancer", STRING_VERSION); 
plugin_registercmd("admin_ptb", "admin_ptb", ACCESS_ALL, "admin_ptb <^"on^" | ^"off^" | ^"status^" | ^"^">: Switch Ptahhotep's Team Balancer on or off, get status or statistics."); 
da stehts doch !!!
admin_ptb on, off oder status

Autor:  NIGHTMARE! [ 27.04.2002, 21:33 ]
Betreff des Beitrags:  Das ist ein ...

Das ist ein Teambalancer, der nicht nach der Anzahl der Spieler in einem Team, sondern nach den kills und dem skill der spieler ...
Ist oft fairer ..
( also z.B. macht der 3 Profis gegen 5 n00bs oda so ... )

Seite 1 von 1 Alle Zeiten sind UTC+01:00
Powered by phpBB® Forum Software © phpBB Limited
https://www.phpbb.com/