Xonotic
keys.qc
Go to the documentation of this file.
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 
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 
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)
107  else
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
float MOVETYPE_NONE
Definition: progsdefs.qc:246
const int MF_ROTATE
string string_null
Definition: nil.qh:9
#define ITEM_KEY_BIT(n)
Returns the bit ID of a key.
Definition: keys.qh:6
#define SND(id)
Definition: all.qh:35
vector colormod
Definition: powerups.qc:21
string noise
Definition: progsdefs.qc:209
float MOVETYPE_TOSS
Definition: progsdefs.qc:252
entity() spawn
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition: triggers.qc:366
string netname
Definition: powerups.qc:20
#define PS(this)
Definition: state.qh:18
ERASEABLE int lowestbit(int f)
Definition: bits.qh:17
spawnfunc(info_player_attacker)
Definition: sv_assault.qc:283
origin
Definition: ent_cs.qc:114
#define droptofloor
Definition: pre.qh:5
float noalign
Definition: items.qh:42
float effects
Definition: csprogsdefs.qc:111
float spawnflags
Definition: progsdefs.qc:191
int modelflags
string model
Definition: csprogsdefs.qc:108
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition: bits.qh:8
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
string message
Definition: powerups.qc:19
float itemkeys
Definition: subs.qh:61
vector(float skel, float bonenum) _skel_get_boneabs_hidden
const float SOLID_TRIGGER
Definition: csprogsdefs.qc:245
setorigin(ent, v)
void set_movetype(entity this, int mt)
#define IS_PLAYER(v)
Definition: utils.qh:9
float EF_LOWPRECISION
float solid
Definition: csprogsdefs.qc:99