Merge branch 'master' into Mario/vaporizer_damage
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / item_key.qc
1 #include "item_key.qh"
2 #include "_all.qh"
3
4 #include "../common/triggers/subs.qh"
5 #include "../common/monsters/all.qh"
6 #include "../common/notifications.qh"
7 #include "../common/util.qh"
8 #include "../warpzonelib/util_server.qh"
9
10 /*
11 TODO:
12 - add an unlock sound (here to trigger_keylock and to func_door)
13 - display available keys on the HUD
14 - make more tests
15 - think about adding NOT_EASY/NOT_NORMAL/NOT_HARD for Q1 compatibility
16 - should keys have a trigger?
17 */
18
19 bool item_keys_usekey(entity l, entity p)
20 {
21         float valid = l.itemkeys & p.itemkeys;
22
23         if (!valid) {
24                 // other has none of the needed keys
25                 return false;
26         } else if (l.itemkeys == valid) {
27                 // ALL needed keys were given
28                 l.itemkeys = 0;
29                 return true;
30         } else {
31                 // only some of the needed keys were given
32                 l.itemkeys &= ~valid;
33                 return true;
34         }
35 }
36
37 string item_keys_keylist(float keylist) {
38         // no keys
39         if (!keylist)
40                 return "";
41
42         // one key
43         if ((keylist & (keylist-1)) != 0)
44                 return strcat("the ", item_keys_names[lowestbit(keylist)]);
45
46         string n = "";
47         int base = 0;
48         while (keylist) {
49                 int l = lowestbit(keylist);
50                 if (n)
51                         n = strcat(n, ", the ", item_keys_names[base + l]);
52                 else
53                         n = strcat("the ", item_keys_names[base + l]);
54
55                 keylist = bitshift(keylist,  -(l + 1));
56                 base+= l + 1;
57         }
58
59         return n;
60 }
61
62
63 /*
64 ================================
65 item_key
66 ================================
67 */
68
69 /**
70  * Key touch handler.
71  */
72 void item_key_touch(void) {
73         if (!IS_PLAYER(other))
74                 return;
75
76         // player already picked up this key
77         if (other.itemkeys & self.itemkeys)
78                 return;
79
80         other.itemkeys |= self.itemkeys;
81         play2(other, self.noise);
82
83         centerprint(other, self.message);
84 };
85
86 /**
87  * Spawn a key with given model, key code and color.
88  */
89 void spawn_item_key() {
90         precache_model(self.model);
91
92         if (self.spawnflags & 1) // FLOATING
93                 self.noalign = 1;
94
95         if (self.noalign)
96                 self.movetype = MOVETYPE_NONE;
97         else
98                 self.movetype = MOVETYPE_TOSS;
99
100         precache_sound(self.noise);
101
102         self.mdl = self.model;
103         self.effects = EF_LOWPRECISION;
104         setmodel(self, self.model);
105         //setsize(self, '-16 -16 -24', '16 16 32');
106         setorigin(self, self.origin + '0 0 32');
107         setsize(self, '-16 -16 -56', '16 16 0');
108         self.modelflags |= MF_ROTATE;
109         self.solid = SOLID_TRIGGER;
110
111         if (!self.noalign)
112         {
113                 // first nudge it off the floor a little bit to avoid math errors
114                 setorigin(self, self.origin + '0 0 1');
115                 // note droptofloor returns false if stuck/or would fall too far
116                 droptofloor();
117         }
118
119         self.touch = item_key_touch;
120 };
121
122
123 /*QUAKED item_key (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING
124 A key entity.
125 The itemkeys should contain one of the following key IDs:
126 1 - GOLD key -
127 2 - SILVER key
128 4 - BRONZE key
129 8 - RED keycard
130 16 - BLUE keycard
131 32 - GREEN keycard
132 Custom keys:
133 ... - last key is 1<<23
134 Keys with bigger Id than 32 don't have a default netname and model, if you use one of them, you MUST provide those.
135 -----------KEYS------------
136 colormod: color of the key (default: '.9 .9 .9').
137 itemkeys: a key Id.
138 message: message to print when player picks up this key.
139 model: custom key model to use.
140 netname: the display name of the key.
141 noise: custom sound to play when player picks up the key.
142 -------- SPAWNFLAGS --------
143 FLOATING: the item will float in air, instead of aligning to the floor by falling
144 ---------NOTES----------
145 This is the only correct way to put keys on the map!
146
147 itemkeys MUST always have exactly one bit set.
148 */
149 void spawnfunc_item_key() {
150         string _netname;
151         vector _colormod;
152
153         // reject this entity if more than one key was set!
154         if (self.itemkeys>0 && (self.itemkeys & (self.itemkeys-1)) != 0) {
155                 objerror("item_key.itemkeys must contain only 1 bit set specifying the key it represents!");
156                 remove(self);
157                 return;
158         }
159
160         // find default netname and colormod
161         switch(self.itemkeys) {
162         case 1:
163                 _netname = "GOLD key";
164                 _colormod = '1 .9 0';
165                 break;
166
167         case 2:
168                 _netname = "SILVER key";
169                 _colormod = '.9 .9 .9';
170                 break;
171
172         case 4:
173                 _netname = "BRONZE key";
174                 _colormod = '.6 .25 0';
175                 break;
176
177         case 8:
178                 _netname = "RED keycard";
179                 _colormod = '.9 0 0';
180                 break;
181
182         case 16:
183                 _netname = "BLUE keycard";
184                 _colormod = '0 0 .9';
185                 break;
186
187         case 32:
188                 _netname = "GREEN keycard";
189                 _colormod = '0 .9 0';
190                 break;
191
192         default:
193                 _netname = "FLUFFY PINK keycard";
194                 _colormod = '1 1 1';
195
196                 if (self.netname == "") {
197                         objerror("item_key doesn't have a default name for this key and a custom one was not specified!");
198                         remove(self);
199                         return;
200                 }
201                 break;
202
203         }
204
205         // find default model
206         string _model = string_null;
207         if (self.itemkeys <= ITEM_KEY_BIT(2)) {
208                 _model = "models/keys/key.md3";
209         } else if (self.itemkeys >= ITEM_KEY_BIT(3) && self.itemkeys <= ITEM_KEY_BIT(5)) {
210                 _model = "models/keys/key.md3"; // FIXME: replace it by a keycard model!
211         } else if (self.model == "") {
212                 objerror("item_key doesn't have a default model for this key and a custom one was not specified!");
213                 remove(self);
214                 return;
215         }
216
217         // set defailt netname
218         if (self.netname == "")
219                 self.netname = _netname;
220
221         // set default colormod
222         if (!self.colormod)
223                 self.colormod = _colormod;
224
225         // set default model
226         if (self.model == "")
227                 self.model = _model;
228
229         // set default pickup message
230         if (self.message == "")
231                 self.message = strzone(strcat("You've picked up the ", self.netname, "!"));
232
233         if (self.noise == "")
234                 self.noise = "misc/itempickup.wav";
235
236         // save the name for later
237         item_keys_names[lowestbit(self.itemkeys)] = self.netname;
238
239         // put the key on the map
240         spawn_item_key();
241 }
242
243 /*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING
244 SILVER key.
245 -----------KEYS------------
246 colormod: color of the key (default: '.9 .9 .9').
247 message: message to print when player picks up this key.
248 model: custom model to use.
249 noise: custom sound to play when player picks up the key.
250 -------- SPAWNFLAGS --------
251 FLOATING: the item will float in air, instead of aligning to the floor by falling
252 ---------NOTES----------
253 Don't use this entity on new maps! Use item_key instead.
254 */
255 void spawnfunc_item_key1(void) {
256         self.classname = "item_key";
257         self.itemkeys = ITEM_KEY_BIT(1);
258         spawnfunc_item_key();
259 };
260
261 /*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING
262 GOLD key.
263 -----------KEYS------------
264 colormod: color of the key (default: '1 .9 0').
265 message: message to print when player picks up this key.
266 model: custom model to use.
267 noise: custom sound to play when player picks up the key.
268 -------- SPAWNFLAGS --------
269 FLOATING: the item will float in air, instead of aligning to the floor by falling
270 ---------NOTES----------
271 Don't use this entity on new maps! Use item_key instead.
272 */
273 void spawnfunc_item_key2(void) {
274         self.classname = "item_key";
275         self.itemkeys = ITEM_KEY_BIT(0);
276         spawnfunc_item_key();
277 };