]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/w_minelayer.qc
Mines only have their lanching speed, so don't keep two speed cvars
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_minelayer.qc
index de65da56178ab50ac4b3de6e14011e8b2ffffd46..31091d3f99bb974949f208f6d2b324a5a0a15629 100644 (file)
@@ -1,9 +1,14 @@
+/*TODO list (things left to do before this weapon should be ready, delete once it's all done):
+- The weapon currently uses sounds and models from other weapons. We need a modeler and sound artist to make this weapon its own (the gun model should probably be something between the porto and rocket launcher design-wise).
+- The mine model needs to face properly when it sticks to a surface. Once we'll have a correct mine model, we can't afford the model facing any way it falls to the ground. Should probably look at the porto code to see how portals face in the right direction when sticking to walls. 
+*/
+
 #ifdef REGISTER_WEAPON
-REGISTER_WEAPON(MINE_LAYER, w_minelayer, IT_ROCKETS, 9, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_HIGH, "minelayer", "minelayer", "Mine Layer");
+REGISTER_WEAPON(MINE_LAYER, w_minelayer, IT_ROCKETS, 4, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_HIGH, "minelayer", "minelayer", "Mine Layer");
 #else
 #ifdef SVQC
 .float minelayer_detonate;
-.float mine_number;
+.float mine_number, mine_time;
 
 void spawnfunc_weapon_minelayer (void)
 {
@@ -79,8 +84,29 @@ void W_Mine_RemoteExplode()
        }
 }
 
+void W_Mine_ProximityExplode()
+{
+       // make sure no friend is in the mine's radius. If there is any, explosion is delayed until he's at a safe distance
+       if(cvar("g_balance_minelayer_protection"))
+       {
+               entity head;
+               head = findradius(self.origin, cvar("g_balance_minelayer_radius"));
+               while(head)
+               {
+                       if(head == self.owner || !IsDifferentTeam(head, self.owner))
+                               return;
+                       head = head.chain;
+               }
+       }
+
+       self.mine_time = 0;
+       W_Mine_Explode();
+}
+
 void W_Mine_Think (void)
 {
+       entity head;
+
        self.nextthink = time;
        if (time > self.cnt)
        {
@@ -90,22 +116,24 @@ void W_Mine_Think (void)
                return;
        }
 
-       // detect players around the mine and explode if the player should detonate it
-       entity head;
+       // set the mine for detonation when a foe gets too close
        head = findradius(self.origin, cvar("g_balance_minelayer_detectionradius"));
-
        while(head)
        {
                if(head.classname == "player" && head.deadflag == DEAD_NO)
-               if(head != self.owner)
-               if not(teams_matter && head.team == self.owner.team) // don't detonate for team mates
+               if(head != self.owner && IsDifferentTeam(head, self.owner)) // don't trigger for team mates
+               if(!self.mine_time)
                {
-                       W_Mine_Unregister();
-                       W_Mine_Explode();
+                       spamsound (self, CHAN_PROJECTILE, "weapons/mine_trigger.wav", VOL_BASE, ATTN_NORM);
+                       self.mine_time = time + cvar("g_balance_minelayer_time");
                }
                head = head.chain;
        }
 
+       // explode if it's time to
+       if(self.mine_time && time >= self.mine_time)
+               W_Mine_ProximityExplode();
+
        // remote detonation
        if (self.owner.weapon == WEP_MINE_LAYER)
        if (self.owner.deadflag == DEAD_NO)
@@ -119,9 +147,13 @@ void W_Mine_Think (void)
 void W_Mine_Touch (void)
 {
        PROJECTILE_TOUCH;
-       spamsound (self, CHAN_PROJECTILE, "weapons/mine_stick.wav", VOL_BASE, ATTN_NORM);
-       self.movetype = MOVETYPE_NONE; // lock the mine in place
-       // TODO: make sure this doesn't cause the mine to get stuck in the air if it falls over a team mate (doesn't explode) and the team mate leaves
+       if(!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE))
+       {
+               spamsound (self, CHAN_PROJECTILE, "weapons/mine_stick.wav", VOL_BASE, ATTN_NORM);
+               self.movetype = MOVETYPE_NONE; // lock the mine in place
+       }
+       else if(self.movetype != MOVETYPE_NONE) // don't unstick a locked mine when someone touches it
+               self.velocity = '0 0 0';
 }
 
 void W_Mine_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
