Merge branch 'master' into terencehill/min_spec_time
authorterencehill <piuntn@gmail.com>
Wed, 30 May 2018 12:44:23 +0000 (14:44 +0200)
committerterencehill <piuntn@gmail.com>
Wed, 30 May 2018 12:44:23 +0000 (14:44 +0200)
1  2 
qcsrc/server/client.qc
qcsrc/server/client.qh
qcsrc/server/mutators/events.qh

diff --combined qcsrc/server/client.qc
index 01b5055cdb8ba509a57444c80db5ea7b9f671a72,fff50d24959bb5b9d1ddb0fb4f99141409b8fced..d706f8107313d65e8951fb674b9799186bd18fc7
@@@ -152,10 -152,15 +152,15 @@@ void ClientData_Detach(entity this
  
  void ClientData_Touch(entity e)
  {
-       CS(e).clientdata.SendFlags = 1;
+       entity cd = CS(e).clientdata;
+       if (cd) { cd.SendFlags = 1; }
  
        // make it spectatable
-       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e, { CS(it).clientdata.SendFlags = 1; });
+       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e,
+       {
+               entity cd = CS(it).clientdata;
+               if (cd) { cd.SendFlags = 1; }
+       });
  }
  
  void SetSpectatee(entity this, entity spectatee);
@@@ -1219,7 -1224,16 +1224,7 @@@ void ClientConnect(entity this
        JoinBestTeam(this, false); // if the team number is valid, keep it
        this.playerid = playerid_save;
  
 -      if (autocvar_sv_spectate || autocvar_g_campaign || this.team_forced < 0) {
 -              TRANSMUTE(Observer, this);
 -      } else {
 -              if (!teamplay || autocvar_g_balance_teams) {
 -                      TRANSMUTE(Player, this);
 -                      campaign_bots_may_start = true;
 -              } else {
 -                      TRANSMUTE(Observer, this); // do it anyway
 -              }
 -      }
 +      TRANSMUTE(Observer, this);
  
        PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid));
  
