]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Add some more fun stuff (1 flag CTF, return delays when flag touches the void, trigge...
authorMario <mario.mario@y7mail.com>
Wed, 7 May 2014 20:53:47 +0000 (06:53 +1000)
committerMario <mario.mario@y7mail.com>
Wed, 7 May 2014 20:53:47 +0000 (06:53 +1000)
28 files changed:
1  2 
effectinfo.txt
gamemodes.cfg
gfx/hud/default/flag_neutral_carrying.tga
gfx/hud/default/flag_neutral_lost.tga
gfx/hud/default/flag_neutral_shielded.tga
gfx/hud/default/flag_neutral_taken.tga
models/ctf/banner_blue_gloss.tga
models/ctf/banner_neutral.tga
models/ctf/banner_neutral_gloss.tga
models/ctf/flag_neutral.tga
models/ctf/flag_neutral_gloss.tga
models/ctf/flag_neutral_glow.tga
models/ctf/flag_neutral_norm.tga
models/ctf/flags.md3_4.skin
models/ctf/glow_neutral.tga
models/ctf/glow_neutral_glow.tga
qcsrc/client/hud.qc
qcsrc/client/progs.src
qcsrc/client/waypointsprites.qc
qcsrc/common/constants.qh
qcsrc/common/items.qh
qcsrc/common/notifications.qh
qcsrc/server/autocvars.qh
qcsrc/server/mutators/gamemode_ctf.qc
qcsrc/server/mutators/gamemode_ctf.qh
scripts/ctf.shader
sound/ctf/neutral_dropped.wav
sound/ctf/neutral_taken.wav

diff --cc effectinfo.txt
index 88c4f972aa125b3eee1b156596bcde9793d651f1,782521447a3c96ab998a73b28028c6c5f6f95d94..cc819e8ced3be23349351fdf4c8a02aaf985e2b0
@@@ -7670,38 -7670,6 +7670,54 @@@ velocityjitter 300 300 30
  velocitymultiplier 0.5
  airfriction 3
  
 +// yellowflag_touch -- effects for touching the yellow flag
 +// used nowhere in code
 +effect yellowflag_touch
 +count 35
 +type spark
 +tex 40 40
 +color 0xFFFF0F 0xFFFF0F
 +size 1 3
 +alpha 0 256 556
 +gravity 1
 +bounce 1.5
 +originjitter 1 1 1
 +velocityjitter 300 300 300
 +velocitymultiplier 0.5
 +airfriction 3
 +
 +// pinkflag_touch -- effects for touching the pink flag
 +// used nowhere in code
 +effect pinkflag_touch
 +count 35
 +type spark
 +tex 40 40
 +color 0xFF0FFF 0xFF0FFF
 +size 1 3
 +alpha 0 256 556
 +gravity 1
 +bounce 1.5
 +originjitter 1 1 1
 +velocityjitter 300 300 300
 +velocitymultiplier 0.5
 +airfriction 3
 +
++// neutralflag_touch -- effects for touching the neutral flag
++// used nowhere in code
++effect neutralflag_touch
++count 35
++type spark
++tex 40 40
++color 0xFFFFFF 0xFFFFFF
++size 1 3
++alpha 0 256 556
++gravity 1
++bounce 1.5
++originjitter 1 1 1
++velocityjitter 300 300 300
++velocitymultiplier 0.5
++airfriction 3
++
  // red_pass
  // used nowhere in code
  effect red_pass
@@@ -7760,64 -7728,6 +7776,93 @@@ size 4 
  alpha 256 256 1280
  type static
  
 +// yellow_pass
 +// used nowhere in code
 +effect yellow_pass
 +trailspacing 64
 +color 0xFFFF0F 0xFFFF0F
 +size 2 2
 +tex 32 32
 +alpha 64 128 64
 +airfriction 5
 +sizeincrease 2
 +type static
 +effect yellow_pass
 +trailspacing 12
 +color 0xFFFF0F 0xFFFF0F
 +size 1 1
 +tex 0 8
 +alpha 32 64 32
 +airfriction 9
 +sizeincrease 8
 +velocityjitter 64 64 64
 +type static
 +effect yellow_pass
 +trailspacing 12
 +color 0xFFFF0F 0xFFFF0F
 +size 4 4
 +//tex 48 55
 +alpha 256 256 1280
 +type static
 +
 +// pink_pass
 +// used nowhere in code
 +effect pink_pass
 +trailspacing 64
 +color 0xFFFFFF 0xFFFFFF
 +size 2 2
 +tex 32 32
 +alpha 64 128 64
 +airfriction 5
 +sizeincrease 2
 +type static
 +effect pink_pass
 +trailspacing 12
 +color 0xFFFFFF 0xFFFFFF
 +size 1 1
 +tex 0 8
 +alpha 32 64 32
 +airfriction 9
 +sizeincrease 8
 +velocityjitter 64 64 64
 +type static
 +effect pink_pass
 +trailspacing 12
 +color 0xFFFFFF 0xFFFFFF
 +size 4 4
 +//tex 48 55
 +alpha 256 256 1280
 +type static
 +
++// neutral_pass
++// used nowhere in code
++effect neutral_pass
++trailspacing 64
++color 0xFFFFFF 0xFFFFFF
++size 2 2
++tex 32 32
++alpha 64 128 64
++airfriction 5
++sizeincrease 2
++type static
++effect neutral_pass
++trailspacing 12
++color 0xFFFFFF 0xFFFFFF
++size 1 1
++tex 0 8
++alpha 32 64 32
++airfriction 9
++sizeincrease 8
++velocityjitter 64 64 64
++type static
++effect neutral_pass
++trailspacing 12
++color 0xFFFFFF 0xFFFFFF
++size 4 4
++//tex 48 55
++alpha 256 256 1280
++type static
++
  // red_cap -- red team capture effect
  effect red_cap
  count 500
diff --cc gamemodes.cfg
index 0d06be225460d04f07db05adf327ad962f8b4b2d,30352bba7be4bbeef4a341674f5151d4dfb030da..56b256b09ad3d92d4f39c3938ef7f3345a0ef42f
@@@ -278,10 -276,6 +278,12 @@@ set g_ctf_flag_red_model "models/ctf/fl
  set g_ctf_flag_red_skin 0
  set g_ctf_flag_blue_model "models/ctf/flags.md3"
  set g_ctf_flag_blue_skin 1
 +set g_ctf_flag_yellow_model "models/ctf/flags.md3"
 +set g_ctf_flag_yellow_skin 2
 +set g_ctf_flag_pink_model "models/ctf/flags.md3"
 +set g_ctf_flag_pink_skin 3
++set g_ctf_flag_neutral_model "models/ctf/flags.md3"
++set g_ctf_flag_neutral_skin 4
  set g_ctf_flag_glowtrails 1
  set g_ctf_fullbrightflags 0
  set g_ctf_dynamiclights 0
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0e555133e37aa7e6dd5f75563ff8fc2eae7943a2
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7cb1d73be7f7619980bf6af688b5b6103cea5333
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7e83e4d25fb06b125dd055af3a1ae9e810504d7b
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e35b8311bb7240b6dbd54e4db8e4101e2914af26
new file mode 100644 (file)
Binary files differ
diff --cc models/ctf/banner_blue_gloss.tga
index 77168a8a882e5cb54be48464999606e0687a04c5,77168a8a882e5cb54be48464999606e0687a04c5..0000000000000000000000000000000000000000
deleted file mode 100644,100644
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5c3de9461c94eeebd0224983b0976676866086b7
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..77168a8a882e5cb54be48464999606e0687a04c5
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..63feddd4ee83614bc621fc4d6166e2e919d31bce
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3e92985b84aa6721694237ec383ae84931ecf7bd
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..77191aba01a0730d477e1562de33710a2f32a6e6
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..07d5e17aae84a4291031083638d4711a2f3bc68b
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ba35e26c6438a35653f12f2168f58a9e4991b43b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++mesh,models/ctf/flag_neutral.tga
++mesh2,models/ctf/banner_neutral.tga
++mesh3,models/ctf/glow_neutral.tga
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5ffa098e3e704e558d5117d4edb2b944e08ba48a
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5ffa098e3e704e558d5117d4edb2b944e08ba48a
new file mode 100644 (file)
Binary files differ
index 85c3f02a59414847210ad4bf958eb0c6d95f5413,bb5eb4a68f534081953aa7d860c69602659d7fa3..4e725053bfcea8efc0372eea5d7a9d694a063f41
@@@ -2709,36 -2709,30 +2709,39 @@@ void HUD_Mod_CA(vector myPos, vector my
  }
  
  // CTF HUD modicon section
- float redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe; // status during previous frame
- float redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus; // last remembered status
- float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time; // time when the status changed
 -float redflag_prevframe, blueflag_prevframe; // status during previous frame
 -float redflag_prevstatus, blueflag_prevstatus; // last remembered status
 -float redflag_statuschange_time, blueflag_statuschange_time; // time when the status changed
++float redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
++float redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus, neutralflag_prevstatus; // last remembered status
++float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time, neutralflag_statuschange_time; // time when the status changed
  
  void HUD_Mod_CTF_Reset(void)
  {
-       redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = 0;
-       redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = 0;
-       redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = 0;
 -      redflag_prevstatus = blueflag_prevstatus = redflag_prevframe = blueflag_prevframe = redflag_statuschange_time = blueflag_statuschange_time = 0;
++      redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = neutralflag_prevstatus = 0;
++      redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = neutralflag_prevframe = 0;
++      redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = neutralflag_statuschange_time = 0;
  }
  
  void HUD_Mod_CTF(vector pos, vector mySize)
  {
-       vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos;
 -      vector redflag_pos, blueflag_pos;
++      vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
        vector flag_size;
        float f; // every function should have that
  
-       float redflag, blueflag, yellowflag, pinkflag; // current status
-       float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime, yellowflag_statuschange_elapsedtime, pinkflag_statuschange_elapsedtime; // time since the status changed
 -      float redflag, blueflag; // current status
 -      float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime; // time since the status changed
--      float stat_items;
 -
 -      stat_items = getstati(STAT_ITEMS, 0, 24);
 -      redflag = (stat_items/IT_RED_FLAG_TAKEN) & 3;
 -      blueflag = (stat_items/IT_BLUE_FLAG_TAKEN) & 3;
 -
 -      if(redflag || blueflag)
++      float redflag, blueflag, yellowflag, pinkflag, neutralflag; // current status
++      float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime, yellowflag_statuschange_elapsedtime, pinkflag_statuschange_elapsedtime, neutralflag_statuschange_elapsedtime; // time since the status changed
++      float ctf_oneflag; // one-flag CTF mode enabled/disabled
++      float stat_items = getstati(STAT_CTF_FLAGSTATUS, 0, 24);
 +      float fs, fs2, fs3, size1, size2;
 +      vector e1, e2;
 +
-       stat_items = getstati(STAT_ITEMS, 0, 24);
-       redflag = (stat_items/IT_RED_FLAG_TAKEN) & 3;
-       blueflag = (stat_items/IT_BLUE_FLAG_TAKEN) & 3;
-       yellowflag = (stat_items/IT_YELLOW_FLAG_TAKEN) & 3;
-       pinkflag = (stat_items/IT_PINK_FLAG_TAKEN) & 3;
++      redflag = (stat_items/CTF_RED_FLAG_TAKEN) & 3;
++      blueflag = (stat_items/CTF_BLUE_FLAG_TAKEN) & 3;
++      yellowflag = (stat_items/CTF_YELLOW_FLAG_TAKEN) & 3;
++      pinkflag = (stat_items/CTF_PINK_FLAG_TAKEN) & 3;
++      neutralflag = (stat_items/CTF_NEUTRAL_FLAG_TAKEN) & 3;
++      
++      ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
 +
-       if(redflag || blueflag || yellowflag || pinkflag)
++      if(redflag || blueflag || yellowflag || pinkflag || neutralflag)
                mod_active = 1;
        else
                mod_active = 0;
        {
                redflag = 1;
                blueflag = 2;
 +              if(team_count >= 3)
 +                      yellowflag = 2;
 +              if(team_count >= 4)
 +                      pinkflag = 3;
++              ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
        }
  
        // when status CHANGES, set old status into prevstatus and current status into status
                blueflag_prevframe = blueflag;
        }
  
 +      if (yellowflag != yellowflag_prevframe)
 +      {
 +              yellowflag_statuschange_time = time;
 +              yellowflag_prevstatus = yellowflag_prevframe;
 +              yellowflag_prevframe = yellowflag;
 +      }
 +
 +      if (pinkflag != pinkflag_prevframe)
 +      {
 +              pinkflag_statuschange_time = time;
 +              pinkflag_prevstatus = pinkflag_prevframe;
 +              pinkflag_prevframe = pinkflag;
 +      }
 +
++      if (neutralflag != neutralflag_prevframe)
++      {
++              neutralflag_statuschange_time = time;
++              neutralflag_prevstatus = neutralflag_prevframe;
++              neutralflag_prevframe = neutralflag;
++      }
++
        redflag_statuschange_elapsedtime = time - redflag_statuschange_time;
        blueflag_statuschange_elapsedtime = time - blueflag_statuschange_time;
 +      yellowflag_statuschange_elapsedtime = time - yellowflag_statuschange_time;
 +      pinkflag_statuschange_elapsedtime = time - pinkflag_statuschange_time;
++      neutralflag_statuschange_elapsedtime = time - neutralflag_statuschange_time;
  
        float BLINK_FACTOR = 0.15;
        float BLINK_BASE = 0.85;
                case 2: red_icon = "flag_red_lost"; break;
                case 3: red_icon = "flag_red_carrying"; red_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
                default:
-                       if((stat_items & IT_CTF_SHIELDED) && (myteam != NUM_TEAM_1))
 -                      if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_2))
