]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Many more bug fixes/new features/cleanups
authorSamual <samual@xonotic.org>
Fri, 30 Mar 2012 17:50:04 +0000 (13:50 -0400)
committerSamual <samual@xonotic.org>
Fri, 30 Mar 2012 17:50:04 +0000 (13:50 -0400)
defaultXonotic.cfg
qcsrc/server/autocvars.qh
qcsrc/server/bot/havocbot/role_ctf.qc
qcsrc/server/constants.qh
qcsrc/server/defs.qh
qcsrc/server/mutators/gamemode_ctf.qc
qcsrc/server/mutators/gamemode_ctf.qh

index e979d556b63b4790c695773c769f67099652c57b..663db3f89780167ec7df54abb237b3ec1e72124d 100644 (file)
@@ -591,7 +591,7 @@ set gamecfg 1       // "deathmatch"
 
 // ctf
 set g_ctf 0 "Capture The Flag: take the enemy flag and bring it to yours at your base to score"
-set g_ctf_flag_returntime 30
+set g_ctf_flag_returntime 15
 set g_ctf_flagcarrier_selfdamage 1
 set g_ctf_flagcarrier_selfforce 1
 set g_ctf_fullbrightflags 0
@@ -599,8 +599,9 @@ set g_ctf_dynamiclights 0
 set g_ctf_flag_damageforcescale 2
 set g_ctf_allow_drop 1 "dropping allows circumventing carrierkill score, so enable this with care!"
 set g_ctf_reverse 0    "if enabled, flags positions are switched: you have to capture the enemy's flag from your own base by bringing it to your own flag in the enemy base"
-set g_balance_ctf_delay_collect 1.0
-set g_balance_ctf_damageforcescale 1
+set g_ctf_flag_collect_delay 1
+set g_ctf_flag_health 0
+set g_ctf_flag_take_damage 0
 
 set g_ctf_shield_max_ratio 0   "shield at most this percentage of a team from the enemy flag (try: 0.4 for 40%)"
 set g_ctf_shield_min_negscore 20       "shield the player from the flag if he's got this negative amount of points or less"
index 6d3cdd9ef48f107be9a162b3a5c2b4f1b4589911..15637500249e9f2737d22afabaf6dba31d3589cb 100644 (file)
@@ -179,8 +179,6 @@ float autocvar_g_balance_crylink_secondary_speed;
 float autocvar_g_balance_crylink_secondary_spread;
 float autocvar_g_balance_crylink_reload_ammo;
 float autocvar_g_balance_crylink_reload_time;
-float autocvar_g_balance_ctf_damageforcescale;
-float autocvar_g_balance_ctf_delay_collect;
 float autocvar_g_balance_curse_empathy_minhealth;
 float autocvar_g_balance_curse_empathy_takedamage;
 float autocvar_g_balance_curse_slow_atkrate;
@@ -768,13 +766,16 @@ float autocvar_g_ctf_dynamiclights;
 string autocvar_g_ctf_flag_blue_model;
 float autocvar_g_ctf_flag_blue_skin;
 float autocvar_g_ctf_flag_capture_effects;
+float autocvar_g_ctf_flag_collect_delay;
 float autocvar_g_ctf_flag_damageforcescale;
 float autocvar_g_ctf_flag_glowtrails;
+float autocvar_g_ctf_flag_health;
 float autocvar_g_ctf_flag_pickup_effects;
 float autocvar_g_ctf_flag_pickup_verbosename;
 string autocvar_g_ctf_flag_red_model;
 float autocvar_g_ctf_flag_red_skin;
 float autocvar_g_ctf_flag_returntime;
+float autocvar_g_ctf_flag_take_damage;
 float autocvar_g_ctf_flagcarrier_selfdamage;
 float autocvar_g_ctf_flagcarrier_selfforce;
 float autocvar_g_ctf_fullbrightflags;
index fe7b732acc7ec51bd3474a88da5ba26020ba2f0e..74be6e766465f4443258d9ce958b29eb16cb2248 100644 (file)
@@ -143,7 +143,7 @@ void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
 
        mf = havocbot_ctf_find_flag(self);
 
