]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/w_tuba.qc
add a simple test function for last tuba notes
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_tuba.qc
index 4a7978808319109c2d2de1f7f61d652b512e168a..1e47a3b3d1b36a512a910b793a02fc04be498de4 100644 (file)
@@ -3,9 +3,56 @@ REGISTER_WEAPON(TUBA, w_tuba, 0, 1, WEP_FLAG_HIDDEN | WEP_TYPE_SPLASH, BOT_PICKU
 #else
 #ifdef SVQC
 //#define TUBA_NOTE(n) strcat("weapons/tuba_note", ftos(n), ".wav")
-.float tuba_notecount;
 .entity tuba_note;
 .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 i;
+       float n = tokenize_console(melody);
+       if(n > pl.tuba_lastnotes_cnt)
+               return 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));
+               // n counts the last played notes BACKWARDS
+               // _x is start
+               // _y is end
+               // _z is note pitch
+               if(v_z != floor(ai))
+                       return FALSE;
+               // FIXME verify rhythm
+       }
+       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);
+
+               // debug
+               if(W_Tuba_HasPlayed(self.owner, "4 0 4 2"))
+                       dprint("Someone knows how to play Loom!\n");
+       }
+       remove(self);
+}
 
 float Tuba_GetNote(entity pl, float hittype)
 {
@@ -48,7 +95,7 @@ float Tuba_GetNote(entity pl, float hittype)
        // kind of tuba currently is player slot number, or team number if in
        // teamplay
        // that way, holes in the range of notes are "plugged"
-       if(teams_matter)
+       if(teamplay)
        {
                if(pl.team == COLOR_TEAM2 || pl.team == COLOR_TEAM4)
                        note += 3;
@@ -76,14 +123,28 @@ float Tuba_GetNote(entity pl, float hittype)
 
 float W_Tuba_NoteSendEntity(entity to, float sf)
 {
+       float f;
+
+       msg_entity = to;
+       if(!sound_allowed(MSG_ONE, self.realowner))
+               return FALSE;
+
        WriteByte(MSG_ENTITY, ENT_CLIENT_TUBANOTE);
-       WriteByte(MSG_ENTITY, (sf & 1) | ((self.cnt + 42) * 2));
+       WriteByte(MSG_ENTITY, sf);
        if(sf & 1)
+       {
+               WriteChar(MSG_ENTITY, self.cnt);
+               f = 0;
+               if(self.realowner != to)
+                       f |= 1;
+               f |= 2 * self.tuba_instrument;
+               WriteByte(MSG_ENTITY, f);
+       }
+       if(sf & 2)
        {
                WriteCoord(MSG_ENTITY, self.origin_x);
                WriteCoord(MSG_ENTITY, self.origin_y);
                WriteCoord(MSG_ENTITY, self.origin_z);
-               WriteByte(MSG_ENTITY, self.owner != to);
        }
        return TRUE;
 }
@@ -97,78 +158,76 @@ void W_Tuba_NoteThink()
        entity e;
        if(time > self.teleport_time)
        {
-               self.owner.tuba_note = world;
-               remove(self);
+               W_Tuba_NoteOff();
                return;
        }
        self.nextthink = time;
        dist_mult = autocvar_g_balance_tuba_attenuation / autocvar_snd_soundradius;
        FOR_EACH_REALCLIENT(e)
-       if(e != self.owner)
+       if(e != self.realowner)
        {
                v = self.origin - (e.origin + e.view_ofs);
                vol0 = max(0, 1 - vlen(v) * dist_mult);
                dir0 = normalize(v);
-               v = self.owner.origin - (e.origin + e.view_ofs);
+               v = self.realowner.origin - (e.origin + e.view_ofs);
                vol1 = max(0, 1 - vlen(v) * dist_mult);
                dir1 = normalize(v);
                if(fabs(vol0 - vol1) > 0.005) // 0.5 percent change in volume
                {
-                       setorigin(self, self.owner.origin);
-                       self.SendFlags |= 1;
+                       setorigin(self, self.realowner.origin);
+                       self.SendFlags |= 2;
                        break;
                }
                if(dir0 * dir1 < 0.9994) // 2 degrees change in angle
                {
-                       setorigin(self, self.owner.origin);
-                       self.SendFlags |= 1;
+                       setorigin(self, self.realowner.origin);
+                       self.SendFlags |= 2;
                        break;
                }
        }
 }
 
-void W_Tuba_Attack(float hittype)
+void W_Tuba_NoteOn(float hittype)
 {
        vector o;
-       float c, n;
+       float n;
+
        W_SetupShot(self, FALSE, 2, "", 0, autocvar_g_balance_tuba_damage);
-       if(self.tuba_notecount)
-       {
-               self.tuba_notecount = FALSE;
-               c = CHAN_WEAPON;
-       }
-       else
-       {
-               self.tuba_notecount = TRUE;
-               c = CHAN_WEAPON2;
-       }
 
        n = Tuba_GetNote(self, hittype);
 
+       hittype = 0;
+       if(self.tuba_instrument & 1)
+               hittype |= HITTYPE_SECONDARY;
+       if(self.tuba_instrument & 2)
+               hittype |= HITTYPE_BOUNCE;
+       if(self.tuba_instrument & 4)
+               hittype |= HITTYPE_HEADSHOT;
+
        if(self.tuba_note)
        {
-               if(self.tuba_note.cnt != n)
+               if(self.tuba_note.cnt != n || self.tuba_note.tuba_instrument != self.tuba_instrument)
                {
-                       /*
-                       self.tuba_note.cnt = n;
-                       self.tuba_note.SendFlags |= 2;
-                       */
-                       remove(self.tuba_note);
-                       self.tuba_note = world;
+                       entity oldself = self;
+                       self = self.tuba_note;
+                       W_Tuba_NoteOff();
+                       self = oldself;
                }
        }
 
        if not(self.tuba_note)
        {
                self.tuba_note = spawn();
-               self.tuba_note.owner = self;
+               self.tuba_note.owner = self.tuba_note.realowner = self;
                self.tuba_note.cnt = n;
+               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);
        }
 
-       self.tuba_note.teleport_time = time + autocvar_g_balance_tuba_refire * 2; // so it can get prolonged safely
+       self.tuba_note.teleport_time = time + autocvar_g_balance_tuba_refire * 2 * W_WeaponRateFactor(); // so it can get prolonged safely
 
        //sound(self, c, TUBA_NOTE(n), bound(0, VOL_BASE * cvar("g_balance_tuba_volume"), 1), autocvar_g_balance_tuba_attenuation);
        RadiusDamage(self, self, autocvar_g_balance_tuba_damage, autocvar_g_balance_tuba_edgedamage, autocvar_g_balance_tuba_radius, world, autocvar_g_balance_tuba_force, hittype | WEP_TUBA, world);
@@ -205,14 +264,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);
                }