++                      if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_1))
                                red_icon = "flag_red_shielded";
                        else
                                red_icon = string_null;
                default:
                        if(redflag == 3)
                                red_icon_prevstatus = "flag_red_carrying"; // make it more visible
-                       else if((stat_items & IT_CTF_SHIELDED) && (myteam != NUM_TEAM_1))
 -                      else if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_2))
++                      else if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_1))
                                red_icon_prevstatus = "flag_red_shielded";
                        else
                                red_icon_prevstatus = string_null;
                case 2: blue_icon = "flag_blue_lost"; break;
                case 3: blue_icon = "flag_blue_carrying"; blue_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
                default:
-                       if((stat_items & IT_CTF_SHIELDED) && (myteam != NUM_TEAM_2))
 -                      if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_1))
++                      if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_2))
                                blue_icon = "flag_blue_shielded";
                        else
                                blue_icon = string_null;
                default:
                        if(blueflag == 3)
                                blue_icon_prevstatus = "flag_blue_carrying"; // make it more visible
-                       else if((stat_items & IT_CTF_SHIELDED) && (myteam != NUM_TEAM_2))
 -                      else if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_1))
++                      else if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_2))
                                blue_icon_prevstatus = "flag_blue_shielded";
                        else
                                blue_icon_prevstatus = string_null;
                        break;
        }
  
 -      if(mySize_x > mySize_y) {
 -              if (myteam == NUM_TEAM_1) { // always draw own flag on left
 +      string yellow_icon, yellow_icon_prevstatus;
 +      float yellow_alpha, yellow_alpha_prevstatus;
 +      yellow_alpha = yellow_alpha_prevstatus = 1;
 +      switch(yellowflag) {
 +              case 1: yellow_icon = "flag_yellow_taken"; break;
 +              case 2: yellow_icon = "flag_yellow_lost"; break;
 +              case 3: yellow_icon = "flag_yellow_carrying"; yellow_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
 +              default:
-                       if((stat_items & IT_CTF_SHIELDED) && (myteam != NUM_TEAM_3))
++                      if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_3))
 +                              yellow_icon = "flag_yellow_shielded";
 +                      else
 +                              yellow_icon = string_null;
 +                      break;
 +      }
 +      switch(yellowflag_prevstatus) {
 +              case 1: yellow_icon_prevstatus = "flag_yellow_taken"; break;
 +              case 2: yellow_icon_prevstatus = "flag_yellow_lost"; break;
 +              case 3: yellow_icon_prevstatus = "flag_yellow_carrying"; yellow_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
 +              default:
 +                      if(yellowflag == 3)
 +                              yellow_icon_prevstatus = "flag_yellow_carrying"; // make it more visible
-                       else if((stat_items & IT_CTF_SHIELDED) && (myteam != NUM_TEAM_3))
++                      else if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_3))
 +                              yellow_icon_prevstatus = "flag_yellow_shielded";
 +                      else
 +                              yellow_icon_prevstatus = string_null;
 +                      break;
 +      }
 +
 +      string pink_icon, pink_icon_prevstatus;
 +      float pink_alpha, pink_alpha_prevstatus;
 +      pink_alpha = pink_alpha_prevstatus = 1;
 +      switch(pinkflag) {
 +              case 1: pink_icon = "flag_pink_taken"; break;
 +              case 2: pink_icon = "flag_pink_lost"; break;
 +              case 3: pink_icon = "flag_pink_carrying"; pink_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
 +              default:
-                       if((stat_items & IT_CTF_SHIELDED) && (myteam != NUM_TEAM_4))
++                      if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_4))
 +                              pink_icon = "flag_pink_shielded";
 +                      else
 +                              pink_icon = string_null;
 +                      break;
 +      }
 +      switch(pinkflag_prevstatus) {
 +              case 1: pink_icon_prevstatus = "flag_pink_taken"; break;
 +              case 2: pink_icon_prevstatus = "flag_pink_lost"; break;
 +              case 3: pink_icon_prevstatus = "flag_pink_carrying"; pink_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
 +              default:
 +                      if(pinkflag == 3)
 +                              pink_icon_prevstatus = "flag_pink_carrying"; // make it more visible
-                       else if((stat_items & IT_CTF_SHIELDED) && (myteam != NUM_TEAM_4))
++                      else if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_4))
 +                              pink_icon_prevstatus = "flag_pink_shielded";
 +                      else
 +                              pink_icon_prevstatus = string_null;
 +                      break;
 +      }
 +
-       switch(team_count)
++      string neutral_icon, neutral_icon_prevstatus;
++      float neutral_alpha, neutral_alpha_prevstatus;
++      neutral_alpha = neutral_alpha_prevstatus = 1;
++      switch(neutralflag) {
++              case 1: neutral_icon = "flag_neutral_taken"; break;
++              case 2: neutral_icon = "flag_neutral_lost"; break;
++              case 3: neutral_icon = "flag_neutral_carrying"; neutral_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
++              default:
++                      if((stat_items & CTF_SHIELDED))
++                              neutral_icon = "flag_neutral_shielded";
++                      else
++                              neutral_icon = string_null;
++                      break;
++      }
++      switch(neutralflag_prevstatus) {
++              case 1: neutral_icon_prevstatus = "flag_neutral_taken"; break;
++              case 2: neutral_icon_prevstatus = "flag_neutral_lost"; break;
++              case 3: neutral_icon_prevstatus = "flag_neutral_carrying"; neutral_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
++              default:
++                      if(neutralflag == 3)
++                              neutral_icon_prevstatus = "flag_neutral_carrying"; // make it more visible
++                      else if((stat_items & CTF_SHIELDED))
++                              neutral_icon_prevstatus = "flag_neutral_shielded";
++                      else
++                              neutral_icon_prevstatus = string_null;
++                      break;
++      }
++
++      if(ctf_oneflag)
++      {
++              // hacky, but these aren't needed
++              red_icon = red_icon_prevstatus = blue_icon = blue_icon_prevstatus = yellow_icon = yellow_icon_prevstatus = pink_icon = pink_icon_prevstatus = string_null;
++              fs = fs2 = fs3 = 1;
++      }
++      else switch(team_count)
 +      {
 +              default:
 +              case 2: fs = 0.5; fs2 = 0.5; fs3 = 0.5; break;
 +              case 3: fs = 1; fs2 = 0.35; fs3 = 0.35; break;
 +              case 4: fs = 0.75; fs2 = 0.25; fs3 = 0.5; break;
 +      }
 +
 +      if(mySize_x > mySize_y)
 +      {
 +              size1 = mySize_x;
 +              size2 = mySize_y;
 +              e1 = eX;
 +              e2 = eY;
 +      }
 +      else
 +      {
 +              size1 = mySize_y;
 +              size2 = mySize_x;
 +              e1 = eY;
 +              e2 = eX;
 +      }
 +
 +      switch(myteam)
 +      {
 +              default:
 +              case NUM_TEAM_1:
 +              {
                        redflag_pos = pos;
 -                      blueflag_pos = pos + eX * 0.5 * mySize_x;
 -              } else {
 -                      blueflag_pos = pos;
 -                      redflag_pos = pos + eX * 0.5 * mySize_x;
 +                      blueflag_pos = pos + eX * fs2 * size1;
 +                      yellowflag_pos = pos - eX * fs2 * size1;
 +                      pinkflag_pos = pos + eX * fs3 * size1;
 +                      break;
                }
 -              flag_size = eX * 0.5 * mySize_x + eY * mySize_y;
 -      } else {
 -              if (myteam == NUM_TEAM_1) { // always draw own flag on left
 -                      redflag_pos = pos;
 -                      blueflag_pos = pos + eY * 0.5 * mySize_y;
 -              } else {
 +              case NUM_TEAM_2:
 +              {
 +                      redflag_pos = pos + eX * fs2 * size1;
                        blueflag_pos = pos;
 -                      redflag_pos = pos + eY * 0.5 * mySize_y;
 +                      yellowflag_pos = pos - eX * fs2 * size1;
 +                      pinkflag_pos = pos + eX * fs3 * size1;
 +                      break;
 +              }
 +              case NUM_TEAM_3:
 +              {
 +                      redflag_pos = pos + eX * fs3 * size1;
 +                      blueflag_pos = pos - eX * fs2 * size1;
 +                      yellowflag_pos = pos;
 +                      pinkflag_pos = pos + eX * fs2 * size1;
 +                      break;
 +              }
 +              case NUM_TEAM_4:
 +              {
 +                      redflag_pos = pos - eX * fs2 * size1;
 +                      blueflag_pos = pos + eX * fs3 * size1;
 +                      yellowflag_pos = pos + eX * fs2 * size1;
 +                      pinkflag_pos = pos;
 +                      break;
                }
 -              flag_size = eY * 0.5 * mySize_y + eX * mySize_x;
        }
++      neutralflag_pos = pos;
 +      flag_size = e1 * fs * size1 + e2 * size2;
  
        f = bound(0, redflag_statuschange_elapsedtime*2, 1);
        if(red_icon_prevstatus && f < 1)
                drawpic_aspect_skin_expanding(blueflag_pos, blue_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * blue_alpha_prevstatus, DRAWFLAG_NORMAL, f);
        if(blue_icon)
                drawpic_aspect_skin(blueflag_pos, blue_icon, flag_size, '1 1 1', panel_fg_alpha * blue_alpha * f, DRAWFLAG_NORMAL);
 +
 +      f = bound(0, yellowflag_statuschange_elapsedtime*2, 1);
 +      if(yellow_icon_prevstatus && f < 1)
 +              drawpic_aspect_skin_expanding(yellowflag_pos, yellow_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * yellow_alpha_prevstatus, DRAWFLAG_NORMAL, f);
 +      if(yellow_icon)
 +              drawpic_aspect_skin(yellowflag_pos, yellow_icon, flag_size, '1 1 1', panel_fg_alpha * yellow_alpha * f, DRAWFLAG_NORMAL);
 +
 +      f = bound(0, pinkflag_statuschange_elapsedtime*2, 1);
 +      if(pink_icon_prevstatus && f < 1)
 +              drawpic_aspect_skin_expanding(pinkflag_pos, pink_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * pink_alpha_prevstatus, DRAWFLAG_NORMAL, f);
 +      if(pink_icon)
 +              drawpic_aspect_skin(pinkflag_pos, pink_icon, flag_size, '1 1 1', panel_fg_alpha * pink_alpha * f, DRAWFLAG_NORMAL);
++
++      f = bound(0, neutralflag_statuschange_elapsedtime*2, 1);
++      if(neutral_icon_prevstatus && f < 1)
++              drawpic_aspect_skin_expanding(neutralflag_pos, neutral_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * neutral_alpha_prevstatus, DRAWFLAG_NORMAL, f);
++      if(neutral_icon)
++              drawpic_aspect_skin(neutralflag_pos, neutral_icon, flag_size, '1 1 1', panel_fg_alpha * neutral_alpha * f, DRAWFLAG_NORMAL);
  }
  
  // Keyhunt HUD modicon section