@@ -142,11 +174,10 @@ void W_Mine_Attack (void)
        // scan how many mines we placed, and return if we reached our limit
        if(cvar("g_balance_minelayer_limit"))
        {
-               entity min;
+               entity mine;
                self.mine_number = 0;
-               for(min = world; (min = find(min, classname, "mine")); )
-                       if(min.owner == self)
-                               self.mine_number += 1;
+               for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self)
+                       self.mine_number += 1;
 
                if(self.mine_number >= cvar("g_balance_minelayer_limit"))
                {
@@ -160,7 +191,7 @@ void W_Mine_Attack (void)
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
                self.ammo_rockets = self.ammo_rockets - cvar("g_balance_minelayer_ammo");
 
-       W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 5, "weapons/mine_fire.wav", cvar("g_balance_minelayer_damage"));
+       W_SetupShot_ProjectileSize (self, '-4 -4 -4', '4 4 4', FALSE, 5, "weapons/mine_fire.wav", cvar("g_balance_minelayer_damage"));
        pointparticles(particleeffectnum("rocketlauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
 
        mine = WarpZone_RefSys_SpawnSameRefSys(self);
@@ -172,7 +203,7 @@ void W_Mine_Attack (void)
                mine.spawnshieldtime = -1;
        mine.classname = "mine";
        mine.bot_dodge = TRUE;
-       mine.bot_dodgerating = cvar("g_balance_minelayer_damage") * 2; // * 2 because it can be detonated inflight which makes it even more dangerous
+       mine.bot_dodgerating = cvar("g_balance_minelayer_damage") * 2; // * 2 because it can detonate inflight which makes it even more dangerous
 
        mine.takedamage = DAMAGE_YES;
        mine.damageforcescale = cvar("g_balance_minelayer_damageforcescale");
@@ -182,10 +213,10 @@ void W_Mine_Attack (void)
        mine.movetype = MOVETYPE_TOSS;
        PROJECTILE_MAKETRIGGER(mine);
        mine.projectiledeathtype = WEP_MINE_LAYER;
-       setsize (mine, '-6 -6 -6', '6 6 6'); // give it some size so it can be shot
+       setsize (mine, '-4 -4 -4', '4 4 4'); // give it some size so it can be shot
 
-       setorigin (mine, w_shotorg - v_forward * 6); // move it back so it hits the wall at the right point
-       W_SetupProjectileVelocity(mine, cvar("g_balance_minelayer_speedstart"), 0);
+       setorigin (mine, w_shotorg - v_forward * 4); // move it back so it hits the wall at the right point
+       W_SetupProjectileVelocity(mine, cvar("g_balance_minelayer_speed"), 0);
        mine.angles = vectoangles (mine.velocity);
 
        mine.touch = W_Mine_Touch;
@@ -194,7 +225,7 @@ void W_Mine_Attack (void)
        mine.cnt = time + cvar("g_balance_minelayer_lifetime");
        mine.flags = FL_PROJECTILE;
 
-       CSQCProjectile(mine, FALSE, PROJECTILE_MINE, FALSE);
+       CSQCProjectile(mine, FALSE, PROJECTILE_MINE, TRUE);
 
        // muzzle flash for 1st person view
        flash = spawn ();
@@ -210,7 +241,7 @@ void spawnfunc_weapon_minelayer (void); // defined in t_items.qc
 
 float w_minelayer(float req)
 {
-       entity min;
+       entity mine;
        float minfound;
        if (req == WR_AIM)
        {
@@ -285,7 +316,7 @@ float w_minelayer(float req)
                                }else{
                                        local float distance; distance= bound(300,vlen(self.origin-self.enemy.origin),30000);
                                        //As the distance gets larger, a correct detonation gets near imposible
-                                       //Bots are assumed to use the rocket spawnfunc_light to see if the rocket gets near a player
+                                       //Bots are assumed to use the mine spawnfunc_light to see if the mine gets near a player
                                        if(v_forward * normalize(mine.origin - self.enemy.origin)< 0.1)
                                                if(self.enemy.classname == "player")
                                                        if(desirabledamage >= 0.1*coredamage)
@@ -321,11 +352,11 @@ float w_minelayer(float req)
                if (self.BUTTON_ATCK2)
                {
                        minfound = 0;
-                       for(min = world; (min = find(min, classname, "mine")); ) if(min.owner == self)
+                       for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self)
                        {
-                               if(!min.minelayer_detonate)
+                               if(!mine.minelayer_detonate)
                                {
-                                       min.minelayer_detonate = TRUE;
+                                       mine.minelayer_detonate = TRUE;
                                        minfound = 1;
                                }
                        }
@@ -342,6 +373,7 @@ float w_minelayer(float req)
                precache_sound ("weapons/mine_det.wav");
                precache_sound ("weapons/mine_fire.wav");
                precache_sound ("weapons/mine_stick.wav");
+               precache_sound ("weapons/mine_trigger.wav");
        }
        else if (req == WR_SETUP)
        {
@@ -368,11 +400,11 @@ float w_minelayer(float req)
                org2 = w_org + w_backoff * 12;
                pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1);
                if(!w_issilent)
-                       sound(self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
+                       sound(self, CHAN_PROJECTILE, "weapons/mine_exp.wav", VOL_BASE, ATTN_NORM);
        }
        else if(req == WR_PRECACHE)
        {
-               precache_sound("weapons/rocket_impact.wav");
+               precache_sound("weapons/mine_exp.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
                w_deathtypestring = "%s exploded";
@@ -383,7 +415,7 @@ float w_minelayer(float req)
                else if(w_deathtype & HITTYPE_SPLASH)
                        w_deathtypestring = "%s almost dodged %s's mine";
                else
-                       w_deathtypestring = "%s ate %s's mine";
+                       w_deathtypestring = "%s stepped on %s's mine";
        }
        return TRUE;
 }