]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/w_tuba.qc
fix most uninitialized stuff in svqc
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_tuba.qc
index c10d1f544a2d01e67fdef7e2c3b8b396fe53b515..5f2dc5adbbf1a4ab01eb7ff64e06f2f8c0533e63 100644 (file)
@@ -7,6 +7,138 @@ 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;
+                               case 2:
+                                       bprint(strcat("\{1}\{13}* ^3", self.owner.netname, "^3 played on the @!#%'n Klein Bottle: ^7", s, "\n"));
+                                       break;
+                       }
+               }
+       }
+       remove(self);
+}
+
 float Tuba_GetNote(entity pl, float hittype)
 {
        float note;
@@ -16,6 +148,9 @@ float Tuba_GetNote(entity pl, float hittype)
        if(pl.movement_x > 0) movestate += 3;
        if(pl.movement_y < 0) movestate -= 1;
        if(pl.movement_y > 0) movestate += 1;
+#ifdef GMQCC
+       note = 0;
+#endif
        switch(movestate)
        {
        // layout: originally I wanted
@@ -31,6 +166,7 @@ float Tuba_GetNote(entity pl, float hittype)
                case 2: note = -5; break; // G
                case 3: note = -4; break; // G#
                case 4: note = +5; break; // e#
+               default:
                case 5: note =  0; break; // c
                case 6: note = +2; break; // d
                case 7: note = +3; break; // eb
@@ -111,8 +247,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 +276,7 @@ void W_Tuba_NoteThink()
        }
 }
 
-void W_Tuba_Attack(float hittype)
+void W_Tuba_NoteOn(float hittype)
 {
        vector o;
        float n;
@@ -162,8 +297,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 +312,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 +353,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 +368,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;
                        }
                }
        }
@@ -240,6 +380,10 @@ 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/v_akordeon.md3");
+               precache_model ("models/weapons/h_akordeon.iqm");
+               precache_model ("models/weapons/v_kleinbottle.md3");
+               precache_model ("models/weapons/h_kleinbottle.iqm");
 
                //float i;
                //for(i = -18; i <= +27; ++i)
@@ -263,6 +407,10 @@ float w_tuba(float req)
                                        self.weaponname = "akordeon";
                                        break;
                                case 1:
+                                       self.tuba_instrument = 2;
+                                       self.weaponname = "kleinbottle";
+                                       break;
+                               case 2:
                                        self.tuba_instrument = 0;
                                        self.weaponname = "tuba";
                                        break;
@@ -310,6 +458,9 @@ float w_tuba(float req)
                        case 1: // Accordeon
                                w_deathtypestring = _("%s hurt his own ears with the @!#%%'n Accordeon");
                                break;
+                       case 2: // Klein Bottle
+                               w_deathtypestring = _("%s hurt his own ears with the @!#%%'n Klein Bottle");
+                               break;
                }
        }
        else if (req == WR_KILLMESSAGE)
@@ -331,6 +482,9 @@ float w_tuba(float req)
                        case 1: // Accordeon
                                w_deathtypestring = _("%s died of %s's great playing on the @!#%%'n Accordeon");
                                break;
+                       case 2: // Klein Bottle
+                               w_deathtypestring = _("%s died of %s's great playing on the @!#%%'n Klein Bottle");
+                               break;
                }
        }
        return TRUE;