8 #define MAX_TUBANOTES 32 9 .float tuba_lastnotes_last;
10 .float tuba_lastnotes_cnt;
11 .vector tuba_lastnotes[MAX_TUBANOTES];
13 bool W_Tuba_HasPlayed(
entity pl, .
entity weaponentity,
string melody,
int instrument,
bool ignorepitch,
float mintempo,
float maxtempo)
15 float i, j, mmin, mmax, nolength;
17 if(n > pl.(weaponentity).tuba_lastnotes_cnt)
22 if(pl.(weaponentity).tuba_instrument != instrument)
27 for(i = 0; i < n; ++i)
29 vector v = pl.(weaponentity).(tuba_lastnotes[(pl.(weaponentity).tuba_lastnotes_last - i + MAX_TUBANOTES) % MAX_TUBANOTES]);
38 if(ignorepitch && i == 0)
40 pitchshift = np - v.z;
44 if(v.z + pitchshift != np)
55 mmin = 240 / maxtempo;
59 mmax = 240 / mintempo;
64 for(i = 0; i < n; ++i)
66 vector vi = pl.(weaponentity).(tuba_lastnotes[(pl.(weaponentity).tuba_lastnotes_last - i + MAX_TUBANOTES) % MAX_TUBANOTES]);
68 ti -= 1 / (ai -
floor(ai));
70 for(j = i+1; j < n; ++j)
72 vector vj = pl.(weaponentity).(tuba_lastnotes[(pl.(weaponentity).tuba_lastnotes_last - j + MAX_TUBANOTES) % MAX_TUBANOTES]);
74 tj -= (aj -
floor(aj));
90 mmin =
max(mmin, (vi.x - vj.y) / (ti - tj));
91 mmax =
min(mmax, (vi.y - vj.x) / (ti - tj));
99 pl.(weaponentity).tuba_lastnotes_cnt = 0;
104 void W_Tuba_NoteOff(
entity this)
112 if (actor.(weaponentity).tuba_note ==
this)
114 actor.(weaponentity).tuba_lastnotes_last = (actor.(weaponentity).tuba_lastnotes_last + 1) % MAX_TUBANOTES;
117 actor.(weaponentity).tuba_lastnotes_cnt =
bound(0, actor.(weaponentity).tuba_lastnotes_cnt + 1, MAX_TUBANOTES);
119 string s = trigger_magicear_processmessage_forallears(actor, 0,
NULL,
string_null);
127 bprint(
strcat(
"\{1}\{13}* ^3", actor.netname,
"^3 played on the @!#%'n Tuba: ^7", s,
"\n"));
130 bprint(
strcat(
"\{1}\{13}* ^3", actor.netname,
"^3 played on the @!#%'n Accordeon: ^7", s,
"\n"));
133 bprint(
strcat(
"\{1}\{13}* ^3", actor.netname,
"^3 played on the @!#%'n Klein Bottle: ^7", s,
"\n"));
141 int W_Tuba_GetNote(
entity pl,
int hittype)
145 else if (
CS(pl).
movement.x > 0) movestate += 3;
147 else if (
CS(pl).
movement.y > 0) movestate += 1;
161 case 1: note = -6;
break;
162 case 2: note = -5;
break;
163 case 3: note = -4;
break;
164 case 4: note = +5;
break;
166 case 5: note = 0;
break;
167 case 6: note = +2;
break;
168 case 7: note = +3;
break;
169 case 8: note = +4;
break;
170 case 9: note = -1;
break;
190 if(pl.clientcolors & 1)
214 WriteHeader(MSG_ENTITY, ENT_CLIENT_TUBANOTE);
226 WriteVector(MSG_ENTITY, this.
origin);
231 void W_Tuba_NoteThink(
entity this)
239 W_Tuba_NoteOff(
this);
243 dist_mult =
WEP_CVAR(tuba, attenuation) / autocvar_snd_soundradius;
245 v = this.
origin - (it.origin + it.view_ofs);
246 vol0 =
max(0, 1 -
vlen(v) * dist_mult);
248 v = this.
realowner.origin - (it.origin + it.view_ofs);
249 vol1 =
max(0, 1 -
vlen(v) * dist_mult);
251 if(
fabs(vol0 - vol1) > 0.005)
257 if(dir0 * dir1 < 0.9994)
266 void W_Tuba_NoteOn(
entity actor, .
entity weaponentity,
float hittype)
268 float n = W_Tuba_GetNote(actor, hittype);
271 if(actor.(weaponentity).tuba_instrument & 1)
272 hittype |= HITTYPE_SECONDARY;
273 if(actor.(weaponentity).tuba_instrument & 2)
276 W_SetupShot(actor, weaponentity,
false, 2, SND_Null, 0,
WEP_CVAR(tuba, damage), hittype | WEP_TUBA.m_id);
278 if(actor.(weaponentity).tuba_note)
280 if(actor.(weaponentity).tuba_note.cnt != n || actor.(weaponentity).
tuba_note.tuba_instrument != actor.(weaponentity).tuba_instrument)
282 W_Tuba_NoteOff(actor.(weaponentity).tuba_note);
286 if(!actor.(weaponentity).tuba_note)
289 note.weaponentity_fld = weaponentity;
291 note.owner = note.realowner = actor;
295 note.nextthink =
time;
296 note.spawnshieldtime =
time;
297 Net_LinkEntity(note,
false, 0, W_Tuba_NoteSendEntity);
303 RadiusDamage(actor, actor,
WEP_CVAR(tuba, damage),
WEP_CVAR(tuba, edgedamage),
WEP_CVAR(tuba,
radius),
NULL,
NULL,
WEP_CVAR(tuba, force), hittype | WEP_TUBA.m_id, weaponentity,
NULL);
305 if(
time > actor.(weaponentity).tuba_smoketime)
309 if(actor.(weaponentity).tuba_instrument == 1)
311 else if(actor.(weaponentity).tuba_instrument == 2)
315 actor.(weaponentity).tuba_smoketime =
time + 0.25;
339 W_Tuba_NoteOn(actor, weaponentity, 0);
345 W_Tuba_NoteOn(actor, weaponentity, HITTYPE_SECONDARY);
348 if (actor.(weaponentity).tuba_note)
350 if (!(fire & 1) && !(fire & 2))
352 W_Tuba_NoteOff(actor.(weaponentity).tuba_note);
365 if (actor.(weaponentity).state ==
WS_READY)
367 switch (actor.(weaponentity).tuba_instrument)
371 actor.(weaponentity).weaponname =
"akordeon";
375 actor.(weaponentity).weaponname =
"kleinbottle";
379 actor.(weaponentity).weaponname =
"tuba";
383 if(actor.(weaponentity).tuba_instrument & 1)
384 hittype |= HITTYPE_SECONDARY;
385 if(actor.(weaponentity).tuba_instrument & 2)
387 W_SetupShot(actor, weaponentity,
false, 0, SND_Null, 0, 0, hittype | WEP_TUBA.m_id);
388 Send_Effect(EFFECT_TELEPORT,
w_shotorg,
'0 0 0', 1);
404 return WEAPON_KLEINBOTTLE_SUICIDE;
406 return WEAPON_ACCORDEON_SUICIDE;
408 return WEAPON_TUBA_SUICIDE;
413 return WEAPON_KLEINBOTTLE_MURDER;
415 return WEAPON_ACCORDEON_MURDER;
417 return WEAPON_TUBA_MURDER;
424 return (wep.tuba_instrument == 0) ?
"tuba" :
425 (wep.tuba_instrument == 1) ?
"akordeon" :
433 #define TUBA_STARTNOTE(i, n) _Sound_fixpath(W_Sound(strcat("tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n)))) 435 const int TUBA_MIN = -18;
436 const int TUBA_MAX = 27;
437 const int TUBA_INSTRUMENTS = 3;
441 void tubasound(
entity e,
bool restart)
444 if (Tuba_PitchStep) {
451 int m =
pymod(e.note, Tuba_PitchStep);
453 if (e.note - m < TUBA_MIN) {
455 snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m + Tuba_PitchStep);
457 speed1 = (2.0 ** ((m - Tuba_PitchStep) / 12.0));
458 }
else if (e.note - m + Tuba_PitchStep > TUBA_MAX) {
460 snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m);
462 speed1 = (2.0 ** (m / 12.0));
465 snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m);
468 speed1 = (2.0 ** (m / 12.0));
470 snd2 = TUBA_STARTNOTE(e.tuba_instrument, e.note - m + Tuba_PitchStep);
473 speed2 = (2.0 ** ((m - Tuba_PitchStep) / 12.0));
475 }
else if (restart) {
476 snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note);
479 sound7(e,
CH_TUBA_SINGLE, snd1, e.tuba_volume * vol1, e.tuba_attenuate * autocvar_g_balance_tuba_attenuation, 100 * speed1, 0);
481 sound7(e.enemy,
CH_TUBA_SINGLE, snd2, e.tuba_volume * vol2, e.tuba_attenuate * autocvar_g_balance_tuba_attenuation, 100 * speed2, 0);
485 snd1 = TUBA_STARTNOTE(e.tuba_instrument, e.note);
487 _sound(e,
CH_TUBA_SINGLE, snd1, e.tuba_volume, e.tuba_attenuate * autocvar_g_balance_tuba_attenuation);
491 void Ent_TubaNote_Think(
entity this)
493 float f = autocvar_g_balance_tuba_fadetime;
495 this.tuba_volume -=
frametime * this.tuba_volume_initial / f;
497 this.tuba_volume = 0;
500 if (this.tuba_volume <= 0) {
512 void Ent_TubaNote_UpdateSound(
entity this)
515 this.
enemy.tuba_volume_initial = this.
enemy.tuba_volume;
516 this.
enemy.note = this.note;
518 tubasound(this.
enemy, 1);
521 void Ent_TubaNote_StopSound(
entity this)
539 Ent_TubaNote_StopSound(
this);
543 if (Tuba_PitchStep) {
544 this.
enemy.enemy =
new(tuba_note_2);
549 this.
enemy.tuba_attenuate = att;
559 this.
enemy.origin = ReadVector();
561 if (this.
enemy.enemy) {
566 setthink(
this, Ent_TubaNote_StopSound);
567 this.entremove = Ent_TubaNote_StopSound;
572 Ent_TubaNote_UpdateSound(
this);
579 Tuba_PitchStep = autocvar_g_balance_tuba_pitchstep;
580 if (Tuba_PitchStep) {
582 LOG_WARN(
"requested pitch shifting, but not supported by this engine build");
586 for (
int n = TUBA_MIN; n <= TUBA_MAX; ++n) {
587 if (!Tuba_PitchStep ||
pymod(n, Tuba_PitchStep) == 0) {
588 for (
int i = 0; i < TUBA_INSTRUMENTS; ++i) {
#define PHYS_INPUT_BUTTON_ATCK2(s)
#define PHYS_INPUT_BUTTON_JUMP(s)
#define PHYS_INPUT_BUTTON_CROUCH(s)
ClientState CS(Client this)
#define FOREACH_CLIENT(cond, body)
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)
#define NET_HANDLE(id, param)
#define WEP_CVAR(wepname, name)
#define METHOD(cname, name, prototype)
const int WS_READY
idle frame
#define IS_REAL_CLIENT(v)
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
bool weapon_prepareattack(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
#define PHYS_INPUT_BUTTON_ATCK(s)
const int HITTYPE_SECONDARY
#define W_SetupShot(ent, wepent, antilag, recoil, snd, chan, maxdamage, deathtype)
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define PRECACHE(func)
directly after STATIC_INIT_LATE
const int WS_INUSE
fire state
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
entity Notification
always last
void weapon_thinkf(entity actor,.entity weaponentity, WFRAME fr, float t, void(Weapon thiswep, entity actor,.entity weaponentity, int fire) func)
#define _sound(e, c, s, v, a)
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype,.entity weaponentity, entity directhitentity)
#define sound(e, c, s, v, a)
float pymod(float e, float f)
Pythonic mod: TODO: %% operator?
float W_WeaponRateFactor(entity this)