
   /* AMX Mod script
   PLUGIN CVARS:
   ------------------
       amx.cfg> ftb_auto 1 // 0 - OFF, 1 - ON
       If ftb_auto is set to 1, this plugin automatically
       detects potential "ghosters" (by idential IP).
       amx.cfg> ftb_mode 1 // 0 - OFF, 1 - A & B, 2 - A only
       A. It allows to spectate upon players from group/team
          only. Also first person only (mp_forcechasecam-like)
       B. It fades the screen after death while other
          players from group are alive (mp_fadetoblack-like)
       amx.cfg> ftb_alpha "alpha" // 0-255
       amx.cfg> ftb_color "red green blue" // 0-255 0-255 0-255
       These cvars are for fun only. (It is color by default)
       client console> setinfo ftb "red green blue"
       Also players may set color of the screen.
   COMMANDS:
   ---------------
       amx.cfg> ftb_addip "group name" "part of IP:Port/WONID"
       This command adds IP(s)/WONID to the specified group.
   EXAMPLE A:
   --------------
       ftb_auto 1
       ftb_mode 1
       exec auto-ftb.cfg
   EXAMPLE B:
   ----------
       ftb_auto 1
       ftb_mode 2
       exec auto-ftb.cfg
   EXAMPLE C:
   ----------
       ftb_auto 0
       ftb_mode 1
       exec auto-ftb.cfg
       ftb_addip "club E" "192.168.35.10:"
       ftb_addip "club F" "192.168.45.15:"
   auto-ftb.cfg
   ------------
       ftb_addip "club A" "192.168.100."
       ftb_addip "club B" "192.168.200.10:"
       ftb_addip "club B" "192.168.200.11:"
       ftb_addip "club B" "192.168.200.12:"
       ftb_addip "club B" "192.168.200.13:"
       ftb_addip "club C: room A" "192.168.15.50:"
       ftb_addip "club C: room A" "192.168.15.52:"
       ftb_addip "club C: room B" "192.168.15.51:"
       ftb_addip "club C: room B" "192.168.15.53:"
       ftb_addip "club D: admin" "192.168.10.20:27005"
       ftb_addip "club D: users" "192.168.10.20:"
   */
   #include <amxmod>
   #define IMMUNITY_LEVEL ADMIN_IMMUNITY
   #define ON  1
   #define OFF 0
   #define DELTA_DELAY 0
   #define DEATH_DELAY 3
   #define MAX_RECORDS 32
   #define TABLE_MAX_LEN 24
   #define ALIAS_MAX_LEN 16
   new vers[] = "1.6.3"
   new gmsgFade
   new plugin_mode = 1
   new ip_num = 0
   new ip_table[MAX_RECORDS][TABLE_MAX_LEN]
   new ip_alias[MAX_RECORDS][ALIAS_MAX_LEN]
   new ips[32][ALIAS_MAX_LEN]
   new state[33]
   new smode[33]
   new dtime[33]
   new bool:joinmenu[33]
   new bool:immunity[33]
   new direction[33]
   new color[33][3], fadealpha
   public screen_fade(index[])
   {
       new id = index[0], ftime = 4096, fhold = 1024, flags = 0
       switch (state[id]) {
       case 1: {
           state[id] = 2
           set_task(1.0, "screen_fade", 0, index, 2)
           flags = 1
       }
       case 2: {
           state[id] = 3
           ftime = 1
           fhold = 1
           flags = 4
       }
       case 4: {
           state[id] = 0
           flags = 2
       }
       }
       if (flags) {
       message_begin(MSG_ONE, gmsgFade, {0,0,0}, id)
       write_short(ftime)
       write_short(fhold)
       write_short(flags)
       write_byte(color[id][0])
       write_byte(color[id][1])
       write_byte(color[id][2])
       write_byte(fadealpha)
       message_end()
       }
   }
   public fade_to_black(id, value, delay)
   {
       if ( ( (state[id] == 0 && value ==  ON) ||
          (state[id] == 3 && value == OFF) ) && !immunity[id]) {
       new tmp[2]; tmp[0] = id
       state[id]++
       set_task(delay + 0.1, "screen_fade", 0, tmp, 2)
       } else if (value == OFF) {
       state[id] = 0
       }
       return PLUGIN_CONTINUE
   }
   public set_specmode(index[])
   {
       new id = index[0]
       if (!immunity[id]) {
       switch (plugin_mode) {
           case 1:
           if (state[id] > 2) {
                   dtime[id] = 1
               client_cmd(id, "spec_mode 4;spec_menu 1;follownext 1")
           } else if (state[id] > 0) {
               set_task(1.0, "set_specmode", 0, index, 2)
           }
           case 2:
               if (smode[id]) {
                   dtime[id] = 1
               client_cmd(id, "spec_mode 4;spec_menu 1;follownext 1")
           }
       }
       }
   }
   public check(id, exec_cmd, delay)
   {
       if (plugin_mode == 0 || get_cvar_num("mp_fadetoblack"))
       return PLUGIN_CONTINUE
       new pnum, target, t = 0, ct = 0, others = 0
       new players[32]
       new sameip_cnt = 0
       new sameip_ids[32]
       new usrip[ALIAS_MAX_LEN]
       usrip = ips[id]
       get_players(players, pnum);
       for(new i = 0; i < pnum; i++) {
       target = players[i]
       if (id != target) {
           if (equal(usrip, ips[target])) {
           sameip_ids[sameip_cnt++] = target
           if (is_user_alive(target)) {
               switch (get_user_team(target)) {
               case 1: t++
               case 2: ct++
               }
           }
           } else if (is_user_alive(target)) {
           others++
           }
       }
       }
       if (sameip_cnt) {
       new tmp[2]; tmp[0] = id
       new flag
       if (plugin_mode == 1) {
           flag = (t == 0 && ct == 0) || others == 0
           if (flag) {
           for(new i = 0; i < sameip_cnt; i++)
               fade_to_black(sameip_ids[i], OFF, DELTA_DELAY)
           }
           if (exec_cmd) {
           fade_to_black(id, flag ? OFF : ON, flag ? DELTA_DELAY : delay)
           }
       }
       if (ct == 0) {
           flag = (t == 0) ? 0 : 2
       } else {
           flag = (t == 0) ? 3 : 1
       }
       smode[id] = flag = others ? flag : 0
       for(new i = 0; i < sameip_cnt; i++) {
           smode[sameip_ids[i]] = flag
       }
           if (exec_cmd && flag) {
               set_task(DEATH_DELAY + 0.1, "set_specmode", 0, tmp, 2)
       }
       }
       return PLUGIN_CONTINUE
   }
   public update_colors(id)
   {
       new setinfo[16]
       get_user_info(id, "ftb", setinfo, 15)
       if (!equal(setinfo, "")) {
       new r[4], g[4], b[4]
       parse(setinfo, r, 3, g, 3, b, 3)
       color[id][0] = strtonum(r) % 256
       color[id][1] = strtonum(g) % 256
       color[id][2] = strtonum(b) % 256
       } else {
       color[id][0] = color[0][0]
       color[id][1] = color[0][1]
       color[id][2] = color[0][2]
       }
   }
   public client_connect(id)
   {
       new user_immunity = get_user_flags(id) & IMMUNITY_LEVEL
       new alias[ALIAS_MAX_LEN]
       new usrip[TABLE_MAX_LEN]
       new wonid[TABLE_MAX_LEN]
       new a = get_cvar_num("ftb_auto")
       get_user_ip(id, alias, ALIAS_MAX_LEN-1, a)
       get_user_ip(id, usrip, TABLE_MAX_LEN-1, 0)
       get_user_authid(id, wonid, TABLE_MAX_LEN-1)
       for(new i = 0; i < ip_num; i++) {
       if    (contain(usrip,   ip_table[i])   !=   -1   ||   equal(wonid,
   ip_table[i])) {
           alias = ip_alias[i]
           break
       }
       }
       ips[id] = alias
       joinmenu[id] = true
       immunity[id] = (user_immunity || is_user_bot(id)) ? true : false
       direction[id] = 0
       update_colors(id)
       return PLUGIN_CONTINUE
   }
   public reset(id)
   {
       state[id] = 0
       smode[id] = 0
       dtime[id] = 0
       return PLUGIN_CONTINUE
   }
   public death()
   {
       new id = read_data(2)
       update_colors(id)
       check(id, ON, DEATH_DELAY)
       return PLUGIN_CONTINUE
   }
   public client_disconnect(id)
   {
       check(id, OFF, DELTA_DELAY)
       reset(id)
       return PLUGIN_CONTINUE
   }
   public status(id)
   {
       new target = read_data(2)
       if (plugin_mode && dtime[id] && target) {
       new flag = 1
       switch (smode[id]) {
           case 0: flag = 1
           case 1: flag = equal(ips[id], ips[target])
           case 2: flag = get_user_team(target) == 1
           case 3: flag = get_user_team(target) == 2
       }
       switch (plugin_mode) {
           case   1,   2:  if  (!flag)  client_cmd(id,  "follownext  %i",
   direction[id])
       }
       }
       return PLUGIN_CONTINUE
   }
   public chooseteam(id)
   {
       joinmenu[id] = true
       return PLUGIN_CONTINUE
   }
   public allow_spec(id)
   {
       if (joinmenu[id]) {
       new arg[16], value
       read_argv(1, arg, 15)
       value = strtonum(arg)
       switch (value) {
           case 1, 2, 5: check(id, ON, DEATH_DELAY)
           case 6:
           {
           new pnum, count = 0
           new players[32]
           get_players(players, pnum);
           for(new i = 0; i < pnum; i++) {
               if (equal(ips[id], ips[players[i]])) {
               count++
               if (count > 1) break
               }
           }
           if (count > 1 && !immunity[id]) {
               client_cmd(id, "chooseteam")
               client_print(id,  print_chat,  "[FTB]  Spectator  has been
   disabled!")
               return PLUGIN_HANDLED
           }
           }
       }
       joinmenu[id] = false
       }
       return PLUGIN_CONTINUE
   }
   public spec_menu(id)
   {
       new arg[16]
       read_argv(1, arg, 15)
       if (smode[id] && dtime[id] && !equal(arg, "4"))
       return PLUGIN_HANDLED
       return PLUGIN_CONTINUE
   }
   public spec_mode(id)
   {
       if (smode[id] && dtime[id])
       client_cmd(id, "spec_mode 4")
       return PLUGIN_CONTINUE
   }
   public follownext(id)
   {
       new arg[16]
       read_argv(1, arg, 15)
       direction[id] = strtonum(arg)
       return PLUGIN_CONTINUE
   }
   public round_time(id)
   {
       new Float:rtime = get_cvar_float("mp_roundtime") * 60.0
       if (rtime == read_data(1)) {
       new setinfo[16], r[4], g[4], b[4]
       get_cvar_string("ftb_color", setinfo, 15)
       parse(setinfo, r, 3, g, 3, b, 3)
       color[0][0] = strtonum(r) % 256
       color[0][1] = strtonum(g) % 256
       color[0][2] = strtonum(b) % 256
       fadealpha   = get_cvar_num("ftb_alpha") % 256
       plugin_mode = get_cvar_num("ftb_mode")
       }
       return PLUGIN_CONTINUE
   }
   public end_round(id)
   {
       new players[32], pnum
       get_players(players, pnum, "bc");
       for(new i = 0; i < pnum; i++) {
       dtime[id] = 0
       smode[id] = 0
       fade_to_black(players[i], OFF, DELTA_DELAY)
       }
       return PLUGIN_CONTINUE
   }
   public ftb_addip()
   {
       if (read_argc() != 3) {
       server_print("Usage: ftb_addip <alias> <IP/WONID>")
       return PLUGIN_HANDLED
       } else if (ip_num >= MAX_RECORDS) {
       server_print("[FTB] The internal data structure is full.")
       return PLUGIN_HANDLED
       } else {
       new usrip[TABLE_MAX_LEN], alias[ALIAS_MAX_LEN]
       read_argv(1, alias, ALIAS_MAX_LEN-1)
       read_argv(2, usrip, TABLE_MAX_LEN-1)
       for(new i = 0; i < ip_num; i++) {
           if (equal(usrip, ip_table[i])) {
           server_print("[FTB]  The  IP/WONID  %s  is  already existed.",
   usrip)
           return PLUGIN_HANDLED
           }
       }
       ip_table[ip_num] = usrip
       ip_alias[ip_num] = alias
       ip_num++
       server_print("[FTB]  The IP/WONID %s (%s) has been added!", usrip,
   alias)
       }
       return PLUGIN_CONTINUE
   }
   public plugin_init()
   {
       gmsgFade = get_user_msgid("ScreenFade")
       register_plugin("Auto-FTB", vers, "beast")
       register_srvcmd("ftb_addip", "ftb_addip")
       register_clcmd("chooseteam", "chooseteam")
       register_clcmd("menuselect", "allow_spec")
       register_clcmd("follownext", "follownext")
       register_clcmd("specmode", "spec_menu")
       register_event("StatusValue", "status", "bd", "1=2")
       register_event("RoundTime", "round_time", "bc")
       register_event("TextMsg", "spec_mode", "bd", "2&Spec_Mode")
       register_event("ResetHUD", "reset", "b")
       register_event("DeathMsg", "death", "a")
       register_event("SendAudio",   "end_round","a",  "2=%!MRAD_terwin",
   "2=%!MRAD_ctwin")
       register_cvar("autoftb_version", vers, FCVAR_SERVER)
       register_cvar("ftb_auto", "1")
       register_cvar("ftb_mode", "1")
       register_cvar("ftb_color", "0 0 0")
       register_cvar("ftb_alpha", "255")
       return PLUGIN_CONTINUE
   }
