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