X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fmutators%2Fmutator%2Fnades%2Fnades.qc;h=d1acb8b4dcab85789958ae9a05cfe56a0e09d7ba;hb=224f6d8084e73e0e643cb2d9d58c466defa9d134;hp=f81b58c243494d18df148a347fb8096087eacdfa;hpb=cc37ae9ec08cca9f8b17cdbf91e71380d0d6f700;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/mutators/mutator/nades/nades.qc b/qcsrc/common/mutators/mutator/nades/nades.qc index f81b58c24..d1acb8b4d 100644 --- a/qcsrc/common/mutators/mutator/nades/nades.qc +++ b/qcsrc/common/mutators/mutator/nades/nades.qc @@ -1,5 +1,7 @@ #include "nades.qh" +#include "../overkill/okmachinegun.qh" + #ifdef SVQC bool autocvar_g_nades_nade_small; float autocvar_g_nades_spread = 0.04; @@ -16,7 +18,7 @@ entity Nade_TrailEffect(int proj, int nade_team) case PROJECTILE_NADE_BURN: return EFFECT_NADE_TRAIL_BURN(nade_team); } - FOREACH(Nades, true, LAMBDA( + FOREACH(Nades, true, { for (int j = 0; j < 2; j++) { if (it.m_projectile[j] == proj) @@ -26,7 +28,7 @@ entity Nade_TrailEffect(int proj, int nade_team) break; } } - )); + }); return EFFECT_Null; } @@ -74,14 +76,14 @@ MUTATOR_HOOKFUNCTION(cl_nades, EditProjectile) if (proj.cnt == PROJECTILE_NAPALM_FOUNTAIN) { - loopsound(proj, CH_SHOTS_SINGLE, SND(FIREBALL_FLY2), VOL_BASE, ATTEN_NORM); + loopsound(proj, CH_SHOTS_SINGLE, SND_FIREBALL_FLY2, VOL_BASE, ATTEN_NORM); proj.mins = '-16 -16 -16'; proj.maxs = '16 16 16'; } entity nade_type = Nade_FromProjectile(proj.cnt); if (nade_type == NADE_TYPE_Null) return; - if(STAT(NADES_SMALL, NULL)) + if(STAT(NADES_SMALL)) { proj.mins = '-8 -8 -8'; proj.maxs = '8 8 8'; @@ -133,7 +135,7 @@ void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expan DrawNadeProgressBar(myPos, mySize, bonusProgress, nadeColor); if(autocvar_hud_panel_ammo_text) - drawstring_aspect(textPos, ftos(bonusNades), eX * (2/3) * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(textPos, ftos(bonusNades), vec2((2/3) * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); if(draw_expanding) drawpic_aspect_skin_expanding(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, expand_time); @@ -150,15 +152,17 @@ void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expan #include #include -REGISTER_MUTATOR(nades, cvar("g_nades")); +REGISTER_MUTATOR(nades, autocvar_g_nades); .float nade_time_primed; +.float nade_lifetime; .entity nade_spawnloc; + void nade_timer_think(entity this) { - this.skin = 8 - (this.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10); + this.skin = 8 - (this.owner.wait - time) / (this.owner.nade_lifetime / 10); this.nextthink = time; if(!this.owner || wasfreed(this.owner)) delete(this); @@ -166,7 +170,7 @@ void nade_timer_think(entity this) void nade_burn_spawn(entity _nade) { - CSQCProjectile(_nade, true, Nades_from(_nade.nade_type).m_projectile[true], true); + CSQCProjectile(_nade, true, Nades_from(STAT(NADE_BONUS_TYPE, _nade)).m_projectile[true], true); } void nade_spawn(entity _nade) @@ -184,7 +188,7 @@ void nade_spawn(entity _nade) _nade.effects |= EF_LOWPRECISION; - CSQCProjectile(_nade, true, Nades_from(_nade.nade_type).m_projectile[false], true); + CSQCProjectile(_nade, true, Nades_from(STAT(NADE_BONUS_TYPE, _nade)).m_projectile[false], true); } void napalm_damage(entity this, float dist, float damage, float edgedamage, float burntime) @@ -218,7 +222,7 @@ void napalm_damage(entity this, float dist, float damage, float edgedamage, floa { d = vlen(WarpZone_UnTransformOrigin(RandomSelection_chosen_ent, this.origin) - RandomSelection_chosen_ent.fireball_impactvec); d = damage + (edgedamage - damage) * (d / dist); - Fire_AddDamage(RandomSelection_chosen_ent, this.realowner, d * burntime, burntime, this.projectiledeathtype | HITTYPE_BOUNCE); + Fire_AddDamage(RandomSelection_chosen_ent, this.realowner, d * burntime, burntime, this.projectiledeathtype); //trailparticles(this, particleeffectnum(EFFECT_FIREBALL_LASER), this.origin, RandomSelection_chosen_ent.fireball_impactvec); Send_Effect(EFFECT_FIREBALL_LASER, this.origin, RandomSelection_chosen_ent.fireball_impactvec - this.origin, 1); } @@ -263,7 +267,7 @@ void nade_napalm_ball(entity this) entity proj; vector kick; - spamsound(this, CH_SHOTS, SND(FIREBALL_FIRE), VOL_BASE, ATTEN_NORM); + spamsound(this, CH_SHOTS, SND_FIREBALL_FIRE, VOL_BASE, ATTEN_NORM); proj = new(grenade); proj.owner = this.owner; @@ -395,7 +399,7 @@ void nade_ice_think(entity this) sound(this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM); RadiusDamage(this, this.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, - autocvar_g_nades_nade_radius, this, NULL, autocvar_g_nades_nade_force, this.projectiledeathtype, this.enemy); + autocvar_g_nades_nade_radius, this, NULL, autocvar_g_nades_nade_force, this.projectiledeathtype, DMG_NOWEP, this.enemy); Damage_DamageInfo(this.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, this.projectiledeathtype, 0, this); } @@ -429,7 +433,7 @@ void nade_ice_think(entity this) float current_freeze_time = this.ltime - time - 0.1; - FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_nades_nade_radius, it != this && it.takedamage && !IS_DEAD(it) && it.health > 0 && current_freeze_time > 0, + FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_nades_nade_radius, it != this && it.takedamage && !IS_DEAD(it) && GetResourceAmount(it, RESOURCE_HEALTH) > 0 && current_freeze_time > 0, { if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(it, this.realowner) || it == this.realowner)) if(!it.revival_time || ((time - it.revival_time) >= 1.5)) @@ -575,7 +579,7 @@ void nade_entrap_touch(entity this, entity toucher) if(!pushdeltatime) return; // div0: ticrate independent, 1 = identity (not 20) - toucher.velocity = toucher.velocity * pow(autocvar_g_nades_entrap_strength, pushdeltatime); + toucher.velocity = toucher.velocity * (autocvar_g_nades_entrap_strength ** pushdeltatime); #ifdef SVQC UpdateCSQCProjectile(toucher); @@ -621,17 +625,19 @@ void nade_heal_touch(entity this, entity toucher) if ( health_factor > 0 ) { maxhealth = (IS_MONSTER(toucher)) ? toucher.max_health : g_pickup_healthmega_max; - if ( toucher.health < maxhealth ) + float hp = GetResourceAmount(toucher, RESOURCE_HEALTH); + if (hp < maxhealth) { - if ( this.nade_show_particles ) + if (this.nade_show_particles) + { Send_Effect(EFFECT_HEALING, toucher.origin, '0 0 0', 1); - toucher.health = min(toucher.health+health_factor, maxhealth); + } + GiveResourceWithLimit(toucher, RESOURCE_HEALTH, health_factor, maxhealth); } - toucher.pauserothealth_finished = max(toucher.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot); } else if ( health_factor < 0 ) { - Damage(toucher,this,this.realowner,-health_factor,DEATH_NADE_HEAL.m_id,toucher.origin,'0 0 0'); + Damage(toucher,this,this.realowner,-health_factor,DEATH_NADE_HEAL.m_id,DMG_NOWEP,toucher.origin,'0 0 0'); } } @@ -639,8 +645,8 @@ void nade_heal_touch(entity this, entity toucher) if ( IS_REAL_CLIENT(toucher) || IS_VEHICLE(toucher) ) { entity show_red = (IS_VEHICLE(toucher)) ? toucher.owner : toucher; - show_red.stat_healing_orb = time+0.1; - show_red.stat_healing_orb_alpha = 0.75 * (this.ltime - time) / this.orb_lifetime; + STAT(HEALING_ORB, show_red) = time+0.1; + STAT(HEALING_ORB_ALPHA, show_red) = 0.75 * (this.ltime - time) / this.orb_lifetime; } } @@ -666,7 +672,7 @@ void nade_boom(entity this) entity expef = NULL; bool nade_blast = true; - switch ( Nades_from(this.nade_type) ) + switch ( Nades_from(STAT(NADE_BONUS_TYPE, this)) ) { case NADE_TYPE_NAPALM: nade_blast = autocvar_g_nades_napalm_blast; @@ -718,12 +724,12 @@ void nade_boom(entity this) if(nade_blast) { RadiusDamage(this, this.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, - autocvar_g_nades_nade_radius, this, NULL, autocvar_g_nades_nade_force, this.projectiledeathtype, this.enemy); + autocvar_g_nades_nade_radius, this, NULL, autocvar_g_nades_nade_force, this.projectiledeathtype, DMG_NOWEP, this.enemy); Damage_DamageInfo(this.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, this.projectiledeathtype, 0, this); } if(this.takedamage) - switch ( Nades_from(this.nade_type) ) + switch ( Nades_from(STAT(NADE_BONUS_TYPE, this)) ) { case NADE_TYPE_NAPALM: nade_napalm_boom(this); break; case NADE_TYPE_ICE: nade_ice_boom(this); break; @@ -745,11 +751,11 @@ void nade_boom(entity this) void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, string pntype); void nade_pickup(entity this, entity thenade) { - spawn_held_nade(this, thenade.realowner, autocvar_g_nades_pickup_time, thenade.nade_type, thenade.pokenade_type); + spawn_held_nade(this, thenade.realowner, autocvar_g_nades_pickup_time, STAT(NADE_BONUS_TYPE, thenade), thenade.pokenade_type); // set refire so player can't even this.nade_refire = time + autocvar_g_nades_nade_refire; - this.nade_timer = 0; + STAT(NADE_TIMER, this) = 0; if(this.nade) this.nade.nade_time_primed = thenade.nade_time_primed; @@ -766,8 +772,7 @@ void nade_touch(entity this, entity toucher) if(autocvar_g_nades_pickup) if(time >= this.spawnshieldtime) - if(!toucher.nade && this.health == this.max_health) // no boosted shot pickups, thank you very much - if(!STAT(FROZEN, toucher)) + if(!toucher.nade && GetResourceAmount(this, RESOURCE_HEALTH) == this.max_health) // no boosted shot pickups, thank you very much if(CanThrowNade(toucher)) // prevent some obvious things, like dead players if(IS_REAL_CLIENT(toucher)) // above checks for IS_PLAYER, don't need to do it here { @@ -795,9 +800,9 @@ void nade_touch(entity this, entity toucher) //setsize(this, '-2 -2 -2', '2 2 2'); //UpdateCSQCProjectile(this); - if(this.health == this.max_health) + if(GetResourceAmount(this, RESOURCE_HEALTH) == this.max_health) { - spamsound(this, CH_SHOTS, SND(GRENADE_BOUNCE_RANDOM()), VOL_BASE, ATTEN_NORM); + spamsound(this, CH_SHOTS, SND_GRENADE_BOUNCE_RANDOM(), VOL_BASE, ATTEN_NORM); return; } @@ -812,7 +817,7 @@ void nade_beep(entity this) this.nextthink = max(this.wait, time); } -void nade_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +void nade_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) { if(ITEM_DAMAGE_NEEDKILL(deathtype)) { @@ -821,7 +826,7 @@ void nade_damage(entity this, entity inflictor, entity attacker, float damage, i return; } - if(this.nade_type == NADE_TYPE_TRANSLOCATE.m_id || this.nade_type == NADE_TYPE_SPAWN.m_id) + if(STAT(NADE_BONUS_TYPE, this) == NADE_TYPE_TRANSLOCATE.m_id || STAT(NADE_BONUS_TYPE, this) == NADE_TYPE_SPAWN.m_id) return; if (MUTATOR_CALLHOOK(Nade_Damage, this, DEATH_WEAPONOF(deathtype), force, damage)) {} @@ -835,12 +840,12 @@ void nade_damage(entity this, entity inflictor, entity attacker, float damage, i force *= 0.5; // too much damage = 0; } - else if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER)) + else if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER) || DEATH_ISWEAPON(deathtype, WEP_OVERKILL_NEX)) { force *= 6; damage = this.max_health * 0.55; } - else if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN)) + else if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN) || DEATH_ISWEAPON(deathtype, WEP_OVERKILL_MACHINEGUN)) damage = this.max_health * 0.1; else if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO { @@ -859,19 +864,22 @@ void nade_damage(entity this, entity inflictor, entity attacker, float damage, i if(damage <= 0 || ((IS_ONGROUND(this)) && IS_PLAYER(attacker))) return; - if(this.health == this.max_health) + float hp = GetResourceAmount(this, RESOURCE_HEALTH); + if(hp == this.max_health) { sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX)); - this.nextthink = max(time + autocvar_g_nades_nade_lifetime, time); + this.nextthink = max(time + this.nade_lifetime, time); setthink(this, nade_beep); } - this.health -= damage; + hp -= damage; + SetResourceAmount(this, RESOURCE_HEALTH, hp); + - if ( this.nade_type != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) ) + if ( STAT(NADE_BONUS_TYPE, this) != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) ) this.realowner = attacker; - if(this.health <= 0) + if(hp <= 0) W_PrepareExplosionByDamage(this, attacker, nade_boom); else nade_burn_spawn(this); @@ -888,20 +896,18 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time) delete(e.fake_nade); e.fake_nade = NULL; + Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER, CPID_NADES); + makevectors(e.v_angle); // NOTE: always throw from first weapon entity? - W_SetupShot(e, _nade.weaponentity_fld, false, false, SND_Null, CH_WEAPON_A, 0); - - Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER, CPID_NADES); + W_SetupShot(e, _nade.weaponentity_fld, false, false, SND_Null, CH_WEAPON_A, 0, DEATH_NADE.m_id); vector offset = (v_forward * autocvar_g_nades_throw_offset.x) - + (v_right * autocvar_g_nades_throw_offset.y) - + (v_up * autocvar_g_nades_throw_offset.z); - if(autocvar_g_nades_throw_offset == '0 0 0') - offset = '0 0 0'; + + (v_right * autocvar_g_nades_throw_offset.y) + + (v_up * autocvar_g_nades_throw_offset.z); - setorigin(_nade, w_shotorg + offset + (v_right * 25) * -1); + setorigin(_nade, w_shotorg + offset); //setmodel(_nade, MDL_PROJECTILE_NADE); //setattachment(_nade, NULL, ""); PROJECTILE_MAKETRIGGER(_nade); @@ -929,7 +935,7 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time) settouch(_nade, nade_touch); _nade.spawnshieldtime = time + 0.1; // prevent instantly picking up again - _nade.health = autocvar_g_nades_nade_health; + SetResourceAmount(_nade, RESOURCE_HEALTH, autocvar_g_nades_nade_health); _nade.max_health = _nade.health; _nade.takedamage = DAMAGE_AIM; _nade.event_damage = nade_damage; @@ -941,15 +947,16 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time) _nade.gravity = 1; _nade.missile_flags = MIF_SPLASH | MIF_ARC; _nade.damagedbycontents = true; + IL_PUSH(g_damagedbycontents, _nade); _nade.angles = vectoangles(_nade.velocity); _nade.flags = FL_PROJECTILE; IL_PUSH(g_projectiles, _nade); IL_PUSH(g_bot_dodge, _nade); _nade.projectiledeathtype = DEATH_NADE.m_id; _nade.toss_time = time; - _nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX); + _nade.solid = SOLID_CORPSE; //((STAT(NADE_BONUS_TYPE, _nade) == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX); - if(_nade.nade_type == NADE_TYPE_TRANSLOCATE.m_id || _nade.nade_type == NADE_TYPE_SPAWN.m_id) + if(STAT(NADE_BONUS_TYPE, _nade) == NADE_TYPE_TRANSLOCATE.m_id || STAT(NADE_BONUS_TYPE, _nade) == NADE_TYPE_SPAWN.m_id) _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP; else _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY; @@ -963,7 +970,7 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time) } e.nade_refire = time + autocvar_g_nades_nade_refire; - e.nade_timer = 0; + STAT(NADE_TIMER, e) = 0; } void nades_GiveBonus(entity player, float score) @@ -971,19 +978,19 @@ void nades_GiveBonus(entity player, float score) if (autocvar_g_nades) if (autocvar_g_nades_bonus) if (IS_REAL_CLIENT(player)) - if (IS_PLAYER(player) && player.bonus_nades < autocvar_g_nades_bonus_max) + if (IS_PLAYER(player) && STAT(NADE_BONUS, player) < autocvar_g_nades_bonus_max) if (STAT(FROZEN, player) == 0) if (!IS_DEAD(player)) { - if ( player.bonus_nade_score < 1 ) - player.bonus_nade_score += score/autocvar_g_nades_bonus_score_max; + if ( STAT(NADE_BONUS_SCORE, player) < 1 ) + STAT(NADE_BONUS_SCORE, player) += score/autocvar_g_nades_bonus_score_max; - if ( player.bonus_nade_score >= 1 ) + if ( STAT(NADE_BONUS_SCORE, player) >= 1 ) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS); play2(player, SND(KH_ALARM)); - player.bonus_nades++; - player.bonus_nade_score -= 1; + STAT(NADE_BONUS, player)++; + STAT(NADE_BONUS_SCORE, player) -= 1; } } } @@ -991,7 +998,7 @@ void nades_GiveBonus(entity player, float score) /** Remove all bonus nades from a player */ void nades_RemoveBonus(entity player) { - player.bonus_nades = player.bonus_nade_score = 0; + STAT(NADE_BONUS, player) = STAT(NADE_BONUS_SCORE, player) = 0; } MUTATOR_HOOKFUNCTION(nades, PutClientInServer) @@ -1016,7 +1023,7 @@ bool nade_customize(entity this, entity client) { //this.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION; if(!this.traileffectnum) - this.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(this.nade_type).m_projectile[false], this.team).eent_eff_name); + this.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(STAT(NADE_BONUS_TYPE, this)).m_projectile[false], this.team).eent_eff_name); this.alpha = 1; } @@ -1027,11 +1034,11 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin { entity n = new(nade), fn = new(fake_nade); - n.nade_type = max(1, ntype); + STAT(NADE_BONUS_TYPE, n) = max(1, ntype); n.pokenade_type = pntype; - if(Nades_from(n.nade_type) == NADE_TYPE_Null) - n.nade_type = NADE_TYPE_NORMAL.m_id; + if(Nades_from(STAT(NADE_BONUS_TYPE, n)) == NADE_TYPE_Null) + STAT(NADE_BONUS_TYPE, n) = NADE_TYPE_NORMAL.m_id; .entity weaponentity = weaponentities[0]; // TODO: unhardcode @@ -1039,8 +1046,8 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin //setattachment(n, player, "bip01 l hand"); n.exteriormodeltoclient = player; setcefc(n, nade_customize); - n.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(n.nade_type).m_projectile[false], player.team).eent_eff_name); - n.colormod = Nades_from(n.nade_type).m_color; + n.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(STAT(NADE_BONUS_TYPE, n)).m_projectile[false], player.team).eent_eff_name); + n.colormod = Nades_from(STAT(NADE_BONUS_TYPE, n)).m_color; n.realowner = nowner; n.colormap = player.colormap; n.glowmod = player.glowmod; @@ -1050,11 +1057,12 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin n.nextthink = max(n.wait - 3, time); n.projectiledeathtype = DEATH_NADE.m_id; n.weaponentity_fld = weaponentity; + n.nade_lifetime = ntime; setmodel(fn, MDL_NADE_VIEW); setattachment(fn, player.(weaponentity), ""); fn.realowner = fn.owner = player; - fn.colormod = Nades_from(n.nade_type).m_color; + fn.colormod = Nades_from(STAT(NADE_BONUS_TYPE, n)).m_color; fn.colormap = player.colormap; fn.glowmod = player.glowmod; setthink(fn, SUB_Remove); @@ -1068,7 +1076,7 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin void nade_prime(entity this) { if(autocvar_g_nades_bonus_only) - if(!this.bonus_nades) + if(!STAT(NADE_BONUS, this)) return; // only allow bonus nades if(this.nade) @@ -1080,18 +1088,18 @@ void nade_prime(entity this) int ntype; string pntype = this.pokenade_type; - if(this.items & ITEM_Strength.m_itemid && autocvar_g_nades_bonus_onstrength) - ntype = this.nade_type; - else if (this.bonus_nades >= 1) + if((this.items & ITEM_Strength.m_itemid) && autocvar_g_nades_bonus_onstrength) + ntype = STAT(NADE_BONUS_TYPE, this); + else if (STAT(NADE_BONUS, this) >= 1) { - ntype = this.nade_type; + ntype = STAT(NADE_BONUS_TYPE, this); pntype = this.pokenade_type; - this.bonus_nades -= 1; + STAT(NADE_BONUS, this) -= 1; } else { - ntype = ((autocvar_g_nades_client_select) ? this.cvar_cl_nade_type : autocvar_g_nades_nade_type); - pntype = ((autocvar_g_nades_client_select) ? this.cvar_cl_pokenade_type : autocvar_g_nades_pokenade_monster_type); + ntype = ((autocvar_g_nades_client_select) ? CS(this).cvar_cl_nade_type : autocvar_g_nades_nade_type); + pntype = ((autocvar_g_nades_client_select) ? CS(this).cvar_cl_pokenade_type : autocvar_g_nades_pokenade_monster_type); } spawn_held_nade(this, this, autocvar_g_nades_nade_lifetime, ntype, pntype); @@ -1102,9 +1110,6 @@ bool CanThrowNade(entity this) if(this.vehicle) return false; - if(gameover) - return false; - if(IS_DEAD(this)) return false; @@ -1161,7 +1166,7 @@ void nades_Clear(entity player) delete(player.fake_nade); player.nade = player.fake_nade = NULL; - player.nade_timer = 0; + STAT(NADE_TIMER, player) = 0; } MUTATOR_HOOKFUNCTION(nades, VehicleEnter) @@ -1176,18 +1181,6 @@ CLASS(NadeOffhand, OffhandWeapon) METHOD(NadeOffhand, offhand_think, void(NadeOffhand this, entity player, bool key_pressed)) { entity held_nade = player.nade; - if (held_nade) - { - player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / autocvar_g_nades_nade_lifetime, 1); - // LOG_TRACEF("%d %d", player.nade_timer, time - held_nade.nade_time_primed); - makevectors(player.angles); - held_nade.velocity = player.velocity; - setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0); - held_nade.angles_y = player.angles.y; - - if (time + 0.1 >= held_nade.wait) - toss_nade(player, false, '0 0 0', time + 0.05); - } if (!CanThrowNade(player)) return; if (!(time > player.nade_refire)) return; @@ -1229,6 +1222,20 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink) if (player.nade && (player.offhand != OFFHAND_NADE || (player.weapons & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, player, player.nade_altbutton); + entity held_nade = player.nade; + if (held_nade) + { + STAT(NADE_TIMER, player) = bound(0, (time - held_nade.nade_time_primed) / held_nade.nade_lifetime, 1); + // LOG_TRACEF("%d %d", STAT(NADE_TIMER, player), time - held_nade.nade_time_primed); + makevectors(player.angles); + held_nade.velocity = player.velocity; + setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0); + held_nade.angles_y = player.angles.y; + + if (time + 0.1 >= held_nade.wait) + toss_nade(player, false, '0 0 0', time + 0.05); + } + if(IS_PLAYER(player)) { if ( autocvar_g_nades_bonus && autocvar_g_nades ) @@ -1238,7 +1245,7 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink) FOR_EACH_KH_KEY(key) if(key.owner == player) { ++key_count; } float time_score; - if(player.flagcarried || player.ballcarried) // this player is important + if(GameRules_scoring_is_vip(player)) time_score = autocvar_g_nades_bonus_score_time_flagcarrier; else time_score = autocvar_g_nades_bonus_score_time; @@ -1248,55 +1255,52 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink) if(autocvar_g_nades_bonus_client_select) { - player.nade_type = player.cvar_cl_nade_type; - player.pokenade_type = player.cvar_cl_pokenade_type; + STAT(NADE_BONUS_TYPE, player) = CS(player).cvar_cl_nade_type; + player.pokenade_type = CS(player).cvar_cl_pokenade_type; } else { - player.nade_type = autocvar_g_nades_bonus_type; + STAT(NADE_BONUS_TYPE, player) = autocvar_g_nades_bonus_type; player.pokenade_type = autocvar_g_nades_pokenade_monster_type; } - player.nade_type = bound(1, player.nade_type, Nades_COUNT); + STAT(NADE_BONUS_TYPE, player) = bound(1, STAT(NADE_BONUS_TYPE, player), Nades_COUNT); - if(player.bonus_nade_score >= 0 && autocvar_g_nades_bonus_score_max) + if(STAT(NADE_BONUS_SCORE, player) >= 0 && autocvar_g_nades_bonus_score_max) nades_GiveBonus(player, time_score / autocvar_g_nades_bonus_score_max); } else { - player.bonus_nades = player.bonus_nade_score = 0; + STAT(NADE_BONUS, player) = STAT(NADE_BONUS_SCORE, player) = 0; } } - float n = 0; + int n = 0; entity o = NULL; if(player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout) n = -1; - else + else if(STAT(FROZEN, player) == 3) { vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size; n = 0; - FOREACH_CLIENT(IS_PLAYER(it) && it != player, LAMBDA( - if(!IS_DEAD(it)) - if(STAT(FROZEN, it) == 0) - if(SAME_TEAM(it, player)) + FOREACH_CLIENT(IS_PLAYER(it) && it != player, { + if(!IS_DEAD(it) && STAT(FROZEN, it) == 0 && SAME_TEAM(it, player)) if(boxesoverlap(player.absmin - revive_extra_size, player.absmax + revive_extra_size, it.absmin, it.absmax)) { if(!o) o = it; - if(STAT(FROZEN, player) == 1) - it.reviving = true; + it.reviving = true; ++n; } - )); + }); } - if(n && STAT(FROZEN, player) == 3) // OK, there is at least one teammate reviving us + if(n > 0 && STAT(FROZEN, player) == 3) // OK, there is at least one teammate reviving us { - player.revive_progress = bound(0, player.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1); - player.health = max(1, player.revive_progress * start_health); + STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1); + SetResourceAmount(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * start_health)); - if(player.revive_progress >= 1) + if(STAT(REVIVE_PROGRESS, player) >= 1) { Unfreeze(player); @@ -1304,22 +1308,20 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink) Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname); } - FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, LAMBDA( - it.revive_progress = player.revive_progress; + FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, { + STAT(REVIVE_PROGRESS, it) = STAT(REVIVE_PROGRESS, player); it.reviving = false; - )); + }); } } -MUTATOR_HOOKFUNCTION(nades, PlayerPhysics) +MUTATOR_HOOKFUNCTION(nades, PlayerPhysics_UpdateStats) { entity player = M_ARGV(0, entity); + // these automatically reset, no need to worry - if (STAT(ENTRAP_ORB, player) > time) - { - player.stat_sv_maxspeed *= autocvar_g_nades_entrap_speed; - player.stat_sv_airspeedlimit_nonqw *= autocvar_g_nades_entrap_speed; - } + if(STAT(ENTRAP_ORB, player) > time) + STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_nades_entrap_speed; } MUTATOR_HOOKFUNCTION(nades, MonsterMove) @@ -1343,9 +1345,9 @@ MUTATOR_HOOKFUNCTION(nades, PlayerSpawn) player.nade_refire = time + autocvar_g_nades_nade_refire; if(autocvar_g_nades_bonus_client_select) - player.nade_type = player.cvar_cl_nade_type; + STAT(NADE_BONUS_TYPE, player) = CS(player).cvar_cl_nade_type; - player.nade_timer = 0; + STAT(NADE_TIMER, player) = 0; if (!player.offhand) player.offhand = OFFHAND_NADE; @@ -1371,19 +1373,19 @@ MUTATOR_HOOKFUNCTION(nades, PlayerDies, CBC_ORDER_LAST) if(!STAT(FROZEN, frag_target) || !autocvar_g_freezetag_revive_nade) toss_nade(frag_target, true, '0 0 100', max(frag_target.nade.wait, time + 0.05)); - float killcount_bonus = ((frag_attacker.killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * frag_attacker.killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor); - if(IS_PLAYER(frag_attacker)) { + float killcount_bonus = ((CS(frag_attacker).killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * CS(frag_attacker).killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor); + if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target) nades_RemoveBonus(frag_attacker); - else if(frag_target.flagcarried) + else if(GameRules_scoring_is_vip(frag_target)) nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_medium); - else if(autocvar_g_nades_bonus_score_spree && frag_attacker.killcount > 1) + else if(autocvar_g_nades_bonus_score_spree && CS(frag_attacker).killcount > 1) { #define SPREE_ITEM(counta,countb,center,normal,gentle) \ case counta: { nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_spree); break; } - switch(frag_attacker.killcount) + switch(CS(frag_attacker).killcount) { KILL_SPREE_LIST default: nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor); break; @@ -1397,7 +1399,7 @@ MUTATOR_HOOKFUNCTION(nades, PlayerDies, CBC_ORDER_LAST) nades_RemoveBonus(frag_target); } -MUTATOR_HOOKFUNCTION(nades, PlayerDamage_Calculate) +MUTATOR_HOOKFUNCTION(nades, Damage_Calculate) { entity frag_inflictor = M_ARGV(0, entity); entity frag_attacker = M_ARGV(1, entity); @@ -1411,7 +1413,7 @@ MUTATOR_HOOKFUNCTION(nades, PlayerDamage_Calculate) if(time - frag_inflictor.toss_time <= 0.1) { Unfreeze(frag_target); - frag_target.health = autocvar_g_freezetag_revive_nade_health; + SetResourceAmount(frag_target, RESOURCE_HEALTH, autocvar_g_freezetag_revive_nade_health); Send_Effect(EFFECT_ICEORGLASS, frag_target.origin, '0 0 0', 3); M_ARGV(4, float) = 0; M_ARGV(6, vector) = '0 0 0'; @@ -1460,13 +1462,13 @@ MUTATOR_HOOKFUNCTION(nades, SpectateCopy) entity spectatee = M_ARGV(0, entity); entity client = M_ARGV(1, entity); - client.nade_timer = spectatee.nade_timer; - client.nade_type = spectatee.nade_type; + STAT(NADE_TIMER, client) = STAT(NADE_TIMER, spectatee); + STAT(NADE_BONUS_TYPE, client) = STAT(NADE_BONUS_TYPE, spectatee); client.pokenade_type = spectatee.pokenade_type; - client.bonus_nades = spectatee.bonus_nades; - client.bonus_nade_score = spectatee.bonus_nade_score; - client.stat_healing_orb = spectatee.stat_healing_orb; - client.stat_healing_orb_alpha = spectatee.stat_healing_orb_alpha; + STAT(NADE_BONUS, client) = STAT(NADE_BONUS, spectatee); + STAT(NADE_BONUS_SCORE, client) = STAT(NADE_BONUS_SCORE, spectatee); + STAT(HEALING_ORB, client) = STAT(HEALING_ORB, spectatee); + STAT(HEALING_ORB_ALPHA, client) = STAT(HEALING_ORB_ALPHA, spectatee); STAT(ENTRAP_ORB, client) = STAT(ENTRAP_ORB, spectatee); STAT(ENTRAP_ORB_ALPHA, client) = STAT(ENTRAP_ORB_ALPHA, spectatee); } @@ -1479,11 +1481,6 @@ MUTATOR_HOOKFUNCTION(nades, BuildMutatorsString) M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Nades"); } -MUTATOR_HOOKFUNCTION(nades, BuildMutatorsPrettyString) -{ - M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Nades"); -} - MUTATOR_HOOKFUNCTION(nades, BuildGameplayTipsString) { M_ARGV(0, string) = strcat(M_ARGV(0, string), "\n\n^3nades^8 are enabled, press 'g' to use them\n");