index 1a518c5a697f9079977a896ae21cf841cdedeb17,1a518c5a697f9079977a896ae21cf841cdedeb17..0aba4f85306b4a29f8f18102c76fc97334efa4fe
@@@ -59,6 -59,6 +59,8 @@@ vehicles/vehicles.q
  projectile.qh
  player_skeleton.qh
  
++../server/mutators/gamemode_ctf.qh // TODO: remove
++
  sortlist.qc
  miscfunctions.qc
  ../server/t_items.qc
index f7b1cd3da5dca46ff1e81812dc479804eb6016eb,dd7ae36b91fc09897bacb967633819e7cc61db34..4761eeba8f04d8d848d477ef0aa25c437a03daa7
@@@ -261,8 -261,6 +261,9 @@@ string spritelookuptext(string s
                case "keycarrier-red": return _("Key carrier");
                case "keycarrier-yellow": return _("Key carrier");
                case "redbase": return _("Red base");
 +              case "yellowbase": return _("Yellow base");
++              case "neutralbase": return _("White base");
 +              case "pinkbase": return _("Pink base");
                case "waypoint": return _("Waypoint");
                case "ons-gen-red": return _("Generator");
                case "ons-gen-blue": return _("Generator");
index e02fad45f06090b6b3d8e24bfed12f7ade651548,e02fad45f06090b6b3d8e24bfed12f7ade651548..8d622a140ae2294f43743286db53f687bd84c776
@@@ -185,6 -185,6 +185,8 @@@ const float STAT_WEAPONS3 = 75
  const float STAT_MONSTERS_TOTAL = 76;
  const float STAT_MONSTERS_KILLED = 77;
  
++const float STAT_CTF_FLAGSTATUS = 78;
++
  // mod stats (1xx)
  const float STAT_REDALIVE = 100;
  const float STAT_BLUEALIVE = 101;
index 0b27748f9cf9149dde8f6d8e8d17be309f5a59c1,264c9ca73bd56070b6a41d69e0a359ea0f1503db..194f91db9610be8f084f494b028ec5b7a2079373
@@@ -34,19 -34,13 +34,7 @@@ const float   IT_HEALT
        // for items:
        WANT_CONST float        IT_KEY1                                 = 131072;
        WANT_CONST float        IT_KEY2                                 = 262144;
--      // for players:
--      const float     IT_RED_FLAG_TAKEN               = 32768;
--      const float     IT_RED_FLAG_LOST                = 65536;
-       const float     IT_RED_FLAG_CARRYING    = 98304;
 -      const float     IT_RED_FLAG_CARRYING            = 98304;
--      const float     IT_BLUE_FLAG_TAKEN              = 131072;
--      const float     IT_BLUE_FLAG_LOST               = 262144;
--      const float     IT_BLUE_FLAG_CARRYING   = 393216;
-       const float     IT_YELLOW_FLAG_TAKEN    = 524288;
-       const float     IT_YELLOW_FLAG_LOST             = 1048576;
-       const float     IT_YELLOW_FLAG_CARRYING = 1572864;
-       const float     IT_PINK_FLAG_TAKEN              = 2097152;
-       const float     IT_PINK_FLAG_LOST               = 4194304;
-       const float     IT_PINK_FLAG_CARRYING   = 6291456;
++
  // end
  const float   IT_5HP                       = 524288;
  const float   IT_25HP                      = 1048576;
index 6acee55bed23ac17e573cf084314cf023234437a,003c0fcc1d64fc4fa0e112576e4342f5933b5d36..d155e8641ce2aae9571ae76fa1ce54cb167228e5
@@@ -340,20 -340,20 +340,29 @@@ void Send_Notification_WOCOVA
  
  #define MSG_INFO_NOTIFICATIONS \
        MSG_INFO_NOTIF(2, INFO_CHAT_NOSPECTATORS,              0, 0, "", "",                            "",                     _("^F4NOTE: ^BGSpectator chat is not sent to players during the match"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_CAPTURE_, 2,                1, 0, "s1", "s1",                        "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_CAPTURE_BROKEN_, 2,         2, 2, "s1 f1p2dec s2 f2p2dec", "s1",     "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG%s^BG's previous record of ^F2%s^BG seconds"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_CAPTURE_TIME_, 2,           1, 1, "s1 f1p2dec", "s1",                "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_CAPTURE_UNBROKEN_, 2,       2, 2, "s1 f1p2dec s2 f2p2dec", "s1",     "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F2%s^BG seconds, failing to break ^BG%s^BG's previous record of ^F1%s^BG seconds"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_ABORTRUN_, 2,    0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was returned to base by its owner"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DAMAGED_, 2,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was destroyed and returned to base"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DROPPED_, 2,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_NEEDKILL_, 2,    0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to base"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_SPEEDRUN_, 2,    0, 1, "f1p2dec", "",                     "",                     _("^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned itself"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_TIMEOUT_, 2,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag has returned to the base"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_LOST_, 2,                   1, 0, "s1", "s1",                        "notify_%s_lost",       _("^BG%s^BG lost the ^TC^TT^BG flag"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_PICKUP_, 2,                 1, 0, "s1", "s1",                        "notify_%s_taken",      _("^BG%s^BG got the ^TC^TT^BG flag"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_RETURN_, 2,                 1, 0, "s1", "s1",                        "notify_%s_returned",   _("^BG%s^BG returned the ^TC^TT^BG flag"), "") \
 -      MULTITEAM_INFO(1, INFO_CTF_RETURN_MONSTER_, 2,         1, 0, "s1", "s1",                        "notify_%s_returned",   _("^BG%s^BG returned the ^TC^TT^BG flag"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_CAPTURE_, 4,                1, 0, "s1", "s1",                        "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_CAPTURE_BROKEN_, 4,         2, 2, "s1 f1p2dec s2 f2p2dec", "s1",     "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG%s^BG's previous record of ^F2%s^BG seconds"), "") \
++      MSG_INFO_NOTIF(1, INFO_CTF_CAPTURE_NEUTRAL,            1, 0, "s1", "s1",                        "notify_%s_captured",   _("^BG%s^BG captured the flag"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_CAPTURE_TIME_, 4,           1, 1, "s1 f1p2dec", "s1",                "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_CAPTURE_UNBROKEN_, 4,       2, 2, "s1 f1p2dec s2 f2p2dec", "s1",     "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F2%s^BG seconds, failing to break ^BG%s^BG's previous record of ^F1%s^BG seconds"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_ABORTRUN_, 4,    0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was returned to base by its owner"), "") \
++      MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_ABORTRUN_NEUTRAL,0, 0, "", "",                            "",                     _("^BGThe flag was returned by its owner"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DAMAGED_, 4,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was destroyed and returned to base"), "") \
++      MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_DAMAGED_NEUTRAL, 0, 0, "", "",                            "",                     _("^BGThe flag was destroyed and returned to base"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DROPPED_, 4,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"), "") \
++      MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_DROPPED_NEUTRAL, 0, 0, "", "",                            "",                     _("^BGThe flag was dropped in the base and returned itself"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_NEEDKILL_, 4,    0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to base"), "") \
++      MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_NEEDKILL_NEUTRAL,0, 0, "", "",                            "",                     _("^BGThe flag fell somewhere it couldn't be reached and returned to base"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_SPEEDRUN_, 4,    0, 1, "f1p2dec", "",                     "",                     _("^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned itself"), "") \
++      MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_SPEEDRUN_NEUTRAL,0, 1, "f1p2dec", "",                     "",                     _("^BGThe flag became impatient after ^F1%.2f^BG seconds and returned itself"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_TIMEOUT_, 4,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag has returned to the base"), "") \
++      MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_TIMEOUT_NEUTRAL, 0, 0, "", "",                            "",                     _("^BGThe flag has returned to the base"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_LOST_, 4,                   1, 0, "s1", "s1",                        "notify_%s_lost",       _("^BG%s^BG lost the ^TC^TT^BG flag"), "") \
++      MSG_INFO_NOTIF(1, INFO_CTF_LOST_NEUTRAL,               1, 0, "s1", "s1",                        "notify_%s_lost",       _("^BG%s^BG lost the flag"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_PICKUP_, 4,                 1, 0, "s1", "s1",                        "notify_%s_taken",      _("^BG%s^BG got the ^TC^TT^BG flag"), "") \
++      MSG_INFO_NOTIF(1, INFO_CTF_PICKUP_NEUTRAL,             1, 0, "s1", "s1",                        "notify_%s_taken",      _("^BG%s^BG got the flag"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_RETURN_, 4,                 1, 0, "s1", "s1",                        "notify_%s_returned",   _("^BG%s^BG returned the ^TC^TT^BG flag"), "") \
 +      MULTITEAM_INFO(1, INFO_CTF_RETURN_MONSTER_, 4,         1, 0, "s1", "s1",                        "notify_%s_returned",   _("^BG%s^BG returned the ^TC^TT^BG flag"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_CHEAT,             3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_death",         _("^BG%s%s^K1 was unfairly eliminated by ^BG%s^K1%s%s"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_DROWN,             3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_water",         _("^BG%s%s^K1 was drowned by ^BG%s^K1%s%s"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_FALL,              3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_fall",          _("^BG%s%s^K1 was grounded by ^BG%s^K1%s%s"), "") \
        MSG_CENTER_NOTIF(1, CENTER_ROUND_OVER,                  0, 0, "",             CPID_ROUND,          "0 0", _("^BGRound over, there's no winner"), "") \
        MSG_CENTER_NOTIF(1, CENTER_CAMPCHECK,                   0, 0, "",             CPID_CAMPCHECK,      "0 0", _("^F2Don't camp!"), "") \
        MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_FREE,      0, 0, "",             CPID_CTF_CAPSHIELD,  "0 0", _("^BGYou are now free.\n^BGFeel free to ^F2try to capture^BG the flag again\n^BGif you think you will succeed."), "") \
 -      MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_SHIELDED,  0, 0, "",             CPID_CTF_CAPSHIELD,  "0 0", _("^BGYou are now ^F1shielded^BG from the flag\n^BGfor ^F2too many unsuccessful attempts^BG to capture.\n^BGMake some defensive scores before trying again."), "") \
 -      MULTITEAM_CENTER(1, CENTER_CTF_CAPTURE_, 2,             0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou captured the ^TC^TT^BG flag!"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_INACTIVE,  0, 0, "",             CPID_CTF_CAPSHIELD,  "0 0", _("^BGThis flag is currently inactive"), "") \
 +      MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_SHIELDED,  0, 0, "",             CPID_CTF_CAPSHIELD,  "0 0", _("^BGYou are now ^F1shielded^BG from the flag(s)\n^BGfor ^F2too many unsuccessful attempts^BG to capture.\n^BGMake some defensive scores before trying again."), "") \
 +      MULTITEAM_CENTER(1, CENTER_CTF_CAPTURE_, 4,             0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou captured the ^TC^TT^BG flag!"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURE_NEUTRAL,         0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou captured the flag!"), "") \
        MSG_CENTER_NOTIF(1, CENTER_CTF_FLAG_THROW_PUNISH,       0, 1, "f1secs",       CPID_CTF_LOWPRIO,    "0 0", _("^BGToo many flag throws! Throwing disabled for %s."), "") \
 -      MULTITEAM_CENTER(1, CENTER_CTF_PASS_OTHER_, 2,          2, 0, "s1 s2",        CPID_CTF_PASS,       "0 0", _("^BG%s^BG passed the ^TC^TT^BG flag to %s"), "") \
 -      MULTITEAM_CENTER(1, CENTER_CTF_PASS_RECEIVED_, 2,       1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou received the ^TC^TT^BG flag from %s"), "") \
 +      MULTITEAM_CENTER(1, CENTER_CTF_PASS_OTHER_, 4,          2, 0, "s1 s2",        CPID_CTF_PASS,       "0 0", _("^BG%s^BG passed the ^TC^TT^BG flag to %s"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_OTHER_NEUTRAL,      2, 0, "s1 s2",        CPID_CTF_PASS,       "0 0", _("^BG%s^BG passed the flag to %s"), "") \
 +      MULTITEAM_CENTER(1, CENTER_CTF_PASS_RECEIVED_, 4,       1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou received the ^TC^TT^BG flag from %s"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_RECEIVED_NEUTRAL,   1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou received the flag from %s"), "") \
        MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_REQUESTED,          1, 0, "s1 pass_key",  CPID_CTF_PASS,       "0 0", _("^BG%s^BG requests you to pass the flag%s"), "") \
        MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_REQUESTING,         1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGRequesting %s^BG to pass you the flag"), "") \
 -      MULTITEAM_CENTER(1, CENTER_CTF_PASS_SENT_, 2,           1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou passed the ^TC^TT^BG flag to %s"), "") \
 -      MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_, 2,              0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got the ^TC^TT^BG flag!"), "") \
 +      MULTITEAM_CENTER(1, CENTER_CTF_PASS_SENT_, 4,           1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou passed the ^TC^TT^BG flag to %s"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_SENT_NEUTRAL,       1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou passed the flag to %s"), "") \
 +      MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_, 4,              0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got the ^TC^TT^BG flag!"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_NEUTRAL,          0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got the flag!"), "") \
 +      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM,             1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got your %steam^BG's flag, return it!"), "") \
 +      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM_ENEMY,       1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got the %senemy^BG's flag, return it!"), "") \
        MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY,            1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy^BG got your flag! Retrieve it!"), "") \
        MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_VERBOSE,    2, 0, "s1 s2 s1",     CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy (^BG%s%s)^BG got your flag! Retrieve it!"), "") \
 -      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM,             1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate^BG got the flag! Protect them!"), "") \
 -      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM_VERBOSE,     2, 0, "s1 s2 s1",     CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"), "") \
 -      MULTITEAM_CENTER(1, CENTER_CTF_RETURN_, 2,              0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou returned the ^TC^TT^BG flag!"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_NEUTRAL,    1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy^BG got the flag! Retrieve it!"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_NEUTRAL_VERBOSE, 2, 0, "s1 s2 s1",CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy (^BG%s%s)^BG got the flag! Retrieve it!"), "") \
 +      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_TEAM,        1, 0, "s1",          CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy^BG got their flag! Retrieve it!"), "") \
 +      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_TEAM_VERBOSE,2, 0, "s1 s2 s1",    CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy (^BG%s%s)^BG got their flag! Retrieve it!"), "") \
 +      MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_TEAM_, 4,         1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate^BG got the ^TC^TT^BG flag! Protect them!"), "") \
-       MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_TEAM_VERBOSE_, 4, 2, 0, "s1 s2 s1",     CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the ^TC^TT^BG flag! Protect them!"), "") \
++      MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_TEAM_VERBOSE_,    4, 2, 0, "s1 s2 s1",  CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the ^TC^TT^BG flag! Protect them!"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM_NEUTRAL,         1, 0, "s1",       CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate^BG got the flag! Protect them!"), "") \
++      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM_VERBOSE_NEUTRAL, 2, 0, "s1 s2 s1", CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"), "") \
 +      MULTITEAM_CENTER(1, CENTER_CTF_RETURN_, 4,              0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou returned the ^TC^TT^BG flag!"), "") \
        MSG_CENTER_NOTIF(1, CENTER_CTF_STALEMATE_CARRIER,       0, 0, "",             CPID_STALEMATE,      "0 0", _("^BGStalemate! Enemies can now see you on radar!"), "") \
        MSG_CENTER_NOTIF(1, CENTER_CTF_STALEMATE_OTHER,         0, 0, "",             CPID_STALEMATE,      "0 0", _("^BGStalemate! Flag carriers can now be seen by enemies on radar!"), "") \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAG,                 1, 1, "spree_cen s1",             NO_CPID, "0 0", _("^K3%sYou fragged ^BG%s"), _("^K3%sYou scored against ^BG%s")) \
        MULTITEAM_CHOICE##teams(default,challow,prefix,chtype,optiona,optionb)
  
  #define MSG_CHOICE_NOTIFICATIONS \
 -      MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_BROKEN_, 2,    MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_BROKEN_) \
 -      MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_TIME_, 2,      MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_TIME_) \
 -      MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_UNBROKEN_, 2,  MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_UNBROKEN_) \
 -      MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_TEAM,           MSG_CENTER,  CENTER_CTF_PICKUP_TEAM,           CENTER_CTF_PICKUP_TEAM_VERBOSE) \
 +      MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_BROKEN_, 4,    MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_BROKEN_) \
 +      MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_TIME_, 4,      MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_TIME_) \
 +      MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_UNBROKEN_, 4,  MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_UNBROKEN_) \
 +      MULTITEAM_CHOICE(1, 2, CHOICE_CTF_PICKUP_TEAM_, 4,       MSG_CENTER,  CENTER_CTF_PICKUP_TEAM_,          CENTER_CTF_PICKUP_TEAM_VERBOSE_) \
