]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/ctf_updates
authorMario <zacjardine@y7mail.com>
Sun, 3 May 2015 14:43:37 +0000 (00:43 +1000)
committerMario <zacjardine@y7mail.com>
Sun, 3 May 2015 14:43:37 +0000 (00:43 +1000)
Conflicts:
qcsrc/client/hud.qc
qcsrc/server/autocvars.qh

61 files changed:
effectinfo.txt
gamemodes.cfg
gfx/hud/default/flag_neutral_carrying.tga [new file with mode: 0644]
gfx/hud/default/flag_neutral_lost.tga [new file with mode: 0644]
gfx/hud/default/flag_neutral_shielded.tga [new file with mode: 0644]
gfx/hud/default/flag_neutral_taken.tga [new file with mode: 0644]
gfx/hud/default/flag_pink_carrying.tga [new file with mode: 0644]
gfx/hud/default/flag_pink_lost.tga [new file with mode: 0644]
gfx/hud/default/flag_pink_shielded.tga [new file with mode: 0644]
gfx/hud/default/flag_pink_taken.tga [new file with mode: 0644]
gfx/hud/default/flag_yellow_carrying.tga [new file with mode: 0644]
gfx/hud/default/flag_yellow_lost.tga [new file with mode: 0644]
gfx/hud/default/flag_yellow_shielded.tga [new file with mode: 0644]
gfx/hud/default/flag_yellow_taken.tga [new file with mode: 0644]
models/ctf/banner_blue_gloss.tga [deleted file]
models/ctf/banner_neutral.tga [new file with mode: 0644]
models/ctf/banner_neutral_gloss.tga [new file with mode: 0644]
models/ctf/banner_pink.tga [new file with mode: 0644]
models/ctf/banner_pink_gloss.tga [new file with mode: 0644]
models/ctf/banner_yellow.tga [new file with mode: 0644]
models/ctf/banner_yellow_gloss.tga [new file with mode: 0644]
models/ctf/flag_neutral.tga [new file with mode: 0644]
models/ctf/flag_neutral_gloss.tga [new file with mode: 0644]
models/ctf/flag_neutral_glow.tga [new file with mode: 0644]
models/ctf/flag_neutral_norm.tga [new file with mode: 0644]
models/ctf/flag_pink.tga [new file with mode: 0644]
models/ctf/flag_pink_gloss.tga [new file with mode: 0644]
models/ctf/flag_pink_glow.tga [new file with mode: 0644]
models/ctf/flag_pink_norm.tga [new file with mode: 0644]
models/ctf/flag_yellow.tga [new file with mode: 0644]
models/ctf/flag_yellow_gloss.tga [new file with mode: 0644]
models/ctf/flag_yellow_glow.tga [new file with mode: 0644]
models/ctf/flag_yellow_norm.tga [new file with mode: 0644]
models/ctf/flags.md3_2.skin [new file with mode: 0644]
models/ctf/flags.md3_3.skin [new file with mode: 0644]
models/ctf/flags.md3_4.skin [new file with mode: 0644]
models/ctf/glow_neutral.tga [new file with mode: 0644]
models/ctf/glow_neutral_glow.tga [new file with mode: 0644]
models/ctf/glow_pink.tga [new file with mode: 0644]
models/ctf/glow_pink_glow.tga [new file with mode: 0644]
models/ctf/glow_yellow.tga [new file with mode: 0644]
models/ctf/glow_yellow_glow.tga [new file with mode: 0644]
qcsrc/client/hud.qc
qcsrc/client/waypointsprites.qc
qcsrc/common/items.qh [new file with mode: 0644]
qcsrc/common/notifications.qh
qcsrc/common/stats.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 [new file with mode: 0644]
sound/ctf/neutral_taken.wav [new file with mode: 0644]
sound/ctf/pink_capture.ogg [new file with mode: 0644]
sound/ctf/pink_dropped.wav [new file with mode: 0644]
sound/ctf/pink_returned.wav [new file with mode: 0644]
sound/ctf/pink_taken.wav [new file with mode: 0644]
sound/ctf/yellow_capture.ogg [new file with mode: 0644]
sound/ctf/yellow_dropped.wav [new file with mode: 0644]
sound/ctf/yellow_returned.wav [new file with mode: 0644]
sound/ctf/yellow_taken.wav [new file with mode: 0644]

index d9874d909f8a2a44301d86da7e2f33e0563d4a02..334fe7ac9e8d2029e72ad1504ae27d79d6e4c69a 100644 (file)
@@ -7669,6 +7669,54 @@ velocityjitter 300 300 300
 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
@@ -7727,6 +7775,93 @@ size 4 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
@@ -7777,6 +7912,56 @@ alpha 190 190 180
 sizeincrease -80
 color 0x0000FF 0x000097
 
+// yellow_cap -- yellow team capture effect
+effect yellow_cap
+count 500
+type spark
+tex 64 64
+color 0xFFFF0F 0xFFFF0F
+size 1 1
+alpha 0 256 100
+stretchfactor 2
+//gravity 1
+bounce 1.5
+originjitter 1 1 1
+velocityjitter 1000 1000 1500
+velocitymultiplier 0.5
+airfriction 2
+stretchfactor 0.6
+effect yellow_cap
+countabsolute 1
+type smoke
+tex 65 65
+size 150 150
+alpha 190 190 180
+sizeincrease -80
+color 0xFFFF0F 0xFFFF0F
+
+// pink_cap -- pink team capture effect
+effect pink_cap
+count 500
+type spark
+tex 64 64
+color 0xFF0FFF 0xFF0FFF
+size 1 1
+alpha 0 256 100
+stretchfactor 2
+//gravity 1
+bounce 1.5
+originjitter 1 1 1
+velocityjitter 1000 1000 1500
+velocitymultiplier 0.5
+airfriction 2
+stretchfactor 0.6
+effect pink_cap
+countabsolute 1
+type smoke
+tex 65 65
+size 150 150
+alpha 190 190 180
+sizeincrease -80
+color 0xFF0FFF 0xFF0FFF
+
 // spawn_point_red -- red team idle spawn point effect
 effect spawn_point_red
 count 37.5
index b6cbe92cfcba116c79de77e667e30d35d2c6601a..0b289e82827e19e4f2daf53b40e09157bfb656c3 100644 (file)
@@ -242,6 +242,10 @@ set g_ca_teams 0
 //  capture the flag
 // ==================
 set g_ctf 0 "Capture The Flag: take the enemy flag and bring it to yours at your base to score"
+set g_ctf_oneflag 1 "Allow oneflag CTF mode on maps that support it"
+set g_ctf_oneflag_reverse 0 "apply reverse mode to oneflag CTF (take flag to enemy bases to cap), overrides g_ctf_reverse only in oneflag, g_ctf_reverse still affects oneflag"
+set g_ctf_flag_return 1 "auto return the flag to base when touched by a teammate"
+set g_ctf_flag_return_carried_radius 100 "allow flags to be returned by carrier if base is within this radius"
 set g_ctf_flag_return_time 15
 set g_ctf_flag_return_dropped 100
 set g_ctf_flag_return_damage 0
@@ -299,6 +303,12 @@ set g_ctf_flag_red_model "models/ctf/flags.md3"
 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
