]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/g_triggers.qc
Merge remote-tracking branch 'origin/master' into terencehill/menu_focus_stuff
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_triggers.qc
index 0a70de75f802fb13561c7ccf6eb259788b901023..12c75ae9e57199fb5499b0a910c5ecda94d3ed42 100644 (file)
@@ -10,7 +10,7 @@ void DelayThink()
        activator = self.enemy;
        SUB_UseTargets ();
        remove(self);
-};
+}
 
 /*
 ==============================
@@ -33,7 +33,7 @@ match (string)self.target and call their .use function
 */
 void SUB_UseTargets()
 {
-       local entity t, stemp, otemp, act;
+       entity t, stemp, otemp, act;
        string s;
        float i;
 
@@ -66,7 +66,7 @@ void SUB_UseTargets()
                if(clienttype(activator) == CLIENTTYPE_REAL)
                {
                        centerprint (activator, self.message);
-                       if (!self.noise)
+                       if (self.noise == "")
                                play2(activator, "misc/talk.wav");
                }
        }
@@ -88,6 +88,9 @@ void SUB_UseTargets()
        stemp = self;
        otemp = other;
 
+       if(stemp.target_random)
+               RandomSelection_Init();
+
        for(i = 0; i < 4; ++i)
        {
                switch(i)
@@ -103,19 +106,33 @@ void SUB_UseTargets()
                        for(t = world; (t = find(t, targetname, s)); )
                        if(t.use)
                        {
-                               //print(stemp.classname, " ", stemp.targetname, " -> ", t.classname, " ", t.targetname, "\n");
-                               self = t;
-                               other = stemp;
-                               activator = act;
-                               self.use();
+                               if(stemp.target_random)
+                               {
+                                       RandomSelection_Add(t, 0, string_null, 1, 0);
+                               }
+                               else
+                               {
+                                       self = t;
+                                       other = stemp;
+                                       activator = act;
+                                       self.use();
+                               }
                        }
                }
        }
 
+       if(stemp.target_random && RandomSelection_chosen_ent)
+       {
+               self = RandomSelection_chosen_ent;
+               other = stemp;
+               activator = act;
+               self.use();
+       }
+
        activator = act;
        self = stemp;
        other = otemp;
-};
+}
 
 
 //=============================================================================
@@ -132,7 +149,7 @@ void multi_wait()
                self.takedamage = DAMAGE_YES;
                self.solid = SOLID_BBOX;
        }
-};
+}
 
 
 // the trigger was just touched/killed/used
@@ -154,7 +171,7 @@ void multi_trigger()
        }
 
        if (self.noise)
-               sound (self.enemy, CHAN_AUTO, self.noise, VOL_BASE, ATTN_NORM);
+               sound (self.enemy, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
 
 // don't trigger again until reset
        self.takedamage = DAMAGE_NO;
@@ -175,16 +192,16 @@ void multi_trigger()
        else
        {       // we can't just remove (self) here, because this is a touch function
                // called wheil C code is looping through area links...
-               self.touch = SUB_Null;
+               self.touch = func_null;
        }
-};
+}
 
 void multi_use()
 {
        self.goalentity = other;
        self.enemy = activator;
        multi_trigger();
-};
+}
 
 void multi_touch()
 {
@@ -209,7 +226,7 @@ void multi_touch()
        self.enemy = other;
        self.goalentity = other;
        multi_trigger ();
-};
+}
 
 void multi_eventdamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 {
@@ -237,7 +254,8 @@ void multi_reset()
                self.takedamage = DAMAGE_YES;
                self.solid = SOLID_BBOX;
        }
-       self.think = SUB_Null;
+       self.think = func_null;
+       self.nextthink = 0;
        self.team = self.team_saved;
 }
 
@@ -301,7 +319,7 @@ void spawnfunc_trigger_multiple()
                        setorigin (self, self.origin);  // make sure it links into the world
                }
        }
