From: Mario Date: Tue, 11 Jun 2013 07:59:03 +0000 (+1000) Subject: Merge branch 'master' into Mario/mutators X-Git-Tag: xonotic-v0.8.0~366^2~18 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=5d4c4e0d5ffc50d7e10c0a355988eebeff3b065b Merge branch 'master' into Mario/mutators --- 5d4c4e0d5ffc50d7e10c0a355988eebeff3b065b diff --cc qcsrc/server/mutators/mutator_nades.qc index 3f90b46f53,0000000000..b3588c6374 mode 100644,000000..100644 --- a/qcsrc/server/mutators/mutator_nades.qc +++ b/qcsrc/server/mutators/mutator_nades.qc @@@ -1,397 -1,0 +1,397 @@@ +void nade_timer_think() +{ + self.skin = 8 - (self.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10); + self.nextthink = time; + if(!self.owner || wasfreed(self.owner)) + remove(self); + +} + +void nade_burn_spawn(entity _nade) +{ + float p; + + switch(_nade.realowner.team) + { + case NUM_TEAM_1: p = PROJECTILE_NADE_RED_BURN; break; + case NUM_TEAM_2: p = PROJECTILE_NADE_BLUE_BURN; break; + case NUM_TEAM_3: p = PROJECTILE_NADE_YELLOW_BURN; break; + case NUM_TEAM_4: p = PROJECTILE_NADE_PINK_BURN; break; + default: p = PROJECTILE_NADE_BURN; break; + } + + CSQCProjectile(_nade, TRUE, p, TRUE); +} + +void nade_spawn(entity _nade) +{ + float p; + entity timer = spawn(); + setmodel(timer, "models/ok_nade_counter/ok_nade_counter.md3"); + setattachment(timer, _nade, ""); + timer.classname = "nade_timer"; + timer.colormap = _nade.colormap; + timer.glowmod = _nade.glowmod; + timer.think = nade_timer_think; + timer.nextthink = time; + timer.wait = _nade.wait; + timer.owner = _nade; + timer.skin = 10; + + switch(_nade.realowner.team) + { + case NUM_TEAM_1: p = PROJECTILE_NADE_RED; break; + case NUM_TEAM_2: p = PROJECTILE_NADE_BLUE; break; + case NUM_TEAM_3: p = PROJECTILE_NADE_YELLOW; break; + case NUM_TEAM_4: p = PROJECTILE_NADE_PINK; break; + default: p = PROJECTILE_NADE; break; + } + + CSQCProjectile(_nade, TRUE, p, TRUE); + +} + - void nade_boom() // TODO: DamageInfo ++void nade_boom() +{ + string expef; + + switch(self.realowner.team) + { + case NUM_TEAM_1: expef = "nade_red_explode"; break; + case NUM_TEAM_2: expef = "nade_blue_explode"; break; + case NUM_TEAM_3: expef = "nade_yellow_explode"; break; + case NUM_TEAM_4: expef = "nade_pink_explode"; break; + default: expef = "nade_explode"; break; + } + + sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTN_NORM); + sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); + pointparticles(particleeffectnum(expef), self.origin + '0 0 1', '0 0 0', 1); + + Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self); + + self.takedamage = DAMAGE_NO; + RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, + autocvar_g_nades_nade_radius, self, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy); + + remove(self); +} + +void nade_touch() +{ + PROJECTILE_TOUCH; + //setsize(self, '-2 -2 -2', '2 2 2'); + //UpdateCSQCProjectile(self); + if(self.health == autocvar_g_nades_nade_health) + { + spamsound(self, CH_SHOTS, strcat("weapons/grenade_bounce", ftos(1 + rint(random() * 5)), ".wav"), VOL_BASE, ATTN_NORM); + return; + } + + self.enemy = other; + nade_boom(); +} + +void nade_beep() +{ + sound(self, CH_SHOTS_SINGLE, "overkill/grenadebip.ogg", VOL_BASE, 0.5 *(ATTN_LARGE + ATTN_MAX)); + self.think = nade_boom; + self.nextthink = max(self.wait, time); +} + +void nade_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +{ + if(DEATH_ISWEAPON(deathtype, WEP_LASER)) + return; + + if(DEATH_ISWEAPON(deathtype, WEP_NEX) || DEATH_ISWEAPON(deathtype, WEP_MINSTANEX)) + { + force *= 6; + damage = autocvar_g_nades_nade_health * 0.55; + } + + if(DEATH_ISWEAPON(deathtype, WEP_UZI)) + damage = autocvar_g_nades_nade_health * 0.1; + + if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN) && !(deathtype & HITTYPE_SECONDARY)) + damage = autocvar_g_nades_nade_health * 1.1; + + if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN) && (deathtype & HITTYPE_SECONDARY)) + { + damage = autocvar_g_nades_nade_health * 0.1; + force *= 15; + } + + self.velocity += force; + + if(!damage) + return; + + if(self.health == autocvar_g_nades_nade_health) + { + sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, 0.5 *(ATTN_LARGE + ATTN_MAX)); + self.nextthink = max(time + autocvar_g_nades_nade_lifetime, time); + self.think = nade_beep; + } + + self.health -= damage; + self.realowner = attacker; + + if(self.health <= 0) + W_PrepareExplosionByDamage(attacker, nade_boom); + else + nade_burn_spawn(self); +} + +void toss_nade(entity e, vector _velocity, float _time) +{ + entity _nade = e.nade; + e.nade = world; + + remove(e.fake_nade); + e.fake_nade = world; + + makevectors(e.v_angle); + + W_SetupShot(e, FALSE, FALSE, "", CH_WEAPON_A, 0); + + Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_NADES); + + //setorigin(_nade, CENTER_OR_VIEWOFS(e) + (v_right * 10) * -1); + setorigin(_nade, w_shotorg + (v_right * 10) * -1); + setmodel(_nade, "models/weapons/v_ok_grenade.md3"); + setattachment(_nade, world, ""); + PROJECTILE_MAKETRIGGER(_nade); + setsize(_nade, '-16 -16 -16', '16 16 16'); + _nade.movetype = MOVETYPE_BOUNCE; + + tracebox(_nade.origin, _nade.mins, _nade.maxs, _nade.origin, FALSE, _nade); + if (trace_startsolid) + setorigin(_nade, e.origin); + + if(e.crouch) + _nade.velocity = '0 0 -10'; + else if(autocvar_g_nades_nade_newton_style == 1) + _nade.velocity = e.velocity + _velocity; + else if(autocvar_g_nades_nade_newton_style == 2) + _nade.velocity = _velocity; + else + _nade.velocity = W_CalculateProjectileVelocity(e.velocity, _velocity, TRUE); + + //_nade.solid = SOLID_BBOX; // TODO: remember why this was needed + _nade.touch = nade_touch; + _nade.health = autocvar_g_nades_nade_health; + _nade.takedamage = DAMAGE_AIM; + _nade.event_damage = nade_damage; + _nade.teleportable = TRUE; + _nade.pushable = TRUE; + _nade.gravity = 1; + _nade.missile_flags = MIF_SPLASH | MIF_ARC; + _nade.damagedbycontents = TRUE; + _nade.angles = vectoangles(_nade.velocity); + _nade.flags = FL_PROJECTILE; + + nade_spawn(_nade); + + if(_time) + { + _nade.think = nade_boom; + _nade.nextthink = _time; + } + + e.nade_refire = time + autocvar_g_nades_nade_refire; +} + +void nade_prime() +{ + if(self.nade) + remove(self.nade); + + if(self.fake_nade) + remove(self.fake_nade); + + self.nade = spawn(); + setmodel(self.nade, "null"); + setattachment(self.nade, self, "bip01 l hand"); + self.nade.classname = "nade"; + self.nade.realowner = self; + self.nade.colormap = self.colormap; + self.nade.glowmod = self.glowmod; + self.nade.wait = time + autocvar_g_nades_nade_lifetime; + self.nade.lifetime = time; + self.nade.think = nade_beep; + self.nade.nextthink = max(self.nade.wait - 3, time); + self.nade.projectiledeathtype = DEATH_NADE; + + self.fake_nade = spawn(); + setmodel(self.fake_nade, "models/weapons/h_ok_grenade.iqm"); + setattachment(self.fake_nade, self.weaponentity, ""); + self.fake_nade.classname = "fake_nade"; + //self.fake_nade.viewmodelforclient = self; + self.fake_nade.realowner = self.fake_nade.owner = self; + self.fake_nade.colormap = self.colormap; + self.fake_nade.glowmod = self.glowmod; + self.fake_nade.think = SUB_Remove; + self.fake_nade.nextthink = self.nade.wait; +} + +float CanThrowNade() +{ + if(self.vehicle) + return FALSE; + + if(gameover) + return FALSE; + + if(self.deadflag != DEAD_NO) + return FALSE; + + if not(autocvar_g_nades) + return FALSE; // allow turning them off mid match + + if(forbidWeaponUse()) + return FALSE; + + if not(IS_PLAYER(self)) + return FALSE; + + return TRUE; +} + +void nades_CheckThrow() +{ + if(!CanThrowNade()) + return; + + if(!self.nade) + { + if(self.nade_refire < time) + { + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_NADE_THROW); + nade_prime(); + self.nade_refire = time + autocvar_g_nades_nade_refire; + } + } + else + { + if(time - self.nade.lifetime >= 1) + { + makevectors(self.v_angle); + float _force = time - self.nade.lifetime; + _force /= autocvar_g_nades_nade_lifetime; + _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce)); + toss_nade(self, (v_forward * 0.75 + v_up * 0.2 + v_right * 0.05) * _force, 0); + } + } +} + +MUTATOR_HOOKFUNCTION(nades_VehicleEnter) +{ + if(other.nade) + toss_nade(other, '0 0 100', max(other.nade.wait, time + 0.05)); + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(nades_PlayerPreThink) +{ + float key_pressed = ((g_grappling_hook || client_hasweapon(self, WEP_HOOK, FALSE, FALSE) || WEPSET_CONTAINS_AW(weaponsInMap, WEP_HOOK)) ? self.button16 : self.BUTTON_HOOK); + + if(self.nade) + if(self.nade.wait - 0.1 <= time) + toss_nade(self, '0 0 0', time + 0.05); + + if(CanThrowNade()) + if(self.nade_refire < time) + { + if(key_pressed) + { + if(!self.nade) + nade_prime(); + } + else if(time - self.nade.lifetime >= 1) + { + if(self.nade) + { + makevectors(self.v_angle); + float _force = time - self.nade.lifetime; + _force /= autocvar_g_nades_nade_lifetime; + _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce)); + toss_nade(self, (v_forward * 0.7 + v_up * 0.2 + v_right * 0.1) * _force, 0); + } + } + } + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(nades_PlayerSpawn) +{ + if(autocvar_g_nades_spawn) + self.nade_refire = time + autocvar_g_spawnshieldtime; + else + self.nade_refire = time + autocvar_g_nades_nade_refire; + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(nades_PlayerDies) +{ + if(self.nade) + toss_nade(self, '0 0 100', max(self.nade.wait, time + 0.05)); + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(nades_RemovePlayer) +{ + if(self.nade) + remove(self.nade); + + if(self.fake_nade) + remove(self.fake_nade); + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(nades_BuildMutatorsString) +{ + ret_string = strcat(ret_string, ":Nades"); + return FALSE; +} + +MUTATOR_HOOKFUNCTION(nades_BuildMutatorsPrettyString) +{ + ret_string = strcat(ret_string, ", Nades"); + return FALSE; +} + +MUTATOR_DEFINITION(mutator_nades) +{ + MUTATOR_HOOK(VehicleEnter, nades_VehicleEnter, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerPreThink, nades_PlayerPreThink, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerSpawn, nades_PlayerSpawn, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerDies, nades_PlayerDies, CBC_ORDER_ANY); + MUTATOR_HOOK(MakePlayerObserver, nades_RemovePlayer, CBC_ORDER_ANY); + MUTATOR_HOOK(ClientDisconnect, nades_RemovePlayer, CBC_ORDER_ANY); + MUTATOR_HOOK(BuildMutatorsString, nades_BuildMutatorsString, CBC_ORDER_ANY); + MUTATOR_HOOK(BuildMutatorsPrettyString, nades_BuildMutatorsPrettyString, CBC_ORDER_ANY); + + MUTATOR_ONADD + { + precache_model("models/ok_nade_counter/ok_nade_counter.md3"); + + precache_model("models/weapons/h_ok_grenade.iqm"); + precache_model("models/weapons/v_ok_grenade.md3"); + precache_sound("weapons/rocket_impact.wav"); + precache_sound("weapons/grenade_bounce1.wav"); + precache_sound("weapons/grenade_bounce2.wav"); + precache_sound("weapons/grenade_bounce3.wav"); + precache_sound("weapons/grenade_bounce4.wav"); + precache_sound("weapons/grenade_bounce5.wav"); + precache_sound("weapons/grenade_bounce6.wav"); + precache_sound("overkill/grenadebip.ogg"); + } + + return FALSE; +}