diff --git a/gfx/hud/default/flag_neutral_carrying.tga b/gfx/hud/default/flag_neutral_carrying.tga
new file mode 100644 (file)
index 0000000..0e55513
Binary files /dev/null and b/gfx/hud/default/flag_neutral_carrying.tga differ
diff --git a/gfx/hud/default/flag_neutral_lost.tga b/gfx/hud/default/flag_neutral_lost.tga
new file mode 100644 (file)
index 0000000..7cb1d73
Binary files /dev/null and b/gfx/hud/default/flag_neutral_lost.tga differ
diff --git a/gfx/hud/default/flag_neutral_shielded.tga b/gfx/hud/default/flag_neutral_shielded.tga
new file mode 100644 (file)
index 0000000..7e83e4d
Binary files /dev/null and b/gfx/hud/default/flag_neutral_shielded.tga differ
diff --git a/gfx/hud/default/flag_neutral_taken.tga b/gfx/hud/default/flag_neutral_taken.tga
new file mode 100644 (file)
index 0000000..e35b831
Binary files /dev/null and b/gfx/hud/default/flag_neutral_taken.tga differ
diff --git a/gfx/hud/default/flag_pink_carrying.tga b/gfx/hud/default/flag_pink_carrying.tga
new file mode 100644 (file)
index 0000000..920adfd
Binary files /dev/null and b/gfx/hud/default/flag_pink_carrying.tga differ
diff --git a/gfx/hud/default/flag_pink_lost.tga b/gfx/hud/default/flag_pink_lost.tga
new file mode 100644 (file)
index 0000000..87d1141
Binary files /dev/null and b/gfx/hud/default/flag_pink_lost.tga differ
diff --git a/gfx/hud/default/flag_pink_shielded.tga b/gfx/hud/default/flag_pink_shielded.tga
new file mode 100644 (file)
index 0000000..5f92416
Binary files /dev/null and b/gfx/hud/default/flag_pink_shielded.tga differ
diff --git a/gfx/hud/default/flag_pink_taken.tga b/gfx/hud/default/flag_pink_taken.tga
new file mode 100644 (file)
index 0000000..4f8bab3
Binary files /dev/null and b/gfx/hud/default/flag_pink_taken.tga differ
diff --git a/gfx/hud/default/flag_yellow_carrying.tga b/gfx/hud/default/flag_yellow_carrying.tga
new file mode 100644 (file)
index 0000000..48ed501
Binary files /dev/null and b/gfx/hud/default/flag_yellow_carrying.tga differ
diff --git a/gfx/hud/default/flag_yellow_lost.tga b/gfx/hud/default/flag_yellow_lost.tga
new file mode 100644 (file)
index 0000000..f930414
Binary files /dev/null and b/gfx/hud/default/flag_yellow_lost.tga differ
diff --git a/gfx/hud/default/flag_yellow_shielded.tga b/gfx/hud/default/flag_yellow_shielded.tga
new file mode 100644 (file)
index 0000000..92ee3b1
Binary files /dev/null and b/gfx/hud/default/flag_yellow_shielded.tga differ
diff --git a/gfx/hud/default/flag_yellow_taken.tga b/gfx/hud/default/flag_yellow_taken.tga
new file mode 100644 (file)
index 0000000..274e4ce
Binary files /dev/null and b/gfx/hud/default/flag_yellow_taken.tga differ
diff --git a/models/ctf/banner_blue_gloss.tga b/models/ctf/banner_blue_gloss.tga
deleted file mode 100644 (file)
index 77168a8..0000000
Binary files a/models/ctf/banner_blue_gloss.tga and /dev/null differ
diff --git a/models/ctf/banner_neutral.tga b/models/ctf/banner_neutral.tga
new file mode 100644 (file)
index 0000000..5c3de94
Binary files /dev/null and b/models/ctf/banner_neutral.tga differ
diff --git a/models/ctf/banner_neutral_gloss.tga b/models/ctf/banner_neutral_gloss.tga
new file mode 100644 (file)
index 0000000..77168a8
Binary files /dev/null and b/models/ctf/banner_neutral_gloss.tga differ
diff --git a/models/ctf/banner_pink.tga b/models/ctf/banner_pink.tga
new file mode 100644 (file)
index 0000000..68e65b6
Binary files /dev/null and b/models/ctf/banner_pink.tga differ
diff --git a/models/ctf/banner_pink_gloss.tga b/models/ctf/banner_pink_gloss.tga
new file mode 100644 (file)
index 0000000..77168a8
Binary files /dev/null and b/models/ctf/banner_pink_gloss.tga differ
diff --git a/models/ctf/banner_yellow.tga b/models/ctf/banner_yellow.tga
new file mode 100644 (file)
index 0000000..b398e88
Binary files /dev/null and b/models/ctf/banner_yellow.tga differ
diff --git a/models/ctf/banner_yellow_gloss.tga b/models/ctf/banner_yellow_gloss.tga
new file mode 100644 (file)
index 0000000..77168a8
Binary files /dev/null and b/models/ctf/banner_yellow_gloss.tga differ
diff --git a/models/ctf/flag_neutral.tga b/models/ctf/flag_neutral.tga
new file mode 100644 (file)
index 0000000..63feddd
Binary files /dev/null and b/models/ctf/flag_neutral.tga differ
diff --git a/models/ctf/flag_neutral_gloss.tga b/models/ctf/flag_neutral_gloss.tga
new file mode 100644 (file)
index 0000000..3e92985
Binary files /dev/null and b/models/ctf/flag_neutral_gloss.tga differ
diff --git a/models/ctf/flag_neutral_glow.tga b/models/ctf/flag_neutral_glow.tga
new file mode 100644 (file)
index 0000000..77191ab
Binary files /dev/null and b/models/ctf/flag_neutral_glow.tga differ
diff --git a/models/ctf/flag_neutral_norm.tga b/models/ctf/flag_neutral_norm.tga
new file mode 100644 (file)
index 0000000..07d5e17
Binary files /dev/null and b/models/ctf/flag_neutral_norm.tga differ
diff --git a/models/ctf/flag_pink.tga b/models/ctf/flag_pink.tga
new file mode 100644 (file)
index 0000000..63feddd
Binary files /dev/null and b/models/ctf/flag_pink.tga differ
diff --git a/models/ctf/flag_pink_gloss.tga b/models/ctf/flag_pink_gloss.tga
new file mode 100644 (file)
index 0000000..3e92985
Binary files /dev/null and b/models/ctf/flag_pink_gloss.tga differ
diff --git a/models/ctf/flag_pink_glow.tga b/models/ctf/flag_pink_glow.tga
new file mode 100644 (file)
index 0000000..ba70c08
Binary files /dev/null and b/models/ctf/flag_pink_glow.tga differ
diff --git a/models/ctf/flag_pink_norm.tga b/models/ctf/flag_pink_norm.tga
new file mode 100644 (file)
index 0000000..07d5e17
Binary files /dev/null and b/models/ctf/flag_pink_norm.tga differ
diff --git a/models/ctf/flag_yellow.tga b/models/ctf/flag_yellow.tga
new file mode 100644 (file)
index 0000000..63feddd
Binary files /dev/null and b/models/ctf/flag_yellow.tga differ
diff --git a/models/ctf/flag_yellow_gloss.tga b/models/ctf/flag_yellow_gloss.tga
new file mode 100644 (file)
index 0000000..3e92985
Binary files /dev/null and b/models/ctf/flag_yellow_gloss.tga differ
diff --git a/models/ctf/flag_yellow_glow.tga b/models/ctf/flag_yellow_glow.tga
new file mode 100644 (file)
index 0000000..0af88a9
Binary files /dev/null and b/models/ctf/flag_yellow_glow.tga differ
diff --git a/models/ctf/flag_yellow_norm.tga b/models/ctf/flag_yellow_norm.tga
new file mode 100644 (file)
index 0000000..07d5e17
Binary files /dev/null and b/models/ctf/flag_yellow_norm.tga differ
diff --git a/models/ctf/flags.md3_2.skin b/models/ctf/flags.md3_2.skin
new file mode 100644 (file)
index 0000000..44fb67d
--- /dev/null
@@ -0,0 +1,3 @@
+mesh,models/ctf/flag_yellow.tga
+mesh2,models/ctf/banner_yellow.tga
+mesh3,models/ctf/glow_yellow.tga
\ No newline at end of file
diff --git a/models/ctf/flags.md3_3.skin b/models/ctf/flags.md3_3.skin
new file mode 100644 (file)
index 0000000..22d77d2
--- /dev/null
@@ -0,0 +1,3 @@
+mesh,models/ctf/flag_pink.tga
+mesh2,models/ctf/banner_pink.tga
+mesh3,models/ctf/glow_pink.tga
\ No newline at end of file
diff --git a/models/ctf/flags.md3_4.skin b/models/ctf/flags.md3_4.skin
new file mode 100644 (file)
index 0000000..ba35e26
--- /dev/null
@@ -0,0 +1,3 @@
+mesh,models/ctf/flag_neutral.tga
+mesh2,models/ctf/banner_neutral.tga
+mesh3,models/ctf/glow_neutral.tga
\ No newline at end of file
diff --git a/models/ctf/glow_neutral.tga b/models/ctf/glow_neutral.tga
new file mode 100644 (file)
index 0000000..5ffa098
Binary files /dev/null and b/models/ctf/glow_neutral.tga differ
diff --git a/models/ctf/glow_neutral_glow.tga b/models/ctf/glow_neutral_glow.tga
new file mode 100644 (file)
index 0000000..5ffa098
Binary files /dev/null and b/models/ctf/glow_neutral_glow.tga differ
diff --git a/models/ctf/glow_pink.tga b/models/ctf/glow_pink.tga
new file mode 100644 (file)
index 0000000..6a3bb8c
Binary files /dev/null and b/models/ctf/glow_pink.tga differ
diff --git a/models/ctf/glow_pink_glow.tga b/models/ctf/glow_pink_glow.tga
new file mode 100644 (file)
index 0000000..8da95a9
Binary files /dev/null and b/models/ctf/glow_pink_glow.tga differ
diff --git a/models/ctf/glow_yellow.tga b/models/ctf/glow_yellow.tga
new file mode 100644 (file)
index 0000000..8562caa
Binary files /dev/null and b/models/ctf/glow_yellow.tga differ
diff --git a/models/ctf/glow_yellow_glow.tga b/models/ctf/glow_yellow_glow.tga
new file mode 100644 (file)
index 0000000..8562caa
Binary files /dev/null and b/models/ctf/glow_yellow_glow.tga differ
index 0da1b69d2cb71e59a7a48687176f4e97c80ed7f0..15cc1176087b2485502ff45924ea2dab166822bb 100644 (file)
@@ -5,6 +5,7 @@
 #include "../common/mapinfo.qh"
 #include "../common/nades.qh"
 #include "../server/t_items.qh"
