]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/weapons/throwing.qc
Merge branch 'master' into terencehill/keyhunt
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / weapons / throwing.qc
1 #include "throwing.qh"
2
3 #include "weaponsystem.qh"
4 #include "../mutators/_mod.qh"
5 #include <common/t_items.qh>
6 #include "../g_damage.qh"
7 #include <common/items/item.qh>
8 #include <common/mapinfo.qh>
9 #include <common/notifications/all.qh>
10 #include <common/triggers/subs.qh>
11 #include <common/util.qh>
12 #include <common/weapons/_all.qh>
13 #include <common/state.qh>
14
15 void thrown_wep_think(entity this)
16 {
17         this.nextthink = time;
18         if(this.oldorigin != this.origin)
19         {
20                 this.SendFlags |= ISF_LOCATION;
21                 this.oldorigin = this.origin;
22                 this.bot_pickup = false;
23         }
24         else
25                 this.bot_pickup = true;
26         this.owner = NULL;
27         float timeleft = this.savenextthink - time;
28         if(timeleft > 1)
29                 SUB_SetFade(this, this.savenextthink - 1, 1);
30         else if(timeleft > 0)
31                 SUB_SetFade(this, time, timeleft);
32         else
33                 SUB_VanishOrRemove(this);
34 }
35
36 // returns amount of ammo used as string, or -1 for failure, or 0 for no ammo count
37 string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo)
38 {
39         float thisammo;
40         string s;
41         Weapon info = Weapons_from(wpn);
42         var .int ammotype = info.ammo_field;
43
44         entity wep = new(droppedweapon);
45
46         setorigin(wep, org);
47         wep.velocity = velo;
48         wep.owner = wep.enemy = own;
49         wep.flags |= FL_TOSSED;
50         wep.colormap = own.colormap;
51         wep.glowmod = weaponentity_glowmod(info, own, own.clientcolors);
52
53         W_DropEvent(wr_drop,own,wpn,wep);
54
55         if(WepSet_FromWeapon(Weapons_from(wpn)) & WEPSET_SUPERWEAPONS)
56         {
57                 if(own.items & IT_UNLIMITED_SUPERWEAPONS)
58                 {
59                         wep.superweapons_finished = time + autocvar_g_balance_superweapons_time;
60                 }
61                 else
62                 {
63                         int superweapons = 1;
64                         FOREACH(Weapons, it != WEP_Null, LAMBDA(
65                                 WepSet set = it.m_wepset;
66                                 if((set & WEPSET_SUPERWEAPONS) && (own.weapons & set)) ++superweapons;
67                         ));
68                         if(superweapons <= 1)
69                         {
70                                 wep.superweapons_finished = own.superweapons_finished;
71                                 own.superweapons_finished = 0;
72                         }
73                         else
74                         {
75                                 float timeleft = own.superweapons_finished - time;
76                                 float weptimeleft = timeleft / superweapons;
77                                 wep.superweapons_finished = time + weptimeleft;
78                                 own.superweapons_finished -= weptimeleft;
79                         }
80                 }
81         }
82
83         weapon_defaultspawnfunc(wep, info);
84         if(startitem_failed)
85                 return string_null;
86         setthink(wep, thrown_wep_think);
87         wep.savenextthink = wep.nextthink;
88         wep.nextthink = min(wep.nextthink, time + 0.5);
89         wep.pickup_anyway = true; // these are ALWAYS pickable
90
91         //wa = W_AmmoItemCode(wpn);
92         if(ammotype == ammo_none)
93         {
94                 return "";
95         }
96         else
97         {
98                 s = "";
99
100                 if(doreduce && g_weapon_stay == 2)
101                 {
102                         // if our weapon is loaded, give its load back to the player
103                         int i = PS(own).m_weapon.m_id;
104                         if(own.(weapon_load[i]) > 0)
105                         {
106                                 own.(ammotype) += own.(weapon_load[i]);
107                                 own.(weapon_load[i]) = -1; // schedule the weapon for reloading
108                         }
109
110                         wep.(ammotype) = 0;
111                 }
112                 else if(doreduce)
113                 {
114                         // if our weapon is loaded, give its load back to the player
115                         int i = PS(own).m_weapon.m_id;
116                         if(own.(weapon_load[i]) > 0)
117                         {
118                                 own.(ammotype) += own.(weapon_load[i]);
119                                 own.(weapon_load[i]) = -1; // schedule the weapon for reloading
120                         }
121
122                         thisammo = min(own.(ammotype), wep.(ammotype));
123                         wep.(ammotype) = thisammo;
124                         own.(ammotype) -= thisammo;
125
126                         switch(ammotype)
127                         {
128                                 case ammo_shells:  s = sprintf("%s and %d shells", s, thisammo);  break;
129                                 case ammo_nails:   s = sprintf("%s and %d nails", s, thisammo);   break;
130                                 case ammo_rockets: s = sprintf("%s and %d rockets", s, thisammo); break;
131                                 case ammo_cells:   s = sprintf("%s and %d cells", s, thisammo);   break;
132                                 case ammo_plasma:  s = sprintf("%s and %d plasma", s, thisammo);  break;
133                                 case ammo_fuel:    s = sprintf("%s and %d fuel", s, thisammo);    break;
134                         }
135
136                         s = substring(s, 5, -1);
137                 }
138                 return s;
139         }
140 }
141
142 bool W_IsWeaponThrowable(entity this, int w)
143 {
144         if (MUTATOR_CALLHOOK(ForbidDropCurrentWeapon, this))
145                 return false;
146         if (!autocvar_g_pickup_items)
147                 return false;
148         if (g_weaponarena)
149                 return 0;
150         if (g_cts)
151                 return 0;
152     if(w == WEP_Null.m_id)
153         return false;
154
155         #if 0
156         if(start_weapons & WepSet_FromWeapon(Weapons_from(w)))
157         {
158                 // start weapons that take no ammo can't be dropped (this prevents dropping the laser, as long as it continues to use no ammo)
159                 if(start_items & IT_UNLIMITED_WEAPON_AMMO)
160                         return false;
161                 if((Weapons_from(w)).ammo_field == ammo_none)
162                         return false;
163         }
164         return true;
165         #else
166         return (Weapons_from(w)).weaponthrowable;
167         #endif
168 }
169
170 // toss current weapon
171 void W_ThrowWeapon(entity this, .entity weaponentity, vector velo, vector delta, float doreduce)
172 {
173         Weapon w = PS(this).m_weapon;
174         if (w == WEP_Null)
175                 return; // just in case
176         if(MUTATOR_CALLHOOK(ForbidThrowCurrentWeapon, this))
177                 return;
178         if(!autocvar_g_weapon_throwable)
179                 return;
180         if(this.(weaponentity).state != WS_READY)
181                 return;
182         if(!W_IsWeaponThrowable(this, w.m_id))
183                 return;
184
185         WepSet set = WepSet_FromWeapon(w);
186         if(!(this.weapons & set)) return;
187         this.weapons &= ~set;
188
189         W_SwitchWeapon_Force(this, w_getbestweapon(this));
190         string a = W_ThrowNewWeapon(this, w.m_id, doreduce, this.origin + delta, velo);
191
192         if(!a) return;
193         Send_Notification(NOTIF_ONE, this, MSG_MULTI, ITEM_WEAPON_DROP, a, w.m_id);
194 }
195
196 void SpawnThrownWeapon(entity this, vector org, float w)
197 {
198         if(this.weapons & WepSet_FromWeapon(PS(this).m_weapon))
199                 if(W_IsWeaponThrowable(this, PS(this).m_weapon.m_id))
200                         W_ThrowNewWeapon(this, PS(this).m_weapon.m_id, false, org, randomvec() * 125 + '0 0 200');
201 }