]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/w_crylink.qc
fix a crash with crylink when only using 1 shot; fix fade_rate networking
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_crylink.qc
index 566563487b768b7e82fe761df97b9b3f3cbf3b68..b783f5be69257e8588ba2f8ea94d171d61928418 100644 (file)
@@ -44,8 +44,10 @@ void W_Crylink_LinkExplode (entity e, entity e2)
 // stored in w_crylink_linkjoin_time.
 // could possibly network this origin and time, and display a special particle
 // effect when projectiles meet there :P
 // stored in w_crylink_linkjoin_time.
 // could possibly network this origin and time, and display a special particle
 // effect when projectiles meet there :P
+// jspeed: MINIMUM jing speed
+// jtime: MAXIMUM jing time (0: none)
 float w_crylink_linkjoin_time;
 float w_crylink_linkjoin_time;
-vector W_Crylink_LinkJoin(entity e, float joinspeed)
+vector W_Crylink_LinkJoin(entity e, float jspeed, float jtime)
 {
        vector avg_origin, avg_velocity;
        vector targ_origin;
 {
        vector avg_origin, avg_velocity;
        vector targ_origin;
@@ -59,8 +61,8 @@ vector W_Crylink_LinkJoin(entity e, float joinspeed)
        n = 1;
        for(p = e; (p = p.queuenext) != e; )
        {
        n = 1;
        for(p = e; (p = p.queuenext) != e; )
        {
-               avg_origin += p.origin;
-               avg_velocity += p.velocity;
+               avg_origin += WarpZone_RefSys_TransformOrigin(p, e, p.origin);
+               avg_velocity += WarpZone_RefSys_TransformVelocity(p, e, p.velocity);
                ++n;
        }
        avg_origin *= (1.0 / n);
                ++n;
        }
        avg_origin *= (1.0 / n);
@@ -72,46 +74,54 @@ vector W_Crylink_LinkJoin(entity e, float joinspeed)
        // yes, mathematically we can do this in ONE step, but beware of 32bit floats...
        avg_dist = pow(vlen(e.origin - avg_origin), 2);
        for(p = e; (p = p.queuenext) != e; )
        // yes, mathematically we can do this in ONE step, but beware of 32bit floats...
        avg_dist = pow(vlen(e.origin - avg_origin), 2);
        for(p = e; (p = p.queuenext) != e; )
-               avg_dist += pow(vlen(e.origin - avg_origin), 2);
+               avg_dist += pow(vlen(WarpZone_RefSys_TransformOrigin(p, e, p.origin) - avg_origin), 2);
        avg_dist *= (1.0 / n);
        avg_dist = sqrt(avg_dist);
 
        if(avg_dist == 0)
                return avg_origin; // no change needed
 
        avg_dist *= (1.0 / n);
        avg_dist = sqrt(avg_dist);
 
        if(avg_dist == 0)
                return avg_origin; // no change needed
 
-       if(joinspeed == 0)
+       if(jspeed == 0 && jtime == 0)
        {
                e.velocity = avg_velocity;
                UpdateCSQCProjectile(e);
                for(p = e; (p = p.queuenext) != e; )
                {
        {
                e.velocity = avg_velocity;
                UpdateCSQCProjectile(e);
                for(p = e; (p = p.queuenext) != e; )
                {
-                       p.velocity = avg_velocity;
+                       p.velocity = WarpZone_RefSys_TransformVelocity(e, p, avg_velocity);
                        UpdateCSQCProjectile(p);
                }
        }
        else
        {
                        UpdateCSQCProjectile(p);
                }
        }
        else
        {
-               w_crylink_linkjoin_time = avg_dist / joinspeed;
+               if(jtime)
+               {
+                       if(jspeed)
+                               w_crylink_linkjoin_time = min(jtime, avg_dist / jspeed);
+                       else
+                               w_crylink_linkjoin_time = jtime;
+               }
+               else
+                       w_crylink_linkjoin_time = avg_dist / jspeed;
                targ_origin = avg_origin + w_crylink_linkjoin_time * avg_velocity;
 
                targ_origin = avg_origin + w_crylink_linkjoin_time * avg_velocity;
 
-               e.velocity = (targ_origin - e.origin) * (joinspeed / avg_dist);
+               e.velocity = (targ_origin - e.origin) * (1.0 / w_crylink_linkjoin_time);
                UpdateCSQCProjectile(e);
                for(p = e; (p = p.queuenext) != e; )
                {
                UpdateCSQCProjectile(e);
                for(p = e; (p = p.queuenext) != e; )
                {
-                       p.velocity = (targ_origin - p.origin) * (joinspeed / avg_dist);
+                       p.velocity = WarpZone_RefSys_TransformVelocity(e, p, (targ_origin - WarpZone_RefSys_TransformOrigin(p, e, p.origin)) * (1.0 / w_crylink_linkjoin_time));
                        UpdateCSQCProjectile(p);
                }
 
                // analysis:
                        UpdateCSQCProjectile(p);
                }
 
                // analysis:
-               //   joinspeed -> +infinity:
+               //   jspeed -> +infinity:
                //      w_crylink_linkjoin_time -> +0
                //      targ_origin -> avg_origin
                //      p->velocity -> HUEG towards center
                //      w_crylink_linkjoin_time -> +0
                //      targ_origin -> avg_origin
                //      p->velocity -> HUEG towards center
-               //   joinspeed -> 0:
+               //   jspeed -> 0:
                //      w_crylink_linkjoin_time -> +/- infinity
                //      targ_origin -> avg_velocity * +/- infinity
                //      p->velocity -> avg_velocity
                //      w_crylink_linkjoin_time -> +/- infinity
                //      targ_origin -> avg_velocity * +/- infinity
                //      p->velocity -> avg_velocity
-               //   joinspeed -> -infinity:
+               //   jspeed -> -infinity:
                //      w_crylink_linkjoin_time -> -0
                //      targ_origin -> avg_origin
                //      p->velocity -> HUEG away from center
                //      w_crylink_linkjoin_time -> -0
                //      targ_origin -> avg_origin
                //      p->velocity -> HUEG away from center
@@ -173,7 +183,7 @@ void W_Crylink_Touch (void)
                f = cvar("g_balance_crylink_primary_bouncedamagefactor");
        if(a)
                f *= a;
                f = cvar("g_balance_crylink_primary_bouncedamagefactor");
        if(a)
                f *= a;
-       if (RadiusDamage (self, self.realowner, cvar("g_balance_crylink_primary_damage") * f, cvar("g_balance_crylink_primary_edgedamage") * f, cvar("g_balance_crylink_primary_radius"), world, cvar("g_balance_crylink_primary_force") * f, self.projectiledeathtype, other))
+       if (RadiusDamage (self, self.realowner, cvar("g_balance_crylink_primary_damage") * f, cvar("g_balance_crylink_primary_edgedamage") * f, cvar("g_balance_crylink_primary_radius"), world, cvar("g_balance_crylink_primary_force") * f, self.projectiledeathtype, other) && cvar("g_balance_crylink_primary_linkexplode"))
        {
                W_Crylink_LinkExplode(self.queuenext, self);
                remove (self);
        {
                W_Crylink_LinkExplode(self.queuenext, self);
                remove (self);
@@ -221,7 +231,7 @@ void W_Crylink_Touch2 (void)
                f = cvar("g_balance_crylink_secondary_bouncedamagefactor");
        if(a)
                f *= a;
                f = cvar("g_balance_crylink_secondary_bouncedamagefactor");
        if(a)
                f *= a;
-       if (RadiusDamage (self, self.realowner, cvar("g_balance_crylink_secondary_damage") * f, cvar("g_balance_crylink_secondary_edgedamage") * f, cvar("g_balance_crylink_secondary_radius"), world, cvar("g_balance_crylink_secondary_force") * f, self.projectiledeathtype, other))
+       if (RadiusDamage (self, self.realowner, cvar("g_balance_crylink_secondary_damage") * f, cvar("g_balance_crylink_secondary_edgedamage") * f, cvar("g_balance_crylink_secondary_radius"), world, cvar("g_balance_crylink_secondary_force") * f, self.projectiledeathtype, other) && cvar("g_balance_crylink_secondary_linkexplode"))
        {
                W_Crylink_LinkExplode(self.queuenext, self);
                remove (self);
        {
                W_Crylink_LinkExplode(self.queuenext, self);
                remove (self);
@@ -274,7 +284,11 @@ void W_Crylink_Attack (void)
                proj.classname = "spike";
                proj.bot_dodge = TRUE;
                proj.bot_dodgerating = cvar("g_balance_crylink_primary_damage");
                proj.classname = "spike";
                proj.bot_dodge = TRUE;
                proj.bot_dodgerating = cvar("g_balance_crylink_primary_damage");
-               if(counter == 0) { // first projectile, store in firstproj for now
+               if(shots == 1) {
+                       proj.queuenext = proj;
+                       proj.queueprev = proj;
+               }
+               else if(counter == 0) { // first projectile, store in firstproj for now
                        firstproj = proj;
                }
                else if(counter == shots - 1) { // last projectile, link up with first projectile
                        firstproj = proj;
                }
                else if(counter == shots - 1) { // last projectile, link up with first projectile
@@ -316,13 +330,13 @@ void W_Crylink_Attack (void)
                if(counter == 0)
                {
                        proj.fade_time = time + cvar("g_balance_crylink_primary_middle_lifetime");
                if(counter == 0)
                {
                        proj.fade_time = time + cvar("g_balance_crylink_primary_middle_lifetime");
-                       self.fade_rate = 1 / cvar("g_balance_crylink_primary_middle_fadetime");
+                       proj.fade_rate = 1 / cvar("g_balance_crylink_primary_middle_fadetime");
                        proj.nextthink = time + cvar("g_balance_crylink_primary_middle_lifetime") + cvar("g_balance_crylink_primary_middle_fadetime");
                }
                else
                {
                        proj.fade_time = time + cvar("g_balance_crylink_primary_other_lifetime");
                        proj.nextthink = time + cvar("g_balance_crylink_primary_middle_lifetime") + cvar("g_balance_crylink_primary_middle_fadetime");
                }
                else
                {
                        proj.fade_time = time + cvar("g_balance_crylink_primary_other_lifetime");
-                       self.fade_rate = 1 / cvar("g_balance_crylink_primary_other_fadetime");
+                       proj.fade_rate = 1 / cvar("g_balance_crylink_primary_other_fadetime");
                        proj.nextthink = time + cvar("g_balance_crylink_primary_other_lifetime") + cvar("g_balance_crylink_primary_other_fadetime");
                }
                proj.cnt = cvar("g_balance_crylink_primary_bounces");
                        proj.nextthink = time + cvar("g_balance_crylink_primary_other_lifetime") + cvar("g_balance_crylink_primary_other_fadetime");
                }
                proj.cnt = cvar("g_balance_crylink_primary_bounces");
@@ -363,7 +377,11 @@ void W_Crylink_Attack2 (void)
                proj.classname = "spike";
                proj.bot_dodge = TRUE;
                proj.bot_dodgerating = cvar("g_balance_crylink_secondary_damage");
                proj.classname = "spike";
                proj.bot_dodge = TRUE;
                proj.bot_dodgerating = cvar("g_balance_crylink_secondary_damage");
-               if(counter == 0) { // first projectile, store in firstproj for now
+               if(shots == 1) {
+                       proj.queuenext = proj;
+                       proj.queueprev = proj;
+               }
+               else if(counter == 0) { // first projectile, store in firstproj for now
                        firstproj = proj;
                }
                else if(counter == shots - 1) { // last projectile, link up with first projectile
                        firstproj = proj;
                }
                else if(counter == shots - 1) { // last projectile, link up with first projectile
@@ -393,13 +411,13 @@ void W_Crylink_Attack2 (void)
                if(counter == (shots - 1) / 2)
                {
                        proj.fade_time = time + cvar("g_balance_crylink_secondary_middle_lifetime");
                if(counter == (shots - 1) / 2)
                {
                        proj.fade_time = time + cvar("g_balance_crylink_secondary_middle_lifetime");
-                       self.fade_rate = 1 / cvar("g_balance_crylink_secondary_middle_fadetime");
+                       proj.fade_rate = 1 / cvar("g_balance_crylink_secondary_middle_fadetime");
                        proj.nextthink = time + cvar("g_balance_crylink_secondary_middle_lifetime") + cvar("g_balance_crylink_secondary_middle_fadetime");
                }
                else
                {
                        proj.fade_time = time + cvar("g_balance_crylink_secondary_line_lifetime");
                        proj.nextthink = time + cvar("g_balance_crylink_secondary_middle_lifetime") + cvar("g_balance_crylink_secondary_middle_fadetime");
                }
                else
                {
                        proj.fade_time = time + cvar("g_balance_crylink_secondary_line_lifetime");
-                       self.fade_rate = 1 / cvar("g_balance_crylink_secondary_line_fadetime");
+                       proj.fade_rate = 1 / cvar("g_balance_crylink_secondary_line_fadetime");
                        proj.nextthink = time + cvar("g_balance_crylink_secondary_line_lifetime") + cvar("g_balance_crylink_secondary_line_fadetime");
                }
                proj.cnt = cvar("g_balance_crylink_secondary_bounces");
                        proj.nextthink = time + cvar("g_balance_crylink_secondary_line_lifetime") + cvar("g_balance_crylink_secondary_line_fadetime");
                }
                proj.cnt = cvar("g_balance_crylink_secondary_bounces");
@@ -443,7 +461,7 @@ float w_crylink(float req)
                        {
                                W_Crylink_Attack();
                                weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_crylink_primary_animtime"), w_ready);
                        {
                                W_Crylink_Attack();
                                weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_crylink_primary_animtime"), w_ready);
-                               if(cvar("g_balance_crylink_primary_joinspeed") != 0)
+                               if(cvar("g_balance_crylink_primary_joinspeed") != 0 || cvar("g_balance_crylink_primary_jointime") != 0)
                                        self.crylink_waitrelease = 1;
                        }
                }
                                        self.crylink_waitrelease = 1;
                        }
                }
@@ -454,7 +472,7 @@ float w_crylink(float req)
                        {
                                W_Crylink_Attack2();
                                weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_crylink_secondary_animtime"), w_ready);
                        {
                                W_Crylink_Attack2();
                                weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_crylink_secondary_animtime"), w_ready);
-                               if(cvar("g_balance_crylink_secondary_joinspeed") != 0)
+                               if(cvar("g_balance_crylink_secondary_joinspeed") != 0 || cvar("g_balance_crylink_secondary_jointime") != 0)
                                        self.crylink_waitrelease = 2;
                        }
                }
                                        self.crylink_waitrelease = 2;
                        }
                }
@@ -468,11 +486,11 @@ float w_crylink(float req)
                                        vector pos;
                                        if(self.crylink_waitrelease == 1)
                                        {
                                        vector pos;
                                        if(self.crylink_waitrelease == 1)
                                        {
-                                               pos = W_Crylink_LinkJoin(self.crylink_lastgroup, cvar("g_balance_crylink_primary_joinspeed"));
+                                               pos = W_Crylink_LinkJoin(self.crylink_lastgroup, cvar("g_balance_crylink_primary_joinspeed"), cvar("g_balance_crylink_primary_jointime"));
                                        }
                                        else
                                        {
                                        }
                                        else
                                        {
-                                               pos = W_Crylink_LinkJoin(self.crylink_lastgroup, cvar("g_balance_crylink_secondary_joinspeed"));
+                                               pos = W_Crylink_LinkJoin(self.crylink_lastgroup, cvar("g_balance_crylink_secondary_joinspeed"), cvar("g_balance_crylink_secondary_jointime"));
                                        }
 
                                        entity linkjoineffect;
                                        }
 
                                        entity linkjoineffect;