+#include "../server/mutators/gamemode_ctf.qh"
 
 /*
 ==================
@@ -2864,30 +2865,39 @@ void HUD_Mod_CA(vector myPos, vector mySize)
 }
 
 // CTF HUD modicon section
-float redflag_prevframe, blueflag_prevframe; // status during previous frame
-int redflag_prevstatus, blueflag_prevstatus; // last remembered status
-float redflag_statuschange_time, blueflag_statuschange_time; // time when the status changed
+int redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
+int 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 = 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;
+       vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
        vector flag_size;
        float f; // every function should have that
 
-       int redflag, blueflag; // current status
-       float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime; // time since the status changed
-       int 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)
+       int 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
+       bool ctf_oneflag; // one-flag CTF mode enabled/disabled
+       int stat_items = getstati(STAT_CTF_FLAGSTATUS, 0, 24);
+       float fs, fs2, fs3, size1, size2;
+       vector e1, e2;
+
+       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 || neutralflag)
                mod_active = 1;
        else
                mod_active = 0;
@@ -2896,6 +2906,11 @@ void HUD_Mod_CTF(vector pos, vector mySize)
        {
                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
@@ -2913,40 +2928,66 @@ void HUD_Mod_CTF(vector pos, vector mySize)
                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;
+       const float BLINK_FACTOR = 0.15;
+       const float BLINK_BASE = 0.85;
        // note:
        //   RMS = sqrt(BLINK_BASE^2 + 0.5 * BLINK_FACTOR^2)
        // thus
        //   BLINK_BASE = sqrt(RMS^2 - 0.5 * BLINK_FACTOR^2)
        // ensure RMS == 1
-       float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
+       const float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
 
        string red_icon, red_icon_prevstatus;
-       float red_alpha, red_alpha_prevstatus;
+       int red_alpha, red_alpha_prevstatus;
        red_alpha = red_alpha_prevstatus = 1;
-       switch(redflag) {
+       switch(redflag)
+       {
                case 1: red_icon = "flag_red_taken"; break;
                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_2))
+                       if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_1))
                                red_icon = "flag_red_shielded";
                        else
                                red_icon = string_null;
                        break;
        }
-       switch(redflag_prevstatus) {
+       switch(redflag_prevstatus)
+       {
                case 1: red_icon_prevstatus = "flag_red_taken"; break;
                case 2: red_icon_prevstatus = "flag_red_lost"; break;
                case 3: red_icon_prevstatus = "flag_red_carrying"; red_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
                default:
                        if(redflag == 3)
                                red_icon_prevstatus = "flag_red_carrying"; // make it more visible
-                       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;
@@ -2954,52 +2995,192 @@ void HUD_Mod_CTF(vector pos, vector mySize)
        }
 
        string blue_icon, blue_icon_prevstatus;
-       float blue_alpha, blue_alpha_prevstatus;
+       int blue_alpha, blue_alpha_prevstatus;
        blue_alpha = blue_alpha_prevstatus = 1;
-       switch(blueflag) {
+       switch(blueflag)
+       {
                case 1: blue_icon = "flag_blue_taken"; break;
                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_1))
+                       if((stat_items & CTF_SHIELDED) && (myteam != NUM_TEAM_2))
                                blue_icon = "flag_blue_shielded";
                        else
                                blue_icon = string_null;
                        break;
        }
-       switch(blueflag_prevstatus) {
+       switch(blueflag_prevstatus)
+       {
                case 1: blue_icon_prevstatus = "flag_blue_taken"; break;
                case 2: blue_icon_prevstatus = "flag_blue_lost"; break;
                case 3: blue_icon_prevstatus = "flag_blue_carrying"; blue_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
                default:
                        if(blueflag == 3)
                                blue_icon_prevstatus = "flag_blue_carrying"; // make it more visible
-                       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;
+       int 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 & 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 & 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;
+       int 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 & 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 & CTF_SHIELDED) && (myteam != NUM_TEAM_4))
+                               pink_icon_prevstatus = "flag_pink_shielded";
+                       else
+                               pink_icon_prevstatus = string_null;
+                       break;
+       }
+
+       string neutral_icon, neutral_icon_prevstatus;
+       int 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)
@@ -3012,6 +3193,24 @@ void HUD_Mod_CTF(vector pos, vector mySize)
                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 788dd871eed84f74e2050375211ef9eca122ee20..1cef3616482f7f93db5010f75d2871cb52115a35 100644 (file)
@@ -204,6 +204,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");
diff --git a/qcsrc/common/items.qh b/qcsrc/common/items.qh
new file mode 100644 (file)
index 0000000..194f91d
--- /dev/null
@@ -0,0 +1,145 @@
+const float BOT_PICKUP_RATING_LOW      = 2500;
+const float BOT_PICKUP_RATING_MID      = 5000;
+const float BOT_PICKUP_RATING_HIGH     = 10000;
+
+const float WEP_TYPE_OTHER           =  0x00; // not for damaging people
+const float WEP_TYPE_SPLASH          =  0x01; // splash damage
+const float WEP_TYPE_HITSCAN         =  0x02; // hitscan
+const float WEP_TYPEMASK            =  0x0F;
+const float WEP_FLAG_CANCLIMB       =  0x10; // can be used for movement
+const float WEP_FLAG_NORMAL         =  0x20; // in "most weapons" set
+const float WEP_FLAG_HIDDEN         =  0x40; // hides from menu
+const float WEP_FLAG_RELOADABLE     =  0x80; // can has reload
+const float WEP_FLAG_SUPERWEAPON    = 0x100; // powerup timer
+const float WEP_FLAG_MUTATORBLOCKED = 0x200; // hides from impulse 99 etc. (mutators are allowed to clear this flag)
+
+const float    IT_UNLIMITED_WEAPON_AMMO     = 1;
+// when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup.
+const float    IT_UNLIMITED_SUPERWEAPONS    = 2;
+// when this bit is set, superweapons don't expire. Checkpoints can give this powerup.
+const float   IT_CTF_SHIELDED              = 4; // set for the flag shield
+const float   IT_USING_JETPACK             = 8; // confirmation that button is pressed
+const float   IT_JETPACK                   = 16; // actual item
+const float   IT_FUEL_REGEN                = 32; // fuel regeneration trigger
+WANT_CONST float   IT_SHELLS                    = 256;
+WANT_CONST float   IT_NAILS                     = 512;
+WANT_CONST float   IT_ROCKETS                   = 1024;
+WANT_CONST float   IT_CELLS                     = 2048;
+const float   IT_SUPERWEAPON               = 4096;
+const float   IT_FUEL                      = 128;
+const float   IT_STRENGTH                  = 8192;
+const float   IT_INVINCIBLE                = 16384;
+const float   IT_HEALTH                    = 32768;
+// union:
+       // for items:
+       WANT_CONST float        IT_KEY1                                 = 131072;
+       WANT_CONST float        IT_KEY2                                 = 262144;
+
+// end
+const float   IT_5HP                       = 524288;
+const float   IT_25HP                      = 1048576;
+const float   IT_ARMOR_SHARD               = 2097152;
+const float   IT_ARMOR                     = 4194304;
+
+const float   IT_AMMO                      = 3968; // IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS | IT_FUEL;
+const float   IT_PICKUPMASK                = 51; // IT_FUEL_REGEN | IT_JETPACK | IT_UNLIMITED_AMMO; // strength and invincible are handled separately
+const float   IT_UNLIMITED_AMMO            = 3; // IT_UNLIMITED_SUPERWEAPONS | IT_UNLIMITED_WEAPON_AMMO;
+
+// variables:
+string weaponorder_byid;
+
+// functions:
+entity get_weaponinfo(float id);
+string W_FixWeaponOrder(string order, float complete);
+string W_NameWeaponOrder(string order);
+string W_NumberWeaponOrder(string order);
+
+// ammo types
+.float ammo_shells;
+.float ammo_nails;
+.float ammo_rockets;
+.float ammo_cells;
+.float ammo_fuel;
+.float ammo_batteries; // dummy
+
+// Weapon sets
+typedef vector WepSet;
+WepSet WepSet_FromWeapon(float a);
+#ifdef SVQC
+void WepSet_AddStat();
+void WriteWepSet(float dest, WepSet w);
+#endif
+#ifdef CSQC
+WepSet WepSet_GetFromStat();
+WepSet ReadWepSet();
+#endif
+
+// Weapon name macros
+#define WEP_FIRST 1
+#define WEP_MAXCOUNT 24 // Increase as needed. Can be up to three times as much.
+float WEP_COUNT;
+float WEP_LAST;
+WepSet WEPSET_ALL;
+WepSet WEPSET_SUPERWEAPONS;
+
+// entity properties of weaponinfo:
+.float weapon; // WEP_...
+.WepSet weapons; // WEPSET_...
+.string netname; // short name
+.string message; // human readable name
+.float items; // IT_...
+.float(float) weapon_func; // w_...
+.string mdl; // modelname without g_, v_, w_
+.string model; // full name of g_ model
+.float spawnflags; // WEPSPAWNFLAG_... combined
+.float impulse; // weapon impulse
+.float bot_pickupbasevalue; // bot weapon priority
+.string model2; // wpn- sprite name
+..float ammo_field; // main ammo field
+
+// dynamic weapon adding
+float w_null(float dummy);
+void register_weapon(float id, WepSet bit, float(float) func, float ammotype, float i, float weapontype, float pickupbasevalue, string modelname, string shortname, string wname);
+void register_weapons_done();
+
+#define REGISTER_WEAPON_2(id,bit,func,ammotype,i,weapontype,pickupbasevalue,modelname,shortname,wname) \
+       float id; \
+       WepSet bit; \
+       float func(float); \
+       void RegisterWeapons_##id() \
+       { \
+               WEP_LAST = (id = WEP_FIRST + WEP_COUNT); \
+               bit = WepSet_FromWeapon(id); \
+               WEPSET_ALL |= bit; \
+               if((weapontype) & WEP_FLAG_SUPERWEAPON) \
+                       WEPSET_SUPERWEAPONS |= bit; \
+               ++WEP_COUNT; \
+               register_weapon(id,bit,func,ammotype,i,weapontype,pickupbasevalue,modelname,shortname,wname); \
+       } \
+       ACCUMULATE_FUNCTION(RegisterWeapons, RegisterWeapons_##id)
+#ifdef MENUQC
+#define REGISTER_WEAPON(id,func,ammotype,i,weapontype,pickupbasevalue,modelname,shortname,wname) \
+       REGISTER_WEAPON_2(WEP_##id,WEPSET_##id,w_null,ammotype,i,weapontype,pickupbasevalue,modelname,shortname,wname)
+#else
+#define REGISTER_WEAPON(id,func,ammotype,i,weapontype,pickupbasevalue,modelname,shortname,wname) \
+       REGISTER_WEAPON_2(WEP_##id,WEPSET_##id,func,ammotype,i,weapontype,pickupbasevalue,modelname,shortname,wname)
+#endif
+
+#include "../server/w_all.qc"
+
+#undef REGISTER_WEAPON
+ACCUMULATE_FUNCTION(RegisterWeapons, register_weapons_done);
+
+
+string W_FixWeaponOrder(string order, float complete);
+string W_NumberWeaponOrder(string order);
+string W_NameWeaponOrder(string order);
+string W_FixWeaponOrder_BuildImpulseList(string o);
+string W_FixWeaponOrder_AllowIncomplete(string order);
+string W_FixWeaponOrder_ForceComplete(string order);
+
+void W_RandomWeapons(entity e, float n);
+
+string W_Name(float weaponid);
+
+float W_AmmoItemCode(float wpn);
index 1cb1adf51f368e9e97ad2d3b5afebc2cbb8595ee..d582a560fba6c93b233c4976657953c1a5307194 100644 (file)
@@ -346,25 +346,34 @@ 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_, 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(2, INFO_COINTOSS,                       1, 0, "s1", "",                          "",                     _("^F2Throwing coin... Result: %s^F2!"), "") \
     MSG_INFO_NOTIF(1, INFO_JETPACK_NOFUEL,                 0, 0, "", "",                            "",                     _("^BGYou don't have any fuel for the ^F1Jetpack"), "") \
     MSG_INFO_NOTIF(2, INFO_SUPERSPEC_MISSING_UID,          0, 0, "", "",                            "",                     _("^F2You lack a UID, superspec options will not be saved/restored"), "") \
     MSG_INFO_NOTIF(1, INFO_CA_JOIN_LATE,                   0, 0, "", "",                            "",                     _("^F1Round already started, you will join the game in the next round"), "") \
     MSG_INFO_NOTIF(1, INFO_CA_LEAVE,                       0, 0, "", "",                            "",                     _("^F2You will spectate in the next round"), "") \
-    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"), "") \
     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"), "") \
@@ -595,20 +604,34 @@ void Send_Notification_WOCOVA(
     MSG_CENTER_NOTIF(1, CENTER_CAMPCHECK,                   0, 0, "",             CPID_CAMPCHECK,      "0 0", _("^F2Don't camp!"), "") \
     MSG_CENTER_NOTIF(1, CENTER_COINTOSS,                    1, 0, "s1",           NO_CPID,             "0 0", _("^F2Throwing coin... Result: %s^F2!"), "") \
     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!"), "") \
+    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")) \
@@ -921,11 +944,14 @@ void Send_Notification_WOCOVA(
     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) \
@@ -1320,9 +1346,9 @@ float NOTIF_CHOICE_COUNT;
 // notification limits -- INCREASE AS NECESSARY
 const float NOTIF_ANNCE_MAX   = 100;
 const float NOTIF_INFO_MAX    = 300;
-const float NOTIF_CENTER_MAX  = 200;
+const float NOTIF_CENTER_MAX  = 250;
 const float NOTIF_MULTI_MAX   = 200;
-const float NOTIF_CHOICE_MAX  = 20;
+const float NOTIF_CHOICE_MAX  = 30;
 
 // notification entities
 entity msg_annce_notifs[NOTIF_ANNCE_MAX];
index 481713cc9cb8f17df86aad4be260f8fd6f5ba76a..28ec85e30a7cedf7d8c485ba1365403d6f35336e 100644 (file)
@@ -92,7 +92,7 @@ const int STAT_HEALING_ORB_ALPHA      = 83;
 const int STAT_PLASMA                 = 84;
 const int STAT_OK_AMMO_CHARGE         = 85;
 const int STAT_OK_AMMO_CHARGEPOOL     = 86;
-// 87 empty?
+const int STAT_CTF_FLAGSTATUS         = 87;
 // 88 empty?
 // 89 empty?
 // 90 empty?
index f84eb008b2a7aef5f6ba26a84d6c9218fca563ed..65595a0f15a554687c4c9fa5d36d732fd2475e1e 100644 (file)
@@ -238,6 +238,7 @@ float autocvar_g_ctf_throw_velocity_forward;
 float autocvar_g_ctf_throw_velocity_up;
 float autocvar_g_ctf_drop_velocity_up;
 float autocvar_g_ctf_drop_velocity_side;
+bool autocvar_g_ctf_oneflag_reverse;
 bool autocvar_g_ctf_portalteleport;
 bool autocvar_g_ctf_pass;
 float autocvar_g_ctf_pass_arc;
@@ -251,19 +252,18 @@ float autocvar_g_ctf_pass_turnrate;
 float autocvar_g_ctf_pass_timelimit;
 float autocvar_g_ctf_pass_velocity;
 bool autocvar_g_ctf_dynamiclights;
-string autocvar_g_ctf_flag_blue_model;
-int autocvar_g_ctf_flag_blue_skin;
 float autocvar_g_ctf_flag_collect_delay;
 float autocvar_g_ctf_flag_damageforcescale;
-int autocvar_g_ctf_flag_dropped_waypoint;
-float autocvar_g_ctf_flag_dropped_floatinwater;
+bool autocvar_g_ctf_flag_dropped_waypoint;
+bool autocvar_g_ctf_flag_dropped_floatinwater;
 bool autocvar_g_ctf_flag_glowtrails;
-float autocvar_g_ctf_flag_health;
-string autocvar_g_ctf_flag_red_model;
-int autocvar_g_ctf_flag_red_skin;
+int autocvar_g_ctf_flag_health;
+bool autocvar_g_ctf_flag_return;
+float autocvar_g_ctf_flag_return_carried_radius;
 float autocvar_g_ctf_flag_return_time;
 bool 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;
 float autocvar_g_ctf_flagcarrier_auto_helpme_damage;
 float autocvar_g_ctf_flagcarrier_auto_helpme_time;
@@ -278,7 +278,6 @@ int autocvar_g_ctf_score_capture;
 int autocvar_g_ctf_score_capture_assist;
 int autocvar_g_ctf_score_kill;
 int autocvar_g_ctf_score_penalty_drop;
-//int autocvar_g_ctf_score_penalty_suicidedrop;
 int autocvar_g_ctf_score_penalty_returned;
 int autocvar_g_ctf_score_pickup_base;
 int autocvar_g_ctf_score_pickup_dropped_early;
index 0cbcf714c906f956c979c47257a496634ebf894e..a42f2919a48433ded4a83f31e2b80e85e4a58b0d 100644 (file)
@@ -14,10 +14,11 @@ void ctf_FakeTimeLimit(entity e, float t)
                WriteCoord(MSG_ONE, (t + 1) / 60);
 }
 
-void ctf_EventLog(string mode, float flagteam, entity actor) // use an alias for easy changing and quick editing later
+void ctf_EventLog(string mode, int flagteam, entity actor) // use an alias for easy changing and quick editing later
 {
        if(autocvar_sv_eventlog)
-               GameLogEcho(strcat(":ctf:", mode, ":", ftos(flagteam), ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
+               GameLogEcho(sprintf(":ctf:%s:%d:%d:%s", mode, flagteam, actor.team, ((actor != world) ? ftos(actor.playerid) : "")));
+               //GameLogEcho(strcat(":ctf:", mode, ":", ftos(flagteam), ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
 }
 
 void ctf_CaptureRecord(entity flag, entity player)
@@ -27,11 +28,13 @@ void ctf_CaptureRecord(entity flag, entity player)
        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_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;
@@ -80,7 +83,7 @@ void ctf_CalculatePassVelocity(entity flag, vector to, vector from, float turnra
        else { flag.velocity = (desired_direction * autocvar_g_ctf_pass_velocity); }
 }
 
-float ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
+bool ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
 {
        if(autocvar_g_ctf_pass_directional_max || autocvar_g_ctf_pass_directional_min)
        {
@@ -114,17 +117,23 @@ float ctf_CheckPassDirection(vector head_center, vector passer_center, vector pa
 // CaptureShield Functions
 // =======================
 
-float ctf_CaptureShield_CheckStatus(entity p)
+bool ctf_CaptureShield_CheckStatus(entity p)
 {
-       float s, se;
+       int s, s2, s3, s4, se, se2, se3, se4, sr, ser;
        entity e;
-       float players_worseeq, players_total;
+       int players_worseeq, players_total;
 
        if(ctf_captureshield_max_ratio <= 0)
                return false;
 
-       s = PlayerScore_Add(p, SP_SCORE, 0);
-       if(s >= -ctf_captureshield_min_negscore)
+       s = PlayerScore_Add(p, SP_CTF_CAPS, 0);
+       s2 = PlayerScore_Add(p, SP_CTF_PICKUPS, 0);
+       s3 = PlayerScore_Add(p, SP_CTF_RETURNS, 0);
+       s4 = PlayerScore_Add(p, SP_CTF_FCKILLS, 0);
+
+       sr = ((s - s2) + (s3 + s4));
+
+       if(sr >= -ctf_captureshield_min_negscore)
                return false;
 
        players_total = players_worseeq = 0;
@@ -132,8 +141,14 @@ float ctf_CaptureShield_CheckStatus(entity p)
        {
                if(DIFF_TEAM(e, p))
                        continue;
-               se = PlayerScore_Add(e, SP_SCORE, 0);
-               if(se <= s)
+               se = PlayerScore_Add(e, SP_CTF_CAPS, 0);
+               se2 = PlayerScore_Add(e, SP_CTF_PICKUPS, 0);
+               se3 = PlayerScore_Add(e, SP_CTF_RETURNS, 0);
+               se4 = PlayerScore_Add(e, SP_CTF_FCKILLS, 0);
+
+               ser = ((se - se2) + (se3 + se4));
+
+               if(ser <= sr)
                        ++players_worseeq;
                ++players_total;
        }
@@ -147,9 +162,9 @@ float ctf_CaptureShield_CheckStatus(entity p)
        return true;
 }
 
-void ctf_CaptureShield_Update(entity player, float wanted_status)
+void ctf_CaptureShield_Update(entity player, bool wanted_status)
 {
-       float updated_status = ctf_CaptureShield_CheckStatus(player);
+       bool updated_status = ctf_CaptureShield_CheckStatus(player);
        if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only
        {
                Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((updated_status) ? CENTER_CTF_CAPTURESHIELD_SHIELDED : CENTER_CTF_CAPTURESHIELD_FREE));
@@ -157,10 +172,10 @@ void ctf_CaptureShield_Update(entity player, float wanted_status)
        }
 }
 
-float ctf_CaptureShield_Customize()
+bool ctf_CaptureShield_Customize()
 {
        if(!other.ctf_captureshielded) { return false; }
-       if(SAME_TEAM(self, other)) { return false; }
+       if(CTF_SAMETEAM(self, other)) { return false; }
 
        return true;
 }
@@ -168,7 +183,7 @@ float ctf_CaptureShield_Customize()
 void ctf_CaptureShield_Touch()
 {
        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;
@@ -202,7 +217,7 @@ void ctf_CaptureShield_Spawn(entity flag)
 // Drop/Pass/Throw Code
 // ====================
 
-void ctf_Handle_Drop(entity flag, entity player, float droptype)
+void ctf_Handle_Drop(entity flag, entity player, int droptype)
 {
        // declarations
        player = (player ? player : flag.pass_sender);
@@ -217,7 +232,7 @@ void ctf_Handle_Drop(entity flag, entity player, float droptype)
        flag.ctf_status = FLAG_DROPPED;
 
        // messages and sounds
-       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);
 
@@ -279,11 +294,11 @@ void ctf_Handle_Retrieve(entity flag, entity player)
        FOR_EACH_REALPLAYER(tmp_player)
        {
                if(tmp_player == sender)
-                       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_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_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
@@ -297,7 +312,7 @@ void ctf_Handle_Retrieve(entity flag, entity player)
        flag.pass_target = world;
 }
 
-void ctf_Handle_Throw(entity player, entity receiver, float droptype)
+void ctf_Handle_Throw(entity player, entity receiver, int droptype)
 {
        entity flag = player.flagcarried;
        vector targ_origin, flag_velocity;
@@ -387,20 +402,33 @@ void ctf_Handle_Throw(entity player, entity receiver, float droptype)
 // Event Handlers
 // ==============
 
-void ctf_Handle_Capture(entity flag, entity toucher, float capturetype)
+void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
 {
        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)
+       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;
+       }
 
        nades_GiveBonus(player, autocvar_g_nades_bonus_score_high );
 
+       player.throw_prevtime = time;
+       player.throw_count = 0;
+
        // messages and sounds
-       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, 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)
        {
@@ -442,12 +470,12 @@ void ctf_Handle_Return(entity flag, entity player)
        // 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);
@@ -470,14 +498,19 @@ void ctf_Handle_Return(entity flag, entity player)
                flag.ctf_dropper.next_take_time = time + autocvar_g_ctf_flag_collect_delay; // set next take time
        }
 
+       // other
+       if(player.flagcarried == flag)
+               WaypointSprite_Kill(player.wps_flagcarrier);
+
        // reset the flag
        ctf_RespawnFlag(flag);
 }
 
-void ctf_Handle_Pickup(entity flag, entity player, float pickuptype)
+void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
 {
        // declarations
        float pickup_dropped_score; // used to calculate dropped pickup score
+       entity tmp_entity; // temporary entity
 
        // attach the flag to the player
        flag.owner = player;
@@ -509,12 +542,28 @@ void ctf_Handle_Pickup(entity flag, entity player, float pickuptype)
        }
 
        // messages and sounds
-       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); }
-
-       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, ((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);
 
@@ -565,7 +614,7 @@ void ctf_Handle_Pickup(entity flag, entity player, float pickuptype)
 // Main Flag Functions
 // ===================
 
-void ctf_CheckFlagReturn(entity flag, float returntype)
+void ctf_CheckFlagReturn(entity flag, int returntype)
 {
        if((flag.ctf_status == FLAG_DROPPED) || (flag.ctf_status == FLAG_PASSING))
        {
@@ -575,14 +624,14 @@ void ctf_CheckFlagReturn(entity flag, float returntype)
                {
                        switch(returntype)
                        {
-                               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_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);
@@ -591,10 +640,25 @@ void ctf_CheckFlagReturn(entity flag, float returntype)
        }
 }
 
+bool ctf_Stalemate_Customize()
+{
+       // make spectators see what the player would see
+       entity e, wp_owner;
+       e = WaypointSprite_getviewentity(other);
+       wp_owner = self.owner;
+
+       // team waypoints
+       if(CTF_SAMETEAM(wp_owner.flagcarried, wp_owner)) { return false; }
+       if(SAME_TEAM(wp_owner, e)) { return false; }
+       if(!IS_PLAYER(e)) { return false; }
+
+       return true;
+}
+
 void ctf_CheckStalemate(void)
 {
        // declarations
-       float stale_red_flags = 0, stale_blue_flags = 0;
+       int 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
@@ -604,7 +668,7 @@ void ctf_CheckStalemate(void)
        {
                if(autocvar_g_ctf_stalemate)
                if(tmp_entity.ctf_status != FLAG_BASE)
-               if(time >= tmp_entity.ctf_pickuptime + autocvar_g_ctf_stalemate_time)
+               if(time >= tmp_entity.ctf_pickuptime + autocvar_g_ctf_stalemate_time || !tmp_entity.team) // instant stalemate in oneflag
                {
                        tmp_entity.ctf_staleflagnext = ctf_staleflaglist; // link flag into staleflaglist
                        ctf_staleflaglist = tmp_entity;
@@ -613,15 +677,25 @@ void ctf_CheckStalemate(void)
                        {
                                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;
                        }
                }
        }
 
-       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(ctf_oneflag && stale_flags == 1)
+               ctf_stalemate = true;
+       else if(stale_flags >= 2)
                ctf_stalemate = true;
-       else if((!stale_red_flags && !stale_blue_flags) && autocvar_g_ctf_stalemate_endcondition == 2)
+       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 < 2 && 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
@@ -630,7 +704,10 @@ void ctf_CheckStalemate(void)
                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(((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)
@@ -647,9 +724,15 @@ void ctf_FlagDamage(entity inflictor, entity attacker, float damage, int deathty
 {
        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)
@@ -732,7 +815,13 @@ void ctf_FlagThink()
                                        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);
@@ -762,6 +851,13 @@ void ctf_FlagThink()
                                        wpforenemy_nextthink = time + WPFE_THINKRATE; // waypoint for enemy think rate (to reduce unnecessary spam of this check)
                                }
                        }
+                       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;
                }
 
@@ -802,17 +898,22 @@ void ctf_FlagTouch()
        if(gameover) { return; }
        if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
 
-       entity toucher = other;
-       float is_not_monster = (!(toucher.flags & FL_MONSTER));
+       entity toucher = other, tmp_entity;
+       bool 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);
-               return;
+               if(!autocvar_g_ctf_flag_return_damage_delay)
+               {
+                       self.health = 0;
+                       ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
+               }
+               if(!self.ctf_flagdamaged) { return; }
        }
 
+       FOR_EACH_PLAYER(tmp_entity) if(SAME_TEAM(toucher, tmp_entity)) { ++num_perteam; }
+
        // special touch behaviors
        if(toucher.frozen) { return; }
        else if(toucher.vehicle_flags & VHF_ISVEHICLE)
@@ -843,16 +944,23 @@ void ctf_FlagTouch()
        {
                case FLAG_BASE:
                {
-                       if(SAME_TEAM(toucher, self) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, self) && is_not_monster)
+                       if(ctf_oneflag)
+                       {
+                               if(CTF_SAMETEAM(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(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
@@ -891,9 +999,7 @@ void ctf_RespawnFlag(entity flag)
        // reset the player (if there is one)
        if((flag.owner) && (flag.owner.flagcarried == flag))
        {
-               if(flag.owner.wps_enemyflagcarrier)
-                       WaypointSprite_Kill(flag.owner.wps_enemyflagcarrier);
-
+               WaypointSprite_Kill(flag.owner.wps_enemyflagcarrier);
                WaypointSprite_Kill(flag.wps_flagcarrier);
 
                flag.owner.flagcarried = world;
@@ -905,7 +1011,7 @@ void ctf_RespawnFlag(entity flag)
        if((flag.owner) && (flag.owner.vehicle))
                flag.scale = FLAG_SCALE;
 
-       if((flag.ctf_status == FLAG_DROPPED) && (flag.wps_flagdropped))
+       if(flag.ctf_status == FLAG_DROPPED)
                { WaypointSprite_Kill(flag.wps_flagdropped); }
 
        // reset the flag
@@ -928,6 +1034,7 @@ void ctf_RespawnFlag(entity flag)
        flag.ctf_dropper = world;
        flag.ctf_pickuptime = 0;
        flag.ctf_droptime = 0;
+       flag.ctf_flagdamaged = 0;
 
        ctf_CheckStalemate();
 }
@@ -949,17 +1056,34 @@ void ctf_DelayedFlagSetup(void) // called after a flag is placed on a map by ctf
        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, ((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'));
 
        // captureshield setup
        ctf_CaptureShield_Spawn(self);
 }
 
-void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
+void set_flag_string(entity flag, .string field, string value, string teamname)
+{
+       if(flag.field == "")
+               flag.field = strzone(sprintf(value,teamname));
+}
+
+void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
 {
        // declarations
-       teamnumber = fabs(teamnumber - bound(0, autocvar_g_ctf_reverse, 1)); // if we were originally 1, this will become 0. If we were originally 0, this will become 1.
+       string teamname = Static_Team_ColorName_Lower(teamnumber);
        self = flag; // for later usage with droptofloor()
 
        // main setup
@@ -968,9 +1092,8 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
 
        setattachment(flag, world, "");
 
-       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 = strzone(sprintf("%s%s^7 flag", Team_ColorCode(teamnumber), Team_ColorName_Upper(teamnumber)));
+       flag.team = teamnumber;
        flag.classname = "item_flag_team";
        flag.target = "###item###"; // wut?
        flag.flags = FL_ITEM | FL_NOTARGET;
@@ -982,6 +1105,7 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
        flag.event_damage = ctf_FlagDamage;
        flag.pushable = true;
        flag.teleportable = TELEPORT_NORMAL;
+       flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
        flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
        flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable;
        flag.velocity = '0 0 0';
@@ -993,21 +1117,21 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
        flag.ctf_status = FLAG_BASE;
 
        // appearence
-       if(flag.model == "")       { flag.model = ((teamnumber) ? autocvar_g_ctf_flag_red_model : autocvar_g_ctf_flag_blue_model); }
-       if(!flag.scale)            { flag.scale = FLAG_SCALE; }
-       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"); }
-
-       // sound
-       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_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_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(!flag.scale)                         { flag.scale = FLAG_SCALE; }
+       if(flag.skin == 0)                      { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
+       if(flag.model == "")            { flag.model = cvar_string(sprintf("g_ctf_flag_%s_model", teamname)); }
+       set_flag_string(flag, toucheffect,      "%sflag_touch", teamname);
+       set_flag_string(flag, passeffect,       "%sflag_pass",  teamname);
+       set_flag_string(flag, capeffect,        "%sflag_cap",   teamname);
+
+       // sounds
+       set_flag_string(flag, snd_flag_taken,           "ctf/%s_taken.wav",     teamname);
+       set_flag_string(flag, snd_flag_returned,        "ctf/%s_returned.wav",  teamname);
+       set_flag_string(flag, snd_flag_capture,         "ctf/%s_capture.wav",   teamname);
+       set_flag_string(flag, snd_flag_dropped,         "ctf/%s_dropped.wav",   teamname);
+       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_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
 
        // precache
        precache_sound(flag.snd_flag_taken);
@@ -1028,15 +1152,32 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
 
        if(autocvar_g_ctf_flag_glowtrails)
        {
-               flag.glow_color = ((teamnumber) ? 251 : 210); // 251: red - 210: blue
+               switch(teamnumber)
+               {
+                       case NUM_TEAM_1: flag.glow_color = 251; break;
+                       case NUM_TEAM_2: flag.glow_color = 210; break;
+                       case NUM_TEAM_3: flag.glow_color = 110; break;
+                       case NUM_TEAM_4: flag.glow_color = 145; break;
+                       default:                 flag.glow_color = 254; break;
+               }
                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
        {
@@ -1089,7 +1230,7 @@ entity havocbot_ctf_find_flag(entity bot)
        f = ctf_worldflaglist;
        while (f)
        {
-               if (bot.team == f.team)
+               if (CTF_SAMETEAM(bot, f))
                        return f;
                f = f.ctf_worldflagnext;
        }
@@ -1102,24 +1243,37 @@ entity havocbot_ctf_find_enemy_flag(entity bot)
        f = ctf_worldflaglist;
        while (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;
        }
        return world;
 }
 
-float havocbot_ctf_teamcount(entity bot, vector org, float tc_radius)
+int havocbot_ctf_teamcount(entity bot, vector org, float tc_radius)
 {
        if (!teamplay)
                return 0;
 
-       float c = 0;
+       int c = 0;
        entity head;
 
        FOR_EACH_PLAYER(head)
        {
-               if(head.team!=bot.team || head.deadflag != DEAD_NO || head == bot)
+               if(DIFF_TEAM(head, bot) || head.deadflag != DEAD_NO || head == bot)
                        continue;
 
                if(vlen(head.origin - org) < tc_radius)
@@ -1135,7 +1289,7 @@ void havocbot_goalrating_ctf_ourflag(float ratingscale)
        head = ctf_worldflaglist;
        while (head)
        {
-               if (self.team == head.team)
+               if (CTF_SAMETEAM(self, head))
                        break;
                head = head.ctf_worldflagnext;
        }
@@ -1149,7 +1303,7 @@ void havocbot_goalrating_ctf_ourbase(float ratingscale)
        head = ctf_worldflaglist;
        while (head)
        {
-               if (self.team == head.team)
+               if (CTF_SAMETEAM(self, head))
                        break;
                head = head.ctf_worldflagnext;
        }
@@ -1165,7 +1319,20 @@ void havocbot_goalrating_ctf_enemyflag(float ratingscale)
        head = ctf_worldflaglist;
        while (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;
        }
@@ -1333,7 +1500,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);
@@ -1667,7 +1837,7 @@ void havocbot_role_ctf_defense()
        }
 }
 
-void havocbot_role_ctf_setrole(entity bot, float role)
+void havocbot_role_ctf_setrole(entity bot, int role)
 {
        dprint(strcat(bot.netname," switched to "));
        switch(role)
@@ -1720,28 +1890,39 @@ void havocbot_role_ctf_setrole(entity bot, float role)
 MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
 {
        entity flag;
+       int 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_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 = 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 |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_CARRYING : IT_BLUE_FLAG_CARRYING); // carrying: self is currently carrying the flag
-                               else
-                                       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 |= ((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;
                        }
                }
@@ -1749,7 +1930,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
 
        // 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)
@@ -1773,7 +1954,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values t
                        frag_force *= autocvar_g_ctf_flagcarrier_forcefactor;
                }
        }
-       else if(frag_target.flagcarried && (frag_target.deadflag == DEAD_NO) && DIFF_TEAM(frag_target, frag_attacker)) // if the target is a flagcarrier
+       else if(frag_target.flagcarried && (frag_target.deadflag == DEAD_NO) && CTF_DIFFTEAM(frag_target, frag_attacker)) // if the target is a flagcarrier
        {
                if(autocvar_g_ctf_flagcarrier_auto_helpme_damage > ('1 0 0' * healtharmor_maxdamage(frag_target.health, frag_target.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON)))
                if(time > frag_target.wps_helpme_time + autocvar_g_ctf_flagcarrier_auto_helpme_time)
@@ -1795,7 +1976,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;
 }
@@ -1980,7 +2165,7 @@ MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun)
 {
        if(self.flagcarried)
        {
-               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;
        }
@@ -2028,6 +2213,19 @@ MUTATOR_HOOKFUNCTION(ctf_BotRoles)
        return true;
 }
 
+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
@@ -2094,7 +2292,7 @@ void spawnfunc_item_flag_team1()
 {
        if(!g_ctf) { remove(self); return; }
 
-       ctf_FlagSetup(1, self); // 1 = red
+       ctf_FlagSetup(NUM_TEAM_1, self);
 }
 
 /*QUAKED spawnfunc_item_flag_team2 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
@@ -2112,7 +2310,62 @@ 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 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; }
+       if(!cvar("g_ctf_oneflag")) { remove(self); return; }
+
+       ctf_FlagSetup(0, self);
 }
 
 /*QUAKED spawnfunc_ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32)
@@ -2143,9 +2396,10 @@ void spawnfunc_team_CTF_bluespawn()  { spawnfunc_info_player_team2();  }
 // ==============
 
 // scoreboard setup
-void ctf_ScoreRules()
+void ctf_ScoreRules(int teams)
 {
-       ScoreRules_basics(2, SFL_SORT_PRIO_PRIMARY, 0, true);
+       CheckAllowedTeams(world);
+       ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
        ScoreInfo_SetLabel_TeamScore  (ST_CTF_CAPS,     "caps",      SFL_SORT_PRIO_PRIMARY);
        ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPS,     "caps",      SFL_SORT_PRIO_SECONDARY);
        ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPTIME,  "captime",   SFL_LOWER_IS_BETTER | SFL_TIME);
@@ -2157,7 +2411,7 @@ void ctf_ScoreRules()
 }
 
 // code from here on is just to support maps that don't have flag and team entities
-void ctf_SpawnTeam (string teamname, float teamcolor)
+void ctf_SpawnTeam (string teamname, int teamcolor)
 {
        entity oldself;
        oldself = self;
@@ -2173,15 +2427,31 @@ void ctf_SpawnTeam (string teamname, float teamcolor)
 
 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)
        {
                print("No ""ctf_team"" entities found on this map, creating them anyway.\n");
                ctf_SpawnTeam("Red", NUM_TEAM_1 - 1);
                ctf_SpawnTeam("Blue", NUM_TEAM_2 - 1);
+               if(ctf_teams >= 3)
+                       ctf_SpawnTeam("Yellow", NUM_TEAM_3 - 1);
+               if(ctf_teams >= 4)
+                       ctf_SpawnTeam("Pink", NUM_TEAM_4 - 1);
        }
 
-       ctf_ScoreRules();
+       ctf_ScoreRules(ctf_teams);
 }
 
 void ctf_Initialize()
@@ -2192,6 +2462,8 @@ void ctf_Initialize()
        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);
 }
 
@@ -2212,6 +2484,8 @@ MUTATOR_DEFINITION(gamemode_ctf)
        MUTATOR_HOOK(VehicleExit, ctf_VehicleExit, CBC_ORDER_ANY);
        MUTATOR_HOOK(AbortSpeedrun, ctf_AbortSpeedrun, CBC_ORDER_ANY);
        MUTATOR_HOOK(HavocBot_ChooseRole, ctf_BotRoles, CBC_ORDER_ANY);
+       MUTATOR_HOOK(GetTeamCount, ctf_GetTeamCount, CBC_ORDER_ANY);
+       MUTATOR_HOOK(SpectateCopy, ctf_SpectateCopy, CBC_ORDER_ANY);
 
        MUTATOR_ONADD
        {
index 0e5930db2cbe83c95b439e8f75461cdce64eda7f..d2572bc458896ef24159bc9ada697496ed6424aa 100644 (file)
@@ -7,13 +7,13 @@
 void ctf_RespawnFlag(entity flag);
 
 // score rule declarations
-const float ST_CTF_CAPS = 1;
-const float SP_CTF_CAPS = 4;
-const float SP_CTF_CAPTIME = 5;
-const float SP_CTF_PICKUPS = 6;
-const float SP_CTF_DROPS = 7;
-const float SP_CTF_FCKILLS = 8;
-const float SP_CTF_RETURNS = 9;
+const int ST_CTF_CAPS = 1;
+const int SP_CTF_CAPS = 4;
+const int SP_CTF_CAPTIME = 5;
+const int SP_CTF_PICKUPS = 6;
+const int SP_CTF_DROPS = 7;
+const int SP_CTF_FCKILLS = 8;
+const int SP_CTF_RETURNS = 9;
 
 // flag constants // for most of these, there is just one question to be asked: WHYYYYY?
 #define FLAG_MIN (PL_MIN + '0 0 -13')
@@ -25,20 +25,23 @@ const float FLAG_THINKRATE = 0.2;
 const float FLAG_TOUCHRATE = 0.5;
 const float WPFE_THINKRATE = 0.5;
 
-#define FLAG_DROP_OFFSET ('0 0 32')
-#define FLAG_CARRY_OFFSET ('-16 0 8')
+const vector FLAG_DROP_OFFSET = ('0 0 32');
+const vector FLAG_CARRY_OFFSET = ('-16 0 8');
 #define FLAG_SPAWN_OFFSET ('0 0 1' * (PL_MAX_z - 13))
-#define FLAG_WAYPOINT_OFFSET ('0 0 64')
-#define FLAG_FLOAT_OFFSET ('0 0 32')
-#define FLAG_PASS_ARC_OFFSET ('0 0 -10')
+const vector FLAG_WAYPOINT_OFFSET = ('0 0 64');
+const vector FLAG_FLOAT_OFFSET = ('0 0 32');
+const vector FLAG_PASS_ARC_OFFSET = ('0 0 -10');
+
+const vector VEHICLE_FLAG_OFFSET = ('0 0 90');
+
+
 
-#define VEHICLE_FLAG_OFFSET ('0 0 96')
 const float 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
@@ -67,42 +70,44 @@ entity ctf_worldflaglist;
 .entity wps_flagdropped;
 .entity wps_enemyflagcarrier;
 .float wps_helpme_time;
-float wpforenemy_announced;
+bool wpforenemy_announced;
 float wpforenemy_nextthink;
 
 // statuses
-const float FLAG_BASE = 1;
-const float FLAG_DROPPED = 2;
-const float FLAG_CARRY = 3;
-const float FLAG_PASSING = 4;
+const int FLAG_BASE = 1;
+const int FLAG_DROPPED = 2;
+const int FLAG_CARRY = 3;
+const int FLAG_PASSING = 4;
 
-const float DROP_NORMAL = 1;
-const float DROP_THROW = 2;
-const float DROP_PASS = 3;
-const float DROP_RESET = 4;
+const int DROP_NORMAL = 1;
+const int DROP_THROW = 2;
+const int DROP_PASS = 3;
+const int DROP_RESET = 4;
 
-const float PICKUP_BASE = 1;
-const float PICKUP_DROPPED = 2;
+const int PICKUP_BASE = 1;
+const int PICKUP_DROPPED = 2;
 
-const float CAPTURE_NORMAL = 1;
-const float CAPTURE_DROPPED = 2;
+const int CAPTURE_NORMAL = 1;
+const int CAPTURE_DROPPED = 2;
 
-const float RETURN_TIMEOUT = 1;
-const float RETURN_DROPPED = 2;
-const float RETURN_DAMAGE = 3;
-const float RETURN_SPEEDRUN = 4;
-const float RETURN_NEEDKILL = 5;
+const int RETURN_TIMEOUT = 1;
+const int RETURN_DROPPED = 2;
+const int RETURN_DAMAGE = 3;
+const int RETURN_SPEEDRUN = 4;
+const int RETURN_NEEDKILL = 5;
 
 // flag properties
 #define ctf_spawnorigin dropped_origin
-float ctf_stalemate; // indicates that a stalemate is active
+bool ctf_stalemate; // indicates that a stalemate is active
 float ctf_captimerecord; // record time for capturing the flag
 .float ctf_pickuptime;
 .float ctf_droptime;
-.float ctf_status; // status of the flag (FLAG_BASE, FLAG_DROPPED, FLAG_CARRY declared globally)
+.int ctf_status; // status of the flag (FLAG_BASE, FLAG_DROPPED, FLAG_CARRY declared globally)
 .entity ctf_dropper; // don't allow spam of dropping the flag
-.float max_flag_health;
+.int max_flag_health;
 .float next_take_time;
+.bool ctf_flagdamaged;
+int ctf_teams;
 
 // passing/throwing properties
 .float pass_distance;
@@ -110,28 +115,57 @@ float ctf_captimerecord; // record time for capturing the flag
 .entity pass_target;
 .float throw_antispam;
 .float throw_prevtime;
-.float throw_count;
+.int throw_count;
 
 // CaptureShield: If the player is too bad to be allowed to capture, shield them from taking the flag.
-.float ctf_captureshielded; // set to 1 if the player is too bad to be allowed to capture
+.bool ctf_captureshielded; // set to 1 if the player is too bad to be allowed to capture
 float ctf_captureshield_min_negscore; // punish at -20 points
 float ctf_captureshield_max_ratio; // punish at most 30% of each team
 float ctf_captureshield_force; // push force of the shield
 
+// 1 flag ctf
+bool ctf_oneflag; // indicates whether or not a neutral flag has been found
+
 // bot player logic
-const float HAVOCBOT_CTF_ROLE_NONE = 0;
-const float HAVOCBOT_CTF_ROLE_DEFENSE = 2;
-const float HAVOCBOT_CTF_ROLE_MIDDLE = 4;
-const float HAVOCBOT_CTF_ROLE_OFFENSE = 8;
-const float HAVOCBOT_CTF_ROLE_CARRIER = 16;
-const float HAVOCBOT_CTF_ROLE_RETRIEVER = 32;
-const float HAVOCBOT_CTF_ROLE_ESCORT = 64;
+const int HAVOCBOT_CTF_ROLE_NONE = 0;
+const int HAVOCBOT_CTF_ROLE_DEFENSE = 2;
+const int HAVOCBOT_CTF_ROLE_MIDDLE = 4;
+const int HAVOCBOT_CTF_ROLE_OFFENSE = 8;
+const int HAVOCBOT_CTF_ROLE_CARRIER = 16;
+const int HAVOCBOT_CTF_ROLE_RETRIEVER = 32;
+const int HAVOCBOT_CTF_ROLE_ESCORT = 64;
 
-.float havocbot_cantfindflag;
+.bool havocbot_cantfindflag;
 
 vector havocbot_ctf_middlepoint;
 float havocbot_ctf_middlepoint_radius;
 
-void havocbot_role_ctf_setrole(entity bot, float role);
+void havocbot_role_ctf_setrole(entity bot, int role);
+
+// team checking
+#define CTF_SAMETEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? DIFF_TEAM(a,b) : SAME_TEAM(a,b))
+#define CTF_DIFFTEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? SAME_TEAM(a,b) : DIFF_TEAM(a,b))
+
+// networked flag statuses
+.int ctf_flagstatus;
 #endif
+
+const int CTF_RED_FLAG_TAKEN                   = 1;
+const int CTF_RED_FLAG_LOST                            = 2;
+const int CTF_RED_FLAG_CARRYING                        = 3;
+const int CTF_BLUE_FLAG_TAKEN                  = 4;
+const int CTF_BLUE_FLAG_LOST                   = 8;
+const int CTF_BLUE_FLAG_CARRYING               = 12;
+const int CTF_YELLOW_FLAG_TAKEN                        = 16;
+const int CTF_YELLOW_FLAG_LOST                 = 32;
+const int CTF_YELLOW_FLAG_CARRYING             = 48;
+const int CTF_PINK_FLAG_TAKEN                  = 64;
+const int CTF_PINK_FLAG_LOST                   = 128;
+const int CTF_PINK_FLAG_CARRYING               = 192;
+const int CTF_NEUTRAL_FLAG_TAKEN               = 256;
+const int CTF_NEUTRAL_FLAG_LOST                        = 512;
+const int CTF_NEUTRAL_FLAG_CARRYING            = 768;
+const int CTF_FLAG_NEUTRAL                             = 2048;
+const int CTF_SHIELDED                                 = 4096;
+
 #endif
index 2eceff38dd783a33da7ccd066498b98b9d23225a..db6939f154364a2d325d622e9bb4d85c2797f863 100644 (file)
@@ -15,4 +15,31 @@ models/ctf/glow_blue
        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
+ }
 }
\ No newline at end of file
diff --git a/sound/ctf/neutral_dropped.wav b/sound/ctf/neutral_dropped.wav
new file mode 100644 (file)
index 0000000..b3232e2
Binary files /dev/null and b/sound/ctf/neutral_dropped.wav differ
diff --git a/sound/ctf/neutral_taken.wav b/sound/ctf/neutral_taken.wav
new file mode 100644 (file)
index 0000000..fde3fe2
Binary files /dev/null and b/sound/ctf/neutral_taken.wav differ
diff --git a/sound/ctf/pink_capture.ogg b/sound/ctf/pink_capture.ogg
new file mode 100644 (file)
index 0000000..6320614
Binary files /dev/null and b/sound/ctf/pink_capture.ogg differ
diff --git a/sound/ctf/pink_dropped.wav b/sound/ctf/pink_dropped.wav
new file mode 100644 (file)
index 0000000..b3232e2
Binary files /dev/null and b/sound/ctf/pink_dropped.wav differ
diff --git a/sound/ctf/pink_returned.wav b/sound/ctf/pink_returned.wav
new file mode 100644 (file)
index 0000000..b0779a1
Binary files /dev/null and b/sound/ctf/pink_returned.wav differ
diff --git a/sound/ctf/pink_taken.wav b/sound/ctf/pink_taken.wav
new file mode 100644 (file)
index 0000000..fde3fe2
Binary files /dev/null and b/sound/ctf/pink_taken.wav differ
diff --git a/sound/ctf/yellow_capture.ogg b/sound/ctf/yellow_capture.ogg
new file mode 100644 (file)
index 0000000..6320614
Binary files /dev/null and b/sound/ctf/yellow_capture.ogg differ
diff --git a/sound/ctf/yellow_dropped.wav b/sound/ctf/yellow_dropped.wav
new file mode 100644 (file)
index 0000000..b3232e2
Binary files /dev/null and b/sound/ctf/yellow_dropped.wav differ
diff --git a/sound/ctf/yellow_returned.wav b/sound/ctf/yellow_returned.wav
new file mode 100644 (file)
index 0000000..b0779a1
Binary files /dev/null and b/sound/ctf/yellow_returned.wav differ
diff --git a/sound/ctf/yellow_taken.wav b/sound/ctf/yellow_taken.wav
new file mode 100644 (file)
index 0000000..fde3fe2
Binary files /dev/null and b/sound/ctf/yellow_taken.wav differ