]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/cl_weapons.qc
Merge remote-tracking branch 'origin/master' into samual/spawn_weapons
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / cl_weapons.qc
index f0981f5e29cac8bc88e73893d7cf3579b3c2de63..236c0923fdc330834469234bc9eb2285a1f6bb26 100644 (file)
@@ -17,7 +17,7 @@ void W_SwitchWeapon(float imp)
        {
                W_TriggerReload();
        }
-};
+}
 
 .float weaponcomplainindex;
 float W_GetCycleWeapon(entity pl, string weaponorder, float dir, float imp, float complain, float skipmissing)
@@ -149,35 +149,36 @@ void W_LastWeapon()
 float w_getbestweapon(entity e)
 {
        return W_GetCycleWeapon(e, e.cvar_cl_weaponpriority, 0, -1, FALSE, TRUE);
-};
+}
 
 // generic weapons table
 // TODO should they be macros instead?
 float weapon_action(float wpn, float wrequest)
 {
        return (get_weaponinfo(wpn)).weapon_func(wrequest);
-};
+}
 
 string W_Name(float weaponid)
 {
        return (get_weaponinfo(weaponid)).message;
 }
 
-float W_WeaponBit(float wpn)
-{
-       return (get_weaponinfo(wpn)).weapons;
-}
-
 float W_AmmoItemCode(float wpn)
 {
-       return (get_weaponinfo(wpn)).items;
+       return (get_weaponinfo(wpn)).items & IT_AMMO;
 }
 
+.float savenextthink;
 void thrown_wep_think()
 {
-       self.solid = SOLID_TRIGGER;
        self.owner = world;
-       SUB_SetFade(self, time + 20, 1);
+       float timeleft = self.savenextthink - time;
+       if(timeleft > 1)
+               SUB_SetFade(self, self.savenextthink - 1, 1);
+       else if(timeleft > 0)
+               SUB_SetFade(self, time, timeleft);
+       else
+               SUB_VanishOrRemove(self);
 }
 
 // returns amount of ammo used as string, or -1 for failure, or 0 for no ammo count
@@ -197,8 +198,36 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
        wep.flags |= FL_TOSSED;
        wep.colormap = own.colormap;
 
+       if(WEPSET_CONTAINS_AW(WEPBIT_SUPERWEAPONS, wpn))
+       {
+               if(own.items & IT_UNLIMITED_SUPERWEAPONS)
+               {
+                       wep.superweapons_finished = time + autocvar_g_balance_superweapons_time;
+               }
+               else
+               {
+                       float superweapons = 1;
+                       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+                               if(WEPSET_CONTAINS_AW(WEPBIT_SUPERWEAPONS, i))
+                                       if(WEPSET_CONTAINS_EW(own, i))
+                                               ++superweapons;
+                       if(superweapons <= 1)
+                       {
+                               wep.superweapons_finished = own.superweapons_finished;
+                               own.superweapons_finished = 0;
+                       }
+                       else
+                       {
+                               float timeleft = own.superweapons_finished - time;
+                               float weptimeleft = timeleft / superweapons;
+                               wep.superweapons_finished = time + weptimeleft;
+                               own.superweapons_finished -= weptimeleft;
+                       }
+               }
+       }
+
        wa = W_AmmoItemCode(wpn);
-       if(wa == IT_SUPERWEAPON || wa == 0)
+       if(wa == 0)
        {
                oldself = self;
                self = wep;
@@ -208,7 +237,9 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
                        return string_null;
                wep.glowmod = own.weaponentity_glowmod;
                wep.think = thrown_wep_think;
-               wep.nextthink = time + 0.5;
+               wep.savenextthink = wep.nextthink;
+               wep.nextthink = min(wep.nextthink, time + 0.5);
+               wep.pickup_anyway = TRUE; // these are ALWAYS pickable
                return "";
        }
        else
@@ -220,38 +251,60 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
                self = oldself;
                if(startitem_failed)
                        return string_null;
-               if(doreduce)
+               if(doreduce && g_weapon_stay == 2)
                {
                        for(i = 0, j = 1; i < 24; ++i, j *= 2)
                        {
                                if(wa & j)
                                {
                                        ammofield = Item_CounterField(j);
-                                       thisammo = min(own.ammofield, wep.ammofield);
-                                       wep.ammofield = thisammo;
-                                       own.ammofield -= thisammo;
-                                       s = strcat(s, " and ", ftos(thisammo), " ", Item_CounterFieldName(j));
 
                                        // if our weapon is loaded, give its load back to the player
-                                       if(self.weapon_load[self.weapon] > 0)
+                                       if(self.(weapon_load[self.weapon]) > 0)
                                        {
-                                               own.ammofield += self.weapon_load[self.weapon];
-                                               self.weapon_load[self.weapon] = -1; // schedule the weapon for reloading
+                                               own.ammofield += self.(weapon_load[self.weapon]);
+                                               self.(weapon_load[self.weapon]) = -1; // schedule the weapon for reloading
                                        }
+
+                                       wep.ammofield = 0;
+                               }
+                       }
+               }
+               else if(doreduce)
+               {
+                       for(i = 0, j = 1; i < 24; ++i, j *= 2)
+                       {
+                               if(wa & j)
+                               {
+                                       ammofield = Item_CounterField(j);
+
+                                       // if our weapon is loaded, give its load back to the player
+                                       if(self.(weapon_load[self.weapon]) > 0)
+                                       {
+                                               own.ammofield += self.(weapon_load[self.weapon]);
+                                               self.(weapon_load[self.weapon]) = -1; // schedule the weapon for reloading
+                                       }
+
+                                       thisammo = min(own.ammofield, wep.ammofield);
+                                       wep.ammofield = thisammo;
+                                       own.ammofield -= thisammo;
+                                       s = strcat(s, " and ", ftos(thisammo), " ", Item_CounterFieldName(j));
                                }
                        }
                        s = substring(s, 5, -1);
                }
                wep.glowmod = own.weaponentity_glowmod;
                wep.think = thrown_wep_think;