++      MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_TEAM_NEUTRAL,   MSG_CENTER,  CENTER_CTF_PICKUP_TEAM_NEUTRAL,   CENTER_CTF_PICKUP_TEAM_VERBOSE_NEUTRAL) \
        MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_ENEMY,          MSG_CENTER,  CENTER_CTF_PICKUP_ENEMY,          CENTER_CTF_PICKUP_ENEMY_VERBOSE) \
++      MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL,  MSG_CENTER,  CENTER_CTF_PICKUP_ENEMY_NEUTRAL,  CENTER_CTF_PICKUP_ENEMY_NEUTRAL_VERBOSE) \
 +      MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_ENEMY_TEAM,     MSG_CENTER,  CENTER_CTF_PICKUP_ENEMY_TEAM,     CENTER_CTF_PICKUP_ENEMY_TEAM_VERBOSE) \
        MSG_CHOICE_NOTIF(1, 1, CHOICE_FRAG,                      MSG_CENTER,  CENTER_DEATH_MURDER_FRAG,         CENTER_DEATH_MURDER_FRAG_VERBOSE) \
        MSG_CHOICE_NOTIF(1, 1, CHOICE_FRAGGED,                   MSG_CENTER,  CENTER_DEATH_MURDER_FRAGGED,      CENTER_DEATH_MURDER_FRAGGED_VERBOSE) \
        MSG_CHOICE_NOTIF(1, 1, CHOICE_TYPEFRAG,                  MSG_CENTER,  CENTER_DEATH_MURDER_TYPEFRAG,     CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE) \
index 1359e684e479f5cf75a922d4f5e938923d33d5b0,674c95b14ea735e2b67e0cb063f21702e2a1c754..f1d2231504410b2b881da8eb7bf9729e3b4a8224
@@@ -749,18 -749,12 +749,21 @@@ float autocvar_g_ctf_flag_dropped_waypo
  float autocvar_g_ctf_flag_dropped_floatinwater;
  float autocvar_g_ctf_flag_glowtrails;
  float autocvar_g_ctf_flag_health;
++string autocvar_g_ctf_flag_neutral_model;
++float autocvar_g_ctf_flag_neutral_skin;
 +string autocvar_g_ctf_flag_pink_model;
 +float autocvar_g_ctf_flag_pink_skin;
  string autocvar_g_ctf_flag_red_model;
  float autocvar_g_ctf_flag_red_skin;
 +float autocvar_g_ctf_flag_return;
 +float autocvar_g_ctf_flag_return_carried_radius;
  float autocvar_g_ctf_flag_return_time;
  float autocvar_g_ctf_flag_return_when_unreachable;
  float autocvar_g_ctf_flag_return_damage;
++float autocvar_g_ctf_flag_return_damage_delay;
  float autocvar_g_ctf_flag_return_dropped;
 +string autocvar_g_ctf_flag_yellow_model;
 +float autocvar_g_ctf_flag_yellow_skin;
  float autocvar_g_ctf_flagcarrier_auto_helpme_damage;
  float autocvar_g_ctf_flagcarrier_auto_helpme_time;
  float autocvar_g_ctf_flagcarrier_selfdamagefactor;
index 0e1cb6a713ab07d16bb96e98248ddfd9a66cf0d7,66c7b8715f900707381039f7913cf10faddcbc08..aa7a8133704cf6c7c770b07cffe3c08c9e7db1fa
@@@ -27,11 -27,11 +27,13 @@@ void ctf_CaptureRecord(entity flag, ent
        string refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"));
  
        // notify about shit
-       if(!ctf_captimerecord) { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_CAPTURE_TIME_), player.netname, (cap_time * 100)); }
 -      if(!ctf_captimerecord) { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_2(flag, CHOICE_CTF_CAPTURE_TIME_), player.netname, (cap_time * 100)); }
 -      else if(cap_time < cap_record) { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_2(flag, CHOICE_CTF_CAPTURE_BROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
 -      else { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_2(flag, CHOICE_CTF_CAPTURE_UNBROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
++      if(ctf_oneflag) { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_CTF_CAPTURE_NEUTRAL, player.netname); }
++      else if(!ctf_captimerecord) { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_CAPTURE_TIME_), player.netname, (cap_time * 100)); }
 +      else if(cap_time < cap_record) { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_CAPTURE_BROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
 +      else { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_CAPTURE_UNBROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
  
        // write that shit in the database
++      if(!ctf_oneflag) // but not in 1-flag mode
        if((!ctf_captimerecord) || (cap_time < cap_record))
        {
                ctf_captimerecord = cap_time;
@@@ -173,22 -161,22 +175,34 @@@ void ctf_CaptureShield_Update(entity pl
  
  float ctf_CaptureShield_Customize()
  {
++      if(self.enemy.active != ACTIVE_ACTIVE) { return TRUE; }
        if(!other.ctf_captureshielded) { return FALSE; }
 -      if(SAME_TEAM(self, other)) { return FALSE; }
 +      if(CTF_SAMETEAM(self, other)) { return FALSE; }
  
        return TRUE;
  }
  
  void ctf_CaptureShield_Touch()
  {
++      if(self.enemy.active != ACTIVE_ACTIVE)
++      {
++              vector mymid = (self.absmin + self.absmax) * 0.5;
++              vector othermid = (other.absmin + other.absmax) * 0.5;
++
++              Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force);
++              if(IS_REAL_CLIENT(other)) { Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_INACTIVE); }
++
++              return;
++      }
++
        if(!other.ctf_captureshielded) { return; }
 -      if(SAME_TEAM(self, other)) { return; }
 +      if(CTF_SAMETEAM(self, other)) { return; }
  
        vector mymid = (self.absmin + self.absmax) * 0.5;
        vector othermid = (other.absmin + other.absmax) * 0.5;
  
        Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force);
--      Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED);
++      if(IS_REAL_CLIENT(other)) { Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); }
  }
  
  void ctf_CaptureShield_Spawn(entity flag)
@@@ -231,7 -219,7 +245,7 @@@ void ctf_Handle_Drop(entity flag, entit
        flag.ctf_status = FLAG_DROPPED;
  
        // messages and sounds
-       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_LOST_), player.netname);
 -      Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_LOST_), player.netname);
++      Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_LOST_) : INFO_CTF_LOST_NEUTRAL), player.netname);
        sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE);
        ctf_EventLog("dropped", player.team, player);
  
@@@ -269,8 -257,8 +283,17 @@@ void ctf_Handle_Retrieve(entity flag, e
        flag.owner.flagcarried = flag;
  
        // reset flag
--      setattachment(flag, player, "");
--      setorigin(flag, FLAG_CARRY_OFFSET);
++      if(player.vehicle)
++      {
++              setattachment(flag, player.vehicle, "");
++              setorigin(flag, VEHICLE_FLAG_OFFSET);
++              flag.scale = VEHICLE_FLAG_SCALE;
++      }
++      else
++      {
++              setattachment(flag, player, "");
++              setorigin(flag, FLAG_CARRY_OFFSET);
++      }
        flag.movetype = MOVETYPE_NONE;
        flag.takedamage = DAMAGE_NO;
        flag.solid = SOLID_NOT;
        FOR_EACH_REALPLAYER(tmp_player)
        {
                if(tmp_player == sender)
-                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_4(flag, CENTER_CTF_PASS_SENT_), player.netname);
 -                      Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PASS_SENT_), player.netname);
++                      Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT_4(flag, CENTER_CTF_PASS_SENT_) : CENTER_CTF_PASS_SENT_NEUTRAL), player.netname);
                else if(tmp_player == player)
-                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_4(flag, CENTER_CTF_PASS_RECEIVED_), sender.netname);
 -                      Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PASS_RECEIVED_), sender.netname);
++                      Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT_4(flag, CENTER_CTF_PASS_RECEIVED_) : CENTER_CTF_PASS_RECEIVED_NEUTRAL), sender.netname);
                else if(SAME_TEAM(tmp_player, sender))
-                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_4(flag, CENTER_CTF_PASS_OTHER_), sender.netname, player.netname);
 -                      Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PASS_OTHER_), sender.netname, player.netname);
