]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote branch 'origin/master' into samual/updatecommands
authorSamual <samual@xonotic.org>
Sun, 20 Nov 2011 04:45:40 +0000 (23:45 -0500)
committerSamual <samual@xonotic.org>
Sun, 20 Nov 2011 04:45:40 +0000 (23:45 -0500)
effectinfo.txt
qcsrc/client/particles.qc
qcsrc/server/bot/havocbot/havocbot.qc
qcsrc/server/g_triggers.qc
qcsrc/server/w_shotgun.qc
qcsrc/server/w_tuba.qc

index 5c8e610d122cb581f69281acef01147e4712e516..1e7f20270f2bedf7b1877705335da231b8330a68 100644 (file)
@@ -1243,7 +1243,7 @@ trailspacing 4
 type static
 color 0xffdf72 0x811200
 tex 48 55
-size 1 2
+size 5 2
 sizeincrease -15
 alpha 100 144 988
 airfriction 8
index b7233eee14b8c1a5e29a21b1e22b6c59c7584664..6e24893b02e005b08d9b3e142dad4d70e6c1efd7 100644 (file)
@@ -191,12 +191,12 @@ void Ent_PointParticles()
 .float glow_color; // palette index
 void Draw_Rain()
 {
-    te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, self.count * drawframetime, self.glow_color);
+    te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
 }
 
 void Draw_Snow()
 {
-    te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, self.count * drawframetime, self.glow_color);
+    te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
 }
 
 void Ent_RainOrSnow()
index 9b7198cef821f83efb36eeabae7e4923ae502989..3aefc45a75323b45782bea68f59dacc6b986e490 100644 (file)
@@ -168,7 +168,7 @@ void havocbot_ai()
                        for(i = WEP_FIRST; i <= WEP_LAST; ++i)
                        {
                                e = get_weaponinfo(i);
-                               if ((e.spawnflags & WEP_FLAG_RELOADABLE) && (self.weapon_load[i] < cvar(strcat("g_balance_", e.netname, "_reload_ammo"))))
+                               if ((self.weapons & W_WeaponBit(i)) && (e.spawnflags & WEP_FLAG_RELOADABLE) && (self.weapon_load[i] < cvar(strcat("g_balance_", e.netname, "_reload_ammo"))))
                                        self.switchweapon = i;
                        }
                }
index 0ab2b423354013da80c2e56215aecd053eebfcca..4e97136ce8b45354b0a1f695ff36ba9f06fad634 100644 (file)
@@ -1908,19 +1908,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)
@@ -1942,7 +1977,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);
@@ -1993,9 +2028,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;
        }
 
@@ -2041,13 +2080,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
@@ -2062,6 +2104,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()
index 6e8fa00f9677a4d0e7fe774a55ef4c92bbf23b0f..fcf9a27c27482a25432747d58cc37ee974fae513 100644 (file)
@@ -52,6 +52,7 @@ void shotgun_meleethink (void)
 {
        // declarations
        float i, f, swing, swing_factor, swing_damage, meleetime, is_player;
+       entity target_victim;
        vector targpos;
 
        if(!self.cnt) // set start time of melee
@@ -85,7 +86,7 @@ void shotgun_meleethink (void)
                        + (v_right * swing_factor * autocvar_g_balance_shotgun_secondary_melee_swing_side));
 
                WarpZone_traceline_antilag(self.realowner, self.realowner.origin + self.realowner.view_ofs, targpos, FALSE, self.realowner, ANTILAG_LATENCY(self.realowner));
-
+               
                // draw lightning beams for debugging
                //te_lightning2(world, targpos, self.realowner.origin + self.realowner.view_ofs + v_forward * 5 - v_up * 5); 
                //te_customflash(targpos, 40,  2, '1 1 1');
@@ -96,26 +97,29 @@ void shotgun_meleethink (void)
                        && (trace_ent.takedamage == DAMAGE_AIM)  
                        && (trace_ent != self.swing_alreadyhit)
                        && (is_player || autocvar_g_balance_shotgun_secondary_melee_nonplayerdamage))
