]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/all.qh
Monsters: cleanup
[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: crosshair : per-weapon crosshair: "CrosshairImage Size" */
218     ATTRIB(Weapon, w_crosshair, string, "gfx/crosshair1");
219     /** A: crosshair : per-weapon crosshair size (argument two of "crosshair" field) */
220     ATTRIB(Weapon, w_crosshair_size, float, 1);
221     /** M: wepimg    : "weaponfoobar" side view image file of weapon. WEAPONTODO: Move out of skin files, move to common files */
222     ATTRIB(Weapon, model2, string, "");
223     /** M: refname   : reference name name */
224     ATTRIB(Weapon, netname, string, "");
225     /** M: wepname   : human readable name */
226     ATTRIB(Weapon, message, string, "AOL CD Thrower");
227
228         METHOD(Weapon, display, void(entity this, void(string name, string icon) returns)) {
229                 returns(this.message, this.model2 ? sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.model2) : string_null);
230         }
231
232         CONSTRUCTOR(Weapon,
233                 bool(entity this, int req) function,
234                 .int ammotype,
235                 int i,
236                 int weapontype,
237                 float pickupbasevalue,
238                 vector clr,
239                 string modelname,
240                 entity m,
241                 string crosshair,
242                 string wepimg,
243                 string refname,
244                 string wepname
245         ) {
246                 CONSTRUCT(Weapon);
247                 this.weapon_func = function;
248                 this.ammo_field = ammotype;
249                 this.impulse = i;
250                 this.spawnflags = weapontype;
251                 this.bot_pickupbasevalue = pickupbasevalue;
252                 this.wpcolor = clr;
253                 this.mdl = modelname;
254                 this.m_model = m;
255                 this.w_crosshair = strzone(car(crosshair));
256                 string s = cdr(crosshair);
257                 this.w_crosshair_size = ((s != "") ? stof(s) : 1); // so that we can scale the crosshair from code (for compat)
258                 this.model2 = strzone(wepimg);
259                 this.netname = refname;
260                 this.message = wepname;
261         }
262         void register_weapon(entity this, int id, WepSet bit)
263         {
264                 this.weapon = id;
265                 this.weapons = bit;
266                 this.wpmodel = strzone(strcat("wpn-", ftos(id)));
267                 #ifdef CSQC
268                 this.weapon_func(this, WR_INIT);
269                 #endif
270         }
271 ENDCLASS(Weapon)
272
273 void RegisterWeapons();
274 REGISTER_REGISTRY(RegisterWeapons)
275 entity weapon_info[WEP_MAXCOUNT], weapon_info_first, weapon_info_last;
276 entity dummy_weapon_info;
277
278 #define REGISTER_WEAPON(...) EVAL(OVERLOAD(REGISTER_WEAPON, __VA_ARGS__))
279
280 #define REGISTER_WEAPON_2(id, inst) \
281         WepSet WEPSET_##id; \
282         REGISTER(RegisterWeapons, WEP, weapon_info, WEP_COUNT, id, m_id, inst) { \
283                 this.m_id++; \
284                 WEPSET_ALL |= (WEPSET_##id = WepSet_FromWeapon(this.m_id)); \
285                 if ((this.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= WEPSET_##id; \
286                 register_weapon(this, this.m_id, WEPSET_##id); \
287                 localcmd(sprintf("alias weapon_%s \"impulse %d\"\n", this.netname, 230 + this.m_id - 1)); \
288         } \
289         REGISTER_INIT(WEP, id)
290
291 #define _REGISTER_WEAPON(id, function, ammotype, impulse, flags, rating, color, modelname, mdl, crosshair, wepimg, refname, wepname) \
292         REGISTER_WEAPON_2(id, NEW(Weapon, function, ammotype, impulse, flags, rating, color, modelname, mdl, crosshair, wepimg, refname, wepname))
293
294 #ifndef MENUQC
295         #define REGISTER_WEAPON_13(id, function, ammotype, impulse, flags, rating, color, modelname, mdl, crosshair, wepimg, refname, wepname) \
296         bool function(entity this, int); \
297         _REGISTER_WEAPON(id, function, ammotype, impulse, flags, rating, color, modelname, mdl, crosshair, wepimg, refname, wepname)
298 #else
299         #define REGISTER_WEAPON_13(id, function, ammotype, impulse, flags, rating, color, modelname, mdl, crosshair, wepimg, refname, wepname) \
300                 _REGISTER_WEAPON(id, w_new,   ammotype, impulse, flags, rating, color, modelname, NULL, crosshair, wepimg, refname, wepname)
301 #endif
302
303 #include "all.inc"
304
305 #undef WEP_ADD_CVAR_MO_PRI
306 #undef WEP_ADD_CVAR_MO_SEC
307 #undef WEP_ADD_CVAR_MO_BOTH
308 #undef WEP_ADD_CVAR_MO_NONE
309 #undef WEP_ADD_CVAR
310 #undef WEP_ADD_PROP
311 void register_weapons_done();
312 ACCUMULATE_FUNCTION(RegisterWeapons, register_weapons_done)
313 #endif