++                      Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT_4(flag, CENTER_CTF_PASS_OTHER_) : CENTER_CTF_PASS_OTHER_NEUTRAL), sender.netname, player.netname);
        }
  
        // create new waypoint
@@@ -396,15 -384,14 +419,31 @@@ void ctf_Handle_Capture(entity flag, en
  {
        entity enemy_flag = ((capturetype == CAPTURE_NORMAL) ? toucher.flagcarried : toucher);
        entity player = ((capturetype == CAPTURE_NORMAL) ? toucher : enemy_flag.ctf_dropper);
++      entity player_team_flag = world, tmp_entity;
        float old_time, new_time;
  
 -      if (!player) { return; } // without someone to give the reward to, we can't possibly cap
 +      if(!player) { return; } // without someone to give the reward to, we can't possibly cap
-       if(CTF_DIFFTEAM(player, flag)) { return; }
++      if(ctf_oneflag) 
++      {
++              if(CTF_SAMETEAM(player, flag)) { return; }
++      }
++      else if(CTF_DIFFTEAM(player, flag)) { return; }
++      
++      if(ctf_oneflag)
++      for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
++      if(SAME_TEAM(tmp_entity, player))
++      {
++              player_team_flag = tmp_entity;
++              break;
++      }
++
++      player.throw_prevtime = time;
++      player.throw_count = 0;
  
        // messages and sounds
-       Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_4(enemy_flag, CENTER_CTF_CAPTURE_));
 -      Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(enemy_flag, CENTER_CTF_CAPTURE_));
++      Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((enemy_flag.team) ? APP_TEAM_ENT_4(enemy_flag, CENTER_CTF_CAPTURE_) : CENTER_CTF_CAPTURE_NEUTRAL));
        ctf_CaptureRecord(enemy_flag, player);
-       sound(player, CH_TRIGGER, ((DIFF_TEAM(player, flag)) ? enemy_flag.snd_flag_capture : flag.snd_flag_capture), VOL_BASE, ATTEN_NONE);
 -      sound(player, CH_TRIGGER, flag.snd_flag_capture, VOL_BASE, ATTEN_NONE);
++      sound(player, CH_TRIGGER, ((ctf_oneflag) ? player_team_flag.snd_flag_capture : ((DIFF_TEAM(player, flag)) ? enemy_flag.snd_flag_capture : flag.snd_flag_capture)), VOL_BASE, ATTEN_NONE);
  
        switch(capturetype)
        {
@@@ -446,12 -433,12 +485,12 @@@ void ctf_Handle_Return(entity flag, ent
        // messages and sounds
        if(player.flags & FL_MONSTER)
        {
 -              Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_RETURN_MONSTER_), player.monster_name);
 +              Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_RETURN_MONSTER_), player.monster_name);
        }
--      else
++      else if(flag.team)
        {
 -              Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_RETURN_));
 -              Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_RETURN_), player.netname);
 +              Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_4(flag, CENTER_CTF_RETURN_));
 +              Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_RETURN_), player.netname);
        }
        sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
        ctf_EventLog("return", flag.team, player);
@@@ -489,8 -471,8 +528,17 @@@ void ctf_Handle_Pickup(entity flag, ent
        // attach the flag to the player
        flag.owner = player;
        player.flagcarried = flag;
--      setattachment(flag, player, "");
--      setorigin(flag, FLAG_CARRY_OFFSET);
++      if(player.vehicle)
++      {
++              setattachment(flag, player.vehicle, "");
++              setorigin(flag, VEHICLE_FLAG_OFFSET);
++              flag.scale = VEHICLE_FLAG_SCALE;
++      }
++      else
++      {
++              setattachment(flag, player, "");
++              setorigin(flag, FLAG_CARRY_OFFSET);
++      }
  
        // flag setup
        flag.movetype = MOVETYPE_NONE;
        }
  
        // messages and sounds
-       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_PICKUP_), player.netname);
 -      Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_PICKUP_), player.netname);
 -      Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PICKUP_));
++      Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_PICKUP_) : INFO_CTF_PICKUP_NEUTRAL), player.netname);
        if(ctf_stalemate) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER); }
-       if(CTF_DIFFTEAM(player, flag)) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_4(flag, CENTER_CTF_PICKUP_)); }
 -
 -      Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, CHOICE_CTF_PICKUP_TEAM, Team_ColorCode(player.team), player.netname);
 -      Send_Notification(NOTIF_TEAM, flag, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY, Team_ColorCode(player.team), player.netname);
++      if(!flag.team) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL); }
++      else if(CTF_DIFFTEAM(player, flag)) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_4(flag, CENTER_CTF_PICKUP_)); }
 +      else { Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_TEAM : CENTER_CTF_PICKUP_TEAM_ENEMY), Team_ColorCode(flag.team)); }
 +
-       Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_PICKUP_TEAM_), Team_ColorCode(player.team), player.netname);
++      Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, ((flag.team) ? APP_TEAM_ENT_4(flag, CHOICE_CTF_PICKUP_TEAM_) : CHOICE_CTF_PICKUP_TEAM_NEUTRAL), Team_ColorCode(player.team), player.netname);
++      
++      if(!flag.team)
++      FOR_EACH_PLAYER(tmp_entity)
++      if(tmp_entity != player)
++      if(DIFF_TEAM(player, tmp_entity))
++              Send_Notification(NOTIF_ONE, tmp_entity, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname);
++      
++      if(flag.team)
 +      FOR_EACH_PLAYER(tmp_entity)
 +      if(tmp_entity != player)
 +      if(CTF_SAMETEAM(flag, tmp_entity))
 +      if(SAME_TEAM(player, tmp_entity))
 +              Send_Notification(NOTIF_ONE, tmp_entity, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_PICKUP_TEAM_), Team_ColorCode(player.team), player.netname);
 +      else
 +              Send_Notification(NOTIF_ONE, tmp_entity, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
  
        sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
  
@@@ -580,14 -554,14 +636,14 @@@ void ctf_CheckFlagReturn(entity flag, f
                {
                        switch(returntype)
                        {
-                               case RETURN_DROPPED: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_DROPPED_)); break;
-                               case RETURN_DAMAGE: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_DAMAGED_)); break;
-                               case RETURN_SPEEDRUN: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_SPEEDRUN_), ctf_captimerecord); break;
-                               case RETURN_NEEDKILL: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_NEEDKILL_)); break;
 -                              case RETURN_DROPPED: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_DROPPED_)); break;
 -                              case RETURN_DAMAGE: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_DAMAGED_)); break;
 -                              case RETURN_SPEEDRUN: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_SPEEDRUN_), ctf_captimerecord); break;
 -                              case RETURN_NEEDKILL: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_NEEDKILL_)); break;
++                              case RETURN_DROPPED: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_DROPPED_) : INFO_CTF_FLAGRETURN_DROPPED_NEUTRAL)); break;
++                              case RETURN_DAMAGE: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_DAMAGED_) : INFO_CTF_FLAGRETURN_DAMAGED_NEUTRAL)); break;
++                              case RETURN_SPEEDRUN: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_SPEEDRUN_) : INFO_CTF_FLAGRETURN_SPEEDRUN_NEUTRAL), ctf_captimerecord); break;
++                              case RETURN_NEEDKILL: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_NEEDKILL_) : INFO_CTF_FLAGRETURN_NEEDKILL_NEUTRAL)); break;
  
                                default:
                                case RETURN_TIMEOUT:
-                                       { Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_TIMEOUT_)); break; }
 -                                      { Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_TIMEOUT_)); break; }
++                                      { Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_TIMEOUT_) : INFO_CTF_FLAGRETURN_TIMEOUT_NEUTRAL)); break; }
                        }
                        sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE);
                        ctf_EventLog("returned", flag.team, world);
@@@ -614,7 -573,7 +670,7 @@@ float ctf_Stalemate_Customize(
  void ctf_CheckStalemate(void)
  {
        // declarations
-       float stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0;
 -      float stale_red_flags = 0, stale_blue_flags = 0;
++      float stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
        entity tmp_entity;
  
        entity ctf_staleflaglist = world; // reset the list, we need to build the list each time this function runs
                        {
                                case NUM_TEAM_1: ++stale_red_flags; break;
                                case NUM_TEAM_2: ++stale_blue_flags; break;
 +                              case NUM_TEAM_3: ++stale_yellow_flags; break;
 +                              case NUM_TEAM_4: ++stale_pink_flags; break;
++                              default: ++stale_neutral_flags; break;
                        }
                }
        }
  
-       stale_flags = (stale_red_flags >= 1) + (stale_blue_flags >= 1) + (stale_yellow_flags >= 1) + (stale_pink_flags >= 1);
 -      if(stale_red_flags && stale_blue_flags)
++      if(ctf_oneflag)
++              stale_flags = (stale_neutral_flags >= 1);
++      else
++              stale_flags = (stale_red_flags >= 1) + (stale_blue_flags >= 1) + (stale_yellow_flags >= 1) + (stale_pink_flags >= 1);
 +
-       if(stale_flags == ctf_teams)
++      if(ctf_oneflag && stale_flags == 1)
+               ctf_stalemate = TRUE;
 -      else if((!stale_red_flags && !stale_blue_flags) && autocvar_g_ctf_stalemate_endcondition == 2)
++      else if(stale_flags == ctf_teams)
 +              ctf_stalemate = TRUE;
 +      else if(stale_flags == 0 && autocvar_g_ctf_stalemate_endcondition == 2)
                { ctf_stalemate = FALSE; wpforenemy_announced = FALSE; }
 -      else if((!stale_red_flags || !stale_blue_flags) && autocvar_g_ctf_stalemate_endcondition == 1)
 +      else if(stale_flags < ctf_teams && autocvar_g_ctf_stalemate_endcondition == 1)
                { ctf_stalemate = FALSE; wpforenemy_announced = FALSE; }
  
        // if sufficient stalemate, then set up the waypointsprite and announce the stalemate if necessary
                for(tmp_entity = ctf_staleflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_staleflagnext)
                {
                        if((tmp_entity.owner) && (!tmp_entity.owner.wps_enemyflagcarrier))
 -                              WaypointSprite_Spawn("enemyflagcarrier", 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, world, tmp_entity.team, tmp_entity.owner, wps_enemyflagcarrier, TRUE, RADARICON_FLAG, WPCOLOR_ENEMYFC(tmp_entity.owner.team));
 +                      {
-                               WaypointSprite_Spawn("enemyflagcarrier", 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, world, 0, tmp_entity.owner, wps_enemyflagcarrier, TRUE, RADARICON_FLAG, WPCOLOR_ENEMYFC(tmp_entity.owner.team));
++                              WaypointSprite_Spawn(((ctf_oneflag) ? "flagcarrier" : "enemyflagcarrier"), 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, world, 0, tmp_entity.owner, wps_enemyflagcarrier, TRUE, RADARICON_FLAG, WPCOLOR_ENEMYFC(tmp_entity.owner.team));
 +                              tmp_entity.owner.wps_enemyflagcarrier.customizeentityforclient = ctf_Stalemate_Customize;
 +                      }
                }
  
                if (!wpforenemy_announced)
@@@ -674,9 -626,9 +736,15 @@@ void ctf_FlagDamage(entity inflictor, e
  {
        if(ITEM_DAMAGE_NEEDKILL(deathtype))
        {
--              // automatically kill the flag and return it
--              self.health = 0;
--              ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
++              if(autocvar_g_ctf_flag_return_damage_delay)
++              {
++                      self.ctf_flagdamaged = TRUE;
++              }
++              else
++              {
++                      self.health = 0;
++                      ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
++              }
                return;
        }
        if(autocvar_g_ctf_flag_return_damage)
@@@ -704,7 -656,7 +772,7 @@@ void ctf_FlagThink(
        if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX) { // reset the flag boundaries in case it got squished
                dprint("wtf the flag got squashed?\n");
                tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self);
--              if(!trace_startsolid) // can we resize it without getting stuck?
++              if(!trace_startsolid || self.noalign) // can we resize it without getting stuck?
                        setsize(self, FLAG_MIN, FLAG_MAX); }
  
        switch(self.ctf_status) // reset flag angles in case warpzones adjust it
                                        return;
                                }
                        }
--                      if(autocvar_g_ctf_flag_return_time)
++                      if(self.ctf_flagdamaged)
++                      {
++                              self.health -= ((self.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE);
++                              ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
++                              return;
++                      }
++                      else if(autocvar_g_ctf_flag_return_time)
                        {
                                self.health -= ((self.max_flag_health / autocvar_g_ctf_flag_return_time) * FLAG_THINKRATE);
                                ctf_CheckFlagReturn(self, RETURN_TIMEOUT);
                                        wpforenemy_nextthink = time + WPFE_THINKRATE; // waypoint for enemy think rate (to reduce unnecessary spam of this check)
                                }
                        }
