]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into LegendaryGuard/tandem_nade
authorLegendaryGuard <rootuser999@gmail.com>
Mon, 10 Jul 2023 14:36:40 +0000 (16:36 +0200)
committerLegendaryGuard <rootuser999@gmail.com>
Mon, 10 Jul 2023 14:36:40 +0000 (16:36 +0200)
1  2 
effectinfo.txt
mutators.cfg
notifications.cfg
qcsrc/client/main.qc
qcsrc/common/mutators/mutator/nades/nades.inc
qcsrc/common/mutators/mutator/nades/nades.qc
qcsrc/common/mutators/mutator/nades/nades.qh
qcsrc/common/notifications/all.inc
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/vehicles/sv_vehicles.qc
qcsrc/server/client.qh

diff --cc effectinfo.txt
Simple merge
diff --cc mutators.cfg
index ce0f79821b2319188e006930470b4067946630cb,d0337c22dc39610e3a51882717f82877eccaacd5..30ca6101482d039f29e4fd3e91f346b1aaa9e7a4
@@@ -202,12 -204,11 +204,12 @@@ set g_nades_nade_edgedamage 9
  set g_nades_nade_radius 300
  set g_nades_nade_force 650
  set g_nades_nade_newton_style 0 "nade velocity: 0 is absolute, 1 is relative (takes into account player velocity), 2 is something in between"
- set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap 9:veil, 10:ammo, 11:dark"
+ set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap 9:veil, 10:ammo, 11:darkness"
  
  seta cl_nade_timer 1 "show a visual timer for nades, 1 = only circle, 2 = circle with text"
- seta cl_nade_type 3
- seta cl_pokenade_type "zombie" "monster, item, vehicle and turret to spawn"
+ seta cl_nade_type 3 "selected type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap 9:veil 10:ammo 11:dark"
+ seta cl_pokenade_type "zombie" "monster to spawn"
 +seta cl_tandemnade_type 0 "tandem nade selection; 0: monster, 1: item, 2: vehicle, 3: turret"
  
  // ------------
  //  Nade bonus
@@@ -260,14 -261,17 +262,20 @@@ set g_nades_ice 1 "Ice nade: freezes an
  set g_nades_ice_freeze_time 3 "How long the ice field will last"
  set g_nades_ice_health      0 "How much health the player will have after being unfrozen"
  set g_nades_ice_explode     0 "Whether the ice nade should explode again once the ice field dissipated"
- set g_nades_ice_teamcheck   0 "Don't freeze teammates"
+ set g_nades_ice_teamcheck   2 "0: friendly fire, 1: nade owner isn't affected, 2: don't freeze teammates"
+ // Translocate (4)
+ set g_nades_translocate 1 "Translocate nade: teleports into explosion nade location"
+ set g_nades_translocate_destroy_damage 25 "Damage caused when translocate nade is destroyed by some attacker"
  
 +// Translocate (4)
 +set g_nades_translocate 1 "Translocate nade: teleports into explosion nade location"
 +
  // Spawn (5)
- set g_nades_spawntype 1 "Spawn nade: respawns into nade explosion location after being fragged"
+ set g_nades_spawn 1 "Spawn nade: respawns into nade explosion location after being fragged"
  set g_nades_spawn_count 3 "Number of times player will spawn at their spawn nade explosion location"
+ set g_nades_spawn_health_respawn 0 "How much health the player will have when being respawned, if 0, normal health respawn"
+ set g_nades_spawn_destroy_damage 25 "Damage caused when spawn nade is destroyed by some attacker"
  
  // Heal (6)
  set g_nades_heal 1 "Heal nade: spawns a orb to recover health inside, enemies take the reverse effect when being inside orb"
index 4ede8914f58581efef2c036b06c959e4479baa9e,22a4e70a31403caeaef852e66b96d1c74ae9f011..08f4a762247fbb73d5ffcc3e5989fb81c02c4acc
@@@ -539,8 -554,9 +554,10 @@@ seta notification_CENTER_VEHICLE_ENTER 
  seta notification_CENTER_VEHICLE_ENTER_GUNNER "1" "0 = off, 1 = centerprint"
  seta notification_CENTER_VEHICLE_ENTER_STEAL "1" "0 = off, 1 = centerprint"
  seta notification_CENTER_VEHICLE_STEAL "1" "0 = off, 1 = centerprint"
 +seta notification_CENTER_VEHICLE_STEAL_OWNER "1" "0 = off, 1 = centerprint"
  seta notification_CENTER_VEHICLE_STEAL_SELF "1" "0 = off, 1 = centerprint"
+ seta notification_CENTER_VOTEBAN "1" "0 = off, 1 = centerprint"
+ seta notification_CENTER_VOTEBANYN "1" "0 = off, 1 = centerprint"
  seta notification_CENTER_WEAPON_MINELAYER_LIMIT "1" "0 = off, 1 = centerprint"
  
  // MSG_MULTI notifications:
