]> icculus.org git repositories - divverent/nexuiz.git/blob - qcsrc/gamec/cl_weaponsystem.c
more control over starting weapons/ammo/pickups
[divverent/nexuiz.git] / qcsrc / gamec / cl_weaponsystem.c
1 /*
2 ===========================================================================
3
4   CLIENT WEAPONSYSTEM CODE
5   Bring back W_Weaponframe
6
7 ===========================================================================
8 */
9
10 void() CL_Weaponentity_Think =
11 {
12         self.nextthink = time;
13         if (self.owner.weaponentity != self)
14         {
15                 remove(self);
16                 return;
17         }
18         self.effects = self.owner.effects;
19         self.alpha = self.owner.alpha;
20 };
21
22 void() CL_ExteriorWeaponentity_Think =
23 {
24         self.nextthink = time;
25         if (self.owner.exteriorweaponentity != self)
26         {
27                 remove(self);
28                 return;
29         }
30         if (self.cnt != self.owner.weaponentity.modelindex || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag)
31         {
32                 self.cnt = self.owner.weaponentity.modelindex;
33                 self.dmg = self.owner.modelindex;
34                 self.deadflag = self.owner.deadflag;
35                 if (self.owner.deadflag) self.model = "";
36                 else if (self.owner.weapon == WEP_LASER) setmodel(self, "models/weapons/v_laser.md3");
37                 else if (self.owner.weapon == WEP_SHOTGUN) setmodel(self, "models/weapons/v_shotgun.md3");
38                 else if (self.owner.weapon == WEP_UZI) setmodel(self, "models/weapons/v_uzi.md3");
39                 else if (self.owner.weapon == WEP_GRENADE_LAUNCHER) setmodel(self, "models/weapons/v_gl.md3");
40                 else if (self.owner.weapon == WEP_ELECTRO) setmodel(self, "models/weapons/v_electro.md3");
41                 else if (self.owner.weapon == WEP_CRYLINK) setmodel(self, "models/weapons/v_crylink.md3");
42                 else if (self.owner.weapon == WEP_NEX) setmodel(self, "models/weapons/v_nex.md3");
43                 else if (self.owner.weapon == WEP_HAGAR) setmodel(self, "models/weapons/v_hagar.md3");
44                 else if (self.owner.weapon == WEP_ROCKET_LAUNCHER) setmodel(self, "models/weapons/v_rl.md3");
45                 setattachment(self, self.owner, "bip01 r hand");
46                 // if that didn't find a tag, hide the exterior weapon model
47                 if (!self.tag_index)
48                         self.model = "";
49         }
50         self.effects = self.owner.weaponentity.effects;
51 };
52
53 // spawning weaponentity for client
54 void() CL_SpawnWeaponentity =
55 {
56         if (self.weaponentity)
57         {
58                 w_clear();
59                 return;
60         }
61         self.weaponentity = spawn();
62         self.weaponentity.solid = SOLID_NOT;
63         self.weaponentity.owner = self;
64         self.weaponentity.weaponentity = self.weaponentity;
65         setmodel(self.weaponentity, "");
66         self.weaponentity.origin = '0 0 0';
67         self.weaponentity.angles = '0 0 0';
68         self.weaponentity.viewmodelforclient = self;
69         self.weaponentity.flags = 0;
70         self.weaponentity.think = CL_Weaponentity_Think;
71         self.weaponentity.nextthink = time;
72
73         self.exteriorweaponentity = spawn();
74         self.exteriorweaponentity.solid = SOLID_NOT;
75         self.exteriorweaponentity.exteriorweaponentity = self.exteriorweaponentity;
76         self.exteriorweaponentity.owner = self;
77         self.exteriorweaponentity.origin = '0 0 0';
78         self.exteriorweaponentity.angles = '0 0 0';
79         self.exteriorweaponentity.think = CL_ExteriorWeaponentity_Think;
80         self.exteriorweaponentity.nextthink = time;
81 };
82
83 // convertion from index (= impulse) to flag in .items
84 float(float index) weapon_translateindextoflag =
85 {
86         if (index == WEP_LASER)
87                 return IT_LASER;
88         else if (index == WEP_SHOTGUN)
89                 return IT_SHOTGUN;
90         else if (index == WEP_UZI)
91                 return IT_UZI;
92         else if (index == WEP_GRENADE_LAUNCHER)
93                 return IT_GRENADE_LAUNCHER;
94         else if (index == WEP_ELECTRO)
95                 return IT_ELECTRO;
96         else if (index == WEP_CRYLINK)
97                 return IT_CRYLINK;
98         else if (index == WEP_NEX)
99                 return IT_NEX;
100         else if (index == WEP_HAGAR)
101                 return IT_HAGAR;
102         else if (index == WEP_ROCKET_LAUNCHER)
103                 return IT_ROCKET_LAUNCHER;
104         return IT_LASER;
105 };
106
107 float(entity cl, float wpn, float andammo) client_hasweapon =
108 {
109         local float itemcode;
110         local entity oldself;
111
112         weapon_hasammo = TRUE;
113         if (wpn < WEP_FIRST || wpn > WEP_LAST)
114                 return FALSE;
115         itemcode = weapon_translateindextoflag(wpn);
116         if (cl.items & itemcode)
117         {
118                 if (andammo)
119                 {
120                         oldself = self;
121                         self = cl;
122                         weapon_action(wpn, WR_CHECKAMMO);
123                         self = oldself;
124                         if (weapon_hasammo)
125                                 return TRUE;
126                         return FALSE;
127                 }
128                 return TRUE;
129         }
130         return FALSE;
131 };
132
133 // Weapon subs
134 void() w_clear =
135 {
136         weapon_action(self.weapon, WR_CLEAR);
137         if (self.weapon != -1)
138                 self.weapon = 0;
139         if (self.weaponentity)
140         {
141                 self.weaponentity.state = WS_CLEAR;
142                 setmodel(self.weaponentity, "");
143                 self.weaponentity.effects = 0;
144         }
145 };
146
147 void() w_ready =
148 {
149         self.weaponentity.state = WS_READY;
150         weapon_action(self.weapon, WR_IDLE);
151 };
152
153 // FIXME: add qw-style client-custom weaponrating (cl_weaponrating)?
154 float(entity e) w_getbestweapon
155 {// add new weapons here
156         if (client_hasweapon(e, WEP_ROCKET_LAUNCHER, TRUE))
157                 return WEP_ROCKET_LAUNCHER;
158         else if (client_hasweapon(e, WEP_NEX, TRUE))
159                 return WEP_NEX;
160         else if (client_hasweapon(e, WEP_HAGAR, TRUE))
161                 return WEP_HAGAR;
162         else if (client_hasweapon(e, WEP_GRENADE_LAUNCHER, TRUE))
163                 return WEP_GRENADE_LAUNCHER;
164         else if (client_hasweapon(e, WEP_ELECTRO, TRUE))
165                 return WEP_ELECTRO;
166         else if (client_hasweapon(e, WEP_CRYLINK, TRUE))
167                 return WEP_CRYLINK;
168         else if (client_hasweapon(e, WEP_UZI, TRUE))
169                 return WEP_UZI;
170         else if (client_hasweapon(e, WEP_SHOTGUN, TRUE))
171                 return WEP_SHOTGUN;
172         else
173         {
174                 weapon_hasammo = TRUE;
175                 return WEP_LASER;
176         }
177 };
178
179 // Setup weapon for client (after this raise frame will be launched)
180 void(float windex, string wmodel, float hudammo) weapon_setup =
181 {
182         local string weaponmdl;
183
184         self.items = self.items - (self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS));
185         self.items = self.items | hudammo;
186
187         self.weapon = windex;
188
189         if (wmodel != "")
190         {
191                 weaponmdl = strzone(strcat("models/weapons/", wmodel));
192                 setmodel(self.weaponentity, weaponmdl);
193         }
194         // VorteX: update visible weapon
195         // CL_ViswepUpdate();
196 };
197
198 // shot direction
199 float WEAPON_MAXRELX = 14; // if more, shot can be spawned after wall surface (in empty worldspace) or inside other entity if client stands close to it
200 void(float x, float y, float z) weapon_shotdir =
201 {
202         makevectors(self.v_angle);
203         self.shotorg  = self.origin + self.view_ofs + v_forward*bound(0, x, WEAPON_MAXRELX) + v_right*(y + self.weaponentity.view_ofs_y) + v_up*z;
204         self.shotdir = aim(self, 1000);
205 };
206
207 // perform weapon to attack (weaponstate and attack_finished check is here)
208 void(float() checkfunc1, float() checkfunc2, void() firefunc, float atktime) weapon_prepareattack =
209 {
210         if (!checkfunc1())
211         {
212                 if (!checkfunc2())
213                         self.switchweapon = w_getbestweapon(self);
214                 return;
215         }
216         // Don't do shot if previos attack  not finished
217                 if (time < self.attack_finished)
218                         return;
219         // Can't do shot if changing weapon
220                 if (self.weaponentity.state != WS_READY)
221                         return;
222
223         self.attack_finished = time + atktime;
224         firefunc();
225 };
226
227 // perform weapon attack
228 void(float() checkfunc1, float() checkfunc2, void() firefunc) weapon_doattack
229 {
230         if (!checkfunc1())
231         {
232                 if (!checkfunc2())
233                         self.switchweapon = w_getbestweapon(self);
234                 return;
235         }
236         self.weaponentity.state = WS_INUSE;
237         firefunc();
238         weapon_action(self.weapon, WR_UPDATECOUNTS); // update ammo now
239 };
240
241 void(entity ent, float recoil) weapon_recoil =
242 {
243         ent.punchangle = (randomvec() + '-1 0 0')*recoil;
244         ent.punchangle_z = 0; // don't want roll
245         if (recoil > 3) // push back if large recoil
246                 ent.velocity = ent.velocity - normalize(ent.shotdir)*recoil*25;
247 };
248
249 void(float fr, float t, void() func) weapon_thinkf =
250 {
251         if (fr >= 0)
252         {
253                 if (self.weaponentity != world)
254                         self.weaponentity.frame = fr;
255         }
256
257         if(cvar("g_runematch"))
258         {
259                 if(self.runes & RUNE_SPEED)
260                 {
261                         if(self.runes & CURSE_SLOW)
262                                 t = t * cvar("g_balance_rune_speed_combo_atkrate");
263                         else
264                                 t = t * cvar("g_balance_rune_speed_atkrate");
265                 }
266                 else if(self.runes & CURSE_SLOW)
267                 {
268                         t = t * cvar("g_balance_curse_slow_atkrate");
269                 }
270         }
271
272         // VorteX: haste can be added here
273         self.weapon_nextthink = time + t;
274         self.weapon_think = func;
275 };
276
277 void(float spd, vector org) weapon_boblayer1 =
278 {
279         // VorteX: haste can be added here
280         self.weaponentity.pos1 =org;
281         self.weaponentity.lip = spd;
282 };