-       if(mf.cnt == FLAG_BASE)
+       if(mf.ctf_status == FLAG_BASE)
                return;
 
        if(mf.tag_entity)
@@ -157,7 +157,7 @@ void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float r
        while (head)
        {
                // flag is out in the field
-               if(head.cnt != FLAG_BASE)
+               if(head.ctf_status != FLAG_BASE)
                if(head.tag_entity==world)      // dropped
                {
                        if(radius)
@@ -295,7 +295,7 @@ void havocbot_role_ctf_escort()
 
        // If enemy flag is back on the base switch to previous role
        ef = havocbot_ctf_find_enemy_flag(self);
-       if(ef.cnt==FLAG_BASE)
+       if(ef.ctf_status==FLAG_BASE)
        {
                self.havocbot_role = self.havocbot_previous_role;
                self.havocbot_role_timeout = 0;
@@ -304,7 +304,7 @@ void havocbot_role_ctf_escort()
 
        // If the flag carrier reached the base switch to defense
        mf = havocbot_ctf_find_flag(self);
-       if(mf.cnt!=FLAG_BASE)
+       if(mf.ctf_status!=FLAG_BASE)
        if(vlen(ef.origin - mf.dropped_origin) < 300)
        {
                havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_DEFENSE);
@@ -359,7 +359,7 @@ void havocbot_role_ctf_offense()
        ef = havocbot_ctf_find_enemy_flag(self);
 
        // Own flag stolen
-       if(mf.cnt!=FLAG_BASE)
+       if(mf.ctf_status!=FLAG_BASE)
        {
                if(mf.tag_entity)
                        pos = mf.tag_entity.origin;
@@ -375,7 +375,7 @@ void havocbot_role_ctf_offense()
        }
 
        // Escort flag carrier
-       if(ef.cnt!=FLAG_BASE)
+       if(ef.ctf_status!=FLAG_BASE)
        {
                if(ef.tag_entity)
                        pos = ef.tag_entity.origin;
@@ -437,7 +437,7 @@ void havocbot_role_ctf_retriever()
 
        // If flag is back on the base switch to previous role
        mf = havocbot_ctf_find_flag(self);
-       if(mf.cnt==FLAG_BASE)
+       if(mf.ctf_status==FLAG_BASE)
        {
                havocbot_ctf_reset_role(self);
                return;
@@ -484,7 +484,7 @@ void havocbot_role_ctf_middle()
        }
 
        mf = havocbot_ctf_find_flag(self);
-       if(mf.cnt!=FLAG_BASE)
+       if(mf.ctf_status!=FLAG_BASE)
        {
                havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
                return;
@@ -536,7 +536,7 @@ void havocbot_role_ctf_defense()
 
        // If own flag was captured
        mf = havocbot_ctf_find_flag(self);
-       if(mf.cnt!=FLAG_BASE)
+       if(mf.ctf_status!=FLAG_BASE)
        {
                havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
                return;
@@ -635,14 +635,14 @@ void havocbot_ctf_reset_role(entity bot)
        ef = havocbot_ctf_find_enemy_flag(bot);
 
        // Retrieve stolen flag
-       if(mf.cnt!=FLAG_BASE)
+       if(mf.ctf_status!=FLAG_BASE)
        {
                havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_RETRIEVER);
                return;
        }
 
        // If enemy flag is taken go to the middle to intercept pursuers
-       if(ef.cnt!=FLAG_BASE)
+       if(ef.ctf_status!=FLAG_BASE)
        {
                havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
                return;
index b95c7261366b099902f2bb67ac4730661c024db7..aec1e3256b020878305579b179dfeea42a18e67e 100644 (file)
@@ -142,11 +142,6 @@ float      MSG_ENTITY                              = 5; // csqc
 
 float TE_BEAM                                  = 13;           // grappling hook
 
-// CTF
-float FLAG_BASE = 1;
-float FLAG_CARRY = 2;
-float FLAG_DROPPED = 3;
-
 float COLOR_TEAM1      = 5;  // red
 float COLOR_TEAM2      = 14; // blue
 float COLOR_TEAM3      = 13; // yellow
index f324ef11557a61a756de572624cfb4db6a7daf90..62d65791dd87640e09a52ca373c51ce5acbcdcc9 100644 (file)
@@ -569,7 +569,6 @@ float servertime, serverprevtime, serverframetime;
 
 string matchid;
 .float hitplotfh;
-.string noise4;
 
 .float last_pickup;
 
index acb005b09d1159df69c6d89d6c3b137720ac8c7e..3881db9aac207a6305b930c5661fc771e03a36ec 100644 (file)
@@ -82,44 +82,42 @@ void ctf_CaptureShield_Update(entity player, float wanted_status)
 
 float ctf_CaptureShield_Customize()
 {
-       if not(other.ctf_captureshielded)
-               return FALSE;
-       if(self.team == other.team)
-               return FALSE;
+       if not(other.ctf_captureshielded) { return FALSE; }
+       if(self.team == other.team) { return FALSE; }
+       
        return TRUE;
 }
 
 void ctf_CaptureShield_Touch()
 {
-       if not(other.ctf_captureshielded)
-               return;
-       if(self.team == other.team)
-               return;
-       vector mymid;
-       vector othermid;
-       mymid = (self.absmin + self.absmax) * 0.5;
-       othermid = (other.absmin + other.absmax) * 0.5;
+       if not(other.ctf_captureshielded) { return; }
+       if(self.team == other.team) { 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_CSQC_Centerprint_Generic(other, CPID_CTF_CAPTURESHIELD, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.", 5, 0);
 }
 
 void ctf_CaptureShield_Spawn(entity flag)
 {
-       entity e;
-       e = spawn();
-       e.enemy = self;
-       e.team = self.team;
-       e.touch = ctf_CaptureShield_Touch;
-       e.customizeentityforclient = ctf_CaptureShield_Customize;
-       e.classname = "ctf_captureshield";
-       e.effects = EF_ADDITIVE;
-       e.movetype = MOVETYPE_NOCLIP;
-       e.solid = SOLID_TRIGGER;
-       e.avelocity = '7 0 11';
-       setorigin(e, self.origin);
-       setmodel(e, "models/ctf/shield.md3");
-       e.scale = 0.5;
-       setsize(e, e.scale * e.mins, e.scale * e.maxs);
+       entity shield = spawn();
+       
+       shield.enemy = self;
+       shield.team = self.team;
+       shield.touch = ctf_CaptureShield_Touch;
+       shield.customizeentityforclient = ctf_CaptureShield_Customize;
+       shield.classname = "ctf_captureshield";
+       shield.effects = EF_ADDITIVE;
+       shield.movetype = MOVETYPE_NOCLIP;
+       shield.solid = SOLID_TRIGGER;
+       shield.avelocity = '7 0 11';
+       shield.scale = 0.5;
+       
+       setorigin(shield, self.origin);
+       setmodel(shield, "models/ctf/shield.md3");
+       setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
 }
 
 
@@ -142,8 +140,8 @@ void ctf_Handle_Drop(entity player)
        flag.movetype = MOVETYPE_TOSS;
        flag.solid = SOLID_TRIGGER;
        flag.takedamage = DAMAGE_YES;
+       flag.health = flag.max_flag_health;
        flag.velocity = ('0 0 200' + ('0 100 0' * crandom()) + ('100 0 0' * crandom()));
-       flag.pain_finished = time + autocvar_g_ctf_flag_returntime; // replace this later
        
        flag.ctf_droptime = time;
        flag.ctf_dropperid = player.playerid;
@@ -151,7 +149,7 @@ void ctf_Handle_Drop(entity player)
 
        // messages and sounds
        Send_KillNotification(player.netname, flag.netname, "", INFO_LOSTFLAG, MSG_INFO);
-       sound(flag, CH_TRIGGER, flag.noise4, VOL_BASE, ATTN_NONE);
+       sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTN_NONE);
        ctf_EventLog("dropped", player.team, player);
        
        // scoring
@@ -163,6 +161,12 @@ void ctf_Handle_Drop(entity player)
        WaypointSprite_Ping(player.wps_flagcarrier);
        WaypointSprite_Kill(player.wps_flagcarrier);
 
+       if(autocvar_g_ctf_flag_returntime || (autocvar_g_ctf_flag_take_damage && autocvar_g_ctf_flag_health))
+       {
+               WaypointSprite_UpdateMaxHealth(flag.wps_flagdropped, flag.max_flag_health);
+               WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health);
+       }
+
        // captureshield
        ctf_CaptureShield_Update(player, 0); // shield only
 
@@ -202,7 +206,7 @@ void ctf_Handle_Capture(entity flag, entity player)
        
        // messages and sounds
        Send_KillNotification(player.netname, player.flagcarried.netname, cap_message, INFO_CAPTUREFLAG, MSG_INFO);
-       sound(player, CH_TRIGGER, flag.noise2, VOL_BASE, ATTN_NONE); // "ctf/*_capture.wav"
+       sound(player, CH_TRIGGER, flag.snd_flag_capture, VOL_BASE, ATTN_NONE); // "ctf/*_capture.wav"
        ctf_EventLog("capture", player.flagcarried.team, player);
        
        // scoring
@@ -229,7 +233,7 @@ void ctf_Handle_Return(entity flag, entity player)
 {
        // messages and sounds
        Send_KillNotification (player.netname, flag.netname, "", INFO_RETURNFLAG, MSG_INFO);
-       sound(player, CH_TRIGGER, flag.noise1, VOL_BASE, ATTN_NONE);
+       sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTN_NONE);
        ctf_EventLog("return", flag.team, player);
 
        // scoring
@@ -269,7 +273,7 @@ void ctf_Handle_Pickup_Base(entity flag, entity player)
        
        // messages and sounds
        Send_KillNotification (player.netname, flag.netname, "", INFO_GOTFLAG, MSG_INFO);
-       sound(player, CH_TRIGGER, flag.noise, VOL_BASE, ATTN_NONE);
+       sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTN_NONE);
        ctf_EventLog("steal", flag.team, player);
        verbosename = ((autocvar_g_ctf_flag_pickup_verbosename) ? strcat("(", player.netname, ")") : ""); // replace TRUE with an autocvar for it.
        FOR_EACH_PLAYER(tmp_player)
@@ -304,7 +308,7 @@ void ctf_Handle_Pickup_Base(entity flag, entity player)
 void ctf_Handle_Pickup_Dropped(entity flag, entity player) // make sure this works
 {
        // declarations
-       float returnscore = bound(0, (flag.pain_finished - time) / autocvar_g_ctf_flag_returntime, 1); // can this be division by zero?
+       float returnscore = bound(0, (flag.pain_finished - time) / autocvar_g_ctf_flag_returntime, 1); // can this be division by zero? FIXME
        entity tmp_player; // temporary entity which the FOR_EACH_PLAYER loop uses to scan players
        string verbosename; // holds the name of the player OR no name at all for printing in the centerprints
 
@@ -317,6 +321,7 @@ void ctf_Handle_Pickup_Dropped(entity flag, entity player) // make sure this wor
        // set up the flag
        flag.movetype = MOVETYPE_NONE;
        flag.takedamage = DAMAGE_NO;
+       flag.health = flag.max_flag_health;
        flag.solid = SOLID_NOT;
        flag.angles = '0 0 0';
        //flag.ctf_pickuptime = time; // don't update pickuptime since this isn't a real steal. 
@@ -325,7 +330,7 @@ void ctf_Handle_Pickup_Dropped(entity flag, entity player) // make sure this wor
 
        // messages and sounds
        Send_KillNotification (player.netname, flag.netname, "", INFO_PICKUPFLAG, MSG_INFO);
-       sound (player, CH_TRIGGER, flag.noise, VOL_BASE, ATTN_NONE);
+       sound (player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTN_NONE);
        ctf_EventLog("pickup", flag.team, player);
        verbosename = ((autocvar_g_ctf_flag_pickup_verbosename) ? strcat("(", player.netname, ")") : "");
        FOR_EACH_PLAYER(tmp_player)
@@ -360,12 +365,34 @@ void ctf_Handle_Pickup_Dropped(entity flag, entity player) // make sure this wor
 // Main Flag Functions
 // ===================
 
+void ctf_CheckFlagReturn(entity flag)
+{
+       if(flag.wps_flagdropped) { WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health); }
+       
+       if((flag.health <= 0) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_returntime))
+       {
+               bprint("The ", flag.netname, " has returned to base\n");
+               sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTN_NONE);
+               ctf_EventLog("returned", flag.team, world);
+               ctf_RespawnFlag(flag);
+       }
+}
+
+void ctf_FlagDamage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+       if(autocvar_g_ctf_flag_take_damage) 
+       {
+               self.health = self.health - damage;
+               ctf_CheckFlagReturn(self);
+       }
+}
+
 void ctf_FlagThink()
 {
        // declarations
        entity tmp_entity;
 
-       self.nextthink = time + 0.2; // only 5 fps, more is unnecessary.
+       self.nextthink = time + FLAG_THINKRATE; // only 5 fps, more is unnecessary.
 
        // captureshield
        if(self == ctf_worldflaglist) // only for the first flag
@@ -379,38 +406,31 @@ void ctf_FlagThink()
                if(!trace_startsolid) // can we resize it without getting stuck?
                        setsize(self, FLAG_MIN, FLAG_MAX); }
 
-       //if(self.owner.classname == "player" || (self.owner.deadflag) || (self.owner.flagcarried != self)) {
-       //      dprint("CANNOT HAPPEN - player dead and STILL had a flag!\n");
-       //      ctf_Handle_Drop(self.owner);
-       //      return; }
-
        // main think method
-       switch(self.ctf_status) 
+       switch(self.ctf_status)
        {       
                case FLAG_BASE: // nothing to do here
                        return;
                
                case FLAG_DROPPED:
-                       if(time > self.ctf_droptime + autocvar_g_ctf_flag_returntime)
+                       if(autocvar_g_ctf_flag_returntime)
                        {
-                               bprint("The ", self.netname, " has returned to base\n");
-                               sound(self, CH_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
-                               ctf_EventLog("returned", self.team, world);
-                               ctf_RespawnFlag(self);
-                       }
+                               self.health -= ((self.max_flag_health / autocvar_g_ctf_flag_returntime) * FLAG_THINKRATE);
+                               ctf_CheckFlagReturn(self);
+                       } 
                        return;
                                
                case FLAG_CARRY:
                        if((self.owner) && (self.speedrunning) && (ctf_captimerecord) && (time >= self.ctf_pickuptime + ctf_captimerecord)) 
                        {
                                bprint("The ", self.netname, " became impatient after ", ftos_decimals(ctf_captimerecord, 2), " seconds and returned itself\n");
-                               sound (self, CH_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
-
-                               self.owner.impulse = 141; // returning!
+                               sound(self, CH_TRIGGER, self.snd_flag_respawn, VOL_BASE, ATTN_NONE);
+                               ctf_EventLog("returned", self.team, world);
+                               ctf_RespawnFlag(tmp_entity);
 
                                tmp_entity = self;
                                self = self.owner;
-                               ctf_RespawnFlag(tmp_entity);
+                               self.impulse = CHIMPULSE_SPEEDRUN; // move the player back to the waypoint they set
                                ImpulseCommands();
                                self = tmp_entity;
                        }
@@ -430,7 +450,7 @@ void ctf_FlagTouch()
                || ((trace_dpstartcontents | trace_dphitcontents) & (DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_NODROP)))
        { // The flag fell off the map or into lava/slime, respawn it since players can't get to it
                bprint("The ", self.netname, " has returned to base\n");
-               sound (self, CH_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
+               sound (self, CH_TRIGGER, self.snd_flag_respawn, VOL_BASE, ATTN_NONE);
                ctf_EventLog("returned", self.team, world);
                ctf_RespawnFlag(self);
                return;
@@ -456,7 +476,7 @@ void ctf_FlagTouch()
                case FLAG_DROPPED:
                        if(other.team == self.team)
                                ctf_Handle_Return(self, other); // other just returned his own flag
-                       else if((!other.flagcarried) && ((other.playerid != self.ctf_dropperid) || (time > self.ctf_droptime + autocvar_g_balance_ctf_delay_collect)))
+                       else if((!other.flagcarried) && ((other.playerid != self.ctf_dropperid) || (time > self.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
                                ctf_Handle_Pickup_Dropped(self, other); // other just picked up a dropped enemy flag
                        break;
                                
@@ -490,6 +510,7 @@ void ctf_RespawnFlag(entity flag)
        setorigin(flag, flag.ctf_spawnorigin); // replace with flag.ctf_spawnorigin
        flag.movetype = ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS);
        flag.takedamage = DAMAGE_NO;
+       flag.health = flag.max_flag_health;
        flag.solid = SOLID_TRIGGER;
        flag.velocity = '0 0 0';
        flag.angles = flag.mangle;
@@ -546,6 +567,9 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
        flag.solid = SOLID_TRIGGER;
        flag.takedamage = DAMAGE_NO;
        flag.damageforcescale = autocvar_g_ctf_flag_damageforcescale;   
+       flag.max_flag_health = ((autocvar_g_ctf_flag_take_damage && autocvar_g_ctf_flag_health) ? autocvar_g_ctf_flag_health : 100);
+       flag.health = flag.max_flag_health;
+       flag.event_damage = ctf_FlagDamage;
        flag.velocity = '0 0 0';
        flag.mangle = flag.angles;
        flag.reset = ctf_Reset;
@@ -575,18 +599,20 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
        if(autocvar_g_ctf_dynamiclights)   { flag.effects |= ((teamnumber) ? EF_RED : EF_BLUE); }
        
        // sound 
-       if(!flag.noise)  { flag.noise  = ((teamnumber) ? "ctf/red_taken.wav" : "ctf/blue_taken.wav"); }
-       if(!flag.noise1) { flag.noise1 = ((teamnumber) ? "ctf/red_returned.wav" : "ctf/blue_returned.wav"); }
-       if(!flag.noise2) { flag.noise2 = ((teamnumber) ? "ctf/red_capture.wav" : "ctf/blue_capture.wav"); } // blue team scores by capturing the red flag
-       if(!flag.noise3) { flag.noise3 = "ctf/flag_respawn.wav"; } // if there is ever a team-based sound for this, update the code to match.
-       if(!flag.noise4) { flag.noise4 = ((teamnumber) ? "ctf/red_dropped.wav" : "ctf/blue_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_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/flag_touch.wav"; } // again has no team-based sound
        
        // precache
-       precache_sound(flag.noise);
-       precache_sound(flag.noise1);
-       precache_sound(flag.noise2);
-       precache_sound(flag.noise3);
-       precache_sound(flag.noise4);
+       precache_sound(flag.snd_flag_taken);
+       precache_sound(flag.snd_flag_returned);
+       precache_sound(flag.snd_flag_capture);
+       precache_sound(flag.snd_flag_respawn);
+       precache_sound(flag.snd_flag_dropped);
+       precache_sound(flag.snd_flag_touch);
        precache_model(flag.model);
        precache_model("models/ctf/shield.md3");
        precache_model("models/ctf/shockwavetransring.md3");
@@ -597,7 +623,6 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
                flag.dropped_origin = flag.origin; 
                flag.noalign = TRUE;
                flag.movetype = MOVETYPE_NONE;
-               print("^1|^3||||^1| This map was loaded with flags using MOVETYPE_NONE\n");
        }
        else // drop to floor, automatically find a platform and set that as spawn origin
        { 
@@ -605,7 +630,6 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
                self = flag;
                droptofloor();
                flag.movetype = MOVETYPE_TOSS; 
-               print("^1|^3||||^1| This map was loaded with flags using MOVETYPE_TOSS\n");
        }       
        
        InitializeEntity(flag, ctf_DelayedFlagSetup, INITPRIO_SETLOCATION);
@@ -646,6 +670,8 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
                        self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_LOST : IT_BLUE_FLAG_LOST); // lost: the flag is dropped somewhere on the map
        }
        
+       if(self.wps_flagcarrier) { WaypointSprite_UpdateHealth(self.wps_flagcarrier, self.health); }
+       
        return 0;
 }
 
@@ -732,14 +758,16 @@ void spawnfunc_info_player_team4()
 }
 
 /*QUAKED spawnfunc_item_flag_team1 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team one (Red). Multiple flags are allowed.
+CTF flag for team one (Red).
 Keys: 
 "angle" Angle the flag will point (minus 90 degrees)... 
-"model" model to use, note this needs red and blue as skins 0 and 1 (default models/ctf/flag.md3)...
-"noise" sound played when flag is picked up (default ctf/take.wav)...
-"noise1" sound played when flag is returned by a teammate (default ctf/return.wav)...
-"noise2" sound played when flag is captured (default ctf/redcapture.wav)...
-"noise3" sound played when flag is lost in the field and respawns itself (default ctf/respawn.wav)... */
+"model" model to use, note this needs red and blue as skins 0 and 1...
+"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_team1()
 {
        if(!g_ctf) { remove(self); return; }
@@ -748,14 +776,16 @@ void spawnfunc_item_flag_team1()
 }
 
 /*QUAKED spawnfunc_item_flag_team2 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team two (Blue). Multiple flags are allowed.
+CTF flag for team two (Blue).
 Keys: 
 "angle" Angle the flag will point (minus 90 degrees)... 
-"model" model to use, note this needs red and blue as skins 0 and 1 (default models/ctf/flag.md3)...
-"noise" sound played when flag is picked up (default ctf/take.wav)...
-"noise1" sound played when flag is returned by a teammate (default ctf/return.wav)...
-"noise2" sound played when flag is captured (default ctf/redcapture.wav)...
-"noise3" sound played when flag is lost in the field and respawns itself (default ctf/respawn.wav)... */
+"model" model to use, note this needs red and blue as skins 0 and 1...
+"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_team2()
 {
        if(!g_ctf) { remove(self); return; }
index 9f8a65cccb0e774d59b438f78d7220d0411a6fc9..f171d9635afb5e970f7cd796369512c3f7582bc1 100644 (file)
@@ -19,6 +19,22 @@ void spawnfunc_ctf_team();
 #define FLAG_SPAWN_OFFSET ('0 0 1' * (PL_MAX_z - 13))
 #define FLAG_WAYPOINT_OFFSET ('0 0 64')
 #define FLAG_SCALE 0.6
+#define FLAG_THINKRATE 0.2
+
+#define FLAG_BASE 1
+#define FLAG_CARRY 2
+#define FLAG_DROPPED 3
+
+// sounds 
+.string noise4;
+.string noise5;
+
+#define snd_flag_taken noise
+#define snd_flag_returned noise1
+#define snd_flag_capture noise2
+#define snd_flag_respawn noise3
+#define snd_flag_dropped noise4
+#define snd_flag_touch noise5
 
 // list of flags on the map
 entity ctf_worldflaglist;
@@ -38,6 +54,7 @@ float ctf_captimerecord; // record time for capturing the flag
 .float ctf_dropperid; // don't allow spam of dropping the flag
 .float ctf_droptime;
 .float ctf_status; // status of the flag (FLAG_BASE, FLAG_DROPPED, FLAG_CARRY declared globally)
+.float max_flag_health;
 
 // 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