-};
+}
 
 
 /*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
@@ -321,7 +339,7 @@ void spawnfunc_trigger_once()
 {
        self.wait = -1;
        spawnfunc_trigger_multiple();
-};
+}
 
 //=============================================================================
 
@@ -332,7 +350,7 @@ void spawnfunc_trigger_relay()
 {
        self.use = SUB_UseTargets;
        self.reset = spawnfunc_trigger_relay; // this spawnfunc resets fully
-};
+}
 
 void delay_use()
 {
@@ -342,7 +360,8 @@ void delay_use()
 
 void delay_reset()
 {
-       self.think = SUB_Null;
+       self.think = func_null;
+       self.nextthink = 0;
 }
 
 void spawnfunc_trigger_delay()
@@ -385,7 +404,7 @@ void counter_use()
                centerprint(activator, "Sequence completed!");
        self.enemy = activator;
        multi_trigger ();
-};
+}
 
 void counter_reset()
 {
@@ -409,7 +428,15 @@ void spawnfunc_trigger_counter()
 
        self.use = counter_use;
        self.reset = counter_reset;
-};
+}
+
+void trigger_hurt_use()
+{
+       if(activator.classname == "player")
+               self.enemy = activator;
+       else
+               self.enemy = world; // let's just destroy it, if taking over is too much work
+}
 
 .float triggerhurttime;
 void trigger_hurt_touch()
@@ -429,28 +456,29 @@ void trigger_hurt_touch()
                {
                        EXACTTRIGGER_TOUCH;
                        other.triggerhurttime = time + 1;
-                       Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+
+                       entity own;
+                       own = self.enemy;
+                       if(own.classname != "player")
+                       {
+                               own = self;
+                               self.enemy = world; // I still hate you all
+                       }
+
+                       Damage (other, self, own, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
                }
        }
-       else
+       else if(other.damagedbytriggers)
        {
-               if (!other.owner)
+               if(other.takedamage)
                {
-                       if (other.items & IT_KEY1 || other.items & IT_KEY2)     // reset flag
-                       {
-                               EXACTTRIGGER_TOUCH;
-                               other.pain_finished = min(other.pain_finished, time + 2);
-                       }
-                       else if (other.classname == "rune")                     // reset runes
-                       {
-                               EXACTTRIGGER_TOUCH;
-                               other.nextthink = min(other.nextthink, time + 1);
-                       }
+                       EXACTTRIGGER_TOUCH;
+                       Damage(other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
                }
        }
 
        return;
-};
+}
 
 /*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
 Any object touching this will be hurt
@@ -465,11 +493,13 @@ void spawnfunc_trigger_hurt()
        EXACTTRIGGER_INIT;
        self.active = ACTIVE_ACTIVE;
        self.touch = trigger_hurt_touch;
+       self.use = trigger_hurt_use;
+       self.enemy = world; // I hate you all
        if (!self.dmg)
                self.dmg = 1000;
-       if (!self.message)
+       if (self.message == "")
                self.message = "was in the wrong place";
-       if (!self.message2)
+       if (self.message2 == "")
                self.message2 = "was thrown into a world of hurt by";
        // self.message = "someone like %s always gets wrongplaced";
 
@@ -478,7 +508,7 @@ void spawnfunc_trigger_hurt()
        if(trigger_hurt_last)
                trigger_hurt_last.trigger_hurt_next = self;
        trigger_hurt_last = self;
-};
+}
 
 float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
 {
@@ -509,6 +539,7 @@ void trigger_heal_touch()
        if (other.iscreature)
        {
                if (other.takedamage)
+               if (!other.deadflag)
                if (other.triggerhealtime < time)
                {
                        EXACTTRIGGER_TOUCH;
@@ -518,11 +549,11 @@ void trigger_heal_touch()
                        {
                                other.health = min(other.health + self.health, self.max_health);
                                other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
-                               sound (other, CHAN_AUTO, self.noise, VOL_BASE, ATTN_NORM);
+                               sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
                        }
                }
        }
-};
+}
 
 void spawnfunc_trigger_heal()
 {
@@ -537,7 +568,7 @@ void spawnfunc_trigger_heal()
        if(self.noise == "")
                self.noise = "misc/mediumhealth.wav";
        precache_sound(self.noise);
-};
+}
 
 
 //////////////////////////////////////////////////////////////
@@ -579,12 +610,12 @@ void trigger_gravity_check_think()
                self.count -= 1;
                self.nextthink = time;
        }
-};
+}
 
 void trigger_gravity_use()
 {
        self.state = !self.state;
-};
+}
 
 void trigger_gravity_touch()
 {
@@ -629,10 +660,10 @@ void trigger_gravity_touch()
        {
                other.gravity = g;
                if(self.noise != "")
-                       sound (other, CHAN_AUTO, self.noise, VOL_BASE, ATTN_NORM);
+                       sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
                UpdateCSQCProjectile(self.owner);
        }
-};
+}
 
 void spawnfunc_trigger_gravity()
 {
@@ -651,7 +682,7 @@ void spawnfunc_trigger_gravity()
                if(self.spawnflags & 2)
                        self.state = FALSE;
        }
-};
+}
 
 //=============================================================================
 
@@ -685,7 +716,7 @@ void target_speaker_use_activator()
        else
                snd = self.noise;
        msg_entity = activator;
-       soundto(MSG_ONE, self, CHAN_TRIGGER, snd, VOL_BASE * self.volume, self.atten);
+       soundto(MSG_ONE, self, CH_TRIGGER, snd, VOL_BASE * self.volume, self.atten);
 }
 void target_speaker_use_on()
 {
@@ -711,13 +742,13 @@ void target_speaker_use_on()
        }
        else
                snd = self.noise;
-       sound(self, CHAN_TRIGGER, snd, VOL_BASE * self.volume, self.atten);
+       sound(self, CH_TRIGGER_SINGLE, snd, VOL_BASE * self.volume, self.atten);
        if(self.spawnflags & 3)
                self.use = target_speaker_use_off;
 }
 void target_speaker_use_off()
 {
-       sound(self, CHAN_TRIGGER, "misc/null.wav", VOL_BASE * self.volume, self.atten);
+       sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASE * self.volume, self.atten);
        self.use = target_speaker_use_on;
 }
 void target_speaker_reset()
@@ -786,7 +817,7 @@ void spawnfunc_target_speaker()
                ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
                remove(self);
        }
-};
+}
 
 
 void spawnfunc_func_stardust() {
@@ -989,7 +1020,7 @@ float rainsnow_SendEntity(entity to, float sf)
        WriteShort(MSG_ENTITY, self.count);
        WriteByte(MSG_ENTITY, self.cnt);
        return 1;
-};
+}
 
 /*QUAKED spawnfunc_func_rain (0 .5 .8) ?
 This is an invisible area like a trigger, which rain falls inside of.
@@ -1026,7 +1057,7 @@ void spawnfunc_func_rain()
        self.Version = 1;
 
        Net_LinkEntity(self, FALSE, 0, rainsnow_SendEntity);
-};
+}
 
 
 /*QUAKED spawnfunc_func_snow (0 .5 .8) ?
@@ -1064,7 +1095,7 @@ void spawnfunc_func_snow()
        self.Version = 1;
 
        Net_LinkEntity(self, FALSE, 0, rainsnow_SendEntity);
-};
+}
 
 
 void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, float deathtype);
@@ -1297,9 +1328,9 @@ void spawnfunc_misc_laser()
        if(self.colormod == '0 0 0')
                if(!self.alpha)
                        self.colormod = '1 0 0';
-       if(!self.message)
+       if(self.message == "")
                self.message = "saw the light";
-       if (!self.message2)
+       if (self.message2 == "")
                self.message2 = "was pushed into a laser by";
        if(!self.scale)
                self.scale = 1;
@@ -1341,24 +1372,7 @@ void trigger_impulse_touch1()
        if (self.active != ACTIVE_ACTIVE) 
                return;
 
-       // FIXME: Better checking for what to push and not.
-       if not(other.iscreature)
-       if (other.classname != "corpse")
-       if (other.classname != "body")
-       if (other.classname != "gib")
-       if (other.classname != "missile")
-       if (other.classname != "rocket")
-       if (other.classname != "casing")
-       if (other.classname != "grenade")
-       if (other.classname != "plasma")
-       if (other.classname != "plasma_prim")
-       if (other.classname != "plasma_chain")
-       if (other.classname != "droppedweapon")
-       if (other.classname != "nexball_basketball")
-       if (other.classname != "nexball_football")
-               return;
-
-       if (other.deadflag && other.iscreature)
+       if (!isPushable(other))
                return;
 
        EXACTTRIGGER_TOUCH;
@@ -1371,6 +1385,8 @@ void trigger_impulse_touch1()
         return;
     }
 
+    str = min(self.radius, vlen(self.origin - other.origin));
+
     if(self.falloff == 1)
         str = (str / self.radius) * self.strength;
     else if(self.falloff == 2)
@@ -1396,24 +1412,7 @@ void trigger_impulse_touch2()
        if (self.active != ACTIVE_ACTIVE) 
                return;
 
-       // FIXME: Better checking for what to push and not.
-       if not(other.iscreature)
-       if (other.classname != "corpse")
-       if (other.classname != "body")
-       if (other.classname != "gib")
-       if (other.classname != "missile")
-       if (other.classname != "rocket")
-       if (other.classname != "casing")
-       if (other.classname != "grenade")
-       if (other.classname != "plasma")
-       if (other.classname != "plasma_prim")
-       if (other.classname != "plasma_chain")
-       if (other.classname != "droppedweapon")
-       if (other.classname != "nexball_basketball")
-       if (other.classname != "nexball_football")
-               return;
-
-       if (other.deadflag && other.iscreature)
+       if (!isPushable(other))
                return;
 
        EXACTTRIGGER_TOUCH;
@@ -1437,24 +1436,7 @@ void trigger_impulse_touch3()
        if (self.active != ACTIVE_ACTIVE) 
                return;
 
-       // FIXME: Better checking for what to push and not.
-       if not(other.iscreature)
-       if (other.classname != "corpse")
-       if (other.classname != "body")
-       if (other.classname != "gib")
-       if (other.classname != "missile")
-       if (other.classname != "rocket")
-       if (other.classname != "casing")
-       if (other.classname != "grenade")
-       if (other.classname != "plasma")
-       if (other.classname != "plasma_prim")
-       if (other.classname != "plasma_chain")
-       if (other.classname != "droppedweapon")
-       if (other.classname != "nexball_basketball")
-       if (other.classname != "nexball_football")
-               return;
-
-       if (other.deadflag && other.iscreature)
+       if (!isPushable(other))
                return;
 
        EXACTTRIGGER_TOUCH;
@@ -1657,7 +1639,7 @@ void spawnfunc_trigger_multivibrator()
        self.state = 0;
        self.use = multivibrator_toggle;
        self.think = multivibrator_send;
-       self.nextthink = time;
+       self.nextthink = max(1, time);
 
        IFTARGETED
                multivibrator_reset();
@@ -1703,6 +1685,7 @@ void follow_init()
                        attach_sameorigin(dst, src, self.message);
                }
 
+               dst.solid = SOLID_NOT; // solid doesn't work with attachment
                remove(self);
        }
        else
@@ -1922,19 +1905,54 @@ void spawnfunc_trigger_disablerelay()
 }
 
 float magicear_matched;
+float W_Tuba_HasPlayed(entity pl, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo);
 string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin)
 {
        float domatch, dotrigger, matchstart, l;
        string s, msg;
        entity oldself;
+       string savemessage;
 
        magicear_matched = FALSE;
 
-       dotrigger = ((self.classname == "player") && (self.deadflag == DEAD_NO) && ((ear.radius == 0) || (vlen(source.origin - ear.origin) <= ear.radius)));
+       dotrigger = ((source.classname == "player") && (source.deadflag == DEAD_NO) && ((ear.radius == 0) || (vlen(source.origin - ear.origin) <= ear.radius)));
        domatch = ((ear.spawnflags & 32) || dotrigger);
+
        if not(domatch)
                return msgin;
 
+       if not(msgin)
+       {
+               // we are in TUBA mode!
+               if not(ear.spawnflags & 256)
+                       return msgin;
+
+               if(!W_Tuba_HasPlayed(source, ear.message, ear.movedir_x, !(ear.spawnflags & 512), ear.movedir_y, ear.movedir_z))
+                       return msgin;
+
+               magicear_matched = TRUE;
+
+               if(dotrigger)
+               {
+                       oldself = self;
+                       activator = source;
+                       self = ear;
+                       savemessage = self.message;
+                       self.message = string_null;
+                       SUB_UseTargets();
+                       self.message = savemessage;
+                       self = oldself;
+               }
+
+               if(ear.netname != "")
+                       return ear.netname;
+
+               return msgin;
+       }
+
+       if(ear.spawnflags & 256) // ENOTUBA
+               return msgin;
+
        if(privatesay)
        {
                if(ear.spawnflags & 4)
@@ -1956,7 +1974,7 @@ string trigger_magicear_processmessage(entity ear, entity source, float teamsay,
        matchstart = -1;
        l = strlen(ear.message);
 
-       if(self.spawnflags & 128)
+       if(ear.spawnflags & 128)
                msg = msgin;
        else
                msg = strdecolorize(msgin);
@@ -2007,9 +2025,13 @@ string trigger_magicear_processmessage(entity ear, entity source, float teamsay,
 
        if(dotrigger)
        {
-               oldself = activator = self;
+               oldself = self;
+               activator = source;
                self = ear;
+               savemessage = self.message;
+               self.message = string_null;
                SUB_UseTargets();
+               self.message = savemessage;
                self = oldself;
        }
 
@@ -2055,13 +2077,16 @@ void spawnfunc_trigger_magicear()
 
        // actually handled in "say" processing
        // spawnflags:
-       //   1 = ignore say
-       //   2 = ignore teamsay
-       //   4 = ignore tell
-       //   8 = ignore tell to unknown player
+       //    1 = ignore say
+       //    2 = ignore teamsay
+       //    4 = ignore tell
+       //    8 = ignore tell to unknown player
        //   16 = let netname replace the whole message (otherwise, netname is a word replacement if set)
        //   32 = perform the replacement even if outside the radius or dead
        //   64 = continue replacing/triggering even if this one matched
+       //  128 = don't decolorize message before matching
+       //  256 = message is a tuba note sequence (pitch.duration pitch.duration ...)
+       //  512 = tuba notes must be exact right pitch, no transposing
        // message: either
        //   *pattern*
        // or
@@ -2076,6 +2101,10 @@ void spawnfunc_trigger_magicear()
        //   "hearing distance"
        // target:
        //   what to trigger
+       // movedir:
+       //   for spawnflags 256, defines 'instrument+1 mintempo maxtempo' (zero component doesn't matter)
+
+       self.movedir_x -= 1; // map to tuba instrument numbers
 }
 
 void relay_activators_use()
@@ -2132,9 +2161,9 @@ void spawnfunc_target_changelevel_use()
                localcmd("endmatch\n");
        else
                localcmd(strcat("changelevel ", self.chmap, "\n"));
-};
+}
 
 void spawnfunc_target_changelevel()
 {
        self.use = spawnfunc_target_changelevel_use;
-};
+}