Merge branch 'master' into Mario/qc_updates
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / weapons / weapons.qc
1 #ifndef WEAPONS_C
2 #define WEAPONS_C
3
4 #include "weapons.qh"
5
6 #if defined(CSQC)
7         #include "../../dpdefs/csprogsdefs.qh"
8         #include "../../client/defs.qh"
9         #include "../constants.qh"
10         #include "../stats.qh"
11         #include "../../warpzonelib/anglestransform.qh"
12         #include "../../warpzonelib/mathlib.qh"
13         #include "../../warpzonelib/common.qh"
14         #include "../../warpzonelib/client.qh"
15         #include "../util.qh"
16         #include "../buffs.qh"
17         #include "../../client/autocvars.qh"
18         #include "../deathtypes.qh"
19         #include "../../csqcmodellib/interpolate.qh"
20         #include "../../client/movetypes.qh"
21         #include "../../client/main.qh"
22         #include "../../csqcmodellib/cl_model.qh"
23 #elif defined(MENUQC)
24 #elif defined(SVQC)
25         #include "../../dpdefs/progsdefs.qh"
26     #include "../../dpdefs/dpextensions.qh"
27     #include "../../warpzonelib/anglestransform.qh"
28     #include "../../warpzonelib/mathlib.qh"
29     #include "../../warpzonelib/common.qh"
30     #include "../../warpzonelib/util_server.qh"
31     #include "../../warpzonelib/server.qh"
32     #include "../constants.qh"
33     #include "../stats.qh"
34     #include "../teams.qh"
35     #include "../util.qh"
36     #include "../buffs.qh"
37     #include "../monsters/monsters.qh"
38     #include "config.qh"
39     #include "../../server/weapons/csqcprojectile.qh"
40     #include "../../server/weapons/tracing.qh"
41     #include "../../server/t_items.qh"
42     #include "../../server/autocvars.qh"
43     #include "../../server/constants.qh"
44     #include "../../server/defs.qh"
45     #include "../notifications.qh"
46     #include "../deathtypes.qh"
47     #include "../../server/mutators/mutators_include.qh"
48     #include "../mapinfo.qh"
49     #include "../../server/command/common.qh"
50     #include "../../csqcmodellib/sv_model.qh"
51     #include "../../server/portals.qh"
52     #include "../../server/g_hook.qh"
53 #endif
54 #ifndef MENUQC
55 #include "calculations.qc"
56 #endif
57 #include "all.qh"
58
59 // WEAPON PLUGIN SYSTEM
60 entity weapon_info[WEP_MAXCOUNT];
61 entity dummy_weapon_info;
62
63 #if WEP_MAXCOUNT > 72
64 # error Kein Weltraum links auf dem Gerät
65 #endif
66
67 WepSet WepSet_FromWeapon(float a) {
68         a -= WEP_FIRST;
69 #if WEP_MAXCOUNT > 24
70         if(a >= 24) {
71                 a -= 24;
72 #if WEP_MAXCOUNT > 48
73                 if(a >= 24) {
74                         a -= 24;
75                         return '0 0 1' * power2of(a);
76                 }
77 #endif
78                 return '0 1 0' * power2of(a);
79         }
80 #endif
81         return '1 0 0' * power2of(a);
82 }
83 #ifdef SVQC
84 void WepSet_AddStat()
85 {
86         addstat(STAT_WEAPONS, AS_INT, weapons_x);
87 #if WEP_MAXCOUNT > 24
88         addstat(STAT_WEAPONS2, AS_INT, weapons_y);
89 #if WEP_MAXCOUNT > 48
90         addstat(STAT_WEAPONS3, AS_INT, weapons_z);
91 #endif
92 #endif
93 }
94 void WriteWepSet(float dst, WepSet w)
95 {
96 #if WEP_MAXCOUNT > 48
97         WriteInt72_t(dst, w);
98 #elif WEP_MAXCOUNT > 24
99         WriteInt48_t(dst, w);
100 #else
101         WriteInt24_t(dst, w.x);
102 #endif
103 }
104 #endif
105 #ifdef CSQC
106 WepSet WepSet_GetFromStat()
107 {
108         WepSet w = '0 0 0';
109         w.x = getstati(STAT_WEAPONS);
110 #if WEP_MAXCOUNT > 24
111         w.y = getstati(STAT_WEAPONS2);
112 #if WEP_MAXCOUNT > 48
113         w.z = getstati(STAT_WEAPONS3);
114 #endif
115 #endif
116         return w;
117 }
118 WepSet ReadWepSet()
119 {
120 #if WEP_MAXCOUNT > 48
121         return ReadInt72_t();
122 #elif WEP_MAXCOUNT > 24
123         return ReadInt48_t();
124 #else
125         return ReadInt24_t() * '1 0 0';
126 #endif
127 }
128 #endif
129
130 void register_weapon(
131         int id,
132         WepSet bit,
133         float(float) func,
134         .float ammotype,
135         float i,
136         float weapontype,
137         float pickupbasevalue,
138         vector clr,
139         string modelname,
140         string simplemdl,
141         string crosshair,
142         string wepimg,
143         string refname,
144         string wepname)
145 {
146         entity e;
147         weapon_info[id - 1] = e = spawn();
148         e.classname = "weapon_info";
149         e.weapon = id;
150         e.weapons = bit;
151         e.weapon_func = func;
152         e.ammo_field = ammotype;
153         e.impulse = i;
154         e.spawnflags = weapontype;
155         e.bot_pickupbasevalue = pickupbasevalue;
156         e.wpcolor = clr;
157         e.wpmodel = strzone(strcat("wpn-", ftos(id)));
158         e.mdl = modelname;
159         e.model = strzone(strcat("models/weapons/g_", modelname, ".md3"));
160         e.w_simplemdl = strzone(simplemdl); // simpleitems weapon model/image
161         e.w_crosshair = strzone(car(crosshair));
162         string s = cdr(crosshair);
163         e.w_crosshair_size = ((s != "") ? stof(s) : 1); // so that we can scale the crosshair from code (for compat)
164         e.model2 = strzone(wepimg);
165         e.netname = refname;
166         e.message = wepname;
167
168         #ifdef CSQC
169         func(WR_INIT);
170         #endif
171 }
172 float w_null(float dummy)
173 {
174         return 0;
175 }
176 void register_weapons_done()
177 {
178         dummy_weapon_info = spawn();
179         dummy_weapon_info.classname = "weapon_info";
180         dummy_weapon_info.weapon = 0; // you can recognize dummies by this
181         dummy_weapon_info.weapons = '0 0 0';
182         dummy_weapon_info.netname = "";
183         dummy_weapon_info.message = "AOL CD Thrower";
184         dummy_weapon_info.weapon_func = w_null;
185         dummy_weapon_info.wpmodel = "";
186         dummy_weapon_info.mdl = "";
187         dummy_weapon_info.model = "";
188         dummy_weapon_info.spawnflags = 0;
189         dummy_weapon_info.impulse = -1;
190         dummy_weapon_info.bot_pickupbasevalue = 0;
191         dummy_weapon_info.ammo_field = ammo_none;
192
193         dummy_weapon_info.w_crosshair = "gfx/crosshair1";
194         dummy_weapon_info.w_crosshair_size = 1;
195         dummy_weapon_info.model2 = "";
196
197         int i;
198         weaponorder_byid = "";
199         for(i = WEP_MAXCOUNT; i >= 1; --i)
200                 if(weapon_info[i-1])
201                         weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i));
202         weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
203 }
204 entity get_weaponinfo(int id)
205 {
206         entity w;
207         if(id < WEP_FIRST || id > WEP_LAST)
208                 return dummy_weapon_info;
209         w = weapon_info[id - 1];
210         if(w)
211                 return w;
212         return dummy_weapon_info;
213 }
214 string W_FixWeaponOrder(string order, float complete)
215 {
216         return fixPriorityList(order, WEP_FIRST, WEP_LAST, 230 - WEP_FIRST, complete);
217 }
218 string W_NameWeaponOrder_MapFunc(string s)
219 {
220         entity wi;
221         if(s == "0" || stof(s))
222         {
223                 wi = get_weaponinfo(stof(s));
224                 if(wi != dummy_weapon_info)
225                         return wi.netname;
226         }
227         return s;
228 }
229
230 string W_UndeprecateName(string s)
231 {
232         switch ( s )
233         {
234                 case "nex"            : return "vortex";
235                 case "rocketlauncher" : return "devastator";
236                 case "laser"          : return "blaster";
237                 case "minstanex"      : return "vaporizer";
238                 case "grenadelauncher": return "mortar";
239                 case "uzi"            : return "machinegun";
240                 default               : return s;
241         }
242 }
243 string W_NameWeaponOrder(string order)
244 {
245         return mapPriorityList(order, W_NameWeaponOrder_MapFunc);
246 }
247 string W_NumberWeaponOrder_MapFunc(string s)
248 {
249         float i;
250         if(s == "0" || stof(s))
251                 return s;
252         s = W_UndeprecateName(s);
253         for(i = WEP_FIRST; i <= WEP_LAST; ++i)
254                 if(s == get_weaponinfo(i).netname)
255                         return ftos(i);
256         return s;
257 }
258 string W_NumberWeaponOrder(string order)
259 {
260         return mapPriorityList(order, W_NumberWeaponOrder_MapFunc);
261 }
262
263 float W_FixWeaponOrder_BuildImpulseList_buf[WEP_MAXCOUNT];
264 string W_FixWeaponOrder_BuildImpulseList_order;
265 void W_FixWeaponOrder_BuildImpulseList_swap(int i, int j, entity pass)
266 {
267         float h;
268         h = W_FixWeaponOrder_BuildImpulseList_buf[i];
269         W_FixWeaponOrder_BuildImpulseList_buf[i] = W_FixWeaponOrder_BuildImpulseList_buf[j];
270         W_FixWeaponOrder_BuildImpulseList_buf[j] = h;
271 }
272 float W_FixWeaponOrder_BuildImpulseList_cmp(int i, int j, entity pass)
273 {
274         entity e1, e2;
275         float d;
276         e1 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[i]);
277         e2 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[j]);
278         d = (e1.impulse + 9) % 10 - (e2.impulse + 9) % 10;
279         if(d != 0)
280                 return -d; // high impulse first!
281         return
282                 strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[i]), 0)
283                 -
284                 strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[j]), 0)
285                 ; // low char index first!
286 }
287 string W_FixWeaponOrder_BuildImpulseList(string o)
288 {
289         int i;
290         W_FixWeaponOrder_BuildImpulseList_order = o;
291         for(i = WEP_FIRST; i <= WEP_LAST; ++i)
292                 W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST] = i;
293         heapsort(WEP_LAST - WEP_FIRST + 1, W_FixWeaponOrder_BuildImpulseList_swap, W_FixWeaponOrder_BuildImpulseList_cmp, world);
294         o = "";
295         for(i = WEP_FIRST; i <= WEP_LAST; ++i)
296                 o = strcat(o, " ", ftos(W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST]));
297         W_FixWeaponOrder_BuildImpulseList_order = string_null;
298         return substring(o, 1, -1);
299 }
300
301 string W_FixWeaponOrder_AllowIncomplete(string order)
302 {
303         return W_FixWeaponOrder(order, 0);
304 }
305
306 string W_FixWeaponOrder_ForceComplete(string order)
307 {
308         if(order == "")
309                 order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority"));
310         return W_FixWeaponOrder(order, 1);
311 }
312
313 void W_RandomWeapons(entity e, float n)
314 {
315         float i, j;
316         WepSet remaining;
317         WepSet result;
318         remaining = e.weapons;
319         result = '0 0 0';
320         for(i = 0; i < n; ++i)
321         {
322                 RandomSelection_Init();
323                 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
324                         if(remaining & WepSet_FromWeapon(j))
325                                 RandomSelection_Add(world, j, string_null, 1, 1);
326                 result |= WepSet_FromWeapon(RandomSelection_chosen_float);
327                 remaining &= ~WepSet_FromWeapon(RandomSelection_chosen_float);
328         }
329         e.weapons = result;
330 }
331
332 string GetAmmoPicture(.float ammotype)
333 {
334         switch(ammotype)
335         {
336                 case ammo_shells:  return "ammo_shells";
337                 case ammo_nails:   return "ammo_bullets";
338                 case ammo_rockets: return "ammo_rockets";
339                 case ammo_cells:   return "ammo_cells";
340                 case ammo_plasma:  return "ammo_cells";
341                 case ammo_fuel:    return "ammo_fuel";
342                 default: return ""; // wtf, no ammo type?
343         }
344 }
345
346 #ifdef CSQC
347 .float GetAmmoFieldFromNum(int i)
348 {
349         switch(i)
350         {
351                 case 0: return ammo_shells;
352                 case 1: return ammo_nails;
353                 case 2: return ammo_rockets;
354                 case 3: return ammo_cells;
355                 case 4: return ammo_plasma;
356                 case 5: return ammo_fuel;
357                 default: return ammo_none;
358         }
359 }
360
361 int GetAmmoStat(.float ammotype)
362 {
363         switch(ammotype)
364         {
365                 case ammo_shells: return STAT_SHELLS;
366                 case ammo_nails: return STAT_NAILS;
367                 case ammo_rockets: return STAT_ROCKETS;
368                 case ammo_cells: return STAT_CELLS;
369                 case ammo_plasma: return STAT_PLASMA;
370                 case ammo_fuel: return STAT_FUEL;
371                 default: return -1;
372         }
373 }
374 #endif
375 #endif