-                       if(CTF_SAMETEAM(self, self.owner))
++                      if(CTF_SAMETEAM(self, self.owner) && self.team)
 +                      {
 +                              if(autocvar_g_ctf_flag_return) // drop the flag if reverse status has changed
 +                                      ctf_Handle_Throw(self.owner, world, DROP_THROW);
 +                              else if(vlen(self.owner.origin - self.ctf_spawnorigin) <= autocvar_g_ctf_flag_return_carried_radius)
 +                                      ctf_Handle_Return(self, self.owner);
 +                      }
                        return;
                }
  
  void ctf_FlagTouch()
  {
        if(gameover) { return; }
++      if(self.active != ACTIVE_ACTIVE) { return; }
  
--      entity toucher = other;
--      float is_not_monster = (!(toucher.flags & FL_MONSTER));
++      entity toucher = other, tmp_entity;
++      float is_not_monster = (!(toucher.flags & FL_MONSTER)), num_perteam = 0;
  
        // automatically kill the flag and return it if it touched lava/slime/nodrop surfaces
        if(ITEM_TOUCH_NEEDKILL())
        {
--              self.health = 0;
--              ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
++              if(!autocvar_g_ctf_flag_return_damage_delay)
++              {
++                      self.health = 0;
++                      ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
++              }
                return;
        }
  
++      FOR_EACH_PLAYER(tmp_entity) if(SAME_TEAM(toucher, tmp_entity)) { ++num_perteam; }
++
        // special touch behaviors
        if(toucher.vehicle_flags & VHF_ISVEHICLE)
        {
        {
                case FLAG_BASE:
                {
-                       if(CTF_SAMETEAM(toucher, self) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, self) && is_not_monster)
 -                      if(SAME_TEAM(toucher, self) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, self) && is_not_monster)
++                      if(ctf_oneflag)
++                      {
++                              if(CTF_DIFFTEAM(toucher, self) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
++                                      ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
++                              else if(!self.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
++                                      ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the neutral flag
++                      }
++                      else if(CTF_SAMETEAM(toucher, self) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, self) && is_not_monster)
                                ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
 -                      else if(DIFF_TEAM(toucher, self) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
 +                      else if(CTF_DIFFTEAM(toucher, self) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
                                ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the enemies flag
                        break;
                }
  
                case FLAG_DROPPED:
                {
-                       if(CTF_SAMETEAM(toucher, self) && autocvar_g_ctf_flag_return)
 -                      if(SAME_TEAM(toucher, self))
++                      if(CTF_SAMETEAM(toucher, self) && (autocvar_g_ctf_flag_return || num_perteam <= 1) && self.team) // automatically return if there's only 1 player on the team
                                ctf_Handle_Return(self, toucher); // toucher just returned his own flag
                        else if(is_not_monster && (!toucher.flagcarried) && ((toucher != self.ctf_dropper) || (time > self.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
                                ctf_Handle_Pickup(self, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
@@@ -932,7 -878,7 +1019,10 @@@ void ctf_RespawnFlag(entity flag
                        ctf_FakeTimeLimit(flag.owner, -1);
        }
  
 -      if((flag.ctf_status == FLAG_DROPPED) && (flag.wps_flagdropped))
++      if((flag.owner) && (flag.owner.vehicle))
++              flag.scale = FLAG_SCALE;
++
 +      if(flag.ctf_status == FLAG_DROPPED)
                { WaypointSprite_Kill(flag.wps_flagdropped); }
  
        // reset the flag
        flag.ctf_dropper = world;
        flag.ctf_pickuptime = 0;
        flag.ctf_droptime = 0;
++      flag.ctf_flagdamaged = 0;
++      
++      ctf_CheckStalemate();
  }
  
  void ctf_Reset()
        ctf_RespawnFlag(self);
  }
  
++void ctf_Use()
++{
++      if(self.ctf_status != FLAG_BASE) { return; }
++      
++      entity flag;
++      float flag_cnt = 0;
++      
++      for(flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
++      {
++              if(flag != self)
++              if(SAME_TEAM(flag, self))
++              if(flag.active == ACTIVE_ACTIVE)
++                      ++flag_cnt;
++      }
++
++      if(self.active == ACTIVE_ACTIVE)
++      if(flag_cnt < 1)
++      {
++              dprint("ctf_Use: Unable to deactivate flag (not enough active flags on the map)\n");
++              return;
++      }
++
++      self.active = ((self.active) ? ACTIVE_NOT : ACTIVE_ACTIVE);
++      
++      if(self.active == ACTIVE_ACTIVE)
++              WaypointSprite_Ping(self.wps_flagbase);
++}
++
++float ctf_FlagWaypoint_Customize()
++{
++      if(self.owner.active != ACTIVE_ACTIVE) { return FALSE; }
++      return TRUE;
++}
++
  void ctf_DelayedFlagSetup(void) // called after a flag is placed on a map by ctf_FlagSetup()
  {
        // bot waypoints
        self.bot_basewaypoint = self.nearestwaypoint;
  
        // waypointsprites
 -      WaypointSprite_SpawnFixed(((self.team == NUM_TEAM_1) ? "redbase" : "bluebase"), self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE));
 -      WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE));
 +      string basename = "base";
 +
 +      switch(self.team)
 +      {
 +              case NUM_TEAM_1: basename = "redbase"; break;
 +              case NUM_TEAM_2: basename = "bluebase"; break;
 +              case NUM_TEAM_3: basename = "yellowbase"; break;
 +              case NUM_TEAM_4: basename = "pinkbase"; break;
++              default: basename = "neutralbase"; break;
 +      }
 +
-       WaypointSprite_SpawnFixed(basename, self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE));
-       WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE));
++      WaypointSprite_SpawnFixed(basename, self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, ((self.team) ? Team_ColorRGB(self.team) : '1 1 1'));
++      WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, ((self.team) ? colormapPaletteColor(self.team - 1, FALSE) : '1 1 1'));
++      self.wps_flagbase.customizeentityforclient = ctf_FlagWaypoint_Customize;
  
        // captureshield setup
        ctf_CaptureShield_Spawn(self);
@@@ -1002,8 -939,9 +1131,8 @@@ void ctf_FlagSetup(float teamnumber, en
  
        setattachment(flag, world, "");
  
-       flag.netname = ((teamnumber == NUM_TEAM_1) ? "^1RED^7 flag" : ((teamnumber == NUM_TEAM_2) ? "^4BLUE^7 flag" : ((teamnumber == NUM_TEAM_3) ? "^3YELLOW^7 flag" : "^6PINK^7 flag")));
 -      flag.netname = ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag"); // Primarily only used for debugging or when showing nearby item name
 -      flag.team = ((teamnumber) ? NUM_TEAM_1 : NUM_TEAM_2); // NUM_TEAM_1: color 4 team (red) - NUM_TEAM_2: color 13 team (blue)
 -      flag.items = ((teamnumber) ? IT_KEY2 : IT_KEY1); // IT_KEY2: gold key (redish enough) - IT_KEY1: silver key (bluish enough)
++      flag.netname = ((teamnumber == NUM_TEAM_1) ? "^1RED^7 flag" : ((teamnumber == NUM_TEAM_2) ? "^4BLUE^7 flag" : ((teamnumber == NUM_TEAM_3) ? "^3YELLOW^7 flag" : ((teamnumber == NUM_TEAM_4) ? "^6PINK^7 flag" : "^7NEUTRAL flag"))));
 +      flag.team = teamnumber;
        flag.classname = "item_flag_team";
        flag.target = "###item###"; // wut?
        flag.flags = FL_ITEM | FL_NOTARGET;
        flag.velocity = '0 0 0';
        flag.mangle = flag.angles;
        flag.reset = ctf_Reset;
++      flag.use = ctf_Use;
        flag.touch = ctf_FlagTouch;
        flag.think = ctf_FlagThink;
        flag.nextthink = time + FLAG_THINKRATE;
        flag.ctf_status = FLAG_BASE;
  
        // appearence
-       if(flag.model == "")       { flag.model = ((teamnumber == NUM_TEAM_1) ? autocvar_g_ctf_flag_red_model : ((teamnumber == NUM_TEAM_2) ? autocvar_g_ctf_flag_blue_model : ((teamnumber == NUM_TEAM_3) ? autocvar_g_ctf_flag_yellow_model : autocvar_g_ctf_flag_pink_model))); }
 -      if(flag.model == "")       { flag.model = ((teamnumber) ? autocvar_g_ctf_flag_red_model : autocvar_g_ctf_flag_blue_model); }
++      if(flag.model == "")       { flag.model = ((teamnumber == NUM_TEAM_1) ? autocvar_g_ctf_flag_red_model : ((teamnumber == NUM_TEAM_2) ? autocvar_g_ctf_flag_blue_model : ((teamnumber == NUM_TEAM_3) ? autocvar_g_ctf_flag_yellow_model : ((teamnumber == NUM_TEAM_4) ? autocvar_g_ctf_flag_pink_model : autocvar_g_ctf_flag_neutral_model)))); }
        if(!flag.scale)            { flag.scale = FLAG_SCALE; }
-       if(!flag.skin)             { flag.skin = ((teamnumber == NUM_TEAM_1) ? autocvar_g_ctf_flag_red_skin : ((teamnumber == NUM_TEAM_2) ? autocvar_g_ctf_flag_blue_skin : ((teamnumber == NUM_TEAM_3) ? autocvar_g_ctf_flag_yellow_skin : autocvar_g_ctf_flag_pink_skin))); }
-       if(flag.toucheffect == "") { flag.toucheffect = ((teamnumber == NUM_TEAM_1) ? "redflag_touch" : ((teamnumber == NUM_TEAM_2) ? "blueflag_touch" : ((teamnumber == NUM_TEAM_3) ? "yellowflag_touch" : "pinkflag_touch"))); }
-       if(flag.passeffect == "")  { flag.passeffect = ((teamnumber == NUM_TEAM_1) ? "red_pass" : ((teamnumber == NUM_TEAM_2) ? "blue_pass" : ((teamnumber == NUM_TEAM_3) ? "yellow_pass" : "pink_pass"))); }
-       if(flag.capeffect == "")   { flag.capeffect = ((teamnumber == NUM_TEAM_1) ? "red_cap" : ((teamnumber == NUM_TEAM_2) ? "blue_cap" : ((teamnumber == NUM_TEAM_3) ? "yellow_cap" : "pink_cap"))); }
 -      if(!flag.skin)             { flag.skin = ((teamnumber) ? autocvar_g_ctf_flag_red_skin : autocvar_g_ctf_flag_blue_skin); }
 -      if(flag.toucheffect == "") { flag.toucheffect = ((teamnumber) ? "redflag_touch" : "blueflag_touch"); }
 -      if(flag.passeffect == "")  { flag.passeffect = ((teamnumber) ? "red_pass" : "blue_pass"); }
 -      if(flag.capeffect == "")   { flag.capeffect = ((teamnumber) ? "red_cap" : "blue_cap"); }
++      if(!flag.skin)             { flag.skin = ((teamnumber == NUM_TEAM_1) ? autocvar_g_ctf_flag_red_skin : ((teamnumber == NUM_TEAM_2) ? autocvar_g_ctf_flag_blue_skin : ((teamnumber == NUM_TEAM_3) ? autocvar_g_ctf_flag_yellow_skin : ((teamnumber == NUM_TEAM_4) ? autocvar_g_ctf_flag_pink_skin : autocvar_g_ctf_flag_neutral_skin)))); }
++      if(flag.toucheffect == "") { flag.toucheffect = ((teamnumber == NUM_TEAM_1) ? "redflag_touch" : ((teamnumber == NUM_TEAM_2) ? "blueflag_touch" : ((teamnumber == NUM_TEAM_3) ? "yellowflag_touch" : ((teamnumber == NUM_TEAM_4) ? "pinkflag_touch" : "neutralflag_touch")))); }
++      if(flag.passeffect == "")  { flag.passeffect = ((teamnumber == NUM_TEAM_1) ? "red_pass" : ((teamnumber == NUM_TEAM_2) ? "blue_pass" : ((teamnumber == NUM_TEAM_3) ? "yellow_pass" : ((teamnumber == NUM_TEAM_4) ? "pink_pass" : "neutral_pass")))); }
++      if(flag.capeffect == "")   { flag.capeffect = ((teamnumber == NUM_TEAM_1) ? "red_cap" : ((teamnumber == NUM_TEAM_2) ? "blue_cap" : ((teamnumber == NUM_TEAM_3) ? "yellow_cap" : ((teamnumber == NUM_TEAM_4) ? "pink_cap" : "")))); } // neutral flag cant be capped itself
++      if(!flag.active)           { flag.active = ACTIVE_ACTIVE; }
  
        // sound
-       if(flag.snd_flag_taken == "")    { flag.snd_flag_taken = ((teamnumber == NUM_TEAM_1) ? "ctf/red_taken.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_taken.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_taken.wav" : "ctf/pink_taken.wav"))); }
-       if(flag.snd_flag_returned == "") { flag.snd_flag_returned = ((teamnumber == NUM_TEAM_1) ? "ctf/red_returned.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_returned.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_returned.wav" : "ctf/pink_returned.wav"))); }
-       if(flag.snd_flag_capture == "")  { flag.snd_flag_capture = ((teamnumber == NUM_TEAM_1) ? "ctf/red_capture.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_capture.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_capture.wav" : "ctf/pink_capture.wav"))); }
-       if(flag.snd_flag_dropped == "")  { flag.snd_flag_dropped = ((teamnumber == NUM_TEAM_1) ? "ctf/red_dropped.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_dropped.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_dropped.wav" : "ctf/pink_dropped.wav"))); }
 -      if(flag.snd_flag_taken == "")    { flag.snd_flag_taken  = ((teamnumber) ? "ctf/red_taken.wav" : "ctf/blue_taken.wav"); }
 -      if(flag.snd_flag_returned == "") { flag.snd_flag_returned = ((teamnumber) ? "ctf/red_returned.wav" : "ctf/blue_returned.wav"); }
 -      if(flag.snd_flag_capture == "")  { flag.snd_flag_capture = ((teamnumber) ? "ctf/red_capture.wav" : "ctf/blue_capture.wav"); } // blue team scores by capturing the red flag