Simple merge
index 4a949a1b05c15640489fc6ca8e72ae3b41f00ec5,272da56771b58115761e79b4e1e361da4d835270..88431410caae654c6f3ec8502effa760847b9f2a
@@@ -152,8 -188,7 +189,9 @@@ void DrawAmmoNades(vector myPos, vecto
  #include <common/gamemodes/_mod.qh>
  #include <common/monsters/sv_spawn.qh>
  #include <common/monsters/sv_monsters.qh>
 +#include <common/vehicles/all.qh>
 +#include <common/turrets/all.qh>
+ #include <server/command/common.qh>
  
  .float nade_time_primed;
  .float nade_lifetime;
@@@ -639,377 -692,20 +694,377 @@@ void nade_heal_boom(entity this
        settouch(orb, nade_heal_touch);
        orb.colormod = '1 0 0';
  }
-       Item_SetLoot(e, true);
 +void nade_tandem_randomweapon(entity e, vector org)
 +{
 +      RandomSelection_Init();
 +      FOREACH(Weapons, 
 +                      it != WEP_Null 
 +                      && (!((it.spawnflags & WEP_FLAG_HIDDEN) 
 +                      || (it.spawnflags & WEP_FLAG_MUTATORBLOCKED) 
 +                      || (it.spawnflags & WEP_FLAG_SPECIALATTACK) 
 +                      || (it.spawnflags & WEP_FLAG_SUPERWEAPON))
 +                      || autocvar_g_nades_tandem_randomweapon_includespecial),
 +      {
 +              if((it.spawnflags & WEP_FLAG_HIDDEN)
 +                      && (it.spawnflags & WEP_FLAG_MUTATORBLOCKED))
 +                      continue;
 +              if(it.spawnflags & WEP_FLAG_MUTATORBLOCKED) continue;
 +              if(it.spawnflags & WEP_FLAG_SPECIALATTACK) continue;
 +              if(it.spawnflags & WEP_TYPE_OTHER) continue;
 +              if (W_IsWeaponThrowable(e, it.m_id))
 +                      RandomSelection_AddEnt(it, 1, 1);
 +      });
 +
-       Item_SetLoot(e, true);
++      ITEM_SET_LOOT(e, true);
 +      e.pickup_anyway = true;
 +      e.angles = '0 0 0';
 +      e.gravity = 1;
 +      setorigin(e, org);
 +      e.velocity = randomvec() * 150 + '0 0 325';
 +      e.spawnfunc_checked = true;
 +      e.glowmod = weaponentity_glowmod(RandomSelection_chosen_ent, 0, e);
 +      weapon_defaultspawnfunc(e, RandomSelection_chosen_ent);
 +}
 +
 +entity nade_tandem_randomitem()
 +{
 +      RandomSelection_Init();
 +      FOREACH(Items, 
 +                      it != NULL 
 +                      && (!(it.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
 +                      && !(it.m_itemid & IT_JETPACK)
 +                      && !(it.m_itemid & IT_FUEL_REGEN)
 +                      && !(it.m_itemid & IT_STRENGTH)
 +                      && !(it.m_itemid & IT_INVINCIBLE)
 +                      && !(it.m_itemid & IT_INVISIBILITY)
 +                      && !(it.m_itemid & IT_SPEED)
 +                      || autocvar_g_nades_tandem_item_includespecial),
 +      {
 +              if(it.m_canonical_spawnfunc == "item_armor_mega" 
 +              || it.m_canonical_spawnfunc == "item_health_mega" 
 +              || it.m_canonical_spawnfunc == "item_armor_big" 
 +              || it.m_canonical_spawnfunc == "item_health_big" 
 +              || it.m_canonical_spawnfunc == "item_armor_medium" 
 +              || it.m_canonical_spawnfunc == "item_health_medium" 
 +              || it.m_canonical_spawnfunc == "item_extralife"
 +              || (it.spawnflags & ITEM_FLAG_MUTATORBLOCKED)) 
 +                      continue;
 +              RandomSelection_AddEnt(it, 1, 1);
 +      });
 +
 +      return RandomSelection_chosen_ent;
 +}
 +
 +void nade_tandem_spawnitem(entity e, vector org)
 +{
 +      entity itm;
 +
 +      switch (e.pokenade_type)
 +      {
 +              case "health": { itm = ITEM_HealthSmall; break; }
 +              case "armor" : { itm = ITEM_ArmorSmall; break; }
 +              case "ammo"      : 
 +              {
 +                      itm = (random() > 0.5) ? 
 +                              ITEM_Shells  : (random() > 0.5) ? 
 +                              ITEM_Bullets : (random() > 0.5) ?
 +                              ITEM_Rockets : ITEM_Plasma;
 +                      break;
 +              }
 +              case "jetpack": 
 +              { 
 +                      itm = (!autocvar_g_nades_tandem_item_includespecial) ? 
 +                              ITEM_JetpackFuel : (random() < 0.5) ? 
 +                              ITEM_JetpackFuel : ITEM_Jetpack; 
 +                      break; 
 +              }
 +              default: { itm = nade_tandem_randomitem(); break; }
 +      }
 +
 +      if((IS_GAMETYPE(FREEZETAG) || IS_GAMETYPE(LMS)) 
 +              && (itm != ITEM_ArmorSmall || itm != ITEM_HealthSmall))
 +      {
 +              // Non-regular items can't be spawned on survival-type gamemodes
 +              itm = (random() > 0.5) ? ITEM_ArmorSmall : ITEM_HealthSmall;
 +      }
 +
 +      // item setup
++      ITEM_SET_LOOT(e, true);
 +      e.reset = SUB_Remove;
 +      e.noalign = true;
 +      StartItem(e, itm);
 +      e.gravity = 1;
 +      setorigin(e, org);
 +      e.velocity = randomvec() * 175 + '0 0 325';
 +      e.item_spawnshieldtime = time + 0.7;
 +      SUB_SetFade(e, time + autocvar_g_nades_tandem_item_lifetime, 1);
 +}
 +
 +void nade_tandem_dropping(entity this, vector org)
 +{
 +      entity e = spawn();
 +      e.spawnfunc_checked = true;
 +      e.pokenade_type = this.pokenade_type;
 +
 +      // Items can't be spawned on CA and Instagib
 +      if(!IS_GAMETYPE(CA) && !autocvar_g_instagib)
 +      {
 +              switch (this.pokenade_type)
 +              {
 +                      case "weapon"   : 
 +                      {
 +                              if (autocvar_g_nades_tandem_includespecial)
 +                              {
 +                                      nade_tandem_randomweapon(e, org);
 +                                      return;
 +                              }
 +                      }
 +                      case "health"   : 
 +                      case "armor"    : 
 +                      case "ammo"             : 
 +                      case "jetpack"  : 
 +                      default                 : { nade_tandem_spawnitem(e, org); return; }
 +              }
 +      }
 +}
 +
 +void tandem_ball_think(entity this)
 +{
 +      if(round_handler_IsActive())
 +      if(!round_handler_IsRoundStarted())
 +      {
 +              delete(this);
 +              return;
 +      }
 +
 +      if(time > this.pushltime)
 +      {
 +              delete(this);
 +              return;
 +      }
 +
 +      vector midpoint = ((this.absmin + this.absmax) * 0.5);
 +      if(pointcontents(midpoint) == CONTENT_WATER)
 +      {
 +              this.velocity = this.velocity * 0.5;
 +
 +              if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER) 
 +                      this.velocity_z = 200;
 +      }
 +
 +      this.angles = vectoangles(this.velocity);
 +
 +      if (this.nade_item_spawncount < autocvar_g_nades_tandem_ball_item_spawncount)
 +      {
 +              this.nade_item_spawncount++;
 +              nade_tandem_dropping(this, this.origin);
 +      }
 +
 +      this.nextthink = time + 0.1;
 +}
 +
 +void nade_tandem_ball(entity this)
 +{
 +      entity proj;
 +      vector kick;
 +
 +      spamsound(this, CH_SHOTS, SND_FIREBALL_FIRE, VOL_BASE, ATTEN_NORM);
 +
 +      proj = new(grenade);
 +      proj.bot_dodge = true;
 +      proj.pokenade_type = this.pokenade_type;
 +      set_movetype(proj, MOVETYPE_BOUNCE);
 +      setmodel(proj, MDL_Null);
 +      proj.scale = 1; //0.5;
 +      setsize(proj, '-4 -4 -4', '4 4 4');
 +      setorigin(proj, this.origin);
 +      setthink(proj, tandem_ball_think);
 +      proj.nextthink = time;
 +      proj.effects = EF_LOWPRECISION;
 +
 +      kick.x =(random() - 0.5) * 2 * autocvar_g_nades_tandem_ball_spread;
 +      kick.y = (random() - 0.5) * 2 * autocvar_g_nades_tandem_ball_spread;
 +      kick.z = (random() / 2 + 0.5) * autocvar_g_nades_tandem_ball_spread;
 +      proj.velocity = kick;
 +
 +      proj.pushltime = time + autocvar_g_nades_tandem_ball_lifetime;
 +
 +      proj.angles = vectoangles(proj.velocity);
 +      proj.flags = FL_PROJECTILE;
 +      IL_PUSH(g_projectiles, proj);
 +      IL_PUSH(g_bot_dodge, proj);
 +      proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
 +}
  
 -void nade_monster_boom(entity this)
 +void tandem_fountain_think(entity this)
  {
 -      if(!autocvar_g_monsters)
 +      if(round_handler_IsActive())
 +      if(!round_handler_IsRoundStarted())
 +      {
 +              delete(this);
 +              return;
 +      }
 +
 +      if(time >= this.ltime)
 +      {
 +              Send_Effect(EFFECT_SMOKE_SMALL, this.origin + '0 0 1', '0 0 0', 1);
 +              sound(this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
 +
 +              delete(this);
                return;
 +      }
 +
 +      vector midpoint = ((this.absmin + this.absmax) * 0.5);
 +      if(pointcontents(midpoint) == CONTENT_WATER)
 +      {
 +              this.velocity = this.velocity * 0.5;
 +
 +              if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
 +                      this.velocity_z = 200;
 +
 +              UpdateCSQCProjectile(this);
 +      }
 +
 +      this.nextthink = time + 0.1;
 +      if(time >= this.nade_special_time)
 +      {
 +              this.nade_special_time = time + autocvar_g_nades_tandem_fountain_delay;
 +              nade_tandem_ball(this);
 +              Send_Effect(EFFECT_SMOKE_LARGE, this.origin, '0 0 0', 1);
 +      }
 +}
 +
 +void tandem_item_fountain_explode(entity this)
 +{
 +      entity fountain = new(nade_tandem_fountain);
 +      fountain.owner = this.owner;
 +      fountain.realowner = this.realowner;
 +      fountain.origin = this.origin;
 +      fountain.pokenade_type = this.pokenade_type;
 +      fountain.flags = FL_PROJECTILE;
 +      IL_PUSH(g_projectiles, fountain);
 +      IL_PUSH(g_bot_dodge, fountain);
 +      setorigin(fountain, fountain.origin);
 +      setthink(fountain, tandem_fountain_think);
 +      fountain.nextthink = time;
 +      fountain.ltime = time + autocvar_g_nades_tandem_fountain_lifetime;
 +      fountain.pushltime = fountain.ltime;
 +      fountain.team = this.team;
 +      
 +      //nade model maintaining
 +      setmodel(fountain, MDL_PROJECTILE_GRENADE);
 +      entity timer = new(nade_timer);
 +      setmodel(timer, MDL_NADE_TIMER);
 +      setattachment(timer, fountain, "");
 +      timer.colormap = this.colormap;
 +      timer.glowmod = this.glowmod;
 +      setthink(timer, nade_timer_think);
 +      timer.nextthink = time;
 +      timer.wait = fountain.ltime;
 +      timer.owner = fountain;
 +      timer.skin = 10;
 +      
 +      set_movetype(fountain, MOVETYPE_TOSS);
 +      fountain.bot_dodge = true;
 +      fountain.nade_special_time = time;
 +      setsize(fountain, '-16 -16 -16', '16 16 16');
 +      CSQCProjectile(fountain, true, PROJECTILE_NADE_TANDEM_BURN, true);
 +}
 +
 +void nade_tandem_boom(entity this)
 +{
        entity e = spawn();
        e.noalign = true; // don't drop to floor
 -      e = spawnmonster(e, this.pokenade_type, MON_Null, this.realowner, this.realowner, this.origin, false, false, 1);
 -      if(!e)
 -              return; // monster failed to be spawned
 +      e.gravity = 1;
 +
 +      this.nade_item_spawncount = 0;
 +
 +      int tandemnade_type_select = (autocvar_g_nades_tandem_includespecial) ? 
 +              this.tandemnade_type : 1;
  
 -      if(autocvar_g_nades_pokenade_monster_lifetime > 0)
 -              e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime;
 -      e.monster_skill = MONSTER_SKILL_INSANE;
 +      switch (tandemnade_type_select)
 +      {
 +              case 1:
 +              {
 +                      tandem_item_fountain_explode(this);
 +                      return;
 +              }
 +              case 2:
 +              {
 +                      if(!autocvar_g_vehicles) 
 +                              return;
 +
 +                      e = spawnvehicle(
 +                              e, 
 +                              this.pokenade_type, 
 +                              VEH_Null, 
 +                              this.realowner, 
 +                              this.realowner, 
 +                              this.origin, 
 +                              true, 
 +                              false, 
 +                              true,
 +                              false
 +                      );
 +
 +                      if(!e)
 +                              return; // vehicle failed to be spawned
 +
 +                      if(autocvar_g_nades_pokenade_vehicle_lifetime > 0)
 +                              e.vehicle_lifetime = time + autocvar_g_nades_pokenade_vehicle_lifetime;
 +                      return;
 +              }
 +              case 3:
 +              {
 +                      if(!autocvar_g_turrets) 
 +                              return;
 +
 +                      e = spawnturret(
 +                              e, 
 +                              this.pokenade_type, 
 +                              TUR_Null, 
 +                              this.realowner, 
 +                              this.realowner, 
 +                              this.origin, 
 +                              false,
 +                              false, 
 +                              false, 
 +                              1,
 +                              true
 +                      );
 +
 +                      if(!e)
 +                              return; // turret failed to be spawned
 +                      
 +                      if(autocvar_g_nades_pokenade_turret_lifetime > 0)
 +                              e.turret_lifetime = time + autocvar_g_nades_pokenade_turret_lifetime;
 +                      return;
 +              }
 +              default:
 +              {
 +                      if(!autocvar_g_monsters)
 +                              return;
 +
 +                      e = spawnmonster(
 +                              e, 
 +                              this.pokenade_type, 
 +                              MON_Null, 
 +                              this.realowner, 
 +                              this.realowner, 
 +                              this.origin, 
 +                              false, 
 +                              false, 
 +                              1
 +                      );
 +
 +                      if(!e)
 +                              return; // monster failed to be spawned
 +
 +                      if(autocvar_g_nades_pokenade_monster_lifetime > 0)
 +                              e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime;
 +                      e.monster_skill = MONSTER_SKILL_INSANE;
 +              }
 +      }
  }
  
  void nade_veil_touch(entity this, entity toucher)
@@@ -1245,81 -927,36 +1286,36 @@@ void nade_boom(entity this
        entity expef = NULL;
        bool nade_blast = true;
  
-       switch ( REGISTRY_GET(Nades, STAT(NADE_BONUS_TYPE, this)) )
-       {
-               case NADE_TYPE_NAPALM:
-                       nade_blast = autocvar_g_nades_napalm_blast;
-                       expef = EFFECT_EXPLOSION_MEDIUM;
-                       break;
-               
-               case NADE_TYPE_ICE:
-                       nade_blast = false;
-                       expef = EFFECT_ELECTRO_COMBO; // hookbomb_explode electro_combo bigplasma_impact
-                       break;
-               
-               case NADE_TYPE_TRANSLOCATE:
-                       nade_blast = false;
-                       break;
-               
-               case NADE_TYPE_TANDEM:
-                       if(!autocvar_g_monsters)
-                       {
-                               expef = EFFECT_NADE_EXPLODE(this.realowner.team);
-                               break; // fall back to a standard nade explosion
-                       }
-                       if(!autocvar_g_vehicles)
-                       {
-                               expef = EFFECT_NADE_EXPLODE(this.realowner.team);
-                               break; // fall back to a standard nade explosion
-                       }
-                       if(!autocvar_g_turrets)
-                       {
-                               expef = EFFECT_NADE_EXPLODE(this.realowner.team);
-                               break; // fall back to a standard nade explosion
-                       }
-               
-               case NADE_TYPE_SPAWN:
-                       nade_blast = false;
-                       switch(this.realowner.team)
-                       {
-                               case NUM_TEAM_1: expef = EFFECT_SPAWN_RED; break;
-                               case NUM_TEAM_2: expef = EFFECT_SPAWN_BLUE; break;
-                               case NUM_TEAM_3: expef = EFFECT_SPAWN_YELLOW; break;
-                               case NUM_TEAM_4: expef = EFFECT_SPAWN_PINK; break;
-                               default: expef = EFFECT_SPAWN_NEUTRAL; break;
-                       }
-                       break;
-               
-               case NADE_TYPE_HEAL:
-                       nade_blast = false;
-                       expef = EFFECT_SPAWN_RED;
-                       break;
-               case NADE_TYPE_ENTRAP:
-                       nade_blast = false;
-                       expef = EFFECT_SPAWN_YELLOW;
-                       break;
-               case NADE_TYPE_VEIL:
-                       nade_blast = false;
-                       expef = EFFECT_SPAWN_NEUTRAL;
-                       break;
-               case NADE_TYPE_AMMO:
-                       nade_blast = false;
-                       expef = EFFECT_SPAWN_BROWN;
-                       break;
+ #define GET_NADE_TYPE_SPAWN_EFFECT(team_owner) \
+       ((team_owner) == NUM_TEAM_1 ? EFFECT_SPAWN_RED : \
+       ((team_owner) == NUM_TEAM_2 ? EFFECT_SPAWN_BLUE : \
+       ((team_owner) == NUM_TEAM_3 ? EFFECT_SPAWN_YELLOW : \
+       ((team_owner) == NUM_TEAM_4 ? EFFECT_SPAWN_PINK : \
+       EFFECT_SPAWN_NEUTRAL))))
  
-               case NADE_TYPE_DARK:
-                       nade_blast = false;
-                       expef = EFFECT_EXPLOSION_MEDIUM;
-                       break;
+ #define SET_NADE_EFFECT(nade_type, blast, exp_effect) \
+       case nade_type: \
+               nade_blast = blast; \
+               expef = exp_effect; \
 -              break;
++              break
  
-               default:
-               case NADE_TYPE_NORMAL:
-                       expef = EFFECT_NADE_EXPLODE(this.realowner.team);
-                       break;
-       }
+       switch ( REGISTRY_GET(Nades, STAT(NADE_BONUS_TYPE, this)) )
+       {
+               SET_NADE_EFFECT(NADE_TYPE_NAPALM,      autocvar_g_nades_napalm_blast, EFFECT_EXPLOSION_MEDIUM);
+               SET_NADE_EFFECT(NADE_TYPE_ICE,         false,                         EFFECT_ELECTRO_COMBO /* hookbomb_explode electro_combo bigplasma_impact */);
+               SET_NADE_EFFECT(NADE_TYPE_TRANSLOCATE, false,                         NULL);
 -              SET_NADE_EFFECT(NADE_TYPE_MONSTER,     true,                          (!autocvar_g_monsters) ? EFFECT_NADE_EXPLODE(this.realowner.team) : NULL);
++              SET_NADE_EFFECT(NADE_TYPE_TANDEM,      true,                          (!autocvar_g_monsters && !autocvar_g_turrets && !autocvar_g_vehicles) ? EFFECT_NADE_EXPLODE(this.realowner.team) : NULL);
+               SET_NADE_EFFECT(NADE_TYPE_SPAWN,       false,                         GET_NADE_TYPE_SPAWN_EFFECT(this.realowner.team));
+               SET_NADE_EFFECT(NADE_TYPE_HEAL,        false,                         EFFECT_SPAWN_RED);
+               SET_NADE_EFFECT(NADE_TYPE_ENTRAP,      false,                         EFFECT_SPAWN_YELLOW);
+               SET_NADE_EFFECT(NADE_TYPE_VEIL,        false,                         EFFECT_SPAWN_NEUTRAL);
+               SET_NADE_EFFECT(NADE_TYPE_AMMO,        false,                         EFFECT_SPAWN_BROWN);
+               SET_NADE_EFFECT(NADE_TYPE_DARK,        false,                         EFFECT_EXPLOSION_MEDIUM);
+               SET_NADE_EFFECT(NADE_TYPE_NORMAL,      true,                          EFFECT_NADE_EXPLODE(this.realowner.team));
+               default: expef = EFFECT_NADE_EXPLODE(this.realowner.team); break;
+       }
+ #undef GET_NADE_TYPE_SPAWN_EFFECT
+ #undef SET_NADE_EFFECT
  
        if(expef)
                Send_Effect(expef, findbetterlocation(this.origin, 8), '0 0 0', 1);
        if(this.takedamage)
        switch ( REGISTRY_GET(Nades, STAT(NADE_BONUS_TYPE, this)) )
        {
-               case NADE_TYPE_NAPALM: nade_napalm_boom(this); break;
-               case NADE_TYPE_ICE: nade_ice_boom(this); break;
-               case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(this); break;
-               case NADE_TYPE_SPAWN: nade_spawn_boom(this); break;
-               case NADE_TYPE_HEAL: nade_heal_boom(this); break;
-               case NADE_TYPE_TANDEM: nade_tandem_boom(this); break;
-               case NADE_TYPE_ENTRAP: nade_entrap_boom(this); break;
-               case NADE_TYPE_VEIL: nade_veil_boom(this); break;
-               case NADE_TYPE_AMMO: nade_ammo_boom(this); break;
-               case NADE_TYPE_DARK: nade_dark_boom(this); break;
+               case NADE_TYPE_NAPALM:      nade_napalm_boom(this);       break;
+               case NADE_TYPE_ICE:         nade_ice_boom(this);          break;
+               case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(this);  break;
+               case NADE_TYPE_SPAWN:       nade_spawn_boom(this);        break;
+               case NADE_TYPE_HEAL:        nade_heal_boom(this);         break;
 -              case NADE_TYPE_MONSTER:     nade_monster_boom(this);      break;
++              case NADE_TYPE_TANDEM:      nade_tandem_boom(this);       break;
+               case NADE_TYPE_ENTRAP:      nade_entrap_boom(this);       break;
+               case NADE_TYPE_VEIL:        nade_veil_boom(this);         break;
+               case NADE_TYPE_AMMO:        nade_ammo_boom(this);         break;
 -              case NADE_TYPE_DARK:        nade_darkness_boom(this);         break;
++              case NADE_TYPE_DARK:        nade_darkness_boom(this);     break;
        }
  
        IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this,
@@@ -1721,11 -1368,10 +1730,11 @@@ void nade_prime(entity this
        else
        {
                ntype   = ((autocvar_g_nades_client_select) ? CS_CVAR(this).cvar_cl_nade_type : autocvar_g_nades_nade_type);
-               pntype  = ((autocvar_g_nades_client_select) ? CS_CVAR(this).cvar_cl_pokenade_type : autocvar_g_nades_pokenade_type);
+               pntype  = ((autocvar_g_nades_client_select) ? CS_CVAR(this).cvar_cl_pokenade_type : autocvar_g_nades_pokenade_monster_type);
 +              tntype  = ((autocvar_g_nades_client_select) ? CS_CVAR(this).cvar_cl_tandemnade_type : autocvar_g_nades_tandemnade_type);
        }
  
 -      spawn_held_nade(this, this, autocvar_g_nades_nade_lifetime, ntype, pntype);
 +      spawn_held_nade(this, this, autocvar_g_nades_nade_lifetime, ntype, pntype, tntype);
  }
  
  bool CanThrowNade(entity this)
@@@ -1776,23 -1422,28 +1785,28 @@@ void nades_Clear(entity player
        STAT(NADE_TIMER, player) = 0;
  }
  
void nades_CheckTypes(entity player)
int nades_CheckTypes(entity player, int cl_ntype)
  {
-       int cl_ntype = CS_CVAR(player).cvar_cl_nade_type;
+ #define CL_NADE_TYPE_CHECK(cl_ntype, cvar) \
+       case cl_ntype.m_id: \
+               if (!cvar) return NADE_TYPE_NORMAL.m_id; \
+               break
        switch (cl_ntype)
        {
-               case NADE_TYPE_NAPALM.m_id: if (!autocvar_g_nades_napalm)                       cl_ntype = NADE_TYPE_NORMAL.m_id; break;
-               case NADE_TYPE_ICE.m_id: if (!autocvar_g_nades_ice)                                     cl_ntype = NADE_TYPE_NORMAL.m_id; break;
-               case NADE_TYPE_TRANSLOCATE.m_id: if (!autocvar_g_nades_translocate)     cl_ntype = NADE_TYPE_NORMAL.m_id; break;
-               case NADE_TYPE_SPAWN.m_id: if (!autocvar_g_nades_spawntype)                     cl_ntype = NADE_TYPE_NORMAL.m_id; break;
-               case NADE_TYPE_HEAL.m_id: if (!autocvar_g_nades_heal)                           cl_ntype = NADE_TYPE_NORMAL.m_id; break;
-               case NADE_TYPE_TANDEM.m_id: if (!autocvar_g_nades_tandem)                       cl_ntype = NADE_TYPE_NORMAL.m_id; break;
-               case NADE_TYPE_ENTRAP.m_id: if (!autocvar_g_nades_entrap)                       cl_ntype = NADE_TYPE_NORMAL.m_id; break;
-               case NADE_TYPE_VEIL.m_id: if (!autocvar_g_nades_veil)                           cl_ntype = NADE_TYPE_NORMAL.m_id; break;
-               case NADE_TYPE_AMMO.m_id: if (!autocvar_g_nades_ammo)                           cl_ntype = NADE_TYPE_NORMAL.m_id; break;
-               case NADE_TYPE_DARK.m_id: if (!autocvar_g_nades_dark)                           cl_ntype = NADE_TYPE_NORMAL.m_id; break;
+               CL_NADE_TYPE_CHECK(NADE_TYPE_NAPALM,      autocvar_g_nades_napalm);
+               CL_NADE_TYPE_CHECK(NADE_TYPE_ICE,         autocvar_g_nades_ice);
+               CL_NADE_TYPE_CHECK(NADE_TYPE_TRANSLOCATE, autocvar_g_nades_translocate);
+               CL_NADE_TYPE_CHECK(NADE_TYPE_SPAWN,       autocvar_g_nades_spawn);
+               CL_NADE_TYPE_CHECK(NADE_TYPE_HEAL,        autocvar_g_nades_heal);
 -              CL_NADE_TYPE_CHECK(NADE_TYPE_MONSTER,     autocvar_g_nades_pokenade);
++              CL_NADE_TYPE_CHECK(NADE_TYPE_TANDEM,      autocvar_g_nades_tandem);
+               CL_NADE_TYPE_CHECK(NADE_TYPE_ENTRAP,      autocvar_g_nades_entrap);
+               CL_NADE_TYPE_CHECK(NADE_TYPE_VEIL,        autocvar_g_nades_veil);
+               CL_NADE_TYPE_CHECK(NADE_TYPE_AMMO,        autocvar_g_nades_ammo);
+               CL_NADE_TYPE_CHECK(NADE_TYPE_DARK,        autocvar_g_nades_darkness);
        }
-       STAT(NADE_BONUS_TYPE, player) = cl_ntype;
+       return cl_ntype;
+ #undef CL_NADE_TYPE_CHECK
  }
  
  MUTATOR_HOOKFUNCTION(nades, VehicleEnter)
@@@ -1902,15 -1553,13 +1916,15 @@@ MUTATOR_HOOKFUNCTION(nades, PlayerPreTh
  
                        if(autocvar_g_nades_bonus_client_select)
                        {
-                               nades_CheckTypes(player);
+                               STAT(NADE_BONUS_TYPE, player) = nades_CheckTypes(player, CS_CVAR(player).cvar_cl_nade_type);
                                player.pokenade_type = CS_CVAR(player).cvar_cl_pokenade_type;
 +                              player.tandemnade_type = CS_CVAR(player).cvar_cl_tandemnade_type;
                        }
                        else
                        {
                                STAT(NADE_BONUS_TYPE, player) = autocvar_g_nades_bonus_type;
-                               player.pokenade_type = autocvar_g_nades_pokenade_type;
+                               player.pokenade_type = autocvar_g_nades_pokenade_monster_type;
 +                              player.tandemnade_type = autocvar_g_nades_tandemnade_type;
                        }
  
                        STAT(NADE_BONUS_TYPE, player) = bound(1, STAT(NADE_BONUS_TYPE, player), Nades_COUNT);
index d5edba807bada252d3d409f419aebca5cb4ce7d2,7888da7d1bf718e750a5b99bea732405b7dbfe92..e2abf7e1efbe663d3984f4c17c1d934daa340914
@@@ -86,15 -79,13 +89,15 @@@ float autocvar_g_nades_ammo_time
  float autocvar_g_nades_ammo_rate;
  float autocvar_g_nades_ammo_friend;
  float autocvar_g_nades_ammo_foe;
- bool autocvar_g_nades_dark;
- float autocvar_g_nades_dark_damage;
- float autocvar_g_nades_dark_time;
- float autocvar_g_nades_dark_radius;
- string autocvar_g_nades_pokenade_type;
+ bool autocvar_g_nades_darkness;
+ bool autocvar_g_nades_darkness_explode;
+ bool autocvar_g_nades_darkness_teamcheck;
+ float autocvar_g_nades_darkness_time;
 -bool autocvar_g_nades_pokenade;
+ string autocvar_g_nades_pokenade_monster_type;
 +int autocvar_g_nades_tandemnade_type;
  float autocvar_g_nades_pokenade_monster_lifetime;
 +float autocvar_g_nades_pokenade_turret_lifetime;
 +float autocvar_g_nades_pokenade_vehicle_lifetime;
  #endif
  
  // use slots 70-100
@@@ -115,12 -106,10 +118,12 @@@ const int PROJECTILE_NADE_ENTRAP = 84
  const int PROJECTILE_NADE_ENTRAP_BURN = 85;
  const int PROJECTILE_NADE_VEIL = 86;
  const int PROJECTILE_NADE_VEIL_BURN = 87;
 -const int PROJECTILE_NADE_AMMO = 88;
 -const int PROJECTILE_NADE_AMMO_BURN = 89;
 -const int PROJECTILE_NADE_DARKNESS = 90;
 -const int PROJECTILE_NADE_DARKNESS_BURN = 91;
 +const int PROJECTILE_NADE_EMERALD = 88;
 +const int PROJECTILE_NADE_EMERALD_BURN = 89;
 +const int PROJECTILE_NADE_AMMO = 90;
 +const int PROJECTILE_NADE_AMMO_BURN = 91;
- const int PROJECTILE_NADE_DARK = 92;
- const int PROJECTILE_NADE_DARK_BURN = 93;
++const int PROJECTILE_NADE_DARKNESS = 92;
++const int PROJECTILE_NADE_DARKNESS_BURN = 93;
  
  REGISTRY(Nades, BITS(4))
  REGISTER_REGISTRY(Nades)
index d957d7bfd8f97e83938b5796a716ea8f2370cfe9,aa6b4eb56b1e67c484a520b673b43f9cd0c102ee..21e8a91f8bc7635d0bb052db666f973d76b8bad7
@@@ -778,9 -804,11 +804,12 @@@ string multiteam_info_sprintf(string in
      MSG_CENTER_NOTIF(VEHICLE_ENTER_GUNNER,              N_ENABLE,    0, 0, "pass_key",       CPID_VEHICLES,          "0 0",  _("^BGPress ^F2%s^BG to enter the vehicle gunner"), "")
      MSG_CENTER_NOTIF(VEHICLE_ENTER_STEAL,               N_ENABLE,    0, 0, "pass_key",       CPID_VEHICLES,          "0 0",  _("^BGPress ^F2%s^BG to steal this vehicle"), "")
      MSG_CENTER_NOTIF(VEHICLE_STEAL,                     N_ENABLE,    0, 0, "",               CPID_VEHICLES_OTHER,    "0 0",  _("^F2The enemy is stealing one of your vehicles!\n^F4Stop them!"), "")
 +    MSG_CENTER_NOTIF(VEHICLE_STEAL_OWNER,               N_ENABLE,    1, 0, "s1",             CPID_VEHICLES_OTHER,    "4 0",  _("^F2Intruder detected, %s vehicle is being stolen,\n disabling shields!"), "")
      MSG_CENTER_NOTIF(VEHICLE_STEAL_SELF,                N_ENABLE,    0, 0, "",               CPID_VEHICLES_OTHER,    "4 0",  _("^F2Intruder detected, disabling shields!"), "")
  
+     MSG_CENTER_NOTIF(VOTEBAN,                           N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  BOLD(_("^K1You aren't allowed to call a vote because you are banned in this server")), "")
+     MSG_CENTER_NOTIF(VOTEBANYN,                         N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  BOLD(_("^K1You aren't allowed to vote because you are banned in this server")), "")
      MSG_CENTER_NOTIF(WEAPON_MINELAYER_LIMIT,            N_ENABLE,    0, 1, "f1",             CPID_Null,              "0 0",  _("^BGYou cannot place more than ^F2%s^BG mines at a time"), "")
  
  #undef N_DISABL
Simple merge
Simple merge
Simple merge