Weapons: split registration and base weapon definitions
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / weapons / weapon.qh
1 #ifndef WEAPON_H
2 #define WEAPON_H
3
4 bool w_new(entity this, int req);
5
6 .int ammo_shells;
7 .int ammo_nails;
8 .int ammo_rockets;
9 .int ammo_cells;
10 .int ammo_plasma;
11 .int ammo_fuel;
12 .int ammo_none;
13
14 // weapon requests
15 const int WR_SETUP          =  1; // (SERVER) setup weapon data
16 .bool(entity this) wr_setup;
17 /** (SERVER) logic to run every frame */
18 .bool(entity this, bool fire1, bool fire2) wr_think;
19 const int WR_CHECKAMMO1     =  3; // (SERVER) checks ammo for weapon primary
20 .bool(entity this) wr_checkammo1;
21 const int WR_CHECKAMMO2     =  4; // (SERVER) checks ammo for weapon second
22 .bool(entity this) wr_checkammo2;
23 const int WR_AIM            =  5; // (SERVER) runs bot aiming code for this weapon
24 .bool(entity this) wr_aim;
25 const int WR_INIT           =  6; // (BOTH)   precaches models/sounds used by this weapon, also sets up weapon properties
26 .bool(entity this) wr_init;
27 const int WR_SUICIDEMESSAGE =  7; // (SERVER) notification number for suicide message (may inspect w_deathtype for details)
28 .bool(entity this) wr_suicidemessage;
29 const int WR_KILLMESSAGE    =  8; // (SERVER) notification number for kill message (may inspect w_deathtype for details)
30 .bool(entity this) wr_killmessage;
31 const int WR_RELOAD         =  9; // (SERVER) handles reloading for weapon
32 .bool(entity this) wr_reload;
33 const int WR_RESETPLAYER    = 10; // (SERVER) clears fields that the weapon may use
34 .bool(entity this) wr_resetplayer;
35 const int WR_IMPACTEFFECT   = 11; // (CLIENT) impact effect for weapon explosion
36 .bool(entity this) wr_impacteffect;
37 const int WR_PLAYERDEATH    = 12; // (SERVER) called whenever a player dies
38 .bool(entity this) wr_playerdeath;
39 const int WR_GONETHINK      = 13; // (SERVER) logic to run when weapon is lost
40 .bool(entity this) wr_gonethink;
41 const int WR_CONFIG         = 14; // (ALL)    dump weapon cvars to config in data directory (see: sv_cmd dumpweapons)
42 .bool(entity this) wr_config;
43 const int WR_ZOOMRETICLE    = 15; // (CLIENT) weapon specific zoom reticle
44 .bool(entity this) wr_zoomreticle;
45 const int WR_DROP           = 16; // (SERVER) the weapon is dropped
46 .bool(entity this) wr_drop;
47 const int WR_PICKUP         = 17; // (SERVER) a weapon is picked up
48 .bool(entity this) wr_pickup;
49
50 /** fields which are explicitly/manually set are marked with "M", fields set automatically are marked with "A" */
51 CLASS(Weapon, Object)
52         ATTRIB(Weapon, m_id, int, 0)
53     /**
54      * M: WEP_id    : WEP_...
55      * you can recognize dummies when this == 0
56      */
57     ATTRIB(Weapon, weapon, int, 0);
58     /** A: WEPSET_id : WEPSET_... */
59     ATTRIB(Weapon, weapons, WepSet, '0 0 0');
60     /** M: function  : w_... */
61     METHOD(Weapon, weapon_func, bool(entity this, int req)) { return w_new(this, req); }
62     /** M: ammotype  : main ammo field */
63     ATTRIB(Weapon, ammo_field, .int, ammo_none);
64     /** M: impulse   : weapon impulse */
65     ATTRIB(Weapon, impulse, int, -1);
66     /** M: flags     : WEPSPAWNFLAG_... combined */
67     ATTRIB(Weapon, spawnflags, int, 0);
68     /** M: rating    : bot weapon priority */
69     ATTRIB(Weapon, bot_pickupbasevalue, float, 0);
70     /** M: color     : waypointsprite color */
71     ATTRIB(Weapon, wpcolor, vector, '0 0 0');
72     /** A: wpn-id    : wpn- sprite name */
73     ATTRIB(Weapon, wpmodel, string, "");
74     /** M: modelname : name of model (without g_ v_ or h_ prefixes) */
75     ATTRIB(Weapon, mdl, string, "");
76     /** M: model MDL_id_ITEM */
77     ATTRIB(Weapon, m_model, entity, NULL);
78     /** M: crosshair : per-weapon crosshair: "CrosshairImage Size" */
79     ATTRIB(Weapon, w_crosshair, string, "gfx/crosshair1");
80     /** A: crosshair : per-weapon crosshair size (argument two of "crosshair" field) */
81     ATTRIB(Weapon, w_crosshair_size, float, 1);
82     /** M: wepimg    : "weaponfoobar" side view image file of weapon. WEAPONTODO: Move out of skin files, move to common files */
83     ATTRIB(Weapon, model2, string, "");
84     /** M: refname   : reference name name */
85     ATTRIB(Weapon, netname, string, "");
86     /** M: wepname   : human readable name */
87     ATTRIB(Weapon, message, string, "AOL CD Thrower");
88
89         METHOD(Weapon, display, void(entity this, void(string name, string icon) returns)) {
90                 returns(this.message, this.model2 ? sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.model2) : string_null);
91         }
92
93         CONSTRUCTOR(Weapon,
94                 bool(entity this, int req) function,
95                 .int ammotype,
96                 int i,
97                 int weapontype,
98                 float pickupbasevalue,
99                 vector clr,
100                 string modelname,
101                 entity m,
102                 string crosshair,
103                 string wepimg,
104                 string refname,
105                 string wepname
106         ) {
107                 CONSTRUCT(Weapon);
108                 this.weapon_func = function;
109                 this.ammo_field = ammotype;
110                 this.impulse = i;
111                 this.spawnflags = weapontype;
112                 this.bot_pickupbasevalue = pickupbasevalue;
113                 this.wpcolor = clr;
114                 this.mdl = modelname;
115                 this.m_model = m;
116                 this.w_crosshair = strzone(car(crosshair));
117                 string s = cdr(crosshair);
118                 this.w_crosshair_size = ((s != "") ? stof(s) : 1); // so that we can scale the crosshair from code (for compat)
119                 this.model2 = strzone(wepimg);
120                 this.netname = refname;
121                 this.message = wepname;
122         }
123         void register_weapon(entity this, int id, WepSet bit)
124         {
125                 this.weapon = id;
126                 this.weapons = bit;
127                 this.wpmodel = strzone(strcat("wpn-", ftos(id)));
128                 #ifdef CSQC
129                 this.weapon_func(this, WR_INIT);
130                 #endif
131         }
132 ENDCLASS(Weapon)
133
134 CLASS(OffhandWeapon, Object)
135     METHOD(OffhandWeapon, offhand_think, void(OffhandWeapon this, entity player, bool key_pressed)) {}
136 ENDCLASS(OffhandWeapon)
137
138 #ifdef SVQC
139 .OffhandWeapon offhand;
140 #endif
141
142 const int MAX_SHOT_DISTANCE = 32768;
143
144 // weapon pickup ratings for bot logic
145 const int BOT_PICKUP_RATING_LOW  =  2500;
146 const int BOT_PICKUP_RATING_MID  =  5000;
147 const int BOT_PICKUP_RATING_HIGH = 10000;
148
149 // weapon flags
150 const int WEP_TYPE_OTHER          =  0x00; // not for damaging people
151 const int WEP_TYPE_SPLASH         =  0x01; // splash damage
152 const int WEP_TYPE_HITSCAN        =  0x02; // hitscan
153 const int WEP_TYPEMASK            =  0x0F;
154 const int WEP_FLAG_CANCLIMB       =  0x10; // can be used for movement
155 const int WEP_FLAG_NORMAL         =  0x20; // in "most weapons" set
156 const int WEP_FLAG_HIDDEN         =  0x40; // hides from menu
157 const int WEP_FLAG_RELOADABLE     =  0x80; // can has reload
158 const int WEP_FLAG_SUPERWEAPON    = 0x100; // powerup timer
159 const int WEP_FLAG_MUTATORBLOCKED = 0x200; // hides from impulse 99 etc. (mutators are allowed to clear this flag)
160
161 bool w_new(entity this, int req) {
162     if (req == WR_SETUP) return this.wr_setup ? this.wr_setup(this) : false;
163     if (req == WR_CHECKAMMO1) return this.wr_checkammo1 ? this.wr_checkammo1(this) : false;
164     if (req == WR_CHECKAMMO2) return this.wr_checkammo2 ? this.wr_checkammo2(this) : false;
165     if (req == WR_AIM) return this.wr_aim ? this.wr_aim(this) : false;
166     if (req == WR_INIT) return this.wr_init ? this.wr_init(this) : false;
167     if (req == WR_SUICIDEMESSAGE) return this.wr_suicidemessage ? this.wr_suicidemessage(this) : false;
168     if (req == WR_KILLMESSAGE) return this.wr_killmessage ? this.wr_killmessage(this) : false;
169     if (req == WR_RELOAD) return this.wr_reload ? this.wr_reload(this) : false;
170     if (req == WR_RESETPLAYER) return this.wr_resetplayer ? this.wr_resetplayer(this) : false;
171     if (req == WR_IMPACTEFFECT) return this.wr_impacteffect ? this.wr_impacteffect(this) : false;
172     if (req == WR_PLAYERDEATH) return this.wr_playerdeath ? this.wr_playerdeath(this) : false;
173     if (req == WR_GONETHINK) return this.wr_gonethink ? this.wr_gonethink(this) : false;
174     if (req == WR_CONFIG) return this.wr_config ? this.wr_config(this) : false;
175     if (req == WR_ZOOMRETICLE) return this.wr_zoomreticle ? this.wr_zoomreticle(this) : false;
176     if (req == WR_DROP) return this.wr_drop ? this.wr_drop(this) : false;
177     if (req == WR_PICKUP) return this.wr_pickup ? this.wr_pickup(this) : false;
178     return false;
179 }
180
181 // variables:
182 string weaponorder_byid;
183
184 // functions:
185 string W_FixWeaponOrder(string order, float complete);
186 string W_UndeprecateName(string s);
187 string W_NameWeaponOrder(string order);
188 string W_NumberWeaponOrder(string order);
189 string W_FixWeaponOrder_BuildImpulseList(string o);
190 string W_FixWeaponOrder_AllowIncomplete(string order);
191 string W_FixWeaponOrder_ForceComplete(string order);
192 void W_RandomWeapons(entity e, float n);
193
194 string GetAmmoPicture(.int ammotype);
195
196 #ifdef CSQC
197 .int GetAmmoFieldFromNum(int i);
198 int GetAmmoStat(.int ammotype);
199 #endif
200
201 string W_Sound(string w_snd);
202 string W_Model(string w_mdl);
203
204
205 // other useful macros
206 #define WEP_ACTION(wpn,wrequest) wpn.weapon_func(wpn, wrequest)
207 #define _WEP_ACTION(wpn,wrequest) WEP_ACTION(get_weaponinfo(wpn), wrequest)
208 #define WEP_AMMO(wpn) (WEP_##wpn.ammo_field) // only used inside weapon files/with direct name, don't duplicate prefix
209 #define WEP_NAME(wpn) ((get_weaponinfo(wpn)).message)
210
211 #endif