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