]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote-tracking branch 'origin/master' into samual/notification_rewrite
authorSamual Lenks <samual@xonotic.org>
Sun, 10 Feb 2013 00:49:22 +0000 (19:49 -0500)
committerSamual Lenks <samual@xonotic.org>
Sun, 10 Feb 2013 00:49:22 +0000 (19:49 -0500)
Conflicts:
qcsrc/common/util.qc
qcsrc/common/util.qh

13 files changed:
1  2 
defaultXonotic.cfg
qcsrc/client/autocvars.qh
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/progs.src
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/server/autocvars.qh
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/defs.qh
qcsrc/server/progs.src
qcsrc/server/w_electro.qc
qcsrc/server/w_shotgun.qc

diff --combined defaultXonotic.cfg
index 79b7cc60c3c6c78b077be883e5690d9653589263,c7edacdb726f2abc452741d3745967558ada5d33..67d85ca1eeed797348c021adab735ba0bd93165e
@@@ -253,7 -253,6 +253,6 @@@ set sv_doublejump 0 "allow Quake 2-styl
  set sv_jumpspeedcap_min "" "lower bound on the baseline velocity of a jump; final velocity will be >= (jumpheight * min + jumpheight)"
  set sv_jumpspeedcap_max "" "upper bound on the baseline velocity of a jump; final velocity will be <= (jumpheight * max + jumpheight)"
  set sv_jumpspeedcap_max_disable_on_ramps 0 "disable upper baseline velocity bound on ramps to preserve the old rampjump style"
- set sv_player_jumpanim_minfall 48 "minimum distance player has to have below their feet before the jump animation will be activated (only when falling, +jump will play anim instantly)"
  
  seta sv_precacheplayermodels 1
  seta sv_precacheweapons 0
@@@ -819,7 -818,6 +818,7 @@@ set g_chat_flood_lmax_tell 2       "private c
  set g_chat_flood_burst_tell 2 "private chat: allow bursts of so many chat lines"
  set g_chat_flood_notify_flooder 1     "when 0, the flooder still can see his own message"
  set g_chat_teamcolors 0       "colorize nicknames in team color for chat"
 +set g_chat_tellprivacy 1 "when disabled, tell messages are also sent to the server console log... otherwise they're kept private between players."
  set g_nick_flood_timeout 120 "time after which nick flood protection resets (set to 0 to disable nick flood checking)"
  set g_nick_flood_penalty 0.5 "duration of the nick flood penalty"
  set g_nick_flood_penalty_yellow 3 "number of changes to allow before warning and movement blocking"
index caef19108bb5fe57ed24c2c6c50a6d8da16a24ca,beb56874ab4393d0ac036b3d607ac38122fa1cbf..52eb06c699e998bb698cb55ebb5a7b3bba7b4c4f
@@@ -254,6 -254,7 +254,6 @@@ float autocvar_hud_panel_notify
  float autocvar_hud_panel_notify_fadetime;
  float autocvar_hud_panel_notify_flip;
  float autocvar_hud_panel_notify_fontsize;
 -float autocvar_hud_panel_notify_print;
  float autocvar_hud_panel_notify_time;
  float autocvar_hud_panel_physics;
  float autocvar_hud_panel_physics_acceleration_progressbar_mode;
@@@ -413,4 -414,6 +413,6 @@@ string autocvar__cl_playermodel
  float autocvar_cl_precacheplayermodels;
  float autocvar_cl_deathglow;
  float autocvar_developer_csqcentities;
+ float autocvar__animblend;
+ float autocvar__animblend_fixbone;
  float autocvar_g_jetpack_attenuation;
index c4a5b39a6b27c77d0b8829d0658f513195f760b7,1d0c36ae9c1236302d77cc354511a88deeb3d31b..442fe0219d2fd630849876be0528dfc690b66193
@@@ -1,4 -1,4 +1,4 @@@
- void CSQCModel_Hook_PreDraw();
+ void CSQCModel_Hook_PreDraw(float isplayer);
  
  .float isplayermodel;
  
@@@ -218,7 -218,7 +218,7 @@@ void CSQCPlayer_ForceModel_Apply(float 
                entity tm;
  
                for(tm = teams.sort_next; tm; tm = tm.sort_next)
 -                      if(tm.team != COLOR_SPECTATOR)
 +                      if(tm.team != FL_SPECTATOR)
                                ++teams_count;
  
                if(autocvar_cl_forcemyplayercolors)
  // FEATURE: fallback frames
  .float csqcmodel_saveframe;
  .float csqcmodel_saveframe2;
+ #ifdef CSQCMODEL_HAVE_TWO_FRAMES
  .float csqcmodel_saveframe3;
  .float csqcmodel_saveframe4;
+ #endif
  .float csqcmodel_framecount;
  
  #define IS_DEAD_FRAME(f) ((f) == 0 || (f) == 1)
@@@ -279,15 -281,19 +281,19 @@@ void CSQCPlayer_FallbackFrame_PreUpdate
  {
        self.frame = self.csqcmodel_saveframe;
        self.frame2 = self.csqcmodel_saveframe2;
+ #ifdef CSQCMODEL_HAVE_TWO_FRAMES
        self.frame3 = self.csqcmodel_saveframe3;
        self.frame4 = self.csqcmodel_saveframe4;
+ #endif
  }
  void CSQCPlayer_FallbackFrame_PostUpdate(float isnew)
  {
        self.csqcmodel_saveframe = self.frame;
        self.csqcmodel_saveframe2 = self.frame2;
+ #ifdef CSQCMODEL_HAVE_TWO_FRAMES
        self.csqcmodel_saveframe3 = self.frame3;
        self.csqcmodel_saveframe4 = self.frame4;
+ #endif
  
        // hack for death animations: set their frametime to zero in case a
        // player "pops in"
                }
                FIX_FRAMETIME(frame, frame1time)
                FIX_FRAMETIME(frame2, frame2time)
+ #ifdef CSQCMODEL_HAVE_TWO_FRAMES
                FIX_FRAMETIME(frame3, frame3time)
                FIX_FRAMETIME(frame4, frame4time)
+ #endif
        }
        self.csqcmodel_isdead = IS_DEAD_FRAME(self.frame);
  }
