]> icculus.org git repositories - divverent/nexuiz.git/blob - qcsrc/gamec/cl_weaponsystem.c
Updating
[divverent/nexuiz.git] / qcsrc / gamec / cl_weaponsystem.c
1 /*
2 ===========================================================================
3
4   CLIENT WEAPONSYSTEM CODE
5   Bring back W_Weaponframe
6
7 ===========================================================================
8 */ 
9 // definitions (move this part to defs after finishing of weapon system)
10 .entity weaponentity;
11 .float switchweapon;
12 void(float wpn, float wrequest) weapon_action;
13 void() w_clear;
14 // VorteX: standalone think for weapons, so normal think on weaponentity can be reserved by weaponflashes which needs update even player dies)
15 .float weapon_nextthink;
16 .void() weapon_think;
17 .vector shotdir, shotorg;
18 float   weapon_hasammo; // sets by WR_CHECKAMMO request
19
20 // weapon states (self.weaponentity.state)
21 float WS_CLEAR                  = 0; // no weapon selected
22 float WS_RAISE                  = 1; // raise frame
23 float WS_DROP                   = 2; // deselecting frame
24 float WS_INUSE                  = 3; // fire state
25 float WS_READY                  = 4; // idle frame
26
27 // weapon requests
28 float WR_SETUP            = 1;  // setup weapon data
29 float WR_UPDATECOUNTS = 2;  // update ammo display
30 float WR_IDLE             = 3;  // idle frame
31 float WR_DROP             = 4;  // deselect frame
32 float WR_RAISE            = 5;  // select frame
33 float WR_FIRE1            = 6;  // primary fire frame
34 float WR_FIRE2            = 7;  // secondary fire
35 float WR_FIRE3            = 8;  // third fire
36 float WR_CHECKAMMO        = 9;  // checks ammo for weapon 
37 float WR_CLEAR            = 10;  // runs afted deselecting frames, remove weapon parts (if presented). This useful for quake3-style chaingun
38
39 // Weapon indexes
40 float WEP_LASER                         = 1; // float   IT_LASER                                = 4096;
41 float WEP_SHOTGUN                       = 2; // float   IT_SHOTGUN                              = 1;
42 float WEP_UZI                           = 3; // float   IT_UZI                                  = 2;
43 float WEP_GRENADE_LAUNCHER      = 4; // float   IT_GRENADE_LAUNCHER             = 4; 
44 float WEP_ELECTRO                       = 5; // float   IT_ELECTRO                              = 8;
45 float WEP_CRYLINK                       = 6; // float   IT_CRYLINK                              = 16;
46 float WEP_NEX                           = 7; // float   IT_NEX                                  = 32;
47 float WEP_HAGAR                         = 8; // float   IT_HAGAR                                = 64;
48 float WEP_ROCKET_LAUNCHER       = 9; // float   IT_ROCKET_LAUNCHER              = 128;
49
50 // For weapon cycling commands
51 float WEP_FIRST                         = 1;
52 float WEP_LAST                          = 9;
53
54 // spawning weaponentity for client
55 void() CL_SpawnWeaponentity =
56 {
57         if (self.weaponentity)
58         {
59                 w_clear();
60                 return;
61         }
62         self.weaponentity = spawn();
63         self.weaponentity.solid = SOLID_NOT;
64         self.weaponentity.owner = self;
65         self.weaponentity.weaponentity = self.weaponentity;
66         setmodel(self.weaponentity, "");
67         self.weaponentity.origin = '0 0 0';
68         self.weaponentity.angles = '0 0 0';
69         self.weaponentity.viewmodelforclient = self;
70         self.weaponentity.flags = 0;
71 };
72
73 // convertion from index (= impulse) to flag in .items
74 float(float index) weapon_translateindextoflag =
75 {
76         if (index == WEP_LASER) 
77                 return IT_LASER;
78         else if (index == WEP_SHOTGUN) 
79                 return IT_SHOTGUN;
80         else if (index == WEP_UZI) 
81                 return IT_UZI;
82         else if (index == WEP_GRENADE_LAUNCHER) 
83                 return IT_GRENADE_LAUNCHER;
84         else if (index == WEP_ELECTRO)
85                 return IT_ELECTRO;
86         else if (index == WEP_CRYLINK) 
87                 return IT_CRYLINK;
88         else if (index == WEP_NEX) 
89                 return IT_NEX;
90         else if (index == WEP_HAGAR) 
91                 return IT_HAGAR;
92         else if (index == WEP_ROCKET_LAUNCHER)
93                 return IT_ROCKET_LAUNCHER;
94 };
95
96 float(entity cl, float wpn, float andammo) client_hasweapon =
97 {
98         local float itemcode;
99
100         itemcode = weapon_translateindextoflag(wpn);
101         if (cl.items & itemcode)
102         {
103                 if (andammo)
104                 {
105                         weapon_action(wpn, WR_CHECKAMMO);
106                         if (weapon_hasammo)
107                                 return TRUE;
108                         return FALSE;
109                 }
110                 return TRUE;
111         }
112         return FALSE;
113 };
114
115 // Weapon subs
116 void() w_clear =
117 {
118         weapon_action(self.weapon, WR_CLEAR); 
119         if (self.weapon != -1)
120                 self.weapon = 0;
121         self.weaponentity.state = WS_CLEAR;
122         setmodel(self.weaponentity, "");
123         self.weaponentity.effects = 0;
124 };
125
126 void() w_ready =
127 {
128         self.weaponentity.state = WS_READY;
129         weapon_action(self.weapon, WR_IDLE); 
130 };
131
132 // FIXME: add qw-style client-custom weaponrating (cl_weaponrating)?
133 void() w_bestweapon
134 {// add new weapons here
135         weapon_hasammo = TRUE;
136         if (client_hasweapon(self, WEP_ROCKET_LAUNCHER, TRUE))
137                 self.switchweapon = WEP_ROCKET_LAUNCHER;
138         else if (client_hasweapon(self, WEP_NEX, TRUE))
139                 self.switchweapon = WEP_NEX;
140         else if (client_hasweapon(self, WEP_HAGAR, TRUE))
141                 self.switchweapon = WEP_HAGAR;
142         else if (client_hasweapon(self, WEP_GRENADE_LAUNCHER, TRUE))
143                 self.switchweapon = WEP_GRENADE_LAUNCHER;
144         else if (client_hasweapon(self, WEP_ELECTRO, TRUE))
145                 self.switchweapon = WEP_ELECTRO;
146         else if (client_hasweapon(self, WEP_CRYLINK, TRUE))
147                 self.switchweapon = WEP_CRYLINK;
148         else if (client_hasweapon(self, WEP_UZI, TRUE))
149                 self.switchweapon = WEP_UZI;
150         else if (client_hasweapon(self, WEP_SHOTGUN, TRUE))
151                 self.switchweapon = WEP_SHOTGUN;
152         else
153                 self.switchweapon = WEP_LASER;
154 };
155
156 // Setup weapon for client (after this raise frame will be launched)
157 void(float windex, string wmodel, float hudammo) weapon_setup =
158 {
159         local string wdir, weaponmdl;
160
161         self.items = self.items - (self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS));
162         self.items = self.items | hudammo;
163
164         self.weapon = windex;
165
166         if (wmodel != "")
167         {
168                 weaponmdl = strzone(strcat("models/weapons/", wmodel));
169                 setmodel(self.weaponentity, weaponmdl);
170         }
171         // VorteX: update visible weapon
172         // CL_ViswepUpdate();
173 };
174
175 // shot direction
176 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
177 void(float x, float y, float z) weapon_shotdir =
178 {
179         makevectors(self.v_angle);
180         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;
181         self.shotdir = aim(self, 1000);
182 };
183
184 // perform weapon to attack (weaponstate and attack_finished check is here)
185 void(float() checkfunc1, float() checkfunc2, void() firefunc, float atktime) weapon_prepareattack =
186 {
187         // Change to best weapon if failed
188         if (!(game & GAME_INSTAGIB) && !(game & GAME_ROCKET_ARENA))
189         {
190                 if (!checkfunc1())
191                 {
192                         if (!checkfunc2())
193                                 w_bestweapon();
194                         return;
195                 }
196         }
197         // Don't do shot if previos attack  not finished
198         if (!(game & GAME_INSANE))
199                 if (time < self.attack_finished)            
200                         return; 
201         // Can't do shot if changing weapon
202         if (!(game & GAME_INSANE))
203                 if (self.weaponentity.state != WS_READY)        
204                         return;
205
206         self.attack_finished = time + atktime;
207         firefunc();
208 };
209
210 // perform weapon attack
211 void(float() checkfunc1, float() checkfunc2, void() firefunc) weapon_doattack
212 {
213         // Change to best weapon if failed
214         if (!(game & GAME_INSTAGIB) && !(game & GAME_ROCKET_ARENA))
215         {
216                 if (!checkfunc1())
217                 {
218                         if (!checkfunc2())
219                                 w_bestweapon();
220                         return;
221                 }
222         }
223         self.weaponentity.state = WS_INUSE;
224         firefunc();
225         weapon_action(self.weapon, WR_UPDATECOUNTS); // update ammo now
226 };
227
228 void(entity ent, float recoil) weapon_recoil =
229 {
230         ent.punchangle = (randomvec() + '-1 0 0')*recoil;
231         ent.punchangle_z = 0; // don't want roll
232         if (recoil > 3) // push back if large recoil
233                 ent.velocity = ent.velocity - normalize(ent.shotdir)*recoil*25;
234 };
235
236 void(float fr, float t, void() func) weapon_thinkf =
237 {
238         if (fr >= 0)
239                 if (self.weaponentity != world)
240                         self.weaponentity.frame = fr;
241         // VorteX: haste can be added here
242         self.weapon_nextthink = time + t;
243         self.weapon_think = func;
244 };
245
246 void(float spd, vector org) weapon_boblayer1 =
247 {
248         // VorteX: haste can be added here
249         self.weaponentity.pos1 =org;
250         self.weaponentity.lip = spd;
251 };