++      if(flag.snd_flag_taken == "")    { flag.snd_flag_taken = ((teamnumber == NUM_TEAM_1) ? "ctf/red_taken.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_taken.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_taken.wav" : ((teamnumber == NUM_TEAM_4) ? "ctf/pink_taken.wav" : "ctf/neutral_taken.wav")))); }
++      if(flag.snd_flag_returned == "") { flag.snd_flag_returned = ((teamnumber == NUM_TEAM_1) ? "ctf/red_returned.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_returned.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_returned.wav" : ((teamnumber == NUM_TEAM_4) ? "ctf/pink_returned.wav" : "")))); } // neutral flag can't be returned by players
++      if(flag.snd_flag_capture == "")  { flag.snd_flag_capture = ((teamnumber == NUM_TEAM_1) ? "ctf/red_capture.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_capture.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_capture.wav" : ((teamnumber == NUM_TEAM_4) ? "ctf/pink_capture.wav" : "")))); } // again can't be captured
        if(flag.snd_flag_respawn == "")  { flag.snd_flag_respawn = "ctf/flag_respawn.wav"; } // if there is ever a team-based sound for this, update the code to match.
 -      if(flag.snd_flag_dropped == "")  { flag.snd_flag_dropped = ((teamnumber) ? "ctf/red_dropped.wav" : "ctf/blue_dropped.wav"); }
++      if(flag.snd_flag_dropped == "")  { flag.snd_flag_dropped = ((teamnumber == NUM_TEAM_1) ? "ctf/red_dropped.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_dropped.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_dropped.wav" : ((teamnumber == NUM_TEAM_4) ? "ctf/pink_dropped.wav" : "ctf/neutral_dropped.wav")))); }
        if(flag.snd_flag_touch == "")    { flag.snd_flag_touch = "ctf/touch.wav"; } // again has no team-based sound
        if(flag.snd_flag_pass == "")     { flag.snd_flag_pass = "ctf/pass.wav"; } // same story here
  
  
        if(autocvar_g_ctf_flag_glowtrails)
        {
-               flag.glow_color = ((teamnumber == NUM_TEAM_1) ? 251 : ((teamnumber == NUM_TEAM_2) ? 210 : ((teamnumber == NUM_TEAM_3) ? 110 : 145)));
 -              flag.glow_color = ((teamnumber) ? 251 : 210); // 251: red - 210: blue
++              flag.glow_color = ((teamnumber == NUM_TEAM_1) ? 251 : ((teamnumber == NUM_TEAM_2) ? 210 : ((teamnumber == NUM_TEAM_3) ? 110 : ((teamnumber == NUM_TEAM_4) ? 145 : 254))));
                flag.glow_size = 25;
                flag.glow_trail = 1;
        }
  
        flag.effects |= EF_LOWPRECISION;
        if(autocvar_g_ctf_fullbrightflags) { flag.effects |= EF_FULLBRIGHT; }
 -      if(autocvar_g_ctf_dynamiclights)   { flag.effects |= ((teamnumber) ? EF_RED : EF_BLUE); }
 -
 +      if(autocvar_g_ctf_dynamiclights)
 +      {
 +              switch(teamnumber)
 +              {
 +                      case NUM_TEAM_1: flag.effects |= EF_RED; break;
 +                      case NUM_TEAM_2: flag.effects |= EF_BLUE; break;
 +                      case NUM_TEAM_3: flag.effects |= EF_DIMLIGHT; break;
 +                      case NUM_TEAM_4: flag.effects |= EF_RED; break;
++                      default: flag.effects |= EF_DIMLIGHT; break;
 +              }
 +      }
