Team Balencer for AMXX
I'm having troubles; The balancer works perfectly fine, But it does not show the 'best player' and 'best team'; I was wondering if I have made this wrong- Please let me know if so; Feel free to correct it.
Code:
#include <amxmodx>
new bool:endscore = true
new blockjoining[2]
new scores[2]
new Float:ppower[33]
new Float:tpower[2]
new Float:tempf
new Float:avepower
new playersnum[2]
Float:maxf(Float:a,Float:b)
return a < b ? b : a
Float:minf(Float:a,Float:b)
return a < b ? a : b
absn(a)
return a < 0 ? -a : a
public calculate_power(){
new teams[33], ppl[32], ippl
new a, b, c , d, e
new Float:frags
new Float:deaths
new transfer = -1
playersnum[0] = playersnum[1] = 0 // reset player num
tpower[0] = tpower[1] = 0.0 // reset teams power
avepower = 0.0 // reset averange skill
blockjoining[ 0 ] = blockjoining[ 1 ] = PLUGIN_CONTINUE // reset blocking
get_players(ppl,ippl) // get all players in game
/* Get avarange efficiency, player efficiency and team efficiency. */
for(a=0;a<ippl;++a){ // calculate efficiency for each player
b = ppl[a]
c = get_user_team(b) - 1 // in CS the T team has id #1 and CT has id #2
teams[b] = c // save what index of team the player has
if (c!=0&&c!=1) continue // Spectator
frags = float(get_user_frags(b))
deaths = float(get_user_deaths(b))
tempf = (frags / (deaths ? deaths : 1.0)) + (frags * 0.1)
ppower[b] = tempf
avepower += tempf // add to sum of all efficiencies for avarange calculation
playersnum[c]++ // increase number of player in that team
tpower[c] += tempf // add the player efficiency to team efficiency
}
avepower /= float(playersnum[0] + playersnum[1]) // averange efficiency
/* Get best players. */
new goodlist[2][32] // array for list of good players
new goodnum[2] // how many good player the team has
goodnum[0] = goodnum[1] = 0
for(a=0;a<ippl;++a){ // sum eff. for each team
b = ppl[a]
c = teams[b]
if (c!=0&&c!=1) continue // Spectator
if ( ppower[b] > avepower ){ // if better than avarange then save him to list
goodlist[c][goodnum[c]] = b
goodnum[c]++
}
}
/* Display score. */
new Float: cscore = tpower[1]
new Float: tscore = tpower[0]
client_print(0,print_chat,"CT %d (%.2f) -- TERRORIST %d (%.2f)",scores[1],cscore,scores[0],tscore)
/* Try to estimate which team is better and announce about it. */
new Float: winner = maxf(cscore,tscore)
new Float: looser = minf(cscore,tscore)
new Float: compratio = winner / looser
/* Determine index of better team (with higher skill ratio). */
e = (cscore > tscore) ? 1 : 0
if ( compratio >= 6 ){
blockjoining[ e ] = PLUGIN_HANDLED /* Block joining to the better team. */
transfer = e /* Save index of better them to switch from. */
client_print(0,print_chat,"%s team beats %s", e ? "Ct" : "Terrorist", e ? "Terrorists" : "Cts" )
}
else if ( compratio >= 4 ){
blockjoining[ e ] = PLUGIN_HANDLED /* Block joining to the better team. */
transfer = e /* Save index of better them to switch from. */
client_print(0,print_chat,"%s team seems to be more powerful",e ? "Ct" : "Terrorist" )
}
else if ( compratio >= 2 ){
blockjoining[ e ] = PLUGIN_HANDLED /* Block joining to the better team. */
client_print(0,print_chat,"%s team is slightly better",e ? "Ct" : "Terrorist" )
}
else{
/*Sometimes there is a situation that team is balanced but there are different
numbers of players in each team. If the difference is higher then 1 then transfer someone.
NOTE: That this condition will be never true for mp_limitteams 2.0 (this is now, however
we will leave it for possibly future modifications.)
e.g, T 6 -- CT 2, the difference is 4 then get the best from T and worst from CT
and transfor them. Yes it won't balance them but make one team a bit better than
second, ppl tend to switch the team following with the best. If team is to
powerful they won't unbalance team more due to team switching block :)
*/
if ( absn(playersnum[0] - playersnum[1]) > 1 )
transfer = (playersnum[0] > playersnum[1]) ? 0 : 1
client_print(0,print_chat,"Teams are balanced. Terrorists have %d and Cts %d good player(s)",goodnum[0],goodnum[1])
}
/* Build list of best players for each team and display them. */
new list[256], name[32]
c = goodnum[0]
b = 0
for(a=0;a<c;++a) { // TERRORIST
d = goodlist[0][a]
get_user_name(d,name,31)
b += format(list[b],255-b,"%s, ",name )
}
if (c) {
list[b-2] = 0 // remove ", " from after last name
client_print(0,print_chat,"In Terrorists good %s: %s",(c==1)?"is":"are",list)
}
c = goodnum[1]
b = 0
for(a=0;a<c;++a) { // CT
d = goodlist[1][a]
get_user_name(d,name,31)
b += format(list[b],255-b,"%s, ",name )
}
if (c) {
list[b-2] = 0
client_print(0,print_chat,"In Cts good %s: %s",(c==1)?"is":"are",list)
}
/* if there is need to switch someone then determine
best and worst then switch them. */
if (transfer != -1){
new baplayer[2], woplayer[2]
new Float:bestalive[2]
new Float:worstalive[2]
baplayer[0] = baplayer[1] = 0
woplayer[0] = woplayer[1] = 0
bestalive[0] = bestalive[1] = 0.0
worstalive[0] = worstalive[1] = 100.0
for(a=0;a<ippl;++a){ /* For each player. */
b = ppl[a]
c = teams[b] /* The team index will put results to proper place. */
if (c!=0&&c!=1) continue // Spectator
if (is_user_alive(b)) continue
if (bestalive[c] < ppower[b]){ // Get best dead player
bestalive[c] = ppower[b]
baplayer[c] = b
}
if (worstalive[c] > ppower[b]){ // Get worst dead player
worstalive[c] = ppower[b]
woplayer[c] = b
}
}
/* Get the oposite index of team for worst player to transfer. */
new optransfer = transfer ? 0 : 1
/* If there is need for transfering the players then switch them. */
if (baplayer[transfer] && woplayer[optransfer] ){
if (playersnum[transfer] > 1) // if has more than 1 player then you may transfer him
transfer_player(baplayer[transfer],transfer ? "1" : "2" )
if (playersnum[optransfer] > 1) // if has more than 1 player then you may transfer him
transfer_player(woplayer[optransfer], optransfer ? "1" : "2" )
}
}
}
transfer_player(id,key[]){
new oldone[2]
oldone[0] = blockjoining[ 0 ]
oldone[1] = blockjoining[ 1 ]
blockjoining[ 0 ] = blockjoining[ 1 ] = PLUGIN_CONTINUE
//set_cvar_float("mp_limitteams",0.0)
engclient_cmd(id,"chooseteam")
engclient_cmd(id,"menuselect",key)
engclient_cmd(id,"menuselect","5")
client_print(id,print_center,"You have been moved to another team.")
client_cmd(id,"slot10")
//set_cvar_float("mp_limitteams",2.0)
blockjoining[ 0 ] = oldone[0]
blockjoining[ 1 ] = oldone[1]
}
actAtEndOfRound(){
if (!PTB_SWITCH) return
// skip switching for the first few rounds
if (roundCounter <= PTB_SWITCHAFTER) return
// honor switch frequency setting
if (roundCounter - lastSwitchRound < PTB_SWITCHFREQ) return
// skip switching for a small number of players
if (get_playersnum() < PTB_SWITCHMIN) return
say("PTB: Round ended, checking teams.")
checkTeamBalance()
if (winnerTeam) {
sortTeam(CTS)
sortTeam(TS)
if (teamCounts[winnerTeam] <= teamCounts[loserTeam])
doSwitch()
else if (teamCounts[loserTeam] < teamCounts[winnerTeam])
doTransfer()
}
}
createValidTargets(theTeam, bool:deadonly) {
new n = 0
for (new i = 0; i < teamCounts[theTeam]; ++i) {
// Dead only condition
if ( deadonly && is_user_alive(sortedTeams[theTeam][i]) ) continue
// Already switched or in PTB_PLAYERFREQ time condition
if ((lastRoundSwitched[sortedTeams[theTeam][i]] == roundCounter) ||
(roundCounter - lastRoundSwitched[sortedTeams[theTeam][i]] < PTB_PLAYERFREQ)) continue
sortedValidTargets[theTeam][n++] = sortedTeams[theTeam][i]
}
validTargetCounts[theTeam] = n
}
sortTeam(theTeam) {
// create list of players
new n = 0, a = get_maxplayers()
for (new i = 1; i <= a; ++i) {
// Get only members of specified team
if (playerTeam[i] != theTeam) continue
sortedTeams[theTeam][n++] = i
}
// do a selection sort
new swap, count = n
for (new i = count-1; i > 0; --i){
for (new k = i-1; k >= 0; --k){
// compare players (kills better then other or if equal then with less deaths)
if ( (kills[sortedTeams[theTeam][k]]<kills[sortedTeams[theTeam][i]])
|| ( (kills[sortedTeams[theTeam][k]]==kills[sortedTeams[theTeam][i]]) &&
(deaths[sortedTeams[theTeam][k]]>deaths[sortedTeams[theTeam][i]]))) {
// swap
swap = sortedTeams[theTeam][k]
sortedTeams[theTeam][k] = sortedTeams[theTeam][i]
sortedTeams[theTeam][i] = swap
}
}
}
}
Float:score(team, toBeAdded=0, toBeRemoved=0){
new Float:sumKD = 0.0
new a = get_maxplayers()
for (new i = 1; i <= a; ++i) {
if ( (playerTeam[i]!=team&&i!=toBeAdded) || (i==toBeRemoved) )
continue
sumKD += fdivWorkaround(float(kills[i]), float(deaths[i]))
}
new Float:strength = float(teamCounts[team])
if (sumKD) strength *= sumKD
return strength
}
oSwitch() {
new text[256]
//displayStatistics(0,true)
// don't switch, if at least one team is empty
if ( teamCounts[winnerTeam] == 0 || teamCounts[loserTeam] == 0 ) {
copy(text,255, "PTB: Can't switch players, need players in each team.")
doTypesay(text, 5, 0, 255, 0)
say(text)
return
}
// don't switch, if winner is alone (RULER!!!)
if (teamCounts[winnerTeam] == 1) {
copy(text,255, "PTB: Won't switch players, best player makes the winning team.")
doTypesay(text, 5, 0, 255, 0)
say(text)
return
}
// don't switch, if both teams are full
if (teamCounts[winnerTeam] >= PTB_MAXSIZE && teamCounts[loserTeam] >= PTB_MAXSIZE) {
copy(text,255, "PTB: Can't switch players, both teams are full.")
doTypesay(text, 5, 0, 255, 0)
say(text)
return
}
if (!PTB_DEADONLY || couldNotSwitchCounter > PTB_FORCESWITCH) {
// choose from random top or bottom x
createValidTargets(winnerTeam, false)
createValidTargets(loserTeam, false)
if (validTargetCounts[winnerTeam] == 0 || validTargetCounts[loserTeam] == 0) {
++couldNotSwitchCounter
copy(text,255, "PTB: Can't switch players, need valid target in each team.")
doTypesay(text, 5, 0, 255, 0)
say(text)
return
}
}
else {
//say("switch dead")
createValidTargets(winnerTeam, true)
createValidTargets(loserTeam, true)
if (validTargetCounts[winnerTeam] == 0 || validTargetCounts[loserTeam] == 0) {
if (++couldNotSwitchCounter > PTB_FORCESWITCH) {
say("PTB: Couldn't switch dead, switching alive.")
doSwitch()
return
}
copy(text, 255,"PTB: Can't switch players, need valid target in each team.")
doTypesay(text, 5, 0, 255, 0)
say(text)
return
}
}
public team_score() {
set_cvar_float("mp_autoteambalance",0.0)
set_cvar_float("mp_limitteams",0.0)
new tid[2]
read_data(1,tid,1)
scores[ (tid[0]=='C') ? 1 : 0 ] = read_data(2)
if ((endscore = !endscore))// Round end
set_task(1.0,"calculate_power")
}
public team_select(id, key){
if ( blockjoining[ key ] == PLUGIN_HANDLED ){
client_print(id,print_center,"Teams are not balanced.^nPlease join to the opposite side.")
engclient_cmd(id,"chooseteam")
return PLUGIN_HANDLED
}
return PLUGIN_CONTINUE
}
public plugin_init() {
register_plugin("Simple Team Balancer","0.5","default")
register_event("TeamScore","team_score","a")
register_menucmd(register_menuid("Team_Select"),(1<<0)|(1<<1),"team_select")
register_menucmd(-2,(1<<0)|(1<<1),"team_select") // VGUI menu
return PLUGIN_CONTINUE
}
public team_score(){
new arg[2]
read_data(1,arg,1)
teamScores[ ( arg[0] == 'T' ) ? TS : CTS ] = read_data(2)
}
public win_streaks(param[]){
new winner = param[0]
new looser = param[1]
if (winStreaks[winner] < 0) {
winStreaks[winner] = 1
winStreaks[looser] = -1
}
else {
winStreaks[winner]++
winStreaks[looser]--
}
actAtEndOfRound()
}
public round_end(){
new param[12]
read_data(2,param,8)
if (param[7]=='c') {//%!MRAD_ctwin
param[0] = CTS
param[1] = TS
}
else if (param[7]=='t') {//%!MRAD_terwin
param[0] = TS
param[1] = CTS
}
else
return // %!MRAD_rounddraw (both teams have left the game)
set_task(1.5,"win_streaks",0,param,2)
}
public new_round() {
if ( floatround(get_cvar_float("mp_roundtime") * 60.0) != read_data(1) ) return
++roundCounter
announceStatus()
}
// Happen only at team select (also auto-join)
public team_join() {
new arg[32]
read_data(3,arg,31)
lastRoundSwitched[ get_user_index(arg) ] = roundCounter
}
// Can happen at begin of round or team select
public team_assign() {
new arg[2], team
new i = read_data(1)
read_data(2,arg,1)
if ( arg[0] == 'C' )
team = CTS
else if ( arg[0] == 'T' )
team = TS
else
team = UNASSIGNED
teamCounts[playerTeam[i]]-- // Unregister from old team
teamCounts[team]++ // Increase ammount in new team
playerTeam[i] = team // Assign to new
}
public game_restart(){
roundCounter = 0
lastSwitchRound = 0
couldNotSwitchCounter = 0
teamKills[0] = teamKills[1] = teamKills[2] = 0
teamDeaths[0] = teamDeaths[1] = teamDeaths[2] = 0
teamScores[0] = teamScores[1] = teamScores[2] = 0
winStreaks[0] = winStreaks[1] = winStreaks[2] = 0
wtConditions[0] = wtConditions[1] = wtConditions[2] = 0
validTargetCounts[0] = validTargetCounts[1] = validTargetCounts[2] = 0
new a = get_maxplayers()
for (new i = 1; i <= a; ++i){
kills[i] = 0
deaths[i] = 0
wtjCount[i] = 0
lastRoundSwitched[i] = -999
}
}
public death_msg(){
new iWinner = read_data(1)
new iLoser = read_data(2)
if ( iWinner < 1 || iWinner > 32 || iLoser < 1 || iLoser > 32 )
return
if ( playerTeam[iWinner] == playerTeam[iLoser] )
return // no TKS!!!
kills[iWinner]++
deaths[iLoser]++
if (PTB_SCALEDOWN <= 1) return
if (kills[iWinner] + deaths[iWinner] >= PTB_MAXINCIDENTS) {
kills[iWinner] /= PTB_SCALEDOWN
deaths[iWinner] /= PTB_SCALEDOWN
}
if (kills[iLoser] + deaths[iLoser] >= PTB_MAXINCIDENTS) {
kills[iLoser] /= PTB_SCALEDOWN
deaths[iLoser] /= PTB_SCALEDOWN
}
}
if defined CS16_SWITCH
public delay_transfer(args[]) {
new id = args[0]
if defined PTB_DEBUG
og_message("[PTB] Delayed Transfer #%i ('%s',%i)",id,clientVGUIMenu[id],isBeingTransfered[id])
endif
if (!isBeingTransfered[id]) return
user_kill(id,1)
engclient_cmd(id,"jointeam",(playerTeam[id]==TS) ? "2" : "1")
engclient_cmd(id,"joinclass","5")
if (clientVGUIMenu[id][0] != '0') {
set_user_info( id, "_vgui_menus", clientVGUIMenu[id] )
clientVGUIMenu[id][0] = '0'
}
}
Thanks for your time.
|