-               wep.nextthink = time + 0.5;
+               wep.savenextthink = wep.nextthink;
+               wep.nextthink = min(wep.nextthink, time + 0.5);
+               wep.pickup_anyway = TRUE; // these are ALWAYS pickable
                return s;
        }
 }
 
 float W_IsWeaponThrowable(float w)
 {
-       float wb, wa;
+       float wa;
 
        if (!autocvar_g_pickup_items)
                return 0;
@@ -265,18 +318,15 @@ float W_IsWeaponThrowable(float w)
                return 0;
        if (g_nexball && w == WEP_GRENADE_LAUNCHER)
                return 0;
-
-       wb = W_WeaponBit(w);
-       if(!wb)
-               return 0;
+    if(w == 0)
+        return 0;
+       
        wa = W_AmmoItemCode(w);
-       if(start_weapons & wb)
+       if(WEPSET_CONTAINS_AW(start_weapons, w))
        {
-               if(wa == IT_SUPERWEAPON && start_items & IT_UNLIMITED_SUPERWEAPONS)
-                       return 0;
-               if(wa != IT_SUPERWEAPON && start_items & IT_UNLIMITED_WEAPON_AMMO)
-                       return 0;
                // start weapons that take no ammo can't be dropped (this prevents dropping the laser, as long as it continues to use no ammo)
+               if(start_items & IT_UNLIMITED_WEAPON_AMMO)
+                       return 0;
                if(wa == 0)
                        return 0;
        }
@@ -287,7 +337,7 @@ float W_IsWeaponThrowable(float w)
 // toss current weapon
 void W_ThrowWeapon(vector velo, vector delta, float doreduce)
 {
-       local float w, wb;
+       float w;
        string a;
 
        w = self.weapon;
@@ -297,18 +347,15 @@ void W_ThrowWeapon(vector velo, vector delta, float doreduce)
                return;
        if(!autocvar_g_weapon_throwable)
                return;
-       if(autocvar_g_weapon_stay == 1)
-               return;
        if(self.weaponentity.state != WS_READY)
                return;
        if(!W_IsWeaponThrowable(w))
                return;
 
-       wb = W_WeaponBit(w);
-       if(self.weapons & wb != wb)
+       if(!WEPSET_CONTAINS_EW(self, w))
                return;
+       WEPSET_ANDNOT_EW(self, w);
 
-       self.weapons &~= wb;
        W_SwitchWeapon_Force(self, w_getbestweapon(self));
        a = W_ThrowNewWeapon(self, w, doreduce, self.origin + delta, velo);
        if not(a)
@@ -317,7 +364,7 @@ void W_ThrowWeapon(vector velo, vector delta, float doreduce)
                sprint(self, strcat("You dropped the ^2", W_Name(w), "\n"));
        else
                sprint(self, strcat("You dropped the ^2", W_Name(w), " with ", a, "\n"));
-};
+}
 
 // Bringed back weapon frame
 void W_WeaponFrame()
@@ -368,7 +415,7 @@ void W_WeaponFrame()
                        e = get_weaponinfo(self.switchweapon);
                        if(e.spawnflags & WEP_FLAG_RELOADABLE && cvar(strcat("g_balance_", e.netname, "_reload_ammo"))) // prevent accessing undefined cvars
                        {
-                               self.clip_load = self.weapon_load[self.switchweapon];
+                               self.clip_load = self.(weapon_load[self.switchweapon]);
                                self.clip_size = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
                        }
                        else
@@ -408,29 +455,29 @@ void W_WeaponFrame()
        //if (self.button0)
        //      print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(self)), " >= ", ftos(self.weapon_nextthink), "\n");
 
-       float wb;
-       wb = W_WeaponBit(self.weapon);
+       float w;
+       w = self.weapon;
 
        // call the think code which may fire the weapon
        // and do so multiple times to resolve framerate dependency issues if the
        // server framerate is very low and the weapon fire rate very high
-       local float c;
+       float c;
        c = 0;
        while (c < W_TICSPERFRAME)
        {
                c = c + 1;
-               if(wb && ((self.weapons & wb) == 0))
+               if(w && !WEPSET_CONTAINS_EW(self, w))
                {
                        if(self.weapon == self.switchweapon)
                                W_SwitchWeapon_Force(self, w_getbestweapon(self));
-                       wb = 0;
+                       w = 0;
                }
 
                v_forward = fo;
                v_right = ri;
                v_up = up;
 
-               if(wb)
+               if(w)
                        weapon_action(self.weapon, WR_THINK);
                else
                        weapon_action(self.weapon, WR_GONETHINK);
@@ -469,4 +516,21 @@ void W_WeaponFrame()
        else
                self.currentammo = 1;
 #endif
-};
+}
+
+string W_Apply_Weaponreplace(string in)
+{
+       float n = tokenize_console(in);
+       string out = "";
+       float i;
+       for(i = 0; i < n; ++i)
+       {
+               string s = argv(i);
+               string r = cvar_string(strcat("g_weaponreplace_", s));
+               if(r == "")
+                       out = strcat(out, " ", s);
+               else if(r != "0")
+                       out = strcat(out, " ", r);
+       }
+       return substring(out, 1, -1);
+}