From 50a129e43ab0406af320b261bf6321834e9900cc Mon Sep 17 00:00:00 2001 From: przemek Date: Sun, 9 Oct 2011 15:02:37 +0200 Subject: [PATCH] item_key1/item_key2 work now with func_door, new entity: trigger_keylock --- qcsrc/server/defs.qh | 4 + qcsrc/server/item_key.qc | 325 +++++++++++++++++++++++++++++++++++++-- qcsrc/server/t_plats.qc | 91 ++++++++--- 3 files changed, 381 insertions(+), 39 deletions(-) diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 091866a06..5915773ce 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -252,6 +252,9 @@ float alreadychangedlevel; // spawnflags require key (for now only func_door) #define SPAWNFLAGS_GOLD_KEY 8 #define SPAWNFLAGS_SILVER_KEY 16 +// message delay for func_door locked by keys and key locks +// this field is used on player entities +.float key_door_messagetime; .float version; @@ -669,3 +672,4 @@ float serverflags; .float misc_bulletcounter; // replaces uzi & hlac bullet counter. void PlayerUseKey(); + diff --git a/qcsrc/server/item_key.qc b/qcsrc/server/item_key.qc index 6a1ce5383..55f71e3bc 100644 --- a/qcsrc/server/item_key.qc +++ b/qcsrc/server/item_key.qc @@ -1,19 +1,43 @@ /* -Touch handler. +TODO: +- add an unlock sound (here to trigger_keylock and to func_door) +- display available keys on the HUD +- make more tests +- think about adding NOT_EASY/NOT_NORMAL/NOT_HARD for Q1 compatibility +- should keys have a trigger? +*/ + +/* +================================ +item_key1 / item_key2 +================================ +*/ + +/* +Key touch handler. */ void item_key_touch(void) { - if (other.classname != "player") + local entity p; + + if (other.owner) + p = other.owner; + else + p = other; + + if (p.classname != "player") return; // player already picked up this key - if (other.itemkeys & self.itemkeys) + if (p.itemkeys & self.itemkeys) return; - other.itemkeys |= self.itemkeys; + p.itemkeys |= self.itemkeys; + play2(other, self.noise); - if (self.message) - centerprint(other, self.message); -} + if (self.message) { + centerprint(p, self.message); + } +}; /* Spawn a key with given model, key code and color. @@ -22,16 +46,27 @@ void spawn_item_key(float key_code) { self.itemkeys = key_code; precache_model(self.model); - if(self.spawnflags & 1) + if (self.spawnflags & 1) self.noalign = 1; + if (self.noalign) self.movetype = MOVETYPE_NONE; else self.movetype = MOVETYPE_TOSS; - setsize(self, '-16 -16 -24', '16 16 32'); + if (!self.noise) + self.noise = "misc/itempickup.wav"; + + precache_sound(self.noise); + + self.mdl = self.model; + self.effects = EF_LOWPRECISION; setmodel(self, self.model); + //setsize(self, '-16 -16 -24', '16 16 32'); + setorigin(self, self.origin + '0 0 32'); + setsize(self, '-16 -16 -56', '16 16 0'); self.modelflags |= MF_ROTATE; + self.solid = SOLID_TRIGGER; if (!self.noalign) { @@ -42,11 +77,19 @@ void spawn_item_key(float key_code) { } self.touch = item_key_touch; -} +}; -/* -Spawn silver key. +/*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING +SILVER key. +-----------KEYS------------ +colormod: color of the key (default: '.9 .9 .9'). +message: message to print when player picks up this key. +model: custom model to use. +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---------- */ void spawnfunc_item_key1(void) { if (!self.model) @@ -54,15 +97,23 @@ void spawnfunc_item_key1(void) { 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); -} +}; -/* -Spawn gold key. +/*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING +GOLDEN key. +-----------KEYS------------ +colormod: color of the key (default: '1 .9 0'). +message: message to print when player picks up this key. +model: custom model to use. +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---------- */ void spawnfunc_item_key2(void) { if (!self.model) @@ -75,6 +126,246 @@ void spawnfunc_item_key2(void) { self.message = "You've picked up the gold key!"; spawn_item_key(KEYS_GOLD_KEY); -} +}; + + +/* +================================ +trigger_keylock +================================ +*/ + +/* +trigger givent targets +*/ +void trigger_keylock_trigger(string s) { + local entity t, stemp, otemp, atemp; + + stemp = self; + otemp = other; + atemp = activator; + + + for(t = world; (t = find(t, targetname, s)); ) + if (t.use) { + self = t; + other = stemp; + activator = atemp; + self.use(); + } + + self = stemp; + other = otemp; + activator = atemp; +}; + +/* +kill killtarget of trigger keylock. +*/ +void trigger_keylock_kill(string s) { + local entity t, stemp, otemp, atemp; + + stemp = self; + otemp = other; + atemp = activator; + + for(t = world; (t = find(t, targetname, s)); ) + if (t.use) { + remove(t); + } + + self = stemp; + other = otemp; + activator = atemp; +}; + +void trigger_keylock_touch(void) { + local float key_used, silver_key_missing, gold_key_missing, started_delay; + local entity p; + + 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") + 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; + } + } + + + 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) { + // at least one of the keys is missing + + if (key_used) { + // one key was given, but an other one is 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; + } + } + + 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! + play2(other, self.noise); + centerprint(other, self.message); + + if (self.target) + trigger_keylock_trigger(self.target); + + if (self.killtarget) + trigger_keylock_kill(self.killtarget); + + remove(self); + } + +}; + +/*QUAKED trigger_keylock (.0 .5 .8) ? - - - GOLD_KEY SILVER_KEY +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 +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) +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) +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. +---------NOTES---------- +If spawned without any key specified, this trigger will 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))) { + 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) { + self.message = "Unlocked!"; + } + + if (!self.noise) { + if (self.sounds == 1) { + self.noise = "misc/secret.wav"; + } else if (self.sounds == 2) { + self.noise = "misc/talk.wav"; + } else { //if (self.sounds == 3) { + self.noise = "misc/trigger1.wav"; + } + } + + if (!self.noise1) + self.noise1 = "misc/decreasevalue.wav"; + + if (!self.noise2) + self.noise2 = "misc/talk.wav"; + + if (!self.wait) + self.wait = 5; + + precache_sound(self.noise); + precache_sound(self.noise1); + precache_sound(self.noise2); + + EXACTTRIGGER_INIT; + + self.touch = trigger_keylock_touch; +}; diff --git a/qcsrc/server/t_plats.qc b/qcsrc/server/t_plats.qc index 25a25cdd1..db58fb0b7 100644 --- a/qcsrc/server/t_plats.qc +++ b/qcsrc/server/t_plats.qc @@ -885,6 +885,7 @@ void door_go_up() }; + /* ============================================================================= @@ -893,6 +894,63 @@ ACTIVATION FUNCTIONS ============================================================================= */ +float door_check_keys(void) { + local entity door, p; + + + if (self.owner) + door = self.owner; + else + door = self; + + if (other.owner) + p = other.owner; + else + p = other; + + if (door.spawnflags & (SPAWNFLAGS_GOLD_KEY | SPAWNFLAGS_SILVER_KEY)) { + // this door require a key + // only a player can have a key + if (p.classname != "player") + return FALSE; + + // check gold key + if (self.owner.spawnflags & SPAWNFLAGS_GOLD_KEY) { + if (!(other.itemkeys & KEYS_GOLD_KEY)) { + if (p.key_door_messagetime <= time) { + play2(other, "misc/talk.wav"); + centerprint(other, "You don't have the gold key!"); + p.key_door_messagetime = time + 2; + } + return FALSE; + } else { + self.owner.spawnflags &~= SPAWNFLAGS_GOLD_KEY; + } + } + + // check silver key + if (self.owner.spawnflags & SPAWNFLAGS_SILVER_KEY) { + if (!(other.itemkeys & KEYS_SILVER_KEY)) { + if (p.key_door_messagetime <= time) { + play2(other, "misc/talk.wav"); + centerprint(other, "You don't have the silver key!"); + p.wait = key_door_messagetime + 2; + } + return FALSE; + } else { + self.owner.spawnflags &~= SPAWNFLAGS_SILVER_KEY; + } + } + + // door is now unlocked + play2(other, "misc/talk.wav"); + centerprint(other, "Door unlocked!"); + } + + return TRUE; +} + + void door_fire() { local entity oself; @@ -958,6 +1016,7 @@ void door_use() local entity oself; //dprint("door_use (model: ");dprint(self.model);dprint(")\n"); + if (self.owner) { oself = self; @@ -977,26 +1036,9 @@ void door_trigger_touch() if (time < self.attack_finished_single) return; - if (self.spawnflags & (SPAWNFLAGS_GOLD_KEY | SPAWNFLAGS_SILVER_KEY)) { - // this door require a key - // only a player can have a key - if (other.classname != "player") - return; - - // check gold key - if (self.spawnflags & SPAWNFLAGS_GOLD_KEY) - if (!(other.itemkeys & KEYS_GOLD_KEY)) { - centerprint(other, "You don't have the gold key"); - return; - } - - // check silver key - if (self.spawnflags & SPAWNFLAGS_SILVER_KEY) - if (!(other.itemkeys & KEYS_SILVER_KEY)) { - centerprint(other, "You don't have the silver key"); - return; - } - } + // check if door is locked + if (!door_check_keys()) + return; self.attack_finished_single = time + 1; @@ -1345,6 +1387,10 @@ void door_reset() void spawnfunc_func_door() { + print("spawnfunc_func_door() spawnflags=", ftos(self.spawnflags)); + print(", gold_key=", ftos(self.spawnflags & SPAWNFLAGS_GOLD_KEY)); + print(", silver_key=", ftos(self.spawnflags & SPAWNFLAGS_SILVER_KEY), "\n"); + //if (!self.deathtype) // map makers can override this // self.deathtype = " got in the way"; SetMovedir (); @@ -1358,8 +1404,9 @@ void spawnfunc_func_door() self.blocked = door_blocked; self.use = door_use; - if(self.spawnflags & 8) - self.dmg = 10000; + // FIXME: undocumented flag 8, originally (Q1) GOLD_KEY + // if(self.spawnflags & 8) + // self.dmg = 10000; if(self.dmg && (!self.message)) self.message = "was squished"; -- 2.39.2