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