@@ -220,8 +279,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;
                        }
                }
        }
@@ -230,6 +291,9 @@ float w_tuba(float req)
                precache_model ("models/weapons/g_tuba.md3");
                precache_model ("models/weapons/v_tuba.md3");
                precache_model ("models/weapons/h_tuba.iqm");
+               precache_model ("models/weapons/g_akordeon.md3");
+               precache_model ("models/weapons/v_akordeon.md3");
+               precache_model ("models/weapons/h_akordeon.iqm");
 
                //float i;
                //for(i = -18; i <= +27; ++i)
@@ -239,13 +303,36 @@ float w_tuba(float req)
        {
                weapon_setup(WEP_TUBA);
                self.current_ammo = ammo_none;
+               self.tuba_instrument = 0;
+       }
+       else if (req == WR_RELOAD)
+       {
+               // switch to alternate instruments :)
+               if(self.weaponentity.state == WS_READY)
+               {
+                       switch(self.tuba_instrument)
+                       {
+                               case 0:
+                                       self.tuba_instrument = 1;
+                                       self.weaponname = "akordeon";
+                                       break;
+                               case 1:
+                                       self.tuba_instrument = 0;
+                                       self.weaponname = "tuba";
+                                       break;
+                       }
+                       W_SetupShot(self, FALSE, 0, "", 0, 0);
+                       pointparticles(particleeffectnum("teleport"), w_shotorg, '0 0 0', 1);
+                       self.weaponentity.state = WS_INUSE;
+                       weapon_thinkf(WFRAME_RELOAD, 0.5, w_ready);
+               }
        }
        else if (req == WR_CHECKAMMO1)
                return TRUE; // TODO use fuel?
        else if (req == WR_CHECKAMMO2)
                return TRUE; // TODO use fuel?
        return TRUE;
-};
+}
 #endif
 #ifdef CSQC
 float w_tuba(float req)
@@ -260,11 +347,45 @@ float w_tuba(float req)
        }
        else if (req == WR_SUICIDEMESSAGE)
        {
-               w_deathtypestring = _("%s hurt his own ears with the @!#%%'n Tuba");
+               float instr;
+               instr = 0;
+               if(w_deathtype & HITTYPE_SECONDARY)
+                       instr |= 1;
+               if(w_deathtype & HITTYPE_BOUNCE)
+                       instr |= 2;
+               if(w_deathtype & HITTYPE_HEADSHOT)
+                       instr |= 4;
+               switch(instr)
+               {
+                       default:
+                       case 0: // Tuba
+                               w_deathtypestring = _("%s hurt his own ears with the @!#%%'n Tuba");
+                               break;
+                       case 1: // Accordeon
+                               w_deathtypestring = _("%s hurt his own ears with the @!#%%'n Accordeon");
+                               break;
+               }
        }
        else if (req == WR_KILLMESSAGE)
        {
-               w_deathtypestring = _("%s died of %s's great playing on the @!#%%'n Tuba");
+               float instr;
+               instr = 0;
+               if(w_deathtype & HITTYPE_SECONDARY)
+                       instr |= 1;
+               if(w_deathtype & HITTYPE_BOUNCE)
+                       instr |= 2;
+               if(w_deathtype & HITTYPE_HEADSHOT)
+                       instr |= 4;
+               switch(instr)
+               {
+                       default:
+                       case 0: // Tuba
+                               w_deathtypestring = _("%s died of %s's great playing on the @!#%%'n Tuba");
+                               break;
+                       case 1: // Accordeon
+                               w_deathtypestring = _("%s died of %s's great playing on the @!#%%'n Accordeon");
+                               break;
+               }
        }
        return TRUE;
 }