++      
        // flag placement
        if((flag.spawnflags & 1) || flag.noalign) // don't drop to floor, just stay at fixed location
        {
@@@ -1144,7 -1073,7 +1276,20 @@@ entity havocbot_ctf_find_enemy_flag(ent
        f = ctf_worldflaglist;
        while (f)
        {
-               if (CTF_DIFFTEAM(bot, f))
 -              if (bot.team != f.team)
++              if(ctf_oneflag)
++              {
++                      if(CTF_DIFFTEAM(bot, f))
++                      {
++                              if(f.team)
++                              {
++                                      if(bot.flagcarried)
++                                              return f;
++                              }
++                              else if(!bot.flagcarried)
++                                      return f;
++                      }
++              }
++              else if (CTF_DIFFTEAM(bot, f))
                        return f;
                f = f.ctf_worldflagnext;
        }
@@@ -1207,7 -1136,7 +1352,20 @@@ void havocbot_goalrating_ctf_enemyflag(
        head = ctf_worldflaglist;
        while (head)
        {
-               if(CTF_DIFFTEAM(self, head))
 -              if (self.team != head.team)
++              if(ctf_oneflag)
++              {
++                      if(CTF_DIFFTEAM(self, head))
++                      {
++                              if(head.team)
++                              {
++                                      if(self.flagcarried)
++                                              break;
++                              }
++                              else if(!self.flagcarried)
++                                      break;
++                      }
++              }
++              else if(CTF_DIFFTEAM(self, head))
                        break;
                head = head.ctf_worldflagnext;
        }
@@@ -1375,7 -1304,7 +1533,10 @@@ void havocbot_role_ctf_carrier(
                self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
  
                navigation_goalrating_start();
--              havocbot_goalrating_ctf_ourbase(50000);
++              if(ctf_oneflag)
++                      havocbot_goalrating_ctf_enemybase(50000);
++              else
++                      havocbot_goalrating_ctf_ourbase(50000);
  
                if(self.health<100)
                        havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
@@@ -1762,37 -1691,28 +1923,40 @@@ void havocbot_role_ctf_setrole(entity b
  MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
  {
        entity flag;
 +      float t = 0, t2 = 0, t3 = 0;
 +
        // initially clear items so they can be set as necessary later.
-       self.items &= ~(IT_RED_FLAG_CARRYING    | IT_RED_FLAG_TAKEN     | IT_RED_FLAG_LOST 
-                                 | IT_BLUE_FLAG_CARRYING       | IT_BLUE_FLAG_TAKEN    | IT_BLUE_FLAG_LOST
-                                 | IT_YELLOW_FLAG_CARRYING | IT_YELLOW_FLAG_TAKEN      | IT_YELLOW_FLAG_LOST
-                                 | IT_PINK_FLAG_CARRYING       | IT_PINK_FLAG_TAKEN    | IT_PINK_FLAG_LOST
-                                 | IT_CTF_SHIELDED);
 -      self.items &= ~(IT_RED_FLAG_CARRYING | IT_RED_FLAG_TAKEN | IT_RED_FLAG_LOST
 -              | IT_BLUE_FLAG_CARRYING | IT_BLUE_FLAG_TAKEN | IT_BLUE_FLAG_LOST | IT_CTF_SHIELDED);
++      self.ctf_flagstatus &= ~(CTF_RED_FLAG_CARRYING          | CTF_RED_FLAG_TAKEN            | CTF_RED_FLAG_LOST 
++                                                 | CTF_BLUE_FLAG_CARRYING             | CTF_BLUE_FLAG_TAKEN           | CTF_BLUE_FLAG_LOST
++                                                 | CTF_YELLOW_FLAG_CARRYING   | CTF_YELLOW_FLAG_TAKEN         | CTF_YELLOW_FLAG_LOST
++                                                 | CTF_PINK_FLAG_CARRYING     | CTF_PINK_FLAG_TAKEN           | CTF_PINK_FLAG_LOST
++                                                 | CTF_NEUTRAL_FLAG_CARRYING  | CTF_NEUTRAL_FLAG_TAKEN        | CTF_NEUTRAL_FLAG_LOST
++                                                 | CTF_FLAG_NEUTRAL | CTF_SHIELDED);
  
        // scan through all the flags and notify the client about them
        for(flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
        {
-               if(flag.team == NUM_TEAM_1) { t = IT_RED_FLAG_CARRYING;         t2 = IT_RED_FLAG_TAKEN;         t3 = IT_RED_FLAG_LOST; }
-               if(flag.team == NUM_TEAM_2) { t = IT_BLUE_FLAG_CARRYING;        t2 = IT_BLUE_FLAG_TAKEN;        t3 = IT_BLUE_FLAG_LOST; }
-               if(flag.team == NUM_TEAM_3) { t = IT_YELLOW_FLAG_CARRYING;      t2 = IT_YELLOW_FLAG_TAKEN;      t3 = IT_YELLOW_FLAG_LOST; }
-               if(flag.team == NUM_TEAM_4) { t = IT_PINK_FLAG_CARRYING;        t2 = IT_PINK_FLAG_TAKEN;        t3 = IT_PINK_FLAG_LOST; }
++              if(flag.team == NUM_TEAM_1) { t = CTF_RED_FLAG_CARRYING;                t2 = CTF_RED_FLAG_TAKEN;                t3 = CTF_RED_FLAG_LOST; }
++              if(flag.team == NUM_TEAM_2) { t = CTF_BLUE_FLAG_CARRYING;               t2 = CTF_BLUE_FLAG_TAKEN;               t3 = CTF_BLUE_FLAG_LOST; }
++              if(flag.team == NUM_TEAM_3) { t = CTF_YELLOW_FLAG_CARRYING;     t2 = CTF_YELLOW_FLAG_TAKEN;             t3 = CTF_YELLOW_FLAG_LOST; }
++              if(flag.team == NUM_TEAM_4) { t = CTF_PINK_FLAG_CARRYING;               t2 = CTF_PINK_FLAG_TAKEN;               t3 = CTF_PINK_FLAG_LOST; }
++              if(flag.team == 0)                      { t = CTF_NEUTRAL_FLAG_CARRYING;        t2 = CTF_NEUTRAL_FLAG_TAKEN;    t3 = CTF_NEUTRAL_FLAG_LOST; self.ctf_flagstatus |= CTF_FLAG_NEUTRAL; }
 +
                switch(flag.ctf_status)
                {
                        case FLAG_PASSING:
                        case FLAG_CARRY:
                        {
                                if((flag.owner == self) || (flag.pass_sender == self))
-                                       self.items |= t; // carrying: self is currently carrying the flag
 -                                      self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_CARRYING : IT_BLUE_FLAG_CARRYING); // carrying: self is currently carrying the flag
--                              else
-                                       self.items |= t2; // taken: someone else is carrying the flag
 -                                      self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_TAKEN : IT_BLUE_FLAG_TAKEN); // taken: someone on self's team is carrying the flag
++                                      self.ctf_flagstatus |= t; // carrying: self is currently carrying the flag
++                              else 
++                                      self.ctf_flagstatus |= t2; // taken: someone else is carrying the flag
                                break;
                        }
                        case FLAG_DROPPED:
                        {
-                               self.items |= t3; // lost: the flag is dropped somewhere on the map
 -                              self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_LOST : IT_BLUE_FLAG_LOST); // lost: the flag is dropped somewhere on the map
++                              self.ctf_flagstatus |= t3; // lost: the flag is dropped somewhere on the map
                                break;
                        }
                }
  
        // item for stopping players from capturing the flag too often
        if(self.ctf_captureshielded)
--              self.items |= IT_CTF_SHIELDED;
++              self.ctf_flagstatus |= CTF_SHIELDED;
  
        // update the health of the flag carrier waypointsprite
        if(self.wps_flagcarrier)
@@@ -1846,7 -1766,7 +2010,11 @@@ MUTATOR_HOOKFUNCTION(ctf_PlayerDies
        }
  
        if(frag_target.flagcarried)
--              { ctf_Handle_Throw(frag_target, world, DROP_NORMAL); }
++      {
++              entity tmp_entity = frag_target.flagcarried;
++              ctf_Handle_Throw(frag_target, world, DROP_NORMAL);
++              tmp_entity.ctf_dropper = world;
++      }
  
        return FALSE;
  }
@@@ -2031,7 -1951,7 +2199,7 @@@ MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun
  {
        if(self.flagcarried)
        {
-               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(self.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN_));
 -              Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(self.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN_));
++              Send_Notification(NOTIF_ALL, world, MSG_INFO, ((self.flagcarried.team) ? APP_TEAM_ENT_4(self.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN_) : INFO_CTF_FLAGRETURN_ABORTRUN_NEUTRAL));
                ctf_RespawnFlag(self.flagcarried);
                return TRUE;
        }
@@@ -2079,12 -1999,7 +2247,20 @@@ MUTATOR_HOOKFUNCTION(ctf_BotRoles
        return TRUE;
  }
  
-       ret_float = ctf_teams;
-       return 0;
 +MUTATOR_HOOKFUNCTION(ctf_GetTeamCount)
 +{
++      //ret_float = ctf_teams;
++      ret_string = "ctf_team";
++      return TRUE;
++}
++
++MUTATOR_HOOKFUNCTION(ctf_SpectateCopy)
++{
++      self.ctf_flagstatus = other.ctf_flagstatus;
++      return FALSE;
 +}
 +
  // ==========
  // Spawnfuncs
  // ==========
@@@ -2168,45 -2083,9 +2344,63 @@@ void spawnfunc_item_flag_team2(
  {
        if(!g_ctf) { remove(self); return; }
  
 -      ctf_FlagSetup(0, self); // the 0 is misleading, but -- 0 = blue.
 +      ctf_FlagSetup(NUM_TEAM_2, self);
 +}
 +
 +/*QUAKED spawnfunc_item_flag_team3 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
 +CTF flag for team three (Yellow).
 +Keys: 
 +"angle" Angle the flag will point (minus 90 degrees)... 
 +"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
 +"noise" sound played when flag is picked up...
 +"noise1" sound played when flag is returned by a teammate...
 +"noise2" sound played when flag is captured...
 +"noise3" sound played when flag is lost in the field and respawns itself... 
 +"noise4" sound played when flag is dropped by a player...
 +"noise5" sound played when flag touches the ground... */
 +void spawnfunc_item_flag_team3()
 +{
 +      if(!g_ctf) { remove(self); return; }
 +
 +      ctf_FlagSetup(NUM_TEAM_3, self);
 +}
 +
 +/*QUAKED spawnfunc_item_flag_team4 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
- CTF flag for team two (Pink).
++CTF flag for team four (Pink).
 +Keys: 
 +"angle" Angle the flag will point (minus 90 degrees)... 
 +"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
 +"noise" sound played when flag is picked up...
 +"noise1" sound played when flag is returned by a teammate...
 +"noise2" sound played when flag is captured...
 +"noise3" sound played when flag is lost in the field and respawns itself... 
 +"noise4" sound played when flag is dropped by a player...
 +"noise5" sound played when flag touches the ground... */
 +void spawnfunc_item_flag_team4()
 +{
 +      if(!g_ctf) { remove(self); return; }
 +
 +      ctf_FlagSetup(NUM_TEAM_4, self);
 +}
 +
++/*QUAKED spawnfunc_item_flag_neutral (0 0.5 0.8) (-48 -48 -37) (48 48 37)
++CTF flag (Neutral).
++Keys: 
++"angle" Angle the flag will point (minus 90 degrees)... 
++"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
++"noise" sound played when flag is picked up...
++"noise1" sound played when flag is returned by a teammate...
++"noise2" sound played when flag is captured...
++"noise3" sound played when flag is lost in the field and respawns itself... 
++"noise4" sound played when flag is dropped by a player...
++"noise5" sound played when flag touches the ground... */
++void spawnfunc_item_flag_neutral()
++{
++      if(!g_ctf) { remove(self); return; }
++
++      ctf_FlagSetup(0, self);
+ }
  /*QUAKED spawnfunc_ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32)
  Team declaration for CTF gameplay, this allows you to decide what team names and control point models are used in your map.
  Note: If you use spawnfunc_ctf_team entities you must define at least 2!  However, unlike domination, you don't need to make a blank one too.
@@@ -2266,17 -2144,6 +2460,18 @@@ void ctf_SpawnTeam (string teamname, fl
  
  void ctf_DelayedInit() // Do this check with a delay so we can wait for teams to be set up.
  {
 +      ctf_teams = 2;
 +
 +      entity tmp_entity;
 +      for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
 +      {
 +              if(tmp_entity.team == NUM_TEAM_3) { ctf_teams = max(3, ctf_teams); }
 +              if(tmp_entity.team == NUM_TEAM_4) { ctf_teams = max(4, ctf_teams); }
++              if(tmp_entity.team == 0) { ctf_oneflag = TRUE; }
 +      }
 +
 +      ctf_teams = bound(2, ctf_teams, 4);
 +
        // if no teams are found, spawn defaults
        if(find(world, classname, "ctf_team") == world)
        {
@@@ -2299,6 -2162,6 +2494,8 @@@ void ctf_Initialize(
        ctf_captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
        ctf_captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
        ctf_captureshield_force = autocvar_g_ctf_shield_force;
++      
++      addstat(STAT_CTF_FLAGSTATUS, AS_INT, ctf_flagstatus);
  
        InitializeEntity(world, ctf_DelayedInit, INITPRIO_GAMETYPE);
  }
@@@ -2320,7 -2183,6 +2517,8 @@@ MUTATOR_DEFINITION(gamemode_ctf
        MUTATOR_HOOK(VehicleExit, ctf_VehicleExit, CBC_ORDER_ANY);
        MUTATOR_HOOK(AbortSpeedrun, ctf_AbortSpeedrun, CBC_ORDER_ANY);
        MUTATOR_HOOK(HavocBot_ChooseRule, ctf_BotRoles, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(GetTeamCount, ctf_GetTeamCount, CBC_ORDER_ANY);
++      MUTATOR_HOOK(SpectateCopy, ctf_SpectateCopy, CBC_ORDER_ANY);
  
        MUTATOR_ONADD
        {
index 5470a480a994e1e687ce22debfeaa167f33e71b4,ca4961eddc24231a6056943a0b2bffcdb5dcec06..9a06a8c2d90e34e59c7fe6dad80cc9972b91d854
@@@ -34,9 -34,9 +34,9 @@@ void ctf_RespawnFlag(entity flag)
  #define VEHICLE_FLAG_SCALE 1.0
  
  // waypoint colors
--#define WPCOLOR_ENEMYFC(t) (colormapPaletteColor(t - 1, FALSE) * 0.75)
++#define WPCOLOR_ENEMYFC(t) ((t) ? colormapPaletteColor(t - 1, FALSE) * 0.75 : '1 1 1')
  #define WPCOLOR_FLAGCARRIER(t) ('0.8 0.8 0')
--#define WPCOLOR_DROPPEDFLAG(t) (('0.25 0.25 0.25' + colormapPaletteColor(t - 1, FALSE)) * 0.5)
++#define WPCOLOR_DROPPEDFLAG(t) ((t) ? ('0.25 0.25 0.25' + colormapPaletteColor(t - 1, FALSE)) * 0.5 : '1 1 1')
  
  // sounds
  #define snd_flag_taken noise
@@@ -101,7 -101,6 +101,8 @@@ float ctf_captimerecord; // record tim
  .entity ctf_dropper; // don't allow spam of dropping the flag
  .float max_flag_health;
  .float next_take_time;
++.float ctf_flagdamaged;
 +float ctf_teams;
  
  // passing/throwing properties
  .float pass_distance;
@@@ -117,6 -116,6 +118,9 @@@ float ctf_captureshield_min_negscore; /
  float ctf_captureshield_max_ratio; // punish at most 30% of each team
  float ctf_captureshield_force; // push force of the shield
  
++// 1 flag ctf
++float ctf_oneflag; // indicates whether or not a neutral flag has been found
++
  // bot player logic
  #define HAVOCBOT_CTF_ROLE_NONE 0
  #define HAVOCBOT_CTF_ROLE_DEFENSE 2
@@@ -132,8 -131,4 +136,30 @@@ vector havocbot_ctf_middlepoint
  float havocbot_ctf_middlepoint_radius;
  
  void havocbot_role_ctf_setrole(entity bot, float role);
 +
 +// team checking
 +#define CTF_SAMETEAM(a,b) (autocvar_g_ctf_reverse ? DIFF_TEAM(a,b) : SAME_TEAM(a,b))
 +#define CTF_DIFFTEAM(a,b) (autocvar_g_ctf_reverse ? SAME_TEAM(a,b) : DIFF_TEAM(a,b))
++
  #endif
++
++// networked flag statuses
++.float ctf_flagstatus;
++
++const float   CTF_RED_FLAG_TAKEN                      = 1;
++const float   CTF_RED_FLAG_LOST                       = 2;
++const float   CTF_RED_FLAG_CARRYING           = 3;
++const float   CTF_BLUE_FLAG_TAKEN                     = 4;
++const float   CTF_BLUE_FLAG_LOST                      = 8;
++const float   CTF_BLUE_FLAG_CARRYING          = 12;
++const float   CTF_YELLOW_FLAG_TAKEN           = 16;
++const float   CTF_YELLOW_FLAG_LOST            = 32;
++const float   CTF_YELLOW_FLAG_CARRYING        = 48;
++const float   CTF_PINK_FLAG_TAKEN                     = 64;
++const float   CTF_PINK_FLAG_LOST                      = 128;
++const float   CTF_PINK_FLAG_CARRYING          = 192;
++const float   CTF_NEUTRAL_FLAG_TAKEN          = 256;
++const float   CTF_NEUTRAL_FLAG_LOST           = 512;
++const float   CTF_NEUTRAL_FLAG_CARRYING       = 768;
++const float CTF_FLAG_NEUTRAL                  = 2048;
++const float CTF_SHIELDED                              = 4096;
index e597938dc6dec26fe56840d107942822bdebb870,2eceff38dd783a33da7ccd066498b98b9d23225a..db6939f154364a2d325d622e9bb4d85c2797f863
@@@ -15,22 -15,4 +15,31 @@@ models/ctf/glow_blu
        tcMod scroll 0.1 -0.04
        tcMod rotate 0.1
   }
 +}
 +models/ctf/glow_yellow
 +{
 + {
 +      map models/ctf/glow_yellow.tga
 +      tcMod scale 0.03 0.03
 +      tcMod scroll 0.1 -0.04
 +      tcMod rotate 0.1
 + }
 +}
 +models/ctf/glow_pink
 +{
 + {
 +      map models/ctf/glow_pink.tga
 +      tcMod scale 0.03 0.03
 +      tcMod scroll 0.1 -0.04
 +      tcMod rotate 0.1
 + }
++}
++models/ctf/glow_neutral
++{
++ {
++      map models/ctf/glow_neutral.tga
++      tcMod scale 0.03 0.03
++      tcMod scroll 0.1 -0.04
++      tcMod rotate 0.1
++ }
  }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b3232e2436c0e8a8553c337cc8aca7272e68f7ac
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fde3fe2eb0c6599b95a90803941a07154dda8896
new file mode 100644 (file)
Binary files differ