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