@@@ -329,8 -337,10 +337,10 @@@ void CSQCPlayer_FallbackFrame_Apply(voi
  {
        self.frame = CSQCPlayer_FallbackFrame(self.frame);
        self.frame2 = CSQCPlayer_FallbackFrame(self.frame2);
+ #ifdef CSQCMODEL_HAVE_TWO_FRAMES
        self.frame3 = CSQCPlayer_FallbackFrame(self.frame3);
        self.frame4 = CSQCPlayer_FallbackFrame(self.frame4);
+ #endif
  }
  
  // FEATURE: auto tag_index
@@@ -357,7 -367,7 +367,7 @@@ void CSQCModel_AutoTagIndex_Apply(void
                {
                        entity oldself = self;
                        self = self.tag_entity;
-                       CSQCModel_Hook_PreDraw();
+                       CSQCModel_Hook_PreDraw((self.entnum >= 1 && self.entnum <= maxclients));
                        self = oldself;
                }
  
@@@ -419,6 -429,8 +429,8 @@@ float EF_DIMLIGHT  = 8
  float EF_DOUBLESIDED = 32768;
  float EF_NOSELFSHADOW = 65536;
  float EF_DYNAMICMODELLIGHT = 131072;
+ float EF_RESTARTANIM_BIT = 1048576;
+ float EF_TELEPORT_BIT = 2097152;
  float MF_ROCKET  =   1; // leave a trail
  float MF_GRENADE =   2; // leave a trail
  float MF_GIB     =   4; // leave a trail
@@@ -566,7 -578,16 +578,16 @@@ void CSQCPlayer_GlowMod_Apply(void
  
  // general functions
  .float csqcmodel_predraw_run;
- void CSQCModel_Hook_PreDraw()
+ .float anim_frame;
+ .float anim_frame1time;
+ .float anim_frame2;
+ .float anim_frame2time;
+ .float anim_saveframe;
+ .float anim_saveframe1time;
+ .float anim_saveframe2;
+ .float anim_saveframe2time;
+ .float anim_prev_pmove_flags;
+ void CSQCModel_Hook_PreDraw(float isplayer)
  {
        if(self.csqcmodel_predraw_run == framecount)
                return;
                CSQCPlayer_ForceModel_Apply(self.entnum == player_localnum + 1);
                CSQCPlayer_GlowMod_Apply();
                CSQCPlayer_LOD_Apply();
-               CSQCPlayer_FallbackFrame_Apply();
+               if(!isplayer)
+                       CSQCPlayer_FallbackFrame_Apply();
+               else
+               {
+                       // we know that frame3 and frame4 fields, used by InterpolateAnimation, are left alone - but that is all we know!
+                       float doblend = autocvar__animblend;
+                       float onground = 0;
+                       if(self == csqcplayer)
+                       {
+                               if(self.pmove_flags & PMF_ONGROUND)
+                                       onground = 1;
+                               self.anim_prev_pmove_flags = self.pmove_flags;
+                               if(self.pmove_flags & PMF_DUCKED)
+                                       animdecide_setstate(self, self.anim_state | ANIMSTATE_DUCK, FALSE);
+                               else if(self.anim_state & ANIMSTATE_DUCK)
+                                       animdecide_setstate(self, self.anim_state - ANIMSTATE_DUCK, FALSE);
+                       }
+                       else
+                       {
+                               traceline(self.origin + '0 0 1' * self.maxs_z, self.origin + '0 0 1' * (self.mins_z - 4), MOVE_NOMONSTERS, self);
+                               if(trace_startsolid || trace_fraction < 1)
+                                       onground = 1;
+                       }
+                       animdecide_init(self);
+                       animdecide_setimplicitstate(self, onground);
+                       animdecide_setframes(self, doblend, anim_frame, anim_frame1time, anim_frame2, anim_frame2time);
+                       float sf = 0;
+                       if(self.anim_saveframe != self.anim_frame || self.anim_saveframe1time != self.anim_frame1time)
+                               sf |= CSQCMODEL_PROPERTY_FRAME;
+                       if(self.anim_saveframe2 != self.anim_frame2 || self.anim_saveframe2time != self.anim_frame2time)
+                               sf |= CSQCMODEL_PROPERTY_FRAME2;
+                       self.anim_saveframe = self.anim_frame;
+                       self.anim_saveframe1time = self.anim_frame1time;
+                       self.anim_saveframe2 = self.anim_frame2;
+                       self.anim_saveframe2time = self.anim_frame2time;
+                       if(sf)
+                       {
+                               CSQCModel_InterpolateAnimation_2To4_PreNote(sf | CSQCMODEL_PROPERTY_LERPFRAC);
+                               self.lerpfrac = (doblend ? 0.5 : 0);
+                               self.frame = self.anim_frame;
+                               self.frame1time = self.anim_frame1time;
+                               self.frame2 = self.anim_frame2;
+                               self.frame2time = self.anim_frame2time;
+                               CSQCModel_InterpolateAnimation_2To4_Note(sf | CSQCMODEL_PROPERTY_LERPFRAC, FALSE);
+                       }
+                       CSQCModel_InterpolateAnimation_2To4_Do();
+                       if(doblend)
+                       {
+                               skeleton_from_frames(self);
+                       }
+                       else
+                       {
+                               free_skeleton_from_frames(self);
+                               // just in case, clear these (we're animating in frame and frame3)
+                               self.lerpfrac = 0;
+                               self.lerpfrac4 = 0;
+                       }
+               }
        }
  
        CSQCModel_AutoTagIndex_Apply();
@@@ -599,7 -677,8 +677,8 @@@ void CSQCModel_Hook_PreUpdate(float isn
        CSQCModel_Effects_PreUpdate();
        if(self.isplayermodel)
        {
-               CSQCPlayer_FallbackFrame_PreUpdate();
+               if(!isplayer)
+                       CSQCPlayer_FallbackFrame_PreUpdate();
                CSQCPlayer_ForceModel_PreUpdate();
        }
  }
@@@ -613,7 -692,8 +692,8 @@@ void CSQCModel_Hook_PostUpdate(float is
        if(self.isplayermodel)
        {
                CSQCPlayer_ForceModel_PostUpdate();
-               CSQCPlayer_FallbackFrame_PostUpdate(isnew);
+               if(!isplayer)
+                       CSQCPlayer_FallbackFrame_PostUpdate(isnew);
        }
        CSQCModel_Effects_PostUpdate();
  }
diff --combined qcsrc/client/progs.src
index 72f2e0b74626253e25acb2e4ff989c91f8431eac,9d968f1fe7d86e1ceeecf09b135c6dcc1e23d4f7..8b83daebeebdb30253b2722b70db4b71269eb9a4
@@@ -14,11 -14,8 +14,11 @@@ Defs.q
  ../warpzonelib/common.qh
  ../warpzonelib/client.qh
  
 +../common/teams.qh
  ../common/util.qh
  ../common/items.qh
 +../common/deathtypes.qh
 +../common/notifications.qh
  ../common/explosion_equation.qh
  ../common/mapinfo.qh
  ../common/command/markup.qh
@@@ -26,6 -23,7 +26,7 @@@
  ../common/command/generic.qh
  ../common/command/shared_defs.qh
  ../common/urllib.qh
+ ../common/animdecide.qh
  command/cl_cmd.qh
  
  autocvars.qh
@@@ -41,6 -39,7 +42,6 @@@ movetypes.q
  prandom.qh
  bgmscript.qh
  noise.qh
 -teamplay.qh
  tturrets.qh
  ../server/tturrets/include/turrets_early.qh
  ../server/movelib.qc
@@@ -51,9 -50,11 +52,10 @@@ vehicles/vehicles.q
  ../csqcmodellib/cl_model.qh
  ../csqcmodellib/cl_player.qh
  projectile.qh
+ player_skeleton.qh
  
  sortlist.qc
  miscfunctions.qc
 -teamplay.qc
  ../server/t_items.qc
  
  teamradar.qc
@@@ -96,7 -97,6 +98,7 @@@ bgmscript.q
  noise.qc
  
  ../common/util.qc
 +../common/notifications.qc
  ../common/command/markup.qc
  ../common/command/rpn.qc
  ../common/command/generic.qc
@@@ -113,4 -113,7 +115,7 @@@ command/cl_cmd.q
  ../warpzonelib/client.qc
  tturrets.qc
  
+ player_skeleton.qc
+ ../common/animdecide.qc
  ../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail
diff --combined qcsrc/common/util.qc
index dc882194e1463e12e0be9d84877d0be91ad9147c,404bd7e5a486012deec784cb14be934f0c5cd85c..e781a4dcbebbef25a54035aefa85893ec8996831
@@@ -2480,75 -2480,31 +2480,104 @@@ void FindConnectedComponent(entity e, .
                queue_start.FindConnectedComponent_processing = 0;
  }
  
 +float Count_Proper_Strings(string improper, string...count)
 +{
 +      float i, total = 0;
 +      string tmp;
 +      
 +      for(i = 0; i < count; ++i)
 +      {
 +              tmp = ...(i, string);
 +              if((tmp) && (tmp != improper)) { ++total; }
 +      }
 +      
 +      return total;
 +}
 +
 +float Count_Proper_Floats(float improper, float...count)
 +{
 +      float i, total = 0;
 +      
 +      for(i = 0; i < count; ++i)
 +      {
 +              if(...(i, float) != improper) { ++total; }
 +      }
 +      
 +      return total;
 +}
 +
 +// todo: this sucks, lets find a better way to do backtraces?
 +#ifndef MENUQC
 +void backtrace(string msg)
 +{
 +      float dev, war;
 +      #ifdef SVQC
 +      dev = autocvar_developer;
 +      war = autocvar_prvm_backtraceforwarnings;
 +      #else
 +      dev = cvar("developer");
 +      war = cvar("prvm_backtraceforwarnings");
 +      #endif
 +      cvar_set("developer", "1");
 +      cvar_set("prvm_backtraceforwarnings", "1");
 +      print("\n");
 +      print("--- CUT HERE ---\nWARNING: ");
 +      print(msg);
 +      print("\n");
 +      remove(world); // isn't there any better way to cause a backtrace?
 +      print("\n--- CUT UNTIL HERE ---\n");
 +      cvar_set("developer", ftos(dev));
 +      cvar_set("prvm_backtraceforwarnings", ftos(war));
 +}
 +#endif
 +
 +// color code replace, place inside of sprintf and parse the string
 +string CCR(string input)
 +{
 +      // See the autocvar declarations in util.qh for default values
 +      
 +      // foreground/normal colors
 +      input = strreplace("^F1", strcat("^", autocvar_hud_colorset_foreground_1), input); 
 +      input = strreplace("^F2", strcat("^", autocvar_hud_colorset_foreground_2), input); 
 +      input = strreplace("^F3", strcat("^", autocvar_hud_colorset_foreground_3), input); 
 +      input = strreplace("^F4", strcat("^", autocvar_hud_colorset_foreground_4), input); 
 +
 +      // "kill" colors
 +      input = strreplace("^K1", strcat("^", autocvar_hud_colorset_kill_1), input);
 +      input = strreplace("^K2", strcat("^", autocvar_hud_colorset_kill_2), input);
 +      input = strreplace("^K3", strcat("^", autocvar_hud_colorset_kill_3), input);
 +
 +      // background colors
 +      input = strreplace("^BG", strcat("^", autocvar_hud_colorset_background), input);
 +      input = strreplace("^N", "^7", input); // "none"-- reset to white...
 +      return input;
 +}
++
+ vector vec3(float x, float y, float z)
+ {
+       vector v;
+       v_x = x;
+       v_y = y;
+       v_z = z;
+       return v;
+ }
+ #ifndef MENUQC
+ vector animfixfps(entity e, vector a, vector b)
+ {
+       // multi-frame anim: keep as-is
+       if(a_y == 1)
+       {
+               float dur;
+               dur = frameduration(e.modelindex, a_x);
+               if(dur <= 0 && b_y)
+               {
+                       a = b;
+                       dur = frameduration(e.modelindex, a_x);
+               }
+               if(dur > 0)
+                       a_z = 1.0 / dur;
+       }
+       return a;
+ }
+ #endif
diff --combined qcsrc/common/util.qh
index 2c9ed82b25ca4190d0e46b2836be4ab54bff2e84,4e553e4ba5d1611fc73fa83289c45b0d0de27b57..f5fa6eaabfe417f27a9c10bb546a463e6255b2c4
@@@ -1,9 -1,6 +1,9 @@@
  // a dummy macro that prevents the "hanging ;" warning
  #define ENDS_WITH_CURLY_BRACE
  
 +// return the actual code name of a var as a string
 +#define VAR_TO_TEXT(var) #var
 +
  #ifdef HAVE_YO_DAWG_CPP
  // TODO make ascii art pic of xzibit
  // YO DAWG!
@@@ -40,11 -37,6 +40,11 @@@ void ACCUMULATE_call(string func
        ACCUMULATE_call(#func)
  #endif
  
 +// used for simplifying ACCUMULATE_FUNCTIONs
 +#define SET_FIRST_OR_LAST(input,first,count) if(!input) { input = (first + count); }
 +#define SET_FIELD_COUNT(field,first,count) if(!field) { field = (first + count); ++count; }
 +#define CHECK_MAX_COUNT(name,max,count,type) if(count == max) { error(strcat("Maximum ", type, " hit: ", VAR_TO_TEXT(name), ": ", ftos(count), ".\n")); }
 +
  // this returns a tempstring containing a copy of s with additional \n newlines added, it also replaces \n in the text with a real newline
  // NOTE: s IS allowed to be a tempstring
  string wordwrap(string s, float l);
@@@ -373,41 -365,8 +373,47 @@@ typedef entity(entity cur, entity near
  typedef float(entity a, entity b, entity pass) isConnectedFunction_t;
  void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t nxt, isConnectedFunction_t iscon, entity pass);
  
 +// expand multiple arguments into one argument by stripping parenthesis
 +#define XPD(...) __VA_ARGS__
 +
 +float Count_Proper_Strings(string improper, string...count);
 +float Count_Proper_Floats(float improper, float...count);
 +
 +#ifndef MENUQC
 +void backtrace(string msg);
 +#endif
 +
 +// color code replace, place inside of sprintf and parse the string... defaults described as constants
 +// foreground/normal colors
 +var string autocvar_hud_colorset_foreground_1 = "2"; // F1 - Green  // primary priority (important names, etc)
 +var string autocvar_hud_colorset_foreground_2 = "3"; // F2 - Yellow // secondary priority (items, locations, numbers, etc)
 +var string autocvar_hud_colorset_foreground_3 = "4"; // F3 - Blue   // tertiary priority or relatively inconsequential text
 +var string autocvar_hud_colorset_foreground_4 = "1"; // F4 - Red    // notice/attention grabbing texting
 +// "kill" colors
 +var string autocvar_hud_colorset_kill_1 = "1"; // K1 - Red    // "bad" or "dangerous" text (death messages against you, kill notifications, etc)
 +var string autocvar_hud_colorset_kill_2 = "3"; // K2 - Yellow // similar to above, but less important... OR, a highlight out of above message type
 +var string autocvar_hud_colorset_kill_3 = "4"; // K3 - Blue   // "good" or "beneficial" text (you fragging someone, etc)
 +// background color
 +var string autocvar_hud_colorset_background = "7"; // BG - White // neutral/unimportant text
 +
 +string CCR(string input);
 +
 +#ifndef MENUQC
 +#ifdef CSQC
 +#define GENTLE (autocvar_cl_gentle || autocvar_cl_gentle_messages)
 +#else
 +#define GENTLE autocvar_sv_gentle
 +#endif
 +#define normal_or_gentle(normal,gentle) (GENTLE ? ((gentle != "") ? gentle : normal) : normal)
 +#endif
 +
 +// allow writing to also pass through to spectators (like so spectators see the same centerprints as players for example)
 +#define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
 +#define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
 +#define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
++
+ vector vec3(float x, float y, float z);
+ #ifndef MENUQC
+ vector animfixfps(entity e, vector a, vector b);
+ #endif
index 7b603e80fd7a1bb3187be85afc770e2de549d63e,efd5303dd10c8730c6186b15d5a4e67f9772d233..5f7f46a9072c124f59b81448a3d6a655df7ba08c
@@@ -761,7 -761,6 +761,7 @@@ float autocvar_g_chat_flood_spl_team
  float autocvar_g_chat_flood_spl_tell;
  float autocvar_g_chat_nospectators;
  float autocvar_g_chat_teamcolors;
 +float autocvar_g_chat_tellprivacy;
  float autocvar_g_ctf_allow_vehicle_carry;
  float autocvar_g_ctf_allow_vehicle_touch;
  float autocvar_g_ctf_throw;
@@@ -787,6 -786,7 +787,6 @@@ float autocvar_g_ctf_pass_request
  float autocvar_g_ctf_pass_turnrate;
  float autocvar_g_ctf_pass_timelimit;
  float autocvar_g_ctf_pass_velocity;
 -float autocvar_g_ctf_captimerecord_always;
  float autocvar_g_ctf_dynamiclights;
  string autocvar_g_ctf_flag_blue_model;
  float autocvar_g_ctf_flag_blue_skin;
@@@ -796,6 -796,7 +796,6 @@@ float autocvar_g_ctf_flag_dropped_waypo
  float autocvar_g_ctf_flag_dropped_floatinwater;
  float autocvar_g_ctf_flag_glowtrails;
  float autocvar_g_ctf_flag_health;
 -float autocvar_g_ctf_flag_pickup_verbosename;
  string autocvar_g_ctf_flag_red_model;
  float autocvar_g_ctf_flag_red_skin;
  float autocvar_g_ctf_flag_return_time;
@@@ -896,6 -897,7 +896,6 @@@ float autocvar_g_keyhunt_teams_override
  float autocvar_g_lms_campcheck_damage;
  float autocvar_g_lms_campcheck_distance;
  float autocvar_g_lms_campcheck_interval;
 -string autocvar_g_lms_campcheck_message;
  float autocvar_g_lms_join_anytime;
  float autocvar_g_lms_last_join;
  #define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
@@@ -1165,10 -1167,13 +1165,10 @@@ float autocvar_sv_eventlog_files_counte
  string autocvar_sv_eventlog_files_nameprefix;
  string autocvar_sv_eventlog_files_namesuffix;
  float autocvar_sv_eventlog_files_timestamps;
 -float autocvar_sv_fraginfo;
 -float autocvar_sv_fraginfo_handicap;
 -float autocvar_sv_fraginfo_ping;
 -float autocvar_sv_fraginfo_stats;
  float autocvar_sv_friction;
  float autocvar_sv_friction_on_land;
  float autocvar_sv_gameplayfix_q2airaccelerate;
 +float autocvar_sv_gentle;
  #define autocvar_sv_gravity cvar("sv_gravity")
  string autocvar_sv_intermission_cdtrack;
  string autocvar_sv_jumpspeedcap_max;
@@@ -1184,7 -1189,6 +1184,6 @@@ float autocvar_sv_maxairspeed
  float autocvar_sv_maxairstrafespeed;
  float autocvar_sv_maxspeed;
  string autocvar_sv_motd;
- float autocvar_sv_player_jumpanim_minfall;
  float autocvar_sv_precacheplayermodels;
  float autocvar_sv_precacheweapons;
  float autocvar_sv_q3acompat_machineshotgunswap;
index 33b1fd05aa09d251a2b6211634bc107033d772f8,1078eea1308df0c90c4d2f00b07710568894a118..23405484e0730ba162ebea5cf19b2426e74b0782
@@@ -425,11 -425,12 +425,11 @@@ void PutObserverInServer (void
  
        if(self.killcount != -666) {
                if(g_lms) {
 -                      if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
 -                              bprint ("^4", self.netname, "^4 has no more lives left\n");
 +                      if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0 && self.lms_spectate_warning != 2)
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_INFO, INFO_LMS_NOLIVES, self.netname, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        else
 -                              bprint ("^4", self.netname, "^4 is spectating now\n"); // TODO turn this into a proper forfeit?
 -              } else
 -                      bprint ("^4", self.netname, "^4 is spectating now\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_INFO, INFO_LMS_FORFEIT, self.netname, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
 +              } else { Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_INFO, INFO_QUIT_SPECTATE, self.netname, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG); }
  
                if(self.just_joined == FALSE) {
                        LogTeamchange(self.playerid, -1, 4);
@@@ -563,7 -564,7 +563,7 @@@ void FixPlayermodel(
                if(teamplay)
                {
                        string s;
 -                      s = Team_ColorNameLowerCase(self.team);
 +                      s = Team_ColorName_Lower(self.team);
                        if(s != "neutral")
                        {
                                defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s));
@@@ -695,7 -696,7 +695,7 @@@ void PutClientInServer (void
                spot = SelectSpawnPoint (FALSE);
                if(!spot)
                {
 -                      centerprint(self, "Sorry, no spawnpoints available!\nHope your team can fix it...");
 +                      Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_NOSPAWNS, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        return; // spawn failed
                }
  
  
                if(g_assault) {
                        if(self.team == assault_attacker_team)
 -                              centerprint(self, "You are attacking!");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_ATTACKING, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        else
 -                              centerprint(self, "You are defending!");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_DEFENDING, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                }
  
                target_voicescript_clear(self);
@@@ -1082,7 -1083,7 +1082,7 @@@ void ClientKill_Now_TeamChange(
                if(g_ca)
                        self.caplayer = 0;
                if(blockSpectators)
 -                      sprint(self, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
 +                      Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, NO_STR_ARG, NO_STR_ARG, autocvar_g_maxplayers_spectator_blocktime, NO_FL_ARG, NO_FL_ARG);
                PutObserverInServer();
        }
        else
@@@ -1233,28 -1234,28 +1233,28 @@@ void ClientKill_TeamChange (float targe
                        self.killindicator.colormod = '0 0 0';
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        if(self.killindicator.cnt > 0)
 -                              Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "^1Suicide in %d seconds", 1, self.killindicator.cnt);
 +                              Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SUICIDE, NO_STR_ARG, NO_STR_ARG, self.killindicator.cnt, NO_FL_ARG, NO_FL_ARG);
                }
                else if(targetteam == -1) // auto
                {
                        self.killindicator.colormod = '0 1 0';
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        if(self.killindicator.cnt > 0)
 -                              Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Changing team in %d seconds", 1, self.killindicator.cnt);
 +                              Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_AUTO, NO_STR_ARG, NO_STR_ARG, self.killindicator.cnt, NO_FL_ARG, NO_FL_ARG);
                }
                else if(targetteam == -2) // spectate
                {
                        self.killindicator.colormod = '0.5 0.5 0.5';
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        if(self.killindicator.cnt > 0)
 -                              Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Spectating in %d seconds", 1, self.killindicator.cnt);
 +                              Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SPECTATE, NO_STR_ARG, NO_STR_ARG, self.killindicator.cnt, NO_FL_ARG, NO_FL_ARG);
                }
                else
                {
 -                      self.killindicator.colormod = TeamColor(targetteam);
 +                      self.killindicator.colormod = Team_ColorRGB(targetteam);
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        if(self.killindicator.cnt > 0)
 -                              Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, strcat("Changing to ", ColoredTeamName(targetteam), " in %d seconds"), 1, self.killindicator.cnt);
 +                              Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, APP_TEAM_NUM_4(targetteam, CENTER_TEAMCHANGE_), NO_STR_ARG, NO_STR_ARG, self.killindicator.cnt, NO_FL_ARG, NO_FL_ARG);
                }
        }
  
@@@ -1296,7 -1297,7 +1296,7 @@@ void FixClientCvars(entity e
                stuffcmd(e, "cl_cmd settemp cl_movecliptokeyboard 2\n");
        if(autocvar_g_antilag == 3) // client side hitscan
                stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
 -      if(sv_gentle)
 +      if(autocvar_sv_gentle)
                stuffcmd(e, "cl_cmd settemp cl_gentle 1\n");
        /*
         * we no longer need to stuff this. Remove this comment block if you feel
@@@ -1345,6 -1346,7 +1345,6 @@@ ClientConnec
  Called when a client connects to the server
  =============
  */
 -string ColoredTeamName(float t);
  void DecodeLevelParms (void);
  //void dom_player_join_team(entity pl);
  void set_dom_state(entity e);
@@@ -1364,7 -1366,7 +1364,7 @@@ void ClientConnect (void
        DecodeLevelParms();
  
  #ifdef WATERMARK
 -      sprint(self, strcat("^4SVQC Build information: ^1", WATERMARK, "\n"));
 +      Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_WATERMARK, WATERMARK, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
  #endif
  
        self.classname = "player_joining";
        self.flags = FL_CLIENT;
        self.version_nagtime = time + 10 + random() * 10;
  
 +      if(self.netaddress == "local")
 +      {
 +              //print("^3server is local!\n");
 +
 +              if(server_is_local)
 +                      error("Multiple local clients???");
 +              else
 +                      server_is_local = TRUE;
 +      }
 +
        if(player_count<0)
        {
                dprint("BUG player count is lower than zero, this cannot happen!\n");
                {
                        switch(autocvar_g_campaign_forceteam)
                        {
 -                              case 1: self.team_forced = COLOR_TEAM1; break;
 -                              case 2: self.team_forced = COLOR_TEAM2; break;
 -                              case 3: self.team_forced = COLOR_TEAM3; break;
 -                              case 4: self.team_forced = COLOR_TEAM4; break;
 +                              case 1: self.team_forced = FL_TEAM_1; break;
 +                              case 2: self.team_forced = FL_TEAM_2; break;
 +                              case 3: self.team_forced = FL_TEAM_3; break;
 +                              case 4: self.team_forced = FL_TEAM_4; break;
                                default: self.team_forced = 0;
                        }
                }
        }
        else if(PlayerInIDList(self, autocvar_g_forced_team_red))
 -              self.team_forced = COLOR_TEAM1;
 +              self.team_forced = FL_TEAM_1;
        else if(PlayerInIDList(self, autocvar_g_forced_team_blue))
 -              self.team_forced = COLOR_TEAM2;
 +              self.team_forced = FL_TEAM_2;
        else if(PlayerInIDList(self, autocvar_g_forced_team_yellow))
 -              self.team_forced = COLOR_TEAM3;
 +              self.team_forced = FL_TEAM_3;
        else if(PlayerInIDList(self, autocvar_g_forced_team_pink))
 -              self.team_forced = COLOR_TEAM4;
 +              self.team_forced = FL_TEAM_4;
        else if(autocvar_g_forced_team_otherwise == "red")
 -              self.team_forced = COLOR_TEAM1;
 +              self.team_forced = FL_TEAM_1;
        else if(autocvar_g_forced_team_otherwise == "blue")
 -              self.team_forced = COLOR_TEAM2;
 +              self.team_forced = FL_TEAM_2;
        else if(autocvar_g_forced_team_otherwise == "yellow")
 -              self.team_forced = COLOR_TEAM3;
 +              self.team_forced = FL_TEAM_3;
        else if(autocvar_g_forced_team_otherwise == "pink")
 -              self.team_forced = COLOR_TEAM4;
 +              self.team_forced = FL_TEAM_4;
        else if(autocvar_g_forced_team_otherwise == "spectate")
                self.team_forced = -1;
        else if(autocvar_g_forced_team_otherwise == "spectator")
  
        self.netname_previous = strzone(self.netname);
  
 -      bprint("^4", self.netname, "^4 connected");
 -
 -      if(self.classname != "observer" && (g_domination || g_ctf))
 -              bprint(" and joined the ", ColoredTeamName(self.team));
 -
 -      bprint("\n");
 +      if((self.classname == STR_PLAYER && teamplay))
 +              Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_INFO, APP_TEAM_ENT_4(self, INFO_JOIN_CONNECT_TEAM_), self.netname, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
 +      else
 +              Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_INFO, INFO_JOIN_CONNECT, self.netname, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
  
        stuffcmd(self, strcat(clientstuff, "\n"));
        stuffcmd(self, "cl_particles_reloadeffects\n"); // TODO do we still need this?
        self.spectatortime = time;
        if(blockSpectators)
        {
 -              sprint(self, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
 +              Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, NO_STR_ARG, NO_STR_ARG, autocvar_g_maxplayers_spectator_blocktime, NO_FL_ARG, NO_FL_ARG);
        }
  
        self.jointime = time;
@@@ -1641,8 -1635,8 +1641,8 @@@ void ClientDisconnect (void
  
        if(autocvar_sv_eventlog)
                GameLogEcho(strcat(":part:", ftos(self.playerid)));
 -      bprint ("^4",self.netname);
 -      bprint ("^4 disconnected\n");
 +              
 +      Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_INFO, INFO_QUIT_DISCONNECT, self.netname, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
  
        DropAllRunes(self);
        MUTATOR_CALLHOOK(ClientDisconnect);
@@@ -1813,7 -1807,7 +1813,7 @@@ void player_powerups (void
                                self.alpha = default_player_alpha;
                                self.exteriorweaponentity.alpha = default_weapon_alpha;
                                self.items &~= IT_STRENGTH;
 -                              sprint(self, "^3Invisibility has worn off\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_POWERDOWN_INVISIBILITY, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                }
                else
                                self.alpha = g_minstagib_invis_alpha;
                                self.exteriorweaponentity.alpha = g_minstagib_invis_alpha;
                                self.items |= IT_STRENGTH;
 -                              sprint(self, "^3You are invisible\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_POWERUP_INVISIBILITY, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                }
  
                        if (time > self.invincible_finished)
                        {
                                self.items = self.items - (self.items & IT_INVINCIBLE);
 -                              sprint(self, "^3Speed has worn off\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_POWERDOWN_SPEED, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                }
                else
                        if (time < self.invincible_finished)
                        {
                                self.items = self.items | IT_INVINCIBLE;
 -                              sprint(self, "^3You are on speed\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_POWERUP_SPEED, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                }
        }
                        if (time > self.strength_finished)
                        {
                                self.items = self.items - (self.items & IT_STRENGTH);
 -                              sprint(self, "^3Strength has worn off\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_POWERDOWN_STRENGTH, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                }
                else
                        if (time < self.strength_finished)
                        {
                                self.items = self.items | IT_STRENGTH;
 -                              sprint(self, "^3Strength infuses your weapons with devastating power\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_POWERUP_STRENGTH, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                }
                if (self.items & IT_INVINCIBLE)
                        if (time > self.invincible_finished)
                        {
                                self.items = self.items - (self.items & IT_INVINCIBLE);
 -                              sprint(self, "^3Shield has worn off\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_POWERDOWN_SHIELD, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                }
                else
                        if (time < self.invincible_finished)
                        {
                                self.items = self.items | IT_INVINCIBLE;
 -                              sprint(self, "^3Shield surrounds you\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_POWERUP_SHIELD, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                }
                if (self.items & IT_SUPERWEAPON)
                        {
                                self.superweapons_finished = 0;
                                self.items = self.items - (self.items & IT_SUPERWEAPON);
 -                              sprint(self, "^3Superweapons have been lost\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_SUPERWEAPON_LOST, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                        else if (self.items & IT_UNLIMITED_SUPERWEAPONS)
                        {
                                {
                                        self.items = self.items - (self.items & IT_SUPERWEAPON);
                                        WEPSET_ANDNOT_EA(self, WEPBIT_SUPERWEAPONS);
 -                                      sprint(self, "^3Superweapons have broken down\n");
 +                                      Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_SUPERWEAPON_BROKEN, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                                }
                        }
                }
                        if (time < self.superweapons_finished || (self.items & IT_UNLIMITED_SUPERWEAPONS))
                        {
                                self.items = self.items | IT_SUPERWEAPON;
 -                              sprint(self, "^3You now have a superweapon\n");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_INFO, INFO_SUPERWEAPON_PICKUP, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        }
                        else
                        {
@@@ -2332,8 -2326,8 +2332,8 @@@ void LeaveSpectatorMode(
  
                        PutClientInServer();
  
 -                      if(self.classname == "player")
 -                              bprint ("^4", self.netname, "^4 is playing now\n");
 +                      if(self.classname == STR_PLAYER)
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_INFO, INFO_JOIN_PLAY, self.netname, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
  
                        if(!autocvar_g_campaign)
                        if (time < self.jointime + autocvar_welcome_message_time)
  
                        if (self.prevent_join_msgtime)
                        {
 -                              Send_CSQC_Centerprint_Generic_Expire(self, CPID_PREVENT_JOIN);
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                                self.prevent_join_msgtime = 0;
                        }
  
@@@ -2411,7 -2405,7 +2411,7 @@@ float nJoinAllowed(entity ignore) 
  void checkSpectatorBlock() {
        if(self.classname == "spectator" || self.classname == "observer") {
                if( time > (self.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) {
 -                      sprint(self, "^7You were kicked from the server because you are spectator and spectators aren't allowed at the moment.\n");
 +                      Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_QUIT_KICK_SPECTATING, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                        dropclient(self);
                }
        }
@@@ -2598,7 -2592,7 +2598,7 @@@ void PlayerPreThink (void
                                        {
                                                // notify release users if connecting to git
                                                dprint("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
 -                                              sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
 +                                              Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, self.cvar_g_xonoticversion, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                                        }
                                        else
                                        {
                                                {
                                                        // give users new version
                                                        dprint("^1NOTE^7 to ", self.netname, "^7 - ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n");
 -                                                      sprint(self, strcat("\{1}^1NOTE: ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n"));
 +                                                      Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, self.cvar_g_xonoticversion, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                                                }
                                                else if(r > 0)
                                                {
                                                        // notify users about old server version
                                                        print("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
 -                                                      sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
 +                                                      Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, self.cvar_g_xonoticversion, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                                                }
                                        }
                                }
        // GOD MODE info
        if(!(self.flags & FL_GODMODE)) if(self.max_armorvalue)
        {
 -              sprint(self, strcat("godmode saved you ", ftos(self.max_armorvalue), " units of damage, cheater!\n"));
 +              Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_GODMODE_OFF, NO_STR_ARG, NO_STR_ARG, self.max_armorvalue, NO_FL_ARG, NO_FL_ARG);
                self.max_armorvalue = 0;
        }
  
                                //sprint(self, "distance: ", ftos(self.lms_traveled_distance), "\n");
                                if(self.lms_traveled_distance < autocvar_g_lms_campcheck_distance)
                                {
 -                                      centerprint(self, autocvar_g_lms_campcheck_message);
 +                                      Send_Notification_Legacy_Wrapper(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_CAMPCHECK, NO_STR_ARG, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                                        // FIXME KadaverJack: gibbing player here causes playermodel to bounce around, instead of eye.md3
                                        // I wasn't able to find out WHY that happens, so I put a workaround in place that shall prevent players from being gibbed :(
                                        Damage(self, self, self, bound(0, autocvar_g_lms_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP, self.origin, '0 0 0');
  
                self.prevorigin = self.origin;
  
-               if (!self.vehicle)
-               if (((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss) && self.animstate_startframe != self.anim_melee_x && !self.freezetag_frozen) // prevent crouching if using melee attack
+               float do_crouch = self.BUTTON_CROUCH;
+               if(self.hook.state)
+                       do_crouch = 0;
+               if(self.health <= g_bloodloss)
+                       do_crouch = 1;
+               if(self.vehicle)
+                       do_crouch = 0;
+               if(self.freezetag_frozen)
+                       do_crouch = 0;
+               if(self.weapon == WEP_SHOTGUN && self.weaponentity.wframe == WFRAME_FIRE2 && time < self.weapon_nextthink)
+                       do_crouch = 0;
+               if (do_crouch)
                {
                        if (!self.crouch)
                        {
@@@ -2984,7 -2989,11 +2995,7 @@@ void PlayerPostThink (void
        {
                if (time - self.parm_idlesince < 1) // instead of (time == self.parm_idlesince) to support sv_maxidle <= 10
                {
 -                      if(self.idlekick_lasttimeleft)
 -                      {
 -                              Send_CSQC_Centerprint_Generic_Expire(self, CPID_DISCONNECT_IDLING);
 -                              self.idlekick_lasttimeleft = 0;
 -                      }
 +                      if(self.idlekick_lasttimeleft) { self.idlekick_lasttimeleft = 0; }
                }
                else
                {
                        if(timeleft == min(10, sv_maxidle - 1)) // - 1 to support sv_maxidle <= 10
                        {
                                if(!self.idlekick_lasttimeleft)
 -                                      Send_CSQC_Centerprint_Generic(self, CPID_DISCONNECT_IDLING, "^3Stop idling!\n^3Disconnecting in %d seconds...", 1, timeleft);
 +                                      Send_Notification_Legacy_Wrapper(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_DISCONNECT_IDLING, NO_STR_ARG, NO_STR_ARG, timeleft, NO_FL_ARG, NO_FL_ARG);
                        }
                        if(timeleft <= 0)
                        {
 -                              bprint("^3", self.netname, "^3 was kicked for idling.\n");
 -                              AnnounceTo(self, "terminated");
 +                              Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_INFO, INFO_QUIT_KICK_IDLING, self.netname, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
                                dropclient(self);
                                return;
                        }
index 165783781069d9457f367bde54e69ae0ba21f616,03347a9c86d2cb718abae96a77c1eb855feb38a6..10ca2ccab33c23c9586f505af261300474b5fd41
@@@ -161,16 -161,20 +161,20 @@@ void CopyBody(float keepvelocity
        self.effects = oldself.effects;
        self.glowmod = oldself.glowmod;
        self.event_damage = oldself.event_damage;
-       self.animstate_startframe = oldself.animstate_startframe;
-       self.animstate_numframes = oldself.animstate_numframes;
-       self.animstate_framerate = oldself.animstate_framerate;
-       self.animstate_starttime = oldself.animstate_starttime;
-       self.animstate_endtime = oldself.animstate_endtime;
-       self.animstate_override = oldself.animstate_override;
-       self.animstate_looping = oldself.animstate_looping;
+       self.anim_state = oldself.anim_state;
+       self.anim_time = oldself.anim_time;
+       self.anim_lower_action = oldself.anim_lower_action;
+       self.anim_lower_time = oldself.anim_lower_time;
+       self.anim_upper_action = oldself.anim_upper_action;
+       self.anim_upper_time = oldself.anim_upper_time;
+       self.anim_implicit_state = oldself.anim_implicit_state;
+       self.anim_implicit_time = oldself.anim_implicit_time;
+       self.anim_lower_implicit_action = oldself.anim_lower_implicit_action;
+       self.anim_lower_implicit_time = oldself.anim_lower_implicit_time;
+       self.anim_upper_implicit_action = oldself.anim_upper_implicit_action;
+       self.anim_upper_implicit_time = oldself.anim_upper_implicit_time;
        self.dphitcontentsmask = oldself.dphitcontentsmask;
        self.death_time = oldself.death_time;
-       self.frame = oldself.frame;
        self.pain_finished = oldself.pain_finished;
        self.health = oldself.health;
        self.armorvalue = oldself.armorvalue;
        self.CopyBody_think = oldself.think;
        self.nextthink = time;
        self.think = CopyBody_Think;
+       // "bake" the current animation frame for clones (they don't get clientside animation)
+       animdecide_setframes(self, FALSE, frame, frame1time, frame2, frame2time);
  
        self = oldself;
  }
@@@ -225,132 -231,38 +231,38 @@@ float player_getspecies(
  
  void player_setupanimsformodel()
  {
-       // defaults for legacy .zym models without animinfo files
-       self.anim_die1 = animfixfps(self, '0 1 0.5'); // 2 seconds
-       self.anim_die2 = animfixfps(self, '1 1 0.5'); // 2 seconds
-       self.anim_draw = animfixfps(self, '2 1 3');
-       // self.anim_duck = '3 1 100'; // This anim is broken, use slot 3 as a new free slot in the future ;)
-       self.anim_duckwalk = animfixfps(self, '4 1 1');
-       self.anim_duckjump = '5 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it
-       self.anim_duckidle = animfixfps(self, '6 1 1');
-       self.anim_idle = animfixfps(self, '7 1 1');
-       self.anim_jump = '8 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it
-       self.anim_pain1 = animfixfps(self, '9 1 2'); // 0.5 seconds
-       self.anim_pain2 = animfixfps(self, '10 1 2'); // 0.5 seconds
-       self.anim_shoot = animfixfps(self, '11 1 5'); // analyze models and set framerate
-       self.anim_taunt = animfixfps(self, '12 1 0.33');
-       self.anim_run = animfixfps(self, '13 1 1');
-       self.anim_runbackwards = animfixfps(self, '14 1 1');
-       self.anim_strafeleft = animfixfps(self, '15 1 1');
-       self.anim_straferight = animfixfps(self, '16 1 1');
-       //self.anim_dead1 = animfixfps(self, '17 1 1');
-       //self.anim_dead2 = animfixfps(self, '18 1 1');
-       self.anim_forwardright = animfixfps(self, '19 1 1');
-       self.anim_forwardleft = animfixfps(self, '20 1 1');
-       self.anim_backright = animfixfps(self, '21 1 1');
-       self.anim_backleft  = animfixfps(self, '22 1 1');
-       self.anim_melee = animfixfps(self, '23 1 1');
-       self.anim_duckwalkbackwards = animfixfps(self, '24 1 1');
-       self.anim_duckwalkstrafeleft = animfixfps(self, '25 1 1');
-       self.anim_duckwalkstraferight = animfixfps(self, '26 1 1');
-       self.anim_duckwalkforwardright = animfixfps(self, '27 1 1');
-       self.anim_duckwalkforwardleft = animfixfps(self, '28 1 1');
-       self.anim_duckwalkbackright = animfixfps(self, '29 1 1');
-       self.anim_duckwalkbackleft  = animfixfps(self, '30 1 1');
-       // TODO introspect models for finding right "fps" value (1/duration)
-       // reset animstate now
-       setanim(self, self.anim_idle, TRUE, FALSE, TRUE);
+       // load animation info
+       animdecide_init(self);
+       animdecide_setstate(self, 0, FALSE);
  }
  
  void player_anim (void)
  {
-       updateanim(self);
-       if (self.weaponentity)
-               updateanim(self.weaponentity);
-       if (self.deadflag != DEAD_NO)
-               return;
-       if (!self.animstate_override)
-       {
-               if (self.freezetag_frozen)
-                       setanim(self, self.anim_idle, TRUE, FALSE, FALSE);
-               else if (!(self.flags & FL_ONGROUND) || self.BUTTON_JUMP)
-               {
-                       if (self.crouch)
-                       {
-                               if (self.animstate_startframe != self.anim_duckjump_x) // don't perform another trace if already playing the crouch jump anim
-                               {
-                                       traceline(self.origin + '0 0 1' * PL_CROUCH_MIN_z, self.origin + '0 0 1' * (PL_CROUCH_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self);
-                                       if(!trace_startsolid && trace_fraction == 1 || !(self.animstate_startframe == self.anim_duckwalk_x || self.animstate_startframe == self.anim_duckidle_x)) // don't get stuck on non-crouch anims
-                                       {
-                                               setanim(self, self.anim_duckjump, FALSE, TRUE, self.restart_jump);
-                                               self.restart_jump = FALSE;
-                                       }
-                               }
-                       }
-                       else
-                       {
-                 if (self.animstate_startframe != self.anim_jump_x) // don't perform another trace if already playing the jump anim
-                 {
-                     traceline(self.origin + '0 0 1' * PL_MIN_z, self.origin + '0 0 1' * (PL_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self);
-                     if(!trace_startsolid && trace_fraction == 1 || self.animstate_startframe == self.anim_idle_x || (self.animstate_startframe == self.anim_melee_x && time - self.animstate_starttime >= 21/20)) // don't get stuck on idle animation in midair, nor melee after it finished
-                     {
-                         setanim(self, self.anim_jump, FALSE, TRUE, self.restart_jump);
-                         self.restart_jump = FALSE;
-                     }
-                 }
-                       }
-               }
-               else if (self.crouch)
-               {
-                       if (self.movement_x > 0 && self.movement_y == 0)
-                               setanim(self, self.anim_duckwalk, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y == 0)
-                               setanim(self, self.anim_duckwalkbackwards, TRUE, FALSE, FALSE);
-                       else if (self.movement_x == 0 && self.movement_y > 0)
-                               setanim(self, self.anim_duckwalkstraferight, TRUE, FALSE, FALSE);
-                       else if (self.movement_x == 0 && self.movement_y < 0)
-                               setanim(self, self.anim_duckwalkstrafeleft, TRUE, FALSE, FALSE);
-                       else if (self.movement_x > 0 && self.movement_y > 0)
-                               setanim(self, self.anim_duckwalkforwardright, TRUE, FALSE, FALSE);
-                       else if (self.movement_x > 0 && self.movement_y < 0)
-                               setanim(self, self.anim_duckwalkforwardleft, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y > 0)
-                               setanim(self, self.anim_duckwalkbackright, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y < 0)
-                               setanim(self, self.anim_duckwalkbackleft, TRUE, FALSE, FALSE);
-                       else
-                               setanim(self, self.anim_duckidle, TRUE, FALSE, FALSE);
-               }
-               else if ((self.movement_x * self.movement_x + self.movement_y * self.movement_y) > 20)
-               {
-                       if (self.movement_x > 0 && self.movement_y == 0)
-                               setanim(self, self.anim_run, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y == 0)
-                               setanim(self, self.anim_runbackwards, TRUE, FALSE, FALSE);
-                       else if (self.movement_x == 0 && self.movement_y > 0)
-                               setanim(self, self.anim_straferight, TRUE, FALSE, FALSE);
-                       else if (self.movement_x == 0 && self.movement_y < 0)
-                               setanim(self, self.anim_strafeleft, TRUE, FALSE, FALSE);
-                       else if (self.movement_x > 0 && self.movement_y > 0)
-                               setanim(self, self.anim_forwardright, TRUE, FALSE, FALSE);
-                       else if (self.movement_x > 0 && self.movement_y < 0)
-                               setanim(self, self.anim_forwardleft, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y > 0)
-                               setanim(self, self.anim_backright, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y < 0)
-                               setanim(self, self.anim_backleft, TRUE, FALSE, FALSE);
-                       else
-                               setanim(self, self.anim_run, TRUE, FALSE, FALSE);
-               }
+       float deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
+       if(self.deadflag && !deadbits)
+               if(random() < 0.5)
+                       deadbits = ANIMSTATE_DEAD1;
                else
-                       setanim(self, self.anim_idle, TRUE, FALSE, FALSE);
-       }
+                       deadbits = ANIMSTATE_DEAD2;
+       float animbits = deadbits;
+       if(self.freezetag_frozen)
+               animbits |= ANIMSTATE_FROZEN;
+       if(self.crouch)
+               animbits |= ANIMSTATE_DUCK;
+       animdecide_setstate(self, animbits, FALSE);
+       animdecide_setimplicitstate(self, (self.flags & FL_ONGROUND));
+ #ifndef NO_LEGACY_NETWORKING
+       if(!self.iscsqcmodel)
+               animdecide_setframes(self, FALSE, frame, frame1time, frame2, frame2time);
+ #endif
  
        if (self.weaponentity)
-       if (!self.weaponentity.animstate_override)
-               setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE);
+       {
+               updateanim(self.weaponentity);
+               if (!self.weaponentity.animstate_override)
+                       setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE);
+       }
  }
  
  void SpawnThrownWeapon (vector org, float w)
@@@ -560,15 -472,15 +472,15 @@@ void PlayerDamage (entity inflictor, en
                        {
                                self.pain_finished = time + 0.5;        //Supajoe
  
 -                              if(sv_gentle < 1) {
 +                              if(autocvar_sv_gentle < 1) {
                                        if(self.classname != "body") // pain anim is BORKED on our ZYMs, FIXME remove this once we have good models
                                        {
                                                if (!self.animstate_override)
                                                {
                                                        if (random() > 0.5)
-                                                               setanim(self, self.anim_pain1, FALSE, TRUE, TRUE);
+                                                               animdecide_setaction(self, ANIMACTION_PAIN1, TRUE);
                                                        else
-                                                               setanim(self, self.anim_pain2, FALSE, TRUE, TRUE);
+                                                               animdecide_setaction(self, ANIMACTION_PAIN2, TRUE);
                                                }
                                        }
  
                if(valid_damage_for_weaponstats)
                        WeaponStats_LogKill(awep, abot, self.weapon, vbot);
  
 -              if(sv_gentle < 1) // TODO make a "gentle" version?
 +              if(autocvar_sv_gentle < 1) // TODO make a "gentle" version?
                if(sound_allowed(MSG_BROADCAST, attacker))
                {
                        if(deathtype == DEATH_DROWN)
                        self.respawn_countdown = -1; // do not count down
                self.death_time = time;
                if (random() < 0.5)
-                       setanim(self, self.anim_die1, FALSE, TRUE, TRUE);
+                       animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD1, TRUE);
                else
-                       setanim(self, self.anim_die2, FALSE, TRUE, TRUE);
+                       animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD2, TRUE);
                if (self.maxs_z > 5)
                {
                        self.maxs_z = 5;
                // set up to fade out later
                SUB_SetFade (self, time + 6 + random (), 1);
  
 -              if(sv_gentle > 0 || autocvar_ekg) {
 +              if(autocvar_sv_gentle > 0 || autocvar_ekg) {
                        // remove corpse
                        PlayerCorpseDamage (inflictor, attacker, autocvar_sv_gibhealth+1.0, deathtype, hitloc, force);
                }
@@@ -1026,18 -938,17 +938,18 @@@ float Say(entity source, float teamsay
                        if(sourcecmsgstr != "" && !privatesay)
                                centerprint(source, sourcecmsgstr);
                }
 -              else if(privatesay) // private message, between 2 people only, not sent to server console
 +              else if(privatesay) // private message, between 2 people only
                {
                        sprint(source, sourcemsgstr);
                        sprint(privatesay, msgstr);
 +                      if not(autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled
                        if(cmsgstr != "")
                                centerprint(privatesay, cmsgstr);
                }
                else if(teamsay > 0) // team message, only sent to team mates
                {
                        sprint(source, sourcemsgstr);
 -                      //print(msgstr); // send to server console too
 +                      dedicated_print(msgstr); // send to server console too
                        if(sourcecmsgstr != "")
                                centerprint(source, sourcecmsgstr);
                        FOR_EACH_REALPLAYER(head) if(head.team == source.team)
                else if(teamsay < 0) // spectator message, only sent to spectators
                {
                        sprint(source, sourcemsgstr);
 -                      //print(msgstr); // send to server console too
 +                      dedicated_print(msgstr); // send to server console too
                        FOR_EACH_REALCLIENT(head) if(head.classname != "player")
                                if(head != source)
                                        sprint(head, msgstr);
                else if(sourcemsgstr != msgstr) // trimmed/server fixed message, sent to all players
                {
                        sprint(source, sourcemsgstr);
 -                      //print(msgstr); // send to server console too
 +                      dedicated_print(msgstr); // send to server console too
                        FOR_EACH_REALCLIENT(head)
                                if(head != source)
                                        sprint(head, msgstr);
@@@ -1241,7 -1152,7 +1153,7 @@@ void FakeGlobalSound(string sample, flo
                                break;
                        if(!sv_taunt)
                                break;
 -                      if(sv_gentle)
 +                      if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        msg_entity = self;
                case VOICETYPE_TAUNT:
                        if(self.classname == "player")
                                if(self.deadflag == DEAD_NO)
-                                       setanim(self, self.anim_taunt, FALSE, TRUE, TRUE);
+                                       animdecide_setaction(self, ANIMACTION_TAUNT, TRUE);
                        if(!sv_taunt)
                                break;
 -                      if(sv_gentle)
 +                      if(autocvar_sv_gentle)
                                break;
                        msg_entity = self;
                        if (msg_entity.cvar_cl_voice_directional >= 1)
@@@ -1338,7 -1249,7 +1250,7 @@@ void GlobalSound(string sample, float c
                                break;
                        if(!sv_taunt)
                                break;
 -                      if(sv_gentle)
 +                      if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        FOR_EACH_REALCLIENT(msg_entity)
                case VOICETYPE_TAUNT:
                        if(self.classname == "player")
                                if(self.deadflag == DEAD_NO)
-                                       setanim(self, self.anim_taunt, FALSE, TRUE, TRUE);
+                                       animdecide_setaction(self, ANIMACTION_TAUNT, TRUE);
                        if(!sv_taunt)
                                break;
 -                      if(sv_gentle)
 +                      if(autocvar_sv_gentle)
                                break;
                        FOR_EACH_REALCLIENT(msg_entity)
                        {
@@@ -1404,8 -1315,14 +1316,8 @@@ void VoiceMessage(string type, string m
                FakeGlobalSound(self.sample, CH_VOICE, voicetype);
  }
  
 -void MoveToTeam(entity client, float team_colour, float type, float show_message)
 +void MoveToTeam(entity client, float team_colour, float type)
  {
 -//    show_message
 -//    0 (00) automove centerprint, admin message
 -//    1 (01) automove centerprint, no admin message
 -//    2 (10) no centerprint, admin message
 -//    3 (11) no centerprint, no admin message
 -
        float lockteams_backup;
  
        lockteams_backup = lockteams;  // backup any team lock
  
        TeamchangeFrags(client);  // move the players frags
        SetPlayerColors(client, team_colour - 1);  // set the players colour
 -      Damage(client, client, client, 100000, ((show_message & 2) ? DEATH_QUIET : DEATH_AUTOTEAMCHANGE), client.origin, '0 0 0');  // kill the player
 +      Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE, client.origin, '0 0 0');  // kill the player
  
        lockteams = lockteams_backup;  // restore the team lock
  
        LogTeamchange(client.playerid, client.team, type);
 -
 -      if not(show_message & 1) // admin message
 -              sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: You have been moved to the ", Team_ColorNameLowerCase(team_colour), " team\n"));  // send a chat message
 -
 -      bprint(strcat(client.netname, " joined the ", ColoredTeamName(client.team), "\n"));
  }
diff --combined qcsrc/server/defs.qh
index 60191b5bf38f00935be98358e1b09bffd944abc1,ca01caf9ca3098c855a0d716c01fdba697488ad4..58fb8a086972201443f5a9c8df68156c771c0d2e
@@@ -39,6 -39,7 +39,6 @@@ float g_pickup_respawntimejitter_poweru
  float g_jetpack;
  
  float sv_clones;
 -float sv_gentle;
  float sv_foginterval;
  
  entity        activator;
@@@ -57,8 -58,6 +57,8 @@@ float team1_score, team2_score, team3_s
  
  float maxclients;
  
 +float server_is_local; // innocent until proven guilty by ClientConnect() in cl_client.qc
 +
  // Fields
  
  .void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) event_damage;
  .float animstate_override;
  .float animstate_looping;
  
- // player animation data for this model
- // each vector is as follows:
- // _x = startframe
- // _y = numframes
- // _z = framerate
- .vector anim_die1; // player dies
- .vector anim_die2; // player dies differently
- .vector anim_draw; // player pulls out a weapon
- // .vector anim_duck; // player crouches (from idle to duckidle)
- .vector anim_duckwalk; // player walking while crouching
- .vector anim_duckjump; // player jumping from a crouch
- .vector anim_duckidle; // player idling while crouching
- .vector anim_idle; // player standing
- .vector anim_jump; // player jump
- .vector anim_pain1; // player flinches from pain
- .vector anim_pain2; // player flinches from pain, differently
- .vector anim_shoot; // player shoots
- .vector anim_taunt; // player taunts others (FIXME: no code references this)
- .vector anim_run; // player running forward
- .vector anim_runbackwards; // player running backward
- .vector anim_strafeleft; // player shuffling left quickly
- .vector anim_straferight; // player shuffling right quickly
- //.vector anim_dead1; // player dead (must be identical to last frame of die1)
- //.vector anim_dead2; // player dead (must be identical to last frame of die2)
- .vector anim_forwardright; // player running forward and right
- .vector anim_forwardleft; // player running forward and left
- .vector anim_backright; // player running backward and right
- .vector anim_backleft; // player running back and left
- .vector anim_melee; // player doing the melee action
- .vector anim_duck; // player doing the melee action
- .vector anim_duckwalkbackwards;
- .vector anim_duckwalkstrafeleft;
- .vector anim_duckwalkstraferight;
- .vector anim_duckwalkforwardright;
- .vector anim_duckwalkforwardleft;
- .vector anim_duckwalkbackright;
- .vector anim_duckwalkbackleft;
  // weapon animation vectors:
  .vector anim_fire1;
  .vector anim_fire2;
diff --combined qcsrc/server/progs.src
index 71f088ba5aef0c7538300f2e10c2b096af5405d6,db93116109612dd97660f35306509908f43df41c..dcd144d31634b3474985f63f917c564dd02e41dd
@@@ -13,11 -13,8 +13,11 @@@ sys-post.q
  ../warpzonelib/server.qh
  
  ../common/constants.qh
 +../common/teams.qh
  ../common/util.qh
  ../common/items.qh
 +../common/deathtypes.qh
 +../common/notifications.qh
  ../common/explosion_equation.qh
  ../common/urllib.qh
  ../common/command/markup.qh
@@@ -25,6 -22,7 +25,7 @@@
  ../common/command/generic.qh
  ../common/command/shared_defs.qh
  ../common/net_notice.qh
+ ../common/animdecide.qh
  
  autocvars.qh
  constants.qh
@@@ -235,7 -233,7 +236,8 @@@ mutators/mutator_superspec.q
  ../warpzonelib/util_server.qc
  ../warpzonelib/server.qc
  
+ ../common/animdecide.qc
  ../common/util.qc
 +../common/notifications.qc
  
  ../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail
index 802118732b3765144ef46b0b45f353c841a38ce4,082e454ace2de00516090a35270868346ba7a8c8..20aac867e91ae0f3b856be81fecc325b96f14180
@@@ -437,13 -437,8 +437,8 @@@ float w_electro(float req
                {
                        if(autocvar_g_balance_electro_lightning)
                                if(self.BUTTON_ATCK_prev)
-                               {
-                                       // prolong the animtime while the gun is being fired
-                                       if(self.animstate_startframe == self.anim_shoot_x && self.animstate_numframes == self.anim_shoot_y)
-                                               weapon_thinkf(WFRAME_DONTCHANGE, autocvar_g_balance_electro_primary_animtime, w_ready);
-                                       else
-                                               weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready);
-                               }
+                                       weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready);
                        if (weapon_prepareattack(0, (autocvar_g_balance_electro_lightning ? 0 : autocvar_g_balance_electro_primary_refire)))
                        {
                                if(autocvar_g_balance_electro_lightning)
        {
                W_Reload(min(autocvar_g_balance_electro_primary_ammo, autocvar_g_balance_electro_secondary_ammo), autocvar_g_balance_electro_reload_ammo, autocvar_g_balance_electro_reload_time, "weapons/reload.wav");
        }
 +      else if (req == WR_SUICIDEMESSAGE)
 +      {
 +              if(w_deathtype & HITTYPE_SECONDARY)
 +                      return WEAPON_ELECTRO_SUICIDE_ORBS;
 +              else
 +                      return WEAPON_ELECTRO_SUICIDE_BOLT;
 +      }
 +      else if (req == WR_KILLMESSAGE)
 +      {
 +              if(w_deathtype & HITTYPE_SECONDARY)
 +              {
 +                      return WEAPON_ELECTRO_MURDER_ORBS;
 +              }
 +              else
 +              {
 +                      if(w_deathtype & HITTYPE_BOUNCE)
 +                              return WEAPON_ELECTRO_MURDER_COMBO;
 +                      else
 +                              return WEAPON_ELECTRO_MURDER_BOLT;
 +              }
 +      }
        return TRUE;
  }
  #endif
@@@ -607,6 -581,32 +602,6 @@@ float w_electro(float req
                precache_sound("weapons/electro_impact.wav");
                precache_sound("weapons/electro_impact_combo.wav");
        }
 -      else if (req == WR_SUICIDEMESSAGE)
 -      {
 -              if(w_deathtype & HITTYPE_SECONDARY)
 -                      w_deathtypestring = _("%s could not remember where they put their electro plasma");
 -              else
 -                      w_deathtypestring = _("%s played with electro plasma");
 -      }
 -      else if (req == WR_KILLMESSAGE)
 -      {
 -              if(w_deathtype & HITTYPE_SECONDARY)
 -              {
 -                      if(w_deathtype & HITTYPE_SPLASH) // unchecked: BOUNCE
 -                              w_deathtypestring = _("%s just noticed %s's electro plasma");
 -                      else // unchecked: BOUNCE
 -                              w_deathtypestring = _("%s got in touch with %s's electro plasma");
 -              }
 -              else
 -              {
 -                      if(w_deathtype & HITTYPE_BOUNCE) // combo
 -                              w_deathtypestring = _("%s felt the electrifying air of %s's electro combo");
 -                      else if(w_deathtype & HITTYPE_SPLASH)
 -                              w_deathtypestring = _("%s got too close to %s's blue electro bolt");
 -                      else
 -                              w_deathtypestring = _("%s was blasted by %s's blue electro bolt");
 -              }
 -      }
        return TRUE;
  }
  #endif
index 7d175e55ba55249b94f1df02afaabd951082342b,fdfa6af382c27a48347689016cc92a161cb9c36d..350d6e01578fb1f46cf8f43c121e22318ba61a84
@@@ -199,7 -199,7 +199,7 @@@ float w_shotgun(float req
                        }
                }
                if (self.clip_load >= 0) // we are not currently reloading
-               if (!self.crouch) // we are not currently crouching; this fixes an exploit where your melee anim is not visible, and besides wouldn't make much sense
+               if (!self.crouch) // no crouchmelee please
                if (self.BUTTON_ATCK2 && autocvar_g_balance_shotgun_secondary)
                if (weapon_prepareattack(1, autocvar_g_balance_shotgun_secondary_refire))
                {
        {
                W_Reload(autocvar_g_balance_shotgun_primary_ammo, autocvar_g_balance_shotgun_reload_ammo, autocvar_g_balance_shotgun_reload_time, "weapons/reload.wav");
        }
 +      else if (req == WR_SUICIDEMESSAGE)
 +      {
 +              return WEAPON_THINKING_WITH_PORTALS;
 +      }
 +      else if (req == WR_KILLMESSAGE)
 +      {
 +              if(w_deathtype & HITTYPE_SECONDARY)
 +                      return WEAPON_SHOTGUN_MURDER_SLAP;
 +              else
 +                      return WEAPON_SHOTGUN_MURDER;
 +      }
        return TRUE;
  }
  #endif
@@@ -278,6 -267,15 +278,6 @@@ float w_shotgun(float req
                precache_sound("weapons/ric2.wav");
                precache_sound("weapons/ric3.wav");
        }
 -      else if (req == WR_SUICIDEMESSAGE)
 -              w_deathtypestring = _("%s is now thinking with portals");
 -      else if (req == WR_KILLMESSAGE)
 -      {
 -              if(w_deathtype & HITTYPE_SECONDARY)
 -                      w_deathtypestring = _("%2$s slapped %1$s around a bit with a large shotgun");
 -              else
 -                      w_deathtypestring = _("%s was gunned down with a shotgun by %s");
 -      }
        return TRUE;
  }
  #endif