X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fitem_key.qc;h=1b423f5020f5646312a3c0b8d7a14380bb073344;hb=99e4fa0264127dfcf4675d5f645061b51af815e4;hp=e26d6fe801830ac6b1c19a523d147e001a73b2a6;hpb=0822ebd5f8367f4087ccf04129d22519c6ac93ac;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/item_key.qc b/qcsrc/server/item_key.qc index e26d6fe80..1b423f502 100644 --- a/qcsrc/server/item_key.qc +++ b/qcsrc/server/item_key.qc @@ -7,43 +7,79 @@ TODO: - should keys have a trigger? */ +float item_keys_usekey(entity l, entity p) { + float valid = l.itemkeys & p.itemkeys; + + if not(valid) { + // other has none of the needed keys + return FALSE; + } else if (l.itemkeys == valid) { + // ALL needed keys were given + l.itemkeys = 0; + return TRUE; + } else { + // only some of the needed keys were given + l.itemkeys &~= valid; + return TRUE; + } +} + +string item_keys_keylist(float keylist) { + float base, l; + string n; + + // no keys + if not(keylist) + return ""; + + // one key + if ((keylist & (keylist-1)) != 0) + return strcat("the ", item_keys_names[lowestbit(keylist)]); + + n = ""; + base = 0; + while (keylist) { + l = lowestbit(keylist); + if (n) + n = strcat(n, ", the ", item_keys_names[base + l]); + else + n = strcat("the ", item_keys_names[base + l]); + + keylist = bitshift(keylist, -(l + 1)); + base+= l + 1; + } + + return n; +} + + /* ================================ -item_key1 / item_key2 +item_key ================================ */ -/* -Key touch handler. -*/ +/** + * Key touch handler. + */ void item_key_touch(void) { - local entity p; - - if (other.owner) - p = other.owner; - else - p = other; - - if (p.classname != "player") + if (other.classname != "player") return; // player already picked up this key - if (p.itemkeys & self.itemkeys) + if (other.itemkeys & self.itemkeys) return; - p.itemkeys |= self.itemkeys; + other.itemkeys |= self.itemkeys; play2(other, self.noise); - if (self.message) { - centerprint(p, self.message); - } + centerprint(other, self.message); }; -/* -Spawn a key with given model, key code and color. -*/ -void spawn_item_key(float key_code) { - self.itemkeys = key_code; +/** + * Spawn a key with given model, key code and color. + */ +void spawn_item_key() { precache_model(self.model); if (self.spawnflags & 1) // FLOATING @@ -54,9 +90,6 @@ void spawn_item_key(float key_code) { else self.movetype = MOVETYPE_TOSS; - if (!self.noise) - self.noise = "misc/itempickup.wav"; - precache_sound(self.noise); self.mdl = self.model; @@ -80,6 +113,128 @@ void spawn_item_key(float key_code) { }; +/*QUAKED item_key (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING +A key entity. +The itemkeys should contain one of the following key IDs: +1 - GOLD key - +2 - SILVER key +4 - BRONZE key +8 - RED keycard +16 - BLUE keycard +32 - GREEN keycard +Custom keys: +... - last key is 1<<23 +Keys with bigger Id than 32 don't have a default netname and model, if you use one of them, you MUST provide those. +-----------KEYS------------ +colormod: color of the key (default: '.9 .9 .9'). +itemkeys: a key Id. +message: message to print when player picks up this key. +model: custom key model to use. +netname: the display name of the key. +noise: custom sound to play when player picks up the key. +-------- SPAWNFLAGS -------- +FLOATING: the item will float in air, instead of aligning to the floor by falling +---------NOTES---------- +This is the only correct way to put keys on the map! + +itemkeys MUST always have exactly one bit set. +*/ +void spawnfunc_item_key() { + local string _model, _netname; + local vector _colormod; + + // reject this entity if more than one key was set! + if (self.itemkeys>0 && (self.itemkeys & (self.itemkeys-1)) != 0) { + objerror("item_key.itemkeys must contain only 1 bit set specifying the key it represents!"); + remove(self); + return; + } + + // find default netname and colormod + switch(self.itemkeys) { + case 1: + _netname = "GOLD key"; + _colormod = '1 .9 0'; + break; + + case 2: + _netname = "SILVER key"; + _colormod = '.9 .9 .9'; + break; + + case 4: + _netname = "BRONZE key"; + _colormod = '.6 .25 0'; + break; + + case 8: + _netname = "RED keycard"; + _colormod = '.9 0 0'; + break; + + case 16: + _netname = "BLUE keycard"; + _colormod = '0 0 .9'; + break; + + case 32: + _netname = "GREEN keycard"; + _colormod = '0 .9 0'; + break; + + default: + _netname = "FLUFFY PINK keycard"; + _colormod = '1 1 1'; + + if (self.netname == "") { + objerror("item_key doesn't have a default name for this key and a custom one was not specified!"); + remove(self); + return; + } + break; + + } + + // find default model +#ifdef GMQCC + _model = string_null; +#endif + if (self.itemkeys <= ITEM_KEY_BIT(2)) { + _model = "models/keys/key.md3"; + } else if (self.itemkeys >= ITEM_KEY_BIT(3) && self.itemkeys <= ITEM_KEY_BIT(5)) { + _model = "models/keys/key.md3"; // FIXME: replace it by a keycard model! + } else if (self.model == "") { + objerror("item_key doesn't have a default model for this key and a custom one was not specified!"); + remove(self); + return; + } + + // set defailt netname + if (self.netname == "") + self.netname = _netname; + + // set default colormod + if (!self.colormod) + self.colormod = _colormod; + + // set default model + if (self.model == "") + self.model = _model; + + // set default pickup message + if (self.message == "") + self.message = strzone(strcat("You've picked up the ", self.netname, "!")); + + if (self.noise == "") + self.noise = "misc/itempickup.wav"; + + // save the name for later + item_keys_names[lowestbit(self.itemkeys)] = self.netname; + + // put the key on the map + spawn_item_key(); +} + /*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING SILVER key. -----------KEYS------------ @@ -90,18 +245,12 @@ noise: custom sound to play when player picks up the key. -------- SPAWNFLAGS -------- FLOATING: the item will float in air, instead of aligning to the floor by falling ---------NOTES---------- +Don't use this entity on new maps! Use item_key instead. */ void spawnfunc_item_key1(void) { - if (!self.model) - self.model = "models/keys/key.md3"; - - if (!self.colormod) - self.colormod = '.9 .9 .9'; - - if (!self.message) - self.message = "You've picked up the silver key!"; - - spawn_item_key(KEYS_SILVER_KEY); + self.classname = "item_key"; + self.itemkeys = ITEM_KEY_BIT(1); + spawnfunc_item_key(); }; /*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING @@ -114,18 +263,12 @@ noise: custom sound to play when player picks up the key. -------- SPAWNFLAGS -------- FLOATING: the item will float in air, instead of aligning to the floor by falling ---------NOTES---------- +Don't use this entity on new maps! Use item_key instead. */ void spawnfunc_item_key2(void) { - if (!self.model) - self.model = "models/keys/key.md3"; - - if (!self.colormod) - self.colormod = '1 .9 0'; - - if (!self.message) - self.message = "You've picked up the gold key!"; - - spawn_item_key(KEYS_GOLD_KEY); + self.classname = "item_key"; + self.itemkeys = ITEM_KEY_BIT(0); + spawnfunc_item_key(); }; @@ -135,9 +278,9 @@ trigger_keylock ================================ */ -/* -trigger givent targets -*/ +/** + * trigger givent targets + */ void trigger_keylock_trigger(string s) { local entity t, stemp, otemp, atemp; @@ -159,119 +302,52 @@ void trigger_keylock_trigger(string s) { activator = atemp; }; -/* -kill killtarget of trigger keylock. -*/ +/** + * kill killtarget of trigger keylock. + */ void trigger_keylock_kill(string s) { - local entity t, stemp, otemp, atemp; - - stemp = self; - otemp = other; - atemp = activator; - + local entity t; for(t = world; (t = find(t, targetname, s)); ) - if (t.use) { - remove(t); - } - - self = stemp; - other = otemp; - activator = atemp; + remove(t); }; void trigger_keylock_touch(void) { - local float key_used, silver_key_missing, gold_key_missing, started_delay; - local entity p; + local float key_used, started_delay; key_used = FALSE; - silver_key_missing = FALSE; - gold_key_missing = FALSE; started_delay = FALSE; - if (other.owner) - p = other.owner; - else - p = other; - // only player may trigger the lock - if (p.classname != "player") + if (other.classname != "player") return; // check silver key - if (self.itemkeys & KEYS_SILVER_KEY) { - // lock still requires the SILVER key - if (p.itemkeys & KEYS_SILVER_KEY) { - self.itemkeys &~= KEYS_SILVER_KEY; - key_used = TRUE; - } else { - silver_key_missing = TRUE; - } - } - - // check gold key - if (self.itemkeys & KEYS_GOLD_KEY) { - // lock still requires the GOLD key - if (p.itemkeys & KEYS_GOLD_KEY) { - self.itemkeys &~= KEYS_GOLD_KEY; - key_used = TRUE; - } else { - gold_key_missing = TRUE; - } - } - + if (self.itemkeys) + key_used = item_keys_usekey(self, other); activator = other; - if (silver_key_missing) { - // silver key is missing - if (self.delay <= time) { - if (self.target4) { - trigger_keylock_trigger(self.target4); - started_delay = TRUE; - self.delay = time + self.wait; - } - } - } - - if (gold_key_missing) { - // gold key is missing - if (self.delay <= time || started_delay) { - if (self.target3) { - trigger_keylock_trigger(self.target3); - started_delay = TRUE; - self.delay = time + self.wait; - } - } - - } - - if (silver_key_missing || gold_key_missing) { + if (self.itemkeys) { // at least one of the keys is missing - if (key_used) { - // one key was given, but an other one is missing! + // one or more keys were given, but others are still missing! play2(other, self.noise1); - if (silver_key_missing) - centerprint(other, "You also need the silver key!"); - else if (gold_key_missing) - centerprint(other, "You also need the gold key!"); - p.key_door_messagetime = time + 2; - } else { - if (p.key_door_messagetime <= time) { - play2(other, self.noise2); - centerprint(other, self.message2); - p.key_door_messagetime = time + 2; - } + centerprint(other, strcat("You also need ", item_keys_keylist(self.itemkeys), "!")); + other.key_door_messagetime = time + 2; + } else if (other.key_door_messagetime <= time) { + // no keys were given + play2(other, self.noise2); + centerprint(other, strcat("You need ", item_keys_keylist(self.itemkeys), "!")); + other.key_door_messagetime = time + 2; } - if (self.delay <= time || started_delay == TRUE) { - if (self.target2) { - trigger_keylock_trigger(self.target2); - started_delay = TRUE; - self.delay = time + self.wait; - } - + // trigger target2 + if (self.delay <= time || started_delay == TRUE) + if (self.target2) { + trigger_keylock_trigger(self.target2); + started_delay = TRUE; + self.delay = time + self.wait; } } else { // all keys were given! @@ -289,77 +365,58 @@ void trigger_keylock_touch(void) { }; -/*QUAKED trigger_keylock (.0 .5 .8) ? - - - GOLD_KEY SILVER_KEY +/*QUAKED trigger_keylock (.0 .5 .8) ? Keylock trigger. Must target other entities. This trigger will trigger target entities when all required keys are provided. -------- KEYS -------- -wait: prevent triggering again for this amount of time (default: 5) - applies to target2, target3, target4. -sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav +itemkeys: A bit field with key IDs that are needed to open this lock. +sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (3 is default) target: trigger all entities with this targetname when triggered and all keys have been given to it, then remove this trigger target2: trigger all entities with this targetname when triggered without giving it all the required keys. -target3: trigger all entities with this targetname when triggered with GOLD_KEY missing (requires GOLD_KEY spawnflag) -target4: trigger all entities with this targetname when triggered with SILVER_KEY missing (requires SILVER_KEY spawnflag) +killtarget: remove all entities with this targetname when triggered with all the needed keys. message: print this message to the player who activated the trigger when all needed keys have been given. message2: print this message to the player who activated the trigger when not all of the needed keys have been given. noise: sound to play when lock gets unlocked (default: see sounds) -noise1: sound to play when only one of the needed key was used (default: misc/decreasevalue.wav) +noise1: sound to play when only some of the needed key were used but not all (default: misc/decreasevalue.wav) noise2: sound to play when a key is missing (default: misc/talk.wav) -killtarget: remove all entities with this targetname when triggered with all the needed keys. --------- SPAWNFLAGS -------- -GOLD_KEY: causes the door to open only if the activator holds a gold key. -SILVER_KEY: causes the door to open only if the activator holds a silver key. +wait: prevent triggering again for this amount of time (default: 5) - applies to target2, target3, target4. ---------NOTES---------- -If spawned without any key specified, this trigger will remove itself. +If spawned without any key specified in itemkeys, this trigger will display an error and remove itself. message2 and noise2 will be resent to the player every 2 seconds while he is in the trigger zone. */ void spawnfunc_trigger_keylock(void) { - if (!(self.spawnflags & (SPAWNFLAGS_SILVER_KEY | SPAWNFLAGS_GOLD_KEY))) { + if (!self.itemkeys) { remove(self); return; } - // give the trigger the silver key - if (self.spawnflags & SPAWNFLAGS_SILVER_KEY) - self.itemkeys |= KEYS_SILVER_KEY; - - // give the trigger the gold key - if (self.spawnflags & SPAWNFLAGS_GOLD_KEY) - self.itemkeys |= KEYS_GOLD_KEY; - - if (!self.message2) { - // generate default missing key message - if (self.itemkeys & (KEYS_GOLD_KEY | KEYS_SILVER_KEY) == KEYS_GOLD_KEY | KEYS_SILVER_KEY) { - self.message2 = "Silver key and gold key required!"; - } else if (self.itemkeys & KEYS_GOLD_KEY) { - self.message2 = "Gold key required!"; - } else if (self.itemkeys & KEYS_SILVER_KEY) { - self.message2 = "Silver key required!"; - } - } - - if (!self.message) { + // set unlocked message + if (self.message == "") self.message = "Unlocked!"; - } - if (!self.noise) { - if (self.sounds == 1) { + // set default unlock noise + if (self.noise == "") { + if (self.sounds == 1) self.noise = "misc/secret.wav"; - } else if (self.sounds == 2) { + else if (self.sounds == 2) self.noise = "misc/talk.wav"; - } else { //if (self.sounds == 3) { + else //if (self.sounds == 3) { self.noise = "misc/trigger1.wav"; - } } - - if (!self.noise1) + + // set default use key sound + if (self.noise1 == "") self.noise1 = "misc/decreasevalue.wav"; - - if (!self.noise2) + + // set closed sourd + if (self.noise2 == "") self.noise2 = "misc/talk.wav"; + // delay between triggering message2 and trigger2 if (!self.wait) self.wait = 5; + // precache sounds precache_sound(self.noise); precache_sound(self.noise1); precache_sound(self.noise2); @@ -369,3 +426,4 @@ void spawnfunc_trigger_keylock(void) { self.touch = trigger_keylock_touch; }; +