]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/all.qh
Weapons: require explicit pickup model
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / weapons / all.qh
1 #ifndef WEAPONS_ALL_H
2 #define WEAPONS_ALL_H
3
4 #ifndef MENUQC
5 #include "calculations.qh"
6 #include "../models/models.qh"
7 #endif
8
9 #include "../util.qh"
10
11 #ifdef SVQC
12 #include "../../server/bot/aim.qh"
13 #endif
14
15 const int MAX_SHOT_DISTANCE = 32768;
16
17 // weapon pickup ratings for bot logic
18 const int BOT_PICKUP_RATING_LOW  =  2500;
19 const int BOT_PICKUP_RATING_MID  =  5000;
20 const int BOT_PICKUP_RATING_HIGH = 10000;
21
22 // weapon flags
23 const int WEP_TYPE_OTHER          =  0x00; // not for damaging people
24 const int WEP_TYPE_SPLASH         =  0x01; // splash damage
25 const int WEP_TYPE_HITSCAN        =  0x02; // hitscan
26 const int WEP_TYPEMASK            =  0x0F;
27 const int WEP_FLAG_CANCLIMB       =  0x10; // can be used for movement
28 const int WEP_FLAG_NORMAL         =  0x20; // in "most weapons" set
29 const int WEP_FLAG_HIDDEN         =  0x40; // hides from menu
30 const int WEP_FLAG_RELOADABLE     =  0x80; // can has reload
31 const int WEP_FLAG_SUPERWEAPON    = 0x100; // powerup timer
32 const int WEP_FLAG_MUTATORBLOCKED = 0x200; // hides from impulse 99 etc. (mutators are allowed to clear this flag)
33
34 // weapon requests
35 const int WR_SETUP          =  1; // (SERVER) setup weapon data
36 .bool(entity this) wr_setup;
37 const int WR_THINK          =  2; // (SERVER) logic to run every frame
38 .bool(entity this) wr_think;
39 const int WR_CHECKAMMO1     =  3; // (SERVER) checks ammo for weapon primary
40 .bool(entity this) wr_checkammo1;
41 const int WR_CHECKAMMO2     =  4; // (SERVER) checks ammo for weapon second
42 .bool(entity this) wr_checkammo2;
43 const int WR_AIM            =  5; // (SERVER) runs bot aiming code for this weapon
44 .bool(entity this) wr_aim;
45 const int WR_INIT           =  6; // (BOTH)   precaches models/sounds used by this weapon, also sets up weapon properties
46 .bool(entity this) wr_init;
47 const int WR_SUICIDEMESSAGE =  7; // (SERVER) notification number for suicide message (may inspect w_deathtype for details)
48 .bool(entity this) wr_suicidemessage;
49 const int WR_KILLMESSAGE    =  8; // (SERVER) notification number for kill message (may inspect w_deathtype for details)
50 .bool(entity this) wr_killmessage;
51 const int WR_RELOAD         =  9; // (SERVER) handles reloading for weapon
52 .bool(entity this) wr_reload;
53 const int WR_RESETPLAYER    = 10; // (SERVER) clears fields that the weapon may use
54 .bool(entity this) wr_resetplayer;
55 const int WR_IMPACTEFFECT   = 11; // (CLIENT) impact effect for weapon explosion
56 .bool(entity this) wr_impacteffect;
57 const int WR_PLAYERDEATH    = 12; // (SERVER) called whenever a player dies
58 .bool(entity this) wr_playerdeath;
59 const int WR_GONETHINK      = 13; // (SERVER) logic to run when weapon is lost
60 .bool(entity this) wr_gonethink;
61 const int WR_CONFIG         = 14; // (ALL)    dump weapon cvars to config in data directory (see: sv_cmd dumpweapons)
62 .bool(entity this) wr_config;
63 const int WR_ZOOMRETICLE    = 15; // (CLIENT) weapon specific zoom reticle
64 .bool(entity this) wr_zoomreticle;
65 const int WR_DROP           = 16; // (SERVER) the weapon is dropped
66 .bool(entity this) wr_drop;
67 const int WR_PICKUP         = 17; // (SERVER) a weapon is picked up
68 .bool(entity this) wr_pickup;
69
70 bool w_new(entity this, int req) {
71     if (req == WR_SETUP) return this.wr_setup ? this.wr_setup(this) : false;
72     if (req == WR_THINK) return this.wr_think ? this.wr_think(this) : false;
73     if (req == WR_CHECKAMMO1) return this.wr_checkammo1 ? this.wr_checkammo1(this) : false;
74     if (req == WR_CHECKAMMO2) return this.wr_checkammo2 ? this.wr_checkammo2(this) : false;
75     if (req == WR_AIM) return this.wr_aim ? this.wr_aim(this) : false;
76     if (req == WR_INIT) return this.wr_init ? this.wr_init(this) : false;
77     if (req == WR_SUICIDEMESSAGE) return this.wr_suicidemessage ? this.wr_suicidemessage(this) : false;
78     if (req == WR_KILLMESSAGE) return this.wr_killmessage ? this.wr_killmessage(this) : false;
79     if (req == WR_RELOAD) return this.wr_reload ? this.wr_reload(this) : false;
80     if (req == WR_RESETPLAYER) return this.wr_resetplayer ? this.wr_resetplayer(this) : false;
81     if (req == WR_IMPACTEFFECT) return this.wr_impacteffect ? this.wr_impacteffect(this) : false;
82     if (req == WR_PLAYERDEATH) return this.wr_playerdeath ? this.wr_playerdeath(this) : false;
83     if (req == WR_GONETHINK) return this.wr_gonethink ? this.wr_gonethink(this) : false;
84     if (req == WR_CONFIG) return this.wr_config ? this.wr_config(this) : false;
85     if (req == WR_ZOOMRETICLE) return this.wr_zoomreticle ? this.wr_zoomreticle(this) : false;
86     if (req == WR_DROP) return this.wr_drop ? this.wr_drop(this) : false;
87     if (req == WR_PICKUP) return this.wr_pickup ? this.wr_pickup(this) : false;
88     return false;
89 }
90
91 // variables:
92 string weaponorder_byid;
93
94 // weapon sets
95 typedef vector WepSet;
96 WepSet WepSet_FromWeapon(int a);
97 #ifdef SVQC
98 void WepSet_AddStat();
99 void WepSet_AddStat_InMap();
100 void WriteWepSet(float dest, WepSet w);
101 #endif
102
103 #ifdef CSQC
104 WepSet WepSet_GetFromStat();
105 WepSet WepSet_GetFromStat_InMap();
106 WepSet ReadWepSet();
107 #endif
108
109 // weapon name macros
110 const int WEP_FIRST = 1;
111 #define WEP_MAXCOUNT 32 // Increase as needed. Can be up to 72.
112 int WEP_COUNT;
113 #define WEP_LAST (WEP_FIRST + WEP_COUNT - 1)
114 WepSet WEPSET_ALL;
115 WepSet WEPSET_SUPERWEAPONS;
116
117 // functions:
118 entity get_weaponinfo(int id);
119 string W_FixWeaponOrder(string order, float complete);
120 string W_UndeprecateName(string s);
121 string W_NameWeaponOrder(string order);
122 string W_NumberWeaponOrder(string order);
123 string W_FixWeaponOrder_BuildImpulseList(string o);
124 string W_FixWeaponOrder_AllowIncomplete(string order);
125 string W_FixWeaponOrder_ForceComplete(string order);
126 void W_RandomWeapons(entity e, float n);
127
128 string GetAmmoPicture(.int ammotype);
129
130 #ifdef CSQC
131 .int GetAmmoFieldFromNum(int i);
132 int GetAmmoStat(.int ammotype);
133 #endif
134
135 string W_Sound(string w_snd);
136 string W_Model(string w_mdl);
137
138 // ammo types
139 .int ammo_shells;
140 .int ammo_nails;
141 .int ammo_rockets;
142 .int ammo_cells;
143 .int ammo_plasma;
144 .int ammo_fuel;
145 .int ammo_none;
146
147 // other useful macros
148 #define WEP_ACTION(wpn,wrequest) wpn.weapon_func(wpn, wrequest)
149 #define _WEP_ACTION(wpn,wrequest) WEP_ACTION(get_weaponinfo(wpn), wrequest)
150 #define WEP_AMMO(wpn) (WEP_##wpn.ammo_field) // only used inside weapon files/with direct name, don't duplicate prefix
151 #define WEP_NAME(wpn) ((get_weaponinfo(wpn)).message)
152
153
154 // ======================
155 //  Configuration Macros
156 // ======================
157
158 // create cvars for weapon settings
159 #define WEP_ADD_CVAR_NONE(wepname,name) [[last]] float autocvar_g_balance_##wepname##_##name;
160
161 #define WEP_ADD_CVAR_PRI(wepname,name) WEP_ADD_CVAR_NONE(wepname, primary_##name)
162 #define WEP_ADD_CVAR_SEC(wepname,name) WEP_ADD_CVAR_NONE(wepname, secondary_##name)
163 #define WEP_ADD_CVAR_BOTH(wepname,name) \
164         WEP_ADD_CVAR_PRI(wepname, name) \
165         WEP_ADD_CVAR_SEC(wepname, name)
166
167 #define WEP_ADD_CVAR(wepid,wepname,mode,name) WEP_ADD_CVAR_##mode(wepname, name)
168
169 // create properties for weapon settings
170 #define WEP_ADD_PROP(wepid,wepname,type,prop,name) \
171         .type prop; \
172         [[last]] type autocvar_g_balance_##wepname##_##name;
173
174 // read cvars from weapon settings
175 #define WEP_CVAR(wepname,name) autocvar_g_balance_##wepname##_##name
176 #define WEP_CVAR_PRI(wepname,name) WEP_CVAR(wepname, primary_##name)
177 #define WEP_CVAR_SEC(wepname,name) WEP_CVAR(wepname, secondary_##name)
178 #define WEP_CVAR_BOTH(wepname,isprimary,name) ((isprimary) ? WEP_CVAR_PRI(wepname, name) : WEP_CVAR_SEC(wepname, name))
179
180 // set initialization values for weapon settings
181 #define WEP_SKIP_CVAR(unuseda,unusedb,unusedc,unusedd) /* skip cvars */
182 #define WEP_SET_PROP(wepid,wepname,type,prop,name) WEP_##wepid.prop = autocvar_g_balance_##wepname##_##name;
183
184
185 // =====================
186 //  Weapon Registration
187 // =====================
188
189 /** fields which are explicitly/manually set are marked with "M", fields set automatically are marked with "A" */
190 CLASS(Weapon, Object)
191         ATTRIB(Weapon, m_id, int, 0)
192     /**
193      * M: WEP_id    : WEP_...
194      * you can recognize dummies when this == 0
195      */
196     ATTRIB(Weapon, weapon, int, 0);
197     /** A: WEPSET_id : WEPSET_... */
198     ATTRIB(Weapon, weapons, WepSet, '0 0 0');
199     /** M: function  : w_... */
200     METHOD(Weapon, weapon_func, bool(entity this, int req)) { return w_new(this, req); }
201     /** M: ammotype  : main ammo field */
202     ATTRIB(Weapon, ammo_field, .int, ammo_none);
203     /** M: impulse   : weapon impulse */
204     ATTRIB(Weapon, impulse, int, -1);
205     /** M: flags     : WEPSPAWNFLAG_... combined */
206     ATTRIB(Weapon, spawnflags, int, 0);
207     /** M: rating    : bot weapon priority */
208     ATTRIB(Weapon, bot_pickupbasevalue, float, 0);
209     /** M: color     : waypointsprite color */
210     ATTRIB(Weapon, wpcolor, vector, '0 0 0');
211     /** A: wpn-id    : wpn- sprite name */
212     ATTRIB(Weapon, wpmodel, string, "");
213     /** M: modelname : name of model (without g_ v_ or h_ prefixes) */
214     ATTRIB(Weapon, mdl, string, "");
215     /** M: model MDL_id_ITEM */
216     ATTRIB(Weapon, m_model, entity, NULL);
217     /** M: simplemdl : simpleitems weapon model/image */
218     ATTRIB(Weapon, w_simplemdl, string, "foobar");
219     /** M: crosshair : per-weapon crosshair: "CrosshairImage Size" */
220     ATTRIB(Weapon, w_crosshair, string, "gfx/crosshair1");
221     /** A: crosshair : per-weapon crosshair size (argument two of "crosshair" field) */
222     ATTRIB(Weapon, w_crosshair_size, float, 1);
223     /** M: wepimg    : "weaponfoobar" side view image file of weapon. WEAPONTODO: Move out of skin files, move to common files */
224     ATTRIB(Weapon, model2, string, "");
225     /** M: refname   : reference name name */
226     ATTRIB(Weapon, netname, string, "");
227     /** M: wepname   : human readable name */
228     ATTRIB(Weapon, message, string, "AOL CD Thrower");
229
230         METHOD(Weapon, display, void(entity this, void(string name, string icon) returns)) {
231                 returns(this.message, this.model2 ? sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.model2) : string_null);
232         }
233
234         CONSTRUCTOR(Weapon,
235                 bool(entity this, int req) function,
236                 .int ammotype,
237                 int i,
238                 int weapontype,
239                 float pickupbasevalue,
240                 vector clr,
241                 string modelname,
242                 entity m,
243                 string simplemdl,
244                 string crosshair,
245                 string wepimg,
246                 string refname,
247                 string wepname
248         ) {
249                 CONSTRUCT(Weapon);
250                 this.weapon_func = function;
251                 this.ammo_field = ammotype;
252                 this.impulse = i;
253                 this.spawnflags = weapontype;
254                 this.bot_pickupbasevalue = pickupbasevalue;
255                 this.wpcolor = clr;
256                 this.mdl = modelname;
257                 this.m_model = m;
258                 this.w_simplemdl = strzone(simplemdl); // simpleitems weapon model/image
259                 this.w_crosshair = strzone(car(crosshair));
260                 string s = cdr(crosshair);
261                 this.w_crosshair_size = ((s != "") ? stof(s) : 1); // so that we can scale the crosshair from code (for compat)
262                 this.model2 = strzone(wepimg);
263                 this.netname = refname;
264                 this.message = wepname;
265         }
266         void register_weapon(entity this, int id, WepSet bit)
267         {
268                 this.classname = "weapon_info";
269                 this.weapon = id;
270                 this.weapons = bit;
271                 this.wpmodel = strzone(strcat("wpn-", ftos(id)));
272                 #ifdef CSQC
273                 this.weapon_func(this, WR_INIT);
274                 #endif
275         }
276 ENDCLASS(Weapon)
277
278 void RegisterWeapons();
279 REGISTER_REGISTRY(RegisterWeapons)
280 entity weapon_info[WEP_MAXCOUNT], weapon_info_first, weapon_info_last;
281 entity dummy_weapon_info;
282
283 #define REGISTER_WEAPON(...) EVAL(OVERLOAD(REGISTER_WEAPON, __VA_ARGS__))
284
285 #define REGISTER_WEAPON_2(id, inst) \
286         WepSet WEPSET_##id; \
287         REGISTER(RegisterWeapons, WEP, weapon_info, WEP_COUNT, id, m_id, inst) { \
288                 this.m_id++; \
289                 WEPSET_ALL |= (WEPSET_##id = WepSet_FromWeapon(this.m_id)); \
290                 if ((this.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= WEPSET_##id; \
291                 register_weapon(this, this.m_id, WEPSET_##id); \
292                 localcmd(sprintf("alias weapon_%s \"impulse %d\"\n", this.netname, 230 + this.m_id - 1)); \
293         } \
294         REGISTER_INIT(WEP, id)
295
296 #define _REGISTER_WEAPON(id, function, ammotype, impulse, flags, rating, color, modelname, mdl, simplemdl, crosshair, wepimg, refname, wepname) \
297         REGISTER_WEAPON_2(id, NEW(Weapon, function, ammotype, impulse, flags, rating, color, modelname, mdl, simplemdl, crosshair, wepimg, refname, wepname))
298
299 #ifndef MENUQC
300         #define REGISTER_WEAPON_14(id, function, ammotype, impulse, flags, rating, color, modelname, mdl, simplemdl, crosshair, wepimg, refname, wepname) \
301         bool function(entity this, int); \
302         _REGISTER_WEAPON(id, function, ammotype, impulse, flags, rating, color, modelname, mdl, simplemdl, crosshair, wepimg, refname, wepname)
303 #else
304         #define REGISTER_WEAPON_14(id, function, ammotype, impulse, flags, rating, color, modelname, mdl, simplemdl, crosshair, wepimg, refname, wepname) \
305                 _REGISTER_WEAPON(id, w_new,   ammotype, impulse, flags, rating, color, modelname, NULL, simplemdl, crosshair, wepimg, refname, wepname)
306 #endif
307
308 #include "all.inc"
309
310 #undef WEP_ADD_CVAR_MO_PRI
311 #undef WEP_ADD_CVAR_MO_SEC
312 #undef WEP_ADD_CVAR_MO_BOTH
313 #undef WEP_ADD_CVAR_MO_NONE
314 #undef WEP_ADD_CVAR
315 #undef WEP_ADD_PROP
316 void register_weapons_done();
317 ACCUMULATE_FUNCTION(RegisterWeapons, register_weapons_done)
318 #endif