-               {       
+               {
+                       target_victim = trace_ent; // so it persists through other calls
+                       
                        if(is_player) // this allows us to be able to nerf the non-player damage done in e.g. assault or onslaught.
                                swing_damage = (autocvar_g_balance_shotgun_secondary_damage * min(1, swing_factor + 1));
                        else
                                swing_damage = (autocvar_g_balance_shotgun_secondary_melee_nonplayerdamage * min(1, swing_factor + 1));
                        
-                       Damage(trace_ent, self.realowner, self.realowner, 
+                       //print(strcat(self.realowner.netname, " hitting ", target_victim.netname, " with ", strcat(ftos(swing_damage), " damage (factor: ", ftos(swing_factor), ") at "), ftos(time), " seconds.\n"));
+                       
+                       Damage(target_victim, self.realowner, self.realowner, 
                                swing_damage, WEP_SHOTGUN | HITTYPE_SECONDARY, 
                                self.realowner.origin + self.realowner.view_ofs, 
                                v_forward * autocvar_g_balance_shotgun_secondary_force);
                                
-                       if(accuracy_isgooddamage(self.realowner, trace_ent))
-                               accuracy_add(self.realowner, WEP_SHOTGUN, 0, swing_damage);
+                       if(accuracy_isgooddamage(self.realowner, target_victim)) { accuracy_add(self.realowner, WEP_SHOTGUN, 0, swing_damage); }
                                
                        // draw large red flash for debugging
                        //te_customflash(targpos, 200, 2, '15 0 0');
                        
                        if(autocvar_g_balance_shotgun_secondary_melee_multihit) // allow multiple hits with one swing, but not against the same player twice.
                        {
-                               self.swing_alreadyhit = trace_ent;
+                               self.swing_alreadyhit = target_victim;
                                continue; // move along to next trace
                        }
                        else
index 2e4aa4957df67e7d201fa2b11f216f300888d85e..a02061e8b80f741a27e419a786940dc157f9b1c3 100644 (file)
@@ -7,6 +7,135 @@ REGISTER_WEAPON(TUBA, w_tuba, 0, 1, WEP_FLAG_HIDDEN | WEP_TYPE_SPLASH, BOT_PICKU
 .float tuba_smoketime;
 .float tuba_instrument;
 
+#define MAX_TUBANOTES 32
+.float tuba_lastnotes_last;
+.float tuba_lastnotes_cnt; // over
+.vector tuba_lastnotes[MAX_TUBANOTES];
+
+float W_Tuba_HasPlayed(entity pl, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo)
+{
+       float i, j, mmin, mmax, nolength;
+       float n = tokenize_console(melody);
+       if(n > pl.tuba_lastnotes_cnt)
+               return FALSE;
+       float pitchshift = 0;
+
+       if(instrument >= 0)
+               if(pl.tuba_instrument != instrument)
+                       return FALSE;
+
+       // verify notes...
+       nolength = FALSE;
+       for(i = 0; i < n; ++i)
+       {
+               vector v = pl.(tuba_lastnotes[mod(pl.tuba_lastnotes_last - i + MAX_TUBANOTES, MAX_TUBANOTES)]);
+               float ai = stof(argv(n - i - 1));
+               float np = floor(ai);
+               if(ai == np)
+                       nolength = TRUE;
+               // n counts the last played notes BACKWARDS
+               // _x is start
+               // _y is end
+               // _z is note pitch
+               if(ignorepitch && i == 0)
+               {
+                       pitchshift = np - v_z;
+               }
+               else
+               {
+                       if(v_z + pitchshift != np)
+                               return FALSE;
+               }
+       }
+
+       // now we know the right NOTES were played
+       if(!nolength)
+       {
+               // verify rhythm...
+               float ti = 0;
+               if(maxtempo > 0)
+                       mmin = 240 / maxtempo; // 60 = "0.25 means 1 sec", at 120 0.5 means 1 sec, at 240 1 means 1 sec
+               else
+                       mmin = 0;
+               if(mintempo > 0)
+                       mmax = 240 / mintempo; // 60 = "0.25 means 1 sec", at 120 0.5 means 1 sec, at 240 1 means 1 sec
+               else
+                       mmax = 240; // you won't try THAT hard... (tempo 1)
+               //print(sprintf("initial tempo rules: %f %f\n", mmin, mmax));
+
+               for(i = 0; i < n; ++i)
+               {
+                       vector vi = pl.(tuba_lastnotes[mod(pl.tuba_lastnotes_last - i + MAX_TUBANOTES, MAX_TUBANOTES)]);
+                       float ai = stof(argv(n - i - 1));
+                       ti -= 1 / (ai - floor(ai));
+                       float tj = ti;
+                       for(j = i+1; j < n; ++j)
+                       {
+                               vector vj = pl.(tuba_lastnotes[mod(pl.tuba_lastnotes_last - j + MAX_TUBANOTES, MAX_TUBANOTES)]);
+                               float aj = stof(argv(n - j - 1));
+                               tj -= (aj - floor(aj));
+
+                               // note i should be at m*ti+b
+                               // note j should be at m*tj+b
+                               // so:
+                               // we have a LINE l, so that
+                               // vi_x <= l(ti) <= vi_y
+                               // vj_x <= l(tj) <= vj_y
+                               // what is m?
+
+                               // vi_x <= vi_y <= vj_x <= vj_y
+                               // ti <= tj
+                               //print(sprintf("first note: %f to %f, should be %f\n", vi_x, vi_y, ti));
+                               //print(sprintf("second note: %f to %f, should be %f\n", vj_x, vj_y, tj));
+                               //print(sprintf("m1 = %f\n", (vi_x - vj_y) / (ti - tj)));
+                               //print(sprintf("m2 = %f\n", (vi_y - vj_x) / (ti - tj)));
+                               mmin = max(mmin, (vi_x - vj_y) / (ti - tj)); // lower bound
+                               mmax = min(mmax, (vi_y - vj_x) / (ti - tj)); // upper bound
+                       }
+               }
+
+               if(mmin > mmax) // rhythm fail
+                       return FALSE;
+       }
+
+       pl.tuba_lastnotes_cnt = 0;
+
+       return TRUE;
+}
+
+void W_Tuba_NoteOff()
+{
+       // we have a note:
+       //   on: self.spawnshieldtime
+       //   off: time
+       //   note: self.cnt
+       if(self.owner.tuba_note == self)
+       {
+               self.owner.tuba_lastnotes_last = mod(self.owner.tuba_lastnotes_last + 1, MAX_TUBANOTES);
+               self.owner.(tuba_lastnotes[self.owner.tuba_lastnotes_last]) = eX * self.spawnshieldtime + eY * time + eZ * self.cnt;
+               self.owner.tuba_note = world;
+               self.owner.tuba_lastnotes_cnt = bound(0, self.owner.tuba_lastnotes_cnt + 1, MAX_TUBANOTES);
+
+               string s;
+               s = trigger_magicear_processmessage_forallears(self.owner, 0, world, string_null);
+               if(s != "")
+               {
+                       // simulate a server message
+                       switch(self.tuba_instrument)
+                       {
+                               default:
+                               case 0: // Tuba
+                                       bprint(strcat("\{1}\{13}* ^3", self.owner.netname, "^3 played on the @!#%'n Tuba: ^7", s, "\n"));
+                                       break;
+                               case 1:
+                                       bprint(strcat("\{1}\{13}* ^3", self.owner.netname, "^3 played on the @!#%'n Accordeon: ^7", s, "\n"));
+                                       break;
+                       }
+               }
+       }
+       remove(self);
+}
+
 float Tuba_GetNote(entity pl, float hittype)
 {
        float note;
@@ -111,8 +240,7 @@ void W_Tuba_NoteThink()
        entity e;
        if(time > self.teleport_time)
        {
-               self.realowner.tuba_note = world;
-               remove(self);
+               W_Tuba_NoteOff();
                return;
        }
        self.nextthink = time;
@@ -141,7 +269,7 @@ void W_Tuba_NoteThink()
        }
 }
 
-void W_Tuba_Attack(float hittype)
+void W_Tuba_NoteOn(float hittype)
 {
        vector o;
        float n;
@@ -162,8 +290,10 @@ void W_Tuba_Attack(float hittype)
        {
                if(self.tuba_note.cnt != n || self.tuba_note.tuba_instrument != self.tuba_instrument)
                {
-                       remove(self.tuba_note);
-                       self.tuba_note = world;
+                       entity oldself = self;
+                       self = self.tuba_note;
+                       W_Tuba_NoteOff();
+                       self = oldself;
                }
        }
 
@@ -175,6 +305,7 @@ void W_Tuba_Attack(float hittype)
                self.tuba_note.tuba_instrument = self.tuba_instrument;
                self.tuba_note.think = W_Tuba_NoteThink;
                self.tuba_note.nextthink = time;
+               self.tuba_note.spawnshieldtime = time;
                Net_LinkEntity(self.tuba_note, FALSE, 0, W_Tuba_NoteSendEntity);
        }
 
@@ -215,14 +346,14 @@ float w_tuba(float req)
                if (self.BUTTON_ATCK)
                if (weapon_prepareattack(0, autocvar_g_balance_tuba_refire))
                {
-                       W_Tuba_Attack(0);
+                       W_Tuba_NoteOn(0);
                        //weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_tuba_animtime, w_ready);
                        weapon_thinkf(WFRAME_IDLE, autocvar_g_balance_tuba_animtime, w_ready);
                }
                if (self.BUTTON_ATCK2)
                if (weapon_prepareattack(1, autocvar_g_balance_tuba_refire))
                {
-                       W_Tuba_Attack(HITTYPE_SECONDARY);
+                       W_Tuba_NoteOn(HITTYPE_SECONDARY);
                        //weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_tuba_animtime, w_ready);
                        weapon_thinkf(WFRAME_IDLE, autocvar_g_balance_tuba_animtime, w_ready);
                }
@@ -230,8 +361,10 @@ float w_tuba(float req)
                {
                        if(!self.BUTTON_ATCK && !self.BUTTON_ATCK2)
                        {
-                               remove(self.tuba_note);
-                               self.tuba_note = world;
+                               entity oldself = self;
+                               self = self.tuba_note;
+                               W_Tuba_NoteOff();
+                               self = oldself;
                        }
                }
        }