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