@@@ -1343,8 -1357,8 +1348,8 @@@ void ClientDisconnect(entity this
  
      MUTATOR_CALLHOOK(ClientDisconnect, this);
  
-       if (CS(this).netname_previous) strunzone(CS(this).netname_previous); // needs to be before the CS entity is removed!
-       if (CS(this).weaponorder_byimpulse) strunzone(CS(this).weaponorder_byimpulse);
+       strfree(CS(this).netname_previous); // needs to be before the CS entity is removed!
+       strfree(CS(this).weaponorder_byimpulse);
        ClientState_detach(this);
  
        Portal_ClearAll(this);
  
        bot_relinkplayerlist();
  
-       if (this.clientstatus) strunzone(this.clientstatus);
+       strfree(this.clientstatus);
        if (this.personal) delete(this.personal);
  
        this.playerid = 0;
@@@ -1487,7 -1501,7 +1492,7 @@@ void player_powerups(entity this
        Fire_ApplyDamage(this);
        Fire_ApplyEffect(this);
  
-       if (!g_instagib)
+       if (!autocvar_g_instagib)
        {
                if (this.items & ITEM_Strength.m_itemid)
                {
@@@ -2130,11 -2144,9 +2135,11 @@@ void PrintWelcomeMessage(entity this
        }
  }
  
 +const int MIN_SPEC_TIME = 1;
  bool joinAllowed(entity this)
  {
        if (CS(this).version_mismatch) return false;
 +      if (time < CS(this).jointime + MIN_SPEC_TIME) return false;
        if (!nJoinAllowed(this, this)) return false;
        if (teamplay && lockteams) return false;
        if (ShowTeamSelection(this)) return false;
@@@ -2474,8 -2486,7 +2479,7 @@@ void PlayerPreThink (entity this
                }
                if (!assume_unchanged && autocvar_sv_eventlog)
                        GameLogEcho(strcat(":name:", ftos(this.playerid), ":", playername(this, false)));
-               if (CS(this).netname_previous) strunzone(CS(this).netname_previous);
-               CS(this).netname_previous = strzone(this.netname);
+               strcpy(CS(this).netname_previous, this.netname);
        }
  
        // version nagging
                PrintWelcomeMessage(this);
  
        if (IS_PLAYER(this)) {
 +              if (IS_REAL_CLIENT(this) && time < CS(this).jointime + MIN_SPEC_TIME)
 +                      error("Client can't be spawned as player on connection!");
                if(!PlayerThink(this))
                        return;
        }
                        IntermissionThink(this);
                return;
        }
 +      else if (IS_REAL_CLIENT(this) && !CS(this).autojoin_checked && time >= CS(this).jointime + MIN_SPEC_TIME)
 +      {
 +              CS(this).autojoin_checked = true;
 +              // don't do this in ClientConnect
 +              // many things can go wrong if a client is spawned as player on connection
 +              if (MUTATOR_CALLHOOK(AutoJoinOnConnection, this)
 +                      || (!(autocvar_sv_spectate || autocvar_g_campaign || this.team_forced < 0)
 +                              && (!teamplay || autocvar_g_balance_teams)))
 +              {
 +                      campaign_bots_may_start = true;
 +                      Join(this);
 +                      return;
 +              }
 +      }
        else if (IS_OBSERVER(this)) {
                ObserverThink(this);
        }
diff --combined qcsrc/server/client.qh
index 75a01c96baf2314eaf7110d90a5fa264a16c9d8e,7499ee8ddfac0e0fbbd299ab4de285b53c62ea83..72732037fdb91e75afb2b483353c7c5e6366dbd3
@@@ -114,7 -114,6 +114,7 @@@ CLASS(Client, Object
      ATTRIB(Client, cmd_floodtime, float, this.cmd_floodtime);
      ATTRIB(Client, wasplayer, bool, this.wasplayer);
      ATTRIB(Client, weaponorder_byimpulse, string, this.weaponorder_byimpulse);
 +    ATTRIB(Client, autojoin_checked, bool, this.wasplayer);
  
      // networked cvars
  
@@@ -232,5 -231,5 +232,5 @@@ float CalcRotRegen(float current, floa
  
  bool Spectate(entity this, entity pl);
  
- #define SPECTATE_COPY() [[accumulate]] void SpectateCopy(entity this, entity spectatee)
+ #define SPECTATE_COPY() ACCUMULATE void SpectateCopy(entity this, entity spectatee)
  #define SPECTATE_COPYFIELD(fld) SPECTATE_COPY() { this.(fld) = spectatee.(fld); }
index 60651584362b9d7682ea5f64b0112f366c663c8a,d1ba087a2e0ba9e2e2d1743e9d63669560f900f8..ca3ce6fcc82ac4b03e3a3a29092463942d00e6da
@@@ -3,7 -3,7 +3,7 @@@
  #include <common/mutators/base.qh>
  
  // register all possible hooks here
-  
  // to use a hook, first register your mutator using REGISTER_MUTATOR
  // then create your function using MUTATOR_HOOKFUNCTION
  
@@@ -27,12 -27,6 +27,12 @@@ MUTATOR_HOOKABLE(PutClientInServer, EV_
      /**/
  MUTATOR_HOOKABLE(ForbidSpawn, EV_ForbidSpawn);
  
 +/** returns true if client should be put as player on connection */
 +#define EV_AutoJoinOnConnection(i, o) \
 +    /** player */ i(entity, MUTATOR_ARGV_0_entity) \
 +    /**/
 +MUTATOR_HOOKABLE(AutoJoinOnConnection, EV_AutoJoinOnConnection);
 +
  /** called when player spawns to determine whether to give them random start weapons. Return true to forbid giving them. */
  #define EV_ForbidRandomStartWeapons(i, o) \
        /** player */ i(entity, MUTATOR_ARGV_0_entity) \
@@@ -417,7 -411,8 +417,8 @@@ MUTATOR_HOOKABLE(PlayerDamage_SplitHeal
      /** mirrordamage    */ i(float,  MUTATOR_ARGV_5_float) \
      /** mirrordamage  */ o(float,  MUTATOR_ARGV_5_float) \
      /** force           */ i(vector, MUTATOR_ARGV_6_vector) \
-     /** force                         */ o(vector, MUTATOR_ARGV_6_vector) \
+     /** force           */ o(vector, MUTATOR_ARGV_6_vector) \
+     /** weapon entity         */ i(entity, MUTATOR_ARGV_7_entity) \
      /**/
  MUTATOR_HOOKABLE(Damage_Calculate, EV_Damage_Calculate);
  
@@@ -1112,6 -1107,13 +1113,13 @@@ MUTATOR_HOOKABLE(Item_ScheduleRespawn, 
      /**/
  MUTATOR_HOOKABLE(PlayerPhysics_UpdateStats, EV_PlayerPhysics_UpdateStats);
  
+ /** called after physics stats are set on a player, allows post-initialization modifications */
+ #define EV_PlayerPhysics_PostUpdateStats(i, o) \
+     /** player */             i(entity, MUTATOR_ARGV_0_entity) \
+     /** maxspeed_mod */       i(float, MUTATOR_ARGV_1_float) \
+     /**/
+ MUTATOR_HOOKABLE(PlayerPhysics_PostUpdateStats, EV_PlayerPhysics_PostUpdateStats);
  /** return true to use your own aim target (or none at all) */
  #define EV_HavocBot_Aim(i, o) \
      /** bot */ i(entity, MUTATOR_ARGV_0_entity) \