]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into divVerent/csqcmodel
authorRudolf Polzer <divverent@alientrap.org>
Sun, 11 Dec 2011 18:44:10 +0000 (19:44 +0100)
committerRudolf Polzer <divverent@alientrap.org>
Sun, 11 Dec 2011 18:44:10 +0000 (19:44 +0100)
34 files changed:
defaultXonotic.cfg
qcsrc/client/Main.qc
qcsrc/client/View.qc
qcsrc/client/autocvars.qh
qcsrc/client/csqcmodel_hooks.qc [new file with mode: 0644]
qcsrc/client/gibs.qc
qcsrc/client/interpolate.qc [deleted file]
qcsrc/client/interpolate.qh [deleted file]
qcsrc/client/miscfunctions.qc
qcsrc/client/progs.src
qcsrc/common/constants.qh
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/csqcmodel/cl_model.qc [new file with mode: 0644]
qcsrc/csqcmodel/cl_model.qh [new file with mode: 0644]
qcsrc/csqcmodel/cl_player.qc [new file with mode: 0644]
qcsrc/csqcmodel/cl_player.qh [new file with mode: 0644]
qcsrc/csqcmodel/common.qh [new file with mode: 0644]
qcsrc/csqcmodel/interpolate.qc [new file with mode: 0644]
qcsrc/csqcmodel/interpolate.qh [new file with mode: 0644]
qcsrc/csqcmodel/settings.qh [new file with mode: 0644]
qcsrc/csqcmodel/sv_model.qc [new file with mode: 0644]
qcsrc/csqcmodel/sv_model.qh [new file with mode: 0644]
qcsrc/server/autocvars.qh
qcsrc/server/cheats.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/cl_weaponsystem.qc
qcsrc/server/constants.qh
qcsrc/server/defs.qh
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/portals.qc
qcsrc/server/progs.src

index 1044e8abfa4a745a370c2345346b28320251b1c1..cea643b1688f8f4022bc97ef461bf53a4d5674ee 100644 (file)
@@ -1805,11 +1805,6 @@ set menu_updatecheck 1
 set bot_navigation_ignoreplayers 0 // FIXME remove this once the issue is solved
 set bot_sound_monopoly 0 "when enabled, only bots can make any noise"
 
-// broken, sorry (cannot handle weapon attachment properly)
-//seta cl_forceplayermodels 0 "force all players to look like you; WARNING: animations can look very bad with this"
-//seta cl_forceplayermodelsfromxonotic 0 "force models coming from xonotic; WARNING: animations can look very bad with this"
-//set sv_clforceplayermodels 1 "allow clients to use cl_forcemodels"
-
 set sv_loddistance1 1024
 set sv_loddistance2 4096
 seta cl_playerdetailreduction 0        "the higher, the less detailed player models are displayed (LOD)"
@@ -1919,6 +1914,9 @@ set developer_shtest 0 "experimental speedhack detection"
 set waypoint_benchmark 0 "quit after waypoint loading to benchmark bot navigation code"
 set g_debug_bot_commands 0 "print scripted bot commands before executing"
 set g_debug_defaultsounds 0 "always use default sounds"
+set sv_use_csqc_players 0 "set to 1 to network players to CSQC (not compatible to old clients)"
+set cl_forceplayermodels 0 "set to 1 to make everyone look like yourself (requires server to have sv_use_csqc_players 1)"
+set cl_precacheplayermodels 0 "TODO please check if this needs to be 1 or if precaching a model the server already requested is fast enough to do it at runtime"
 
 // debug cvars for keyhunt attaching
 set _angles "0 0 0"
index 2252f6f61cec427d69ebe63d9a26eca8394955f3..8c7c6bc0c7a47509695dd131d48682dca0fdf4f8 100644 (file)
@@ -41,6 +41,55 @@ void menu_sub_null()
 float __engine_check;
 #endif
 
+void precache_playermodel(string m)
+{
+       string f;
+
+       if(substring(m, -9,5) == "_lod1")
+               return;
+       if(substring(m, -9,5) == "_lod2")
+               return;
+       precache_model(m);
+       f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
+       if(fexists(f))
+               precache_model(f);
+       f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1));
+       if(fexists(f))
+               precache_model(f);
+
+       /*
+       float globhandle, i, n;
+       globhandle = search_begin(strcat(m, "_*.sounds"), TRUE, FALSE);
+       if (globhandle < 0)
+               return;
+       n = search_getsize(globhandle);
+       for (i = 0; i < n; ++i)
+       {
+               //print(search_getfilename(globhandle, i), "\n");
+               f = search_getfilename(globhandle, i);
+               PrecachePlayerSounds(f);
+       }
+       search_end(globhandle);
+       */
+}
+void precache_all_playermodels(string pattern)
+{
+       float globhandle, i, n;
+       string f;
+
+       globhandle = search_begin(pattern, TRUE, FALSE);
+       if (globhandle < 0)
+               return;
+       n = search_getsize(globhandle);
+       for (i = 0; i < n; ++i)
+       {
+               //print(search_getfilename(globhandle, i), "\n");
+               f = search_getfilename(globhandle, i);
+               precache_playermodel(f);
+       }
+       search_end(globhandle);
+}
+
 string forcefog;
 void WaypointSprite_Load();
 void CSQC_Init(void)
@@ -135,6 +184,15 @@ void CSQC_Init(void)
        precache_model("null");
        precache_sound("misc/hit.wav");
        precache_sound("misc/typehit.wav");
+       if (autocvar_cl_precacheplayermodels)
+       {
+               precache_all_playermodels("models/player/*.zym");
+               precache_all_playermodels("models/player/*.dpm");
+               precache_all_playermodels("models/player/*.md3");
+               precache_all_playermodels("models/player/*.psk");
+               precache_all_playermodels("models/player/*.iqm");
+       }
+
        Projectile_Precache();
        Hook_Precache();
        GibSplash_Precache();
@@ -1016,6 +1074,7 @@ void CSQC_Ent_Update(float bIsNewEntity)
                case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break;
                case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
                case ENT_CLIENT_TURRET: ent_turret(); break; 
+               case ENT_CLIENT_MODEL: CSQCModel_Read(); break; 
                default:
                        //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype));
                        error(sprintf(_("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n"), self.enttype, num_for_edict(self), self.classname));
index d9f6df7ee77281fdf2e52b650d25680dec5f72a9..ac2f12cb52a9eba1196579b8616b4a6631d6d53a 100644 (file)
@@ -408,6 +408,8 @@ void CSQC_UpdateView(float w, float h)
 
        WaypointSprite_Load();
 
+       CSQCPlayer_SetCamera();
+
 #ifdef COMPAT_XON050_ENGINE
        if(spectatee_status)
                myteam = GetPlayerColor(spectatee_status - 1);
index e18433e9666465ef36702c7ba10637eb4e3d1a6a..d829904631ab0cf20e04d1fe5ffdea4b7b541ad4 100644 (file)
@@ -373,3 +373,10 @@ var float autocvar_cl_eventchase_distance = 140;
 var float autocvar_cl_eventchase_speed = 1.3;
 float autocvar_cl_lerpexcess;
 string autocvar__togglezoom;
+float autocvar_cl_playerdetailreduction;
+float autocvar_cl_loddistance1 = 1024;
+float autocvar_cl_loddistance2 = 4096;
+float autocvar_cl_forceplayermodels;
+float autocvar__cl_playerskin;
+string autocvar__cl_playermodel;
+float autocvar_cl_precacheplayermodels;
diff --git a/qcsrc/client/csqcmodel_hooks.qc b/qcsrc/client/csqcmodel_hooks.qc
new file mode 100644 (file)
index 0000000..1f32480
--- /dev/null
@@ -0,0 +1,211 @@
+.vector glowmod;
+.float lodmodelindex0;
+.float lodmodelindex1;
+.float lodmodelindex2;
+
+.entity tag_entity;
+.float tag_index;
+
+void CSQCModel_Hook_PreDraw(float isplayer)
+{
+       // auto glowmod from colormap
+       if(isplayer)
+       {
+               if(self.colormap > 0)
+                       self.glowmod = colormapPaletteColor(((self.colormap >= 1024) ? self.colormap : stof(getplayerkeyvalue(self.colormap - 1, "colors"))) & 0x0F, TRUE) * 2;
+               else
+                       self.glowmod = '1 1 1';
+
+               if(self.modelindex && self.model != "null")
+               {
+                       if(autocvar_cl_playerdetailreduction <= 0)
+                       {
+                               if(autocvar_cl_playerdetailreduction <= -2)
+                                       self.modelindex = self.lodmodelindex2;
+                               else if(autocvar_cl_playerdetailreduction <= -1)
+                                       self.modelindex = self.lodmodelindex1;
+                               else
+                                       self.modelindex = self.lodmodelindex0;
+                       }
+                       else
+                       {
+                               float distance = vlen(self.origin - other.origin);
+                               float f = (distance + 100.0) * autocvar_cl_playerdetailreduction;
+                               f *= 1.0 / bound(0.01, view_quality, 1);
+                               if(f > autocvar_cl_loddistance2)
+                                       self.modelindex = self.lodmodelindex2;
+                               else if(f > autocvar_cl_loddistance1)
+                                       self.modelindex = self.lodmodelindex1;
+                               else
+                                       self.modelindex = self.lodmodelindex0;
+                       }
+               }
+       }
+
+       if(!isplayer)
+       {
+               if(self.tag_entity && wasfreed(self.tag_entity))
+                       self.tag_entity = world;
+
+               if(self.tag_networkentity)
+               {
+                       // we are ATTACHED!
+                       if(self.tag_entity.entnum == self.tag_networkentity)
+                       {
+                               // already good
+                               self.drawmask = MASK_NORMAL;
+                       }
+                       else
+                       {
+                               // to something NEW NEW NEW NEW!
+                               self.tag_entity = findfloat(world, entnum, self.tag_networkentity);
+                               if(self.tag_entity)
+                               {
+                                       // the best part is: IT EXISTS
+                                       self.drawmask = MASK_NORMAL;
+
+                                       if(substring(self.model, 0, 17) == "models/weapons/v_")
+                                               if(substring(self.tag_entity.model, 0, 17) == "models/weapons/h_")
+                                               {
+                                                       self.tag_index = gettagindex(self.tag_entity, "weapon");
+                                                       if(!self.tag_index)
+                                                               self.tag_index = gettagindex(self.tag_entity, "tag_weapon");
+                                                       if(!self.tag_index)
+                                                       {
+                                                               // we need to prevent this from 'appening
+                                                               self.tag_entity = world;
+                                                               self.drawmask = 0;
+                                                               dprint("h_ model lacks weapon attachment, but v_ model is attached to it\n");
+                                                       }
+                                               }
+
+                                       if(substring(self.model, 0, 17) == "models/weapons/v_")
+                                               if(substring(self.tag_entity.model, 0, 14) == "models/player/")
+                                               {
+                                                       self.tag_index = gettagindex(self.tag_entity, "tag_weapon");
+                                                       if(!self.tag_index)
+                                                               self.tag_index = gettagindex(self.tag_entity, "bip01 r hand");
+                                               }
+
+                                       if(substring(self.tag_entity.model, 0, 17) == "models/weapons/v_")
+                                       {
+                                               self.tag_index = gettagindex(self.tag_entity, "shot");
+                                               if(!self.tag_index)
+                                                       self.tag_index = gettagindex(self.tag_entity, "tag_shot");
+                                       }
+                               }
+                               else
+                               {
+                                       // damn, see you next frame
+                                       self.drawmask = 0;
+                               }
+                       }
+               }
+               else
+               {
+                       // no brain no pain
+                       self.drawmask = MASK_NORMAL;
+               }
+       }
+}
+
+string forceplayermodels_model;
+float forceplayermodels_modelindex;
+float forceplayermodels_skin;
+float forceplayermodels_attempted;
+.string forceplayermodels_savemodel;
+.float forceplayermodels_savemodelindex;
+.float forceplayermodels_saveskin;
+void CSQCModel_Hook_PreUpdate(float isplayer, float islocalplayer)
+{
+       if(isplayer)
+       {
+               // revert to values from server
+               self.model = self.forceplayermodels_savemodel;
+               self.modelindex = self.forceplayermodels_savemodelindex;
+               self.skin = self.forceplayermodels_saveskin;
+       }
+}
+
+void CSQCModel_Hook_PostUpdate(float isplayer, float islocalplayer)
+{
+       if(isplayer)
+       {
+               // save values set by server
+               self.forceplayermodels_savemodel = self.model;
+               self.forceplayermodels_savemodelindex = self.modelindex;
+               self.forceplayermodels_saveskin = self.skin;
+
+               if(self.modelindex && self.model != "null")
+               {
+                       if(islocalplayer)
+                       {
+                               // trust server's idea of "own player model"
+                               forceplayermodels_model = self.model;
+                               forceplayermodels_modelindex = self.modelindex;
+                               forceplayermodels_skin = self.skin;
+                               forceplayermodels_attempted = 1;
+                       }
+
+                       if(!forceplayermodels_attempted)
+                       {
+                               // only if this failed, find it out on our own
+                               entity e;
+                               e = spawn();
+                               setmodel(e, autocvar__cl_playermodel); // this is harmless, see below
+                               forceplayermodels_model = e.model;
+                               forceplayermodels_modelindex = e.modelindex;
+                               forceplayermodels_skin = autocvar__cl_playerskin;
+                               forceplayermodels_attempted = 1;
+                               remove(e);
+                       }
+
+                       if(autocvar_cl_forceplayermodels && forceplayermodels_modelindex)
+                       {
+                               self.model = forceplayermodels_model;
+                               self.modelindex = forceplayermodels_modelindex;
+                               self.skin = forceplayermodels_skin;
+                       }
+
+                       // LOD model loading
+                       if(self.lodmodelindex0 != self.modelindex)
+                       {
+                               string modelname = self.model;
+                               string s;
+
+                               if(!fexists(modelname))
+                               {
+                                       print(sprintf(_("Trying to use non existing model %s. "), modelname));
+                                       modelname = cvar_defstring("_cl_playermodel");
+                                       print(sprintf(_("Reverted to %s."), modelname));
+                               }
+
+                               // set modelindex
+                               self.lodmodelindex0 = self.modelindex;
+                               self.lodmodelindex1 = self.modelindex;
+                               self.lodmodelindex2 = self.modelindex;
+
+                               // FIXME: this only supports 3-letter extensions
+                               s = strcat(substring(modelname, 0, strlen(modelname)-4), "_lod1", substring(modelname, -4, 4));
+                               if(fexists(s))
+                               {
+                                       precache_model(s);
+                                       setmodel(self, s);
+                                       if(self.modelindex)
+                                               self.lodmodelindex1 = self.modelindex;
+                               }
+
+                               s = strcat(substring(modelname, 0, strlen(modelname)-4), "_lod2", substring(modelname, -4, 4));
+                               if(fexists(s))
+                               {
+                                       precache_model(s);
+                                       setmodel(self, s);
+                                       if(self.modelindex)
+                                               self.lodmodelindex2 = self.modelindex;
+                               }
+
+                               setmodel(self, modelname); // make everything normal again
+                       }
+               }
+       }
+}
index 67fa4b3b9ab8f93020918530322cd981ee7f84a1..6f6316bec1d4c46e2fd474e874316b8563f0af29 100644 (file)
@@ -89,6 +89,7 @@ void Gib_Draw()
                return;
 
        if(self.touch == Gib_Touch) // don't do this for the "chunk" thingie...
+               // TODO somehow make it spray in a direction dependent on self.angles
                trailparticles(self, particleeffectnum(strcat(species_prefix(self.cnt), "TR_SLIGHTBLOOD")), oldorg, self.origin);
        else
                trailparticles(self, particleeffectnum(strcat(species_prefix(self.cnt), "TR_BLOOD")), oldorg, self.origin);
diff --git a/qcsrc/client/interpolate.qc b/qcsrc/client/interpolate.qc
deleted file mode 100644 (file)
index 3d6a103..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-// FIXME make this generic code, to be used for other entities too?
-.vector iorigin1, iorigin2;
-.vector ivelocity1, ivelocity2;
-.vector iforward1, iforward2;
-.vector iup1, iup2;
-.float itime1, itime2;
-void InterpolateOrigin_Reset()
-{
-       self.iflags &~= IFLAG_INTERNALMASK;
-       self.itime1 = self.itime2 = 0;
-}
-void InterpolateOrigin_Note()
-{
-       float dt;
-       float f0;
-
-       dt = time - self.itime2;
-
-       f0 = self.iflags;
-       if(self.iflags & IFLAG_PREVALID)
-               self.iflags |= IFLAG_VALID;
-       else
-               self.iflags |= IFLAG_PREVALID;
-
-       self.iorigin1 = self.iorigin2;
-       self.iorigin2 = self.origin;
-
-       if(self.iflags & IFLAG_AUTOANGLES)
-               if(self.iorigin2 != self.iorigin1)
-                       self.angles = vectoangles(self.iorigin2 - self.iorigin1);
-
-       if(self.iflags & IFLAG_ANGLES)
-       {
-               fixedmakevectors(self.angles);
-               if(f0 & IFLAG_VALID)
-               {
-                       self.iforward1 = self.iforward2;
-                       self.iup1 = self.iup2;
-               }
-               else
-               {
-                       self.iforward1 = v_forward;
-                       self.iup1 = v_up;
-               }
-               self.iforward2 = v_forward;
-               self.iup2 = v_up;
-       }
-
-       if(self.iflags & IFLAG_VELOCITY)
-       {
-               self.ivelocity1 = self.ivelocity2;
-               self.ivelocity2 = self.velocity;
-       }
-
-       if(vlen(self.iorigin2 - self.iorigin1) > 1000)
-       {
-               self.itime1 = self.itime2 = time; // don't lerp
-       }
-
-       if((self.iflags & IFLAG_VELOCITY) && (vlen(self.ivelocity2 - self.ivelocity1) > 1000))
-       {
-               self.itime1 = self.itime2 = time; // don't lerp
-       }
-
-       if(dt < 0.2)
-       {
-               self.itime1 = serverprevtime;
-               self.itime2 = time;
-       }
-       else
-       {
-               // don't lerp
-               self.itime1 = self.itime2 = time;
-       }
-}
-void InterpolateOrigin_Do()
-{
-       vector forward, up;
-       if(self.itime1 && self.itime2 && self.itime1 != self.itime2)
-       {
-               float f;
-               f = bound(0, (time - self.itime1) / (self.itime2 - self.itime1), 1 + autocvar_cl_lerpexcess);
-               self.origin = (1 - f) * self.iorigin1 + f * self.iorigin2;
-               if(self.iflags & IFLAG_ANGLES)
-               {
-                       forward = (1 - f) * self.iforward1 + f * self.iforward2;
-                       up = (1 - f) * self.iup1 + f * self.iup2;
-                       self.angles = fixedvectoangles2(forward, up);
-               }
-               if(self.iflags & IFLAG_VELOCITY)
-                       self.velocity = (1 - f) * self.ivelocity1 + f * self.ivelocity2;
-       }
-}
-void InterpolateOrigin_Undo()
-{
-       self.origin = self.iorigin2;
-       if(self.iflags & IFLAG_ANGLES)
-               self.angles = fixedvectoangles2(self.iforward2, self.iup2);
-       if(self.iflags & IFLAG_VELOCITY)
-               self.velocity = self.ivelocity2;
-}
-
diff --git a/qcsrc/client/interpolate.qh b/qcsrc/client/interpolate.qh
deleted file mode 100644 (file)
index a048803..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-.float iflags;
-#define IFLAG_VELOCITY 1
-#define IFLAG_ANGLES 2
-#define IFLAG_AUTOANGLES 4
-#define IFLAG_VALID 8
-#define IFLAG_PREVALID 16
-#define IFLAG_INTERNALMASK (IFLAG_VALID | IFLAG_PREVALID)
-
-// call this BEFORE reading an entity update
-void InterpolateOrigin_Undo();
-
-// call this AFTER receiving an entity update
-void InterpolateOrigin_Note();
-
-// call this when the entity got teleported, before InterpolateOrigin_Note
-void InterpolateOrigin_Reset();
-
-// call this BEFORE drawing
-void InterpolateOrigin_Do();
index 5ed3ab2e78fc6184186f1d43faeb58e32c0ca096..6ad35331ea5e67423a75c51afca8e5c197843fcf 100644 (file)
@@ -575,9 +575,15 @@ vector getplayerorigin(float pl)
        string s;
        entity e;
 
+       e = CSQCPlayer_GetPlayer(pl + 1);
+       if(e)
+               return e.origin;
+
+#ifndef NO_LEGACY_NETWORKING
        s = getplayerkeyvalue(pl, "TEMPHACK_origin");
        if(s != "")
                return stov(s);
+#endif
 
        e = entcs_receiver[pl];
        if(e)
index 06b3e8b7b751469e5d126a7aeb22bb9f3cb8e552..1a303f4f42d57916214aa3db15c804fce89f4294 100644 (file)
@@ -22,7 +22,7 @@ Defs.qc
 
 autocvars.qh
 
-interpolate.qh
+../csqcmodel/interpolate.qh
 teamradar.qh
 hud.qh
 scoreboard.qh
@@ -37,6 +37,10 @@ tturrets.qh
 ../server/movelib.qc
 main.qh
 vehicles/vehicles.qh
+../csqcmodel/settings.qh
+../csqcmodel/common.qh
+../csqcmodel/cl_model.qh
+../csqcmodel/cl_player.qh
 
 sortlist.qc
 miscfunctions.qc
@@ -47,6 +51,7 @@ hud_config.qc
 hud.qc
 scoreboard.qc
 mapvoting.qc
+csqcmodel_hooks.qc
 
 rubble.qc
 hook.qc
@@ -56,6 +61,8 @@ projectile.qc
 gibs.qc
 damage.qc
 casings.qc
+../csqcmodel/cl_model.qc
+../csqcmodel/cl_player.qc
 effects.qc
 wall.qc
 modeleffects.qc
@@ -69,7 +76,7 @@ shownames.qc
 announcer.qc
 Main.qc
 View.qc
-interpolate.qc
+../csqcmodel/interpolate.qc
 waypointsprites.qc
 movetypes.qc
 prandom.qc
index 7e5e99edbf9a5a2c64476c7e526c305a70284c6f..55834f1a6d36bd5f84f20475a908f737c8a6a0a4 100644 (file)
@@ -114,6 +114,7 @@ const float ENT_CLIENT_GAUNTLET = 29;
 const float ENT_CLIENT_ACCURACY = 30;
 const float ENT_CLIENT_SHOWNAMES = 31;
 const float ENT_CLIENT_WARPZONE_TELEPORTED = 32;
+const float ENT_CLIENT_MODEL = 33;
 
 const float ENT_CLIENT_TURRET = 40;
 const float ENT_CLIENT_AUXILIARYXHAIR = 50;
@@ -575,6 +576,32 @@ float HUD_MENU_ENABLE              = 0;
 #define SERVERFLAG_TEAMPLAY 2
 #define SERVERFLAG_PLAYERSTATS 4
 
+var vector autocvar_sv_player_maxs = '16 16 45';
+var vector autocvar_sv_player_mins = '-16 -16 -24';
+var vector autocvar_sv_player_viewoffset = '0 0 20';
+var vector autocvar_sv_player_crouch_maxs = '16 16 25';
+var vector autocvar_sv_player_crouch_mins = '-16 -16 -24';
+var vector autocvar_sv_player_crouch_viewoffset = '0 0 20';
+noref var vector autocvar_sv_player_headsize = '24 24 12';
+
+#define PL_VIEW_OFS autocvar_sv_player_viewoffset
+#define PL_MIN autocvar_sv_player_mins
+#define PL_MAX autocvar_sv_player_maxs
+#define PL_CROUCH_VIEW_OFS autocvar_sv_player_crouch_viewoffset
+#define PL_CROUCH_MIN autocvar_sv_player_crouch_mins
+#define PL_CROUCH_MAX autocvar_sv_player_crouch_maxs
+#define PL_HEAD autocvar_sv_player_headsize
+
+// helpers
+#define PL_VIEW_OFS_z autocvar_sv_player_viewoffset_z
+#define PL_MIN_z autocvar_sv_player_mins_z
+#define PL_MAX_z autocvar_sv_player_maxs_z
+#define PL_CROUCH_VIEW_OFS_z autocvar_sv_player_crouch_viewoffset_z
+#define PL_CROUCH_MIN_z autocvar_sv_player_mins_z
+#define PL_HEAD_x autocvar_sv_player_headsize_x
+#define PL_HEAD_y autocvar_sv_player_headsize_y
+#define PL_HEAD_z autocvar_sv_player_headsize_z
+
 // spawnpoint prios
 #define SPAWN_PRIO_NEAR_TEAMMATE_FOUND    200
 #define SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM 100
index 10e4e345b28298ead91a5420e4c0c11da92dc36b..10f77b6cdfedeb59629f375f4ca5cd9f9a4da2bd 100644 (file)
@@ -2107,3 +2107,14 @@ float lowestbit(float f)
        f &~= f * 65536;
        return f;
 }
+
+#ifdef CSQC
+entity ReadCSQCEntity()
+{
+       float f;
+       f = ReadShort();
+       if(f == 0)
+               return world;
+       return findfloat(world, entnum, f);
+}
+#endif
index b2e77484e398695ea3b2febb290bd217cdf83af5..e2dfcb3b86b1257c7b440837e7714fc78a1e48ff 100644 (file)
@@ -270,3 +270,7 @@ float xdecode(string s);
 #ifndef COMPAT_XON010_CHANNELS
 #define sound(e,c,s,v,a) sound7(e,c,s,v,a,0,0)
 #endif
+
+#ifdef CSQC
+entity ReadCSQCEntity()
+#endif
diff --git a/qcsrc/csqcmodel/cl_model.qc b/qcsrc/csqcmodel/cl_model.qc
new file mode 100644 (file)
index 0000000..c6d2923
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+var float autocvar_cl_lerpanim_maxdelta_framegroups = 0.1;
+var float autocvar_cl_nolerp = 0;
+
+.float csqcmodel_lerpfrac;
+.float csqcmodel_lerpfrac2;
+.float csqcmodel_lerpfractime;
+.float csqcmodel_lerpfrac2time;
+.float csqcmodel_teleported;
+
+void CSQCModel_InterpolateAnimation_PreNote(float sf)
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+       if(sf & CSQCMODEL_PROPERTY_FRAME)
+       {
+               self.frame3 = self.frame;
+               self.frame3time = self.frame1time;
+       }
+       if(sf & CSQCMODEL_PROPERTY_FRAME2)
+       {
+               self.frame4 = self.frame2;
+               self.frame4time = self.frame2time;
+       }
+       if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
+       {
+               self.csqcmodel_lerpfrac2 = self.csqcmodel_lerpfrac;
+               self.csqcmodel_lerpfrac2time = self.csqcmodel_lerpfractime;
+               self.lerpfrac = self.csqcmodel_lerpfrac;
+       }
+#else
+       if(sf & CSQCMODEL_PROPERTY_FRAME)
+       {
+               self.frame2 = self.frame;
+               self.frame2time = self.frame1time;
+       }
+#endif
+}
+
+void CSQCModel_InterpolateAnimation_Note(float sf)
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+       if(sf & CSQCMODEL_PROPERTY_FRAME)
+       {
+               self.frame1time = time;
+       }
+       if(sf & CSQCMODEL_PROPERTY_FRAME2)
+       {
+               self.frame2time = time;
+       }
+       if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
+       {
+               self.csqcmodel_lerpfrac = self.lerpfrac;
+               self.csqcmodel_lerpfractime = time;
+       }
+#else
+       if(sf & CSQCMODEL_PROPERTY_FRAME)
+       {
+               self.frame1time = time;
+       }
+#endif
+}
+
+void CSQCModel_InterpolateAnimation_Do()
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+       if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
+       {
+               self.lerpfrac = self.csqcmodel_lerpfrac;
+               self.lerpfrac3 = 0;
+               self.lerpfrac4 = 0;
+       }
+       else
+       {
+               float l13, l24, llf;
+               float l24_13;
+
+               if(self.frame3time == 0) // if frame1/3 were not previously displayed, only frame1 can make sense
+                       l13 = 1;
+               else
+                       l13 = bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+
+               if(self.frame4time == 0) // if frame2/4 were not previously displayed, only frame2 can make sense
+                       l24 = 1;
+               else
+                       l24 = bound(0, (time - self.frame2time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+
+               if(self.csqcmodel_lerpfrac2time == 0) // if there is no old lerpfrac (newly displayed model), only lerpfrac makes sense
+                       llf = 1;
+               else
+                       llf = bound(0, (time - self.csqcmodel_lerpfractime) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+
+               l24_13 = self.csqcmodel_lerpfrac * llf + self.csqcmodel_lerpfrac2 * (1 - llf);
+
+               self.lerpfrac  = l24 * l24_13;
+               self.lerpfrac4 = (1 - l24) * l24_13;
+               self.lerpfrac3 = (1 - l13) * (1 - l24_13);
+
+               if(l24_13 == 0) // if frames 2/4 are not displayed, clear their frametime
+               {
+                       self.frame2time = 0;
+                       self.frame4time = 0;
+               }
+
+               if(l24_13 == 1) // if frames 1/3 are not displayed, clear their frametime
+               {
+                       self.frame1time = 0;
+                       self.frame3time = 0;
+               }
+       }
+#else
+       if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
+       {
+               self.lerpfrac = 0;
+       }
+       else
+       {
+               self.lerpfrac = 1 - bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+       }
+#endif
+}
+
+void CSQCModel_Draw()
+{
+       // some nice flags for CSQCMODEL_IF and the hooks
+       float isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
+       float islocalplayer = (self.entnum == player_localnum + 1);
+       float isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
+
+       // we don't do this for the local player as that one is already handled
+       // by CSQCPlayer_SetCamera()
+       if(!CSQCPlayer_IsLocalPlayer())
+               InterpolateOrigin_Do();
+
+       // TODO csqcplayers: run prediction here too
+       CSQCModel_InterpolateAnimation_Do();
+
+       { CSQCMODEL_HOOK_PREDRAW }
+
+       // inherit draw flags easily
+       entity root = self;
+       while(root.tag_entity)
+               root = root.tag_entity;
+       if(self != root)
+       {
+               self.renderflags &~= RF_EXTERNALMODEL | RF_VIEWMODEL;
+               self.renderflags |= (root.renderflags & (RF_EXTERNALMODEL | RF_VIEWMODEL));
+       }
+}
+
+void CSQCModel_Read()
+{
+       float sf;
+       sf = ReadShort();
+
+       // some nice flags for CSQCMODEL_IF and the hooks
+       float isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
+       float islocalplayer = (self.entnum == player_localnum + 1);
+       float isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
+
+       self.iflags |= IFLAG_ANGLES; // interpolate angles too
+
+       { CSQCMODEL_HOOK_PREUPDATE }
+
+       CSQCPlayer_PreUpdate();
+       InterpolateOrigin_Undo();
+       CSQCModel_InterpolateAnimation_PreNote(sf);
+
+#define CSQCMODEL_IF(cond) if(cond) {
+#define CSQCMODEL_ENDIF }
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       if(sf & flag) \
+               self.f = r();
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
+       if(sf & flag) \
+               self.f = r() / s;
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+
+       if(sf & CSQCMODEL_PROPERTY_MODELINDEX)
+               setmodelindex(self, self.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
+
+       if(sf & CSQCMODEL_PROPERTY_TELEPORTED)
+       {
+               self.iflags |= IFLAG_TELEPORTED;
+               self.csqcmodel_teleported = 1;
+       }
+       
+       CSQCModel_InterpolateAnimation_Note(sf);
+       InterpolateOrigin_Note();
+       CSQCPlayer_PostUpdate();
+
+       { CSQCMODEL_HOOK_POSTUPDATE }
+
+#ifdef CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
+       InterpolateOrigin_Do();
+       CSQCModel_InterpolateAnimation_Do();
+#endif
+
+       // relink
+       setorigin(self, self.origin);
+
+       // set obvious render flags
+#ifdef COMPAT_XON050_ENGINE
+       if(self.entnum == player_localentnum || self.entnum == spectatee_status)
+#else
+       if(self.entnum == player_localentnum)
+#endif
+               self.renderflags |= RF_EXTERNALMODEL;
+       else
+               self.renderflags &~= RF_EXTERNALMODEL;
+
+       // draw it
+       self.drawmask = MASK_NORMAL;
+       self.predraw = CSQCModel_Draw;
+}
diff --git a/qcsrc/csqcmodel/cl_model.qh b/qcsrc/csqcmodel/cl_model.qh
new file mode 100644 (file)
index 0000000..fba2151
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+void CSQCModel_Read();
+
+#define CSQCMODEL_IF(cond)
+#define CSQCMODEL_ENDIF
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       .t f;
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
diff --git a/qcsrc/csqcmodel/cl_player.qc b/qcsrc/csqcmodel/cl_player.qc
new file mode 100644 (file)
index 0000000..4a7cf2e
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+var float autocvar_cl_predictionerrorcompensation = 0;
+
+// engine stuff
+.float pmove_flags;
+float pmove_onground; // weird engine flag we shouldn't really use but have to for now
+#define PMF_DUCKED 4
+#define PMF_ONGROUND 8
+#define REFDEFFLAG_TELEPORTED 1
+#define REFDEFFLAG_JUMPING 2
+
+entity csqcplayer;
+vector csqcplayer_origin, csqcplayer_velocity;
+float csqcplayer_sequence, player_pmflags;
+float csqcplayer_moveframe;
+vector csqcplayer_predictionerror;
+float csqcplayer_predictionerrortime;
+
+vector CSQCPlayer_GetPredictionError()
+{
+       if(!autocvar_cl_predictionerrorcompensation)
+               return '0 0 0';
+       if(time < csqcplayer_predictionerrortime)
+               return csqcplayer_predictionerror * (csqcplayer_predictionerrortime - time) * autocvar_cl_predictionerrorcompensation;
+       return '0 0 0';
+}
+
+void CSQCPlayer_SetPredictionError(vector v)
+{
+       if(!autocvar_cl_predictionerrorcompensation)
+               return;
+       csqcplayer_predictionerror = (csqcplayer_predictionerrortime - time) * autocvar_cl_predictionerrorcompensation * csqcplayer_predictionerror + v;
+       csqcplayer_predictionerrortime = time + 1.0 / autocvar_cl_predictionerrorcompensation;
+}
+
+void CSQCPlayer_Unpredict()
+{
+       if(csqcplayer_status == CSQCPLAYERSTATUS_UNPREDICTED)
+               return;
+       if(csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED)
+               error("Cannot unpredict in current status");
+       self.origin = csqcplayer_origin;
+       self.velocity = csqcplayer_velocity;
+       csqcplayer_moveframe = csqcplayer_sequence+1; //+1 because the recieved frame has the move already done (server side)
+       self.pmove_flags = player_pmflags;
+}
+
+void CSQCPlayer_SetMinsMaxs()
+{
+       if(self.pmove_flags & PMF_DUCKED)
+       {
+               self.mins = PL_CROUCH_MIN;
+               self.maxs = PL_CROUCH_MAX;
+               self.view_ofs = PL_CROUCH_VIEW_OFS;
+       }
+       else
+       {
+               self.mins = PL_MIN;
+               self.maxs = PL_MAX;
+               self.view_ofs = PL_VIEW_OFS;
+       }
+}
+
+void CSQCPlayer_SavePrediction()
+{
+       player_pmflags = self.pmove_flags;
+       csqcplayer_origin = self.origin;
+       csqcplayer_velocity = self.velocity;
+       csqcplayer_sequence = servercommandframe;
+       csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+}
+
+void CSQCPlayer_PredictTo(float endframe)
+{
+       CSQCPlayer_Unpredict();
+       CSQCPlayer_SetMinsMaxs();
+
+       csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+
+       if (getstatf(STAT_HEALTH) <= 0)
+       {
+               csqcplayer_moveframe = clientcommandframe;
+               getinputstate(csqcplayer_moveframe-1);
+               return;
+       }
+
+       while(csqcplayer_moveframe < endframe)
+       {
+               if (!getinputstate(csqcplayer_moveframe))
+               {
+                       break;
+               }
+               runstandardplayerphysics(self);
+               CSQCPlayer_SetMinsMaxs();
+               csqcplayer_moveframe++;
+       }
+
+       //add in anything that was applied after (for low packet rate protocols)
+       input_angles = view_angles;
+}
+
+float CSQCPlayer_IsLocalPlayer()
+{
+       return (self == csqcplayer);
+}
+
+void(entity e, float fl) V_CalcRefdef = #640; // DP_CSQC_V_CALCREFDEF
+
+void CSQCPlayer_SetCamera()
+{
+       if(csqcplayer)
+       {
+               entity oldself;
+               oldself = self;
+               self = csqcplayer;
+
+#ifdef COMPAT_XON050_ENGINE
+               if(servercommandframe == 0 || !(checkextension("DP_CSQC_V_CALCREFDEF") || checkextension("DP_CSQC_V_CALCREFDEF_WIP1")))
+#else
+               if(servercommandframe == 0)
+#endif
+               {
+                       InterpolateOrigin_Do();
+                       self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
+
+                       // get crouch state from the server
+                       if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
+                               self.pmove_flags &~= PMF_DUCKED;
+                       else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS_z)
+                               self.pmove_flags |= PMF_DUCKED;
+
+                       // get onground state from the server
+                       if(pmove_onground)
+                               self.pmove_flags |= PMF_ONGROUND;
+                       else
+                               self.pmove_flags &~= PMF_ONGROUND;
+
+                       CSQCPlayer_SetMinsMaxs();
+
+                       // override it back just in case
+                       self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
+               }
+               else
+               {
+                       if(csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER)
+                       {
+                               vector o, v;
+                               o = self.origin;
+                               v = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
+                               csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+                               CSQCPlayer_PredictTo(servercommandframe + 1);
+                               CSQCPlayer_SetPredictionError(o - self.origin);
+                               self.origin = o;
+                               self.velocity = v;
+
+                               // get crouch state from the server
+                               if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
+                                       self.pmove_flags &~= PMF_DUCKED;
+                               else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS_z)
+                                       self.pmove_flags |= PMF_DUCKED;
+
+                               // get onground state from the server
+                               if(pmove_onground)
+                                       self.pmove_flags |= PMF_ONGROUND;
+                               else
+                                       self.pmove_flags &~= PMF_ONGROUND;
+
+                               CSQCPlayer_SavePrediction();
+                       }
+                       CSQCPlayer_PredictTo(clientcommandframe);
+
+                       CSQCPlayer_SetMinsMaxs();
+               }
+
+               // relink
+               setorigin(self, self.origin);
+
+               // FIXME support svc_setview?
+
+               if(checkextension("DP_CSQC_V_CALCREFDEF") || checkextension("DP_CSQC_V_CALCREFDEF_WIP1"))
+               {
+                       var float refdefflags = 0;
+
+                       if(self.csqcmodel_teleported)
+                       {
+                               refdefflags |= REFDEFFLAG_TELEPORTED;
+                               self.csqcmodel_teleported = 0;
+                       }
+
+                       if(input_buttons & 4)
+                               refdefflags |= REFDEFFLAG_JUMPING;
+
+                       V_CalcRefdef(self, refdefflags);
+               }
+               else
+                       setproperty(VF_ORIGIN, self.origin + self.view_ofs);
+               self.angles_y = input_angles_y;
+
+               { CSQCPLAYER_HOOK_POSTCAMERASETUP }
+
+               self = oldself;
+       }
+}
+
+void CSQCPlayer_Remove()
+{
+       if(self.entnum != player_localnum + 1)
+               return;
+       csqcplayer = world;
+       cvar_clientsettemp("cl_movement_replay", "1");
+}
+
+float CSQCPlayer_PreUpdate()
+{
+       if(self.entnum != player_localnum + 1)
+               return 0;
+       cvar_clientsettemp("cl_movement_replay", "0");
+       if(csqcplayer_status != CSQCPLAYERSTATUS_FROMSERVER)
+               CSQCPlayer_Unpredict();
+       return 1;
+}
+
+float CSQCPlayer_PostUpdate()
+{
+       if(self.entnum != player_localentnum)
+               return 0;
+       csqcplayer_status = CSQCPLAYERSTATUS_FROMSERVER;
+       csqcplayer = self;
+       self.entremove = CSQCPlayer_Remove;
+       return 1;
+}
+
+entity CSQCPlayer_GetPlayer(float pl)
+{
+       return findfloat(world, entnum, pl); // FIXME optimize this using an array
+}
diff --git a/qcsrc/csqcmodel/cl_player.qh b/qcsrc/csqcmodel/cl_player.qh
new file mode 100644 (file)
index 0000000..f85c4e7
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+float csqcplayer_status;
+#define CSQCPLAYERSTATUS_UNPREDICTED 0
+#define CSQCPLAYERSTATUS_FROMSERVER 1
+#define CSQCPLAYERSTATUS_PREDICTED 2
+
+void CSQCPlayer_SetCamera();
+float CSQCPlayer_PreUpdate();
+float CSQCPlayer_PostUpdate();
+float CSQCPlayer_IsLocalPlayer();
+entity CSQCPlayer_GetPlayer(float pl);
diff --git a/qcsrc/csqcmodel/common.qh b/qcsrc/csqcmodel/common.qh
new file mode 100644 (file)
index 0000000..587645c
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+noref string csqcmodel_license = "\
+Copyright (c) 2011 Rudolf Polzer\
+\
+Permission is hereby granted, free of charge, to any person obtaining a copy\
+of this software and associated documentation files (the \"Software\"), to\
+deal in the Software without restriction, including without limitation the\
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\
+sell copies of the Software, and to permit persons to whom the Software is\
+furnished to do so, subject to the following conditions:\
+\
+The above copyright notice and this permission notice shall be included in\
+all copies or substantial portions of the Software.\
+\
+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\
+IN THE SOFTWARE.\
+";
+
+.vector glowmod;
+.vector view_ofs;
+.float frame;
+.float frame1time;
+.float frame2;
+.float frame2time;
+.float lerpfrac;
+
+#define CSQCMODEL_PROPERTY_FRAME 32768
+#define CSQCMODEL_PROPERTY_FRAME2 16384
+#define CSQCMODEL_PROPERTY_LERPFRAC 8192
+#define CSQCMODEL_PROPERTY_TELEPORTED 4096 // the "teleport bit" cancelling interpolation
+#define CSQCMODEL_PROPERTY_MODELINDEX 2048
+#define CSQCMODEL_PROPERTY_ORIGIN 1024
+#define CSQCMODEL_PROPERTY_YAW 512
+#define CSQCMODEL_PROPERTY_PITCHROLL 256
+
+#define ALLPROPERTIES_COMMON \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME, float, ReadByte, WriteByte, frame) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_MODELINDEX, float, ReadShort, WriteShort, modelindex) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_x) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_y) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_z) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_x) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_YAW, float, ReadAngle, WriteAngle, angles_y) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_z) \
+       CSQCMODEL_EXTRAPROPERTIES
+
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+.float frame3;
+.float frame3time;
+.float lerpfrac3;
+.float frame4;
+.float frame4time;
+.float lerpfrac4;
+#define ALLPROPERTIES ALLPROPERTIES_COMMON \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME2, float, ReadByte, WriteByte, frame2) \
+       CSQCMODEL_PROPERTY_SCALED(CSQCMODEL_PROPERTY_LERPFRAC, float, ReadByte, WriteByte, lerpfrac, 255, 0, 255)
+#else
+#define ALLPROPERTIES ALLPROPERTIES_COMMON
+#endif
diff --git a/qcsrc/csqcmodel/interpolate.qc b/qcsrc/csqcmodel/interpolate.qc
new file mode 100644 (file)
index 0000000..ac0ba6e
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+.vector iorigin1, iorigin2;
+.vector ivelocity1, ivelocity2;
+.vector iforward1, iforward2;
+.vector iup1, iup2;
+.float itime1, itime2;
+void InterpolateOrigin_Reset()
+{
+       self.iflags &~= IFLAG_INTERNALMASK;
+       self.itime1 = self.itime2 = 0;
+}
+void InterpolateOrigin_Note()
+{
+       float dt;
+       float f0;
+
+       dt = time - self.itime2;
+
+       f0 = self.iflags;
+       if(self.iflags & IFLAG_PREVALID)
+               self.iflags |= IFLAG_VALID;
+       else
+               self.iflags |= IFLAG_PREVALID;
+
+       self.iorigin1 = self.iorigin2;
+       self.iorigin2 = self.origin;
+
+       if(self.iflags & IFLAG_AUTOANGLES)
+               if(self.iorigin2 != self.iorigin1)
+                       self.angles = vectoangles(self.iorigin2 - self.iorigin1);
+
+       if(self.iflags & IFLAG_ANGLES)
+       {
+               fixedmakevectors(self.angles);
+               if(f0 & IFLAG_VALID)
+               {
+                       self.iforward1 = self.iforward2;
+                       self.iup1 = self.iup2;
+               }
+               else
+               {
+                       self.iforward1 = v_forward;
+                       self.iup1 = v_up;
+               }
+               self.iforward2 = v_forward;
+               self.iup2 = v_up;
+       }
+
+       if(self.iflags & IFLAG_VELOCITY)
+       {
+               self.ivelocity1 = self.ivelocity2;
+               self.ivelocity2 = self.velocity;
+       }
+
+       if(self.iflags & IFLAG_TELEPORTED)
+       {
+               self.iflags &~= IFLAG_TELEPORTED;
+               self.itime1 = self.itime2 = time; // don't lerp
+       }
+       else if(vlen(self.iorigin2 - self.iorigin1) > 1000)
+       {
+               self.itime1 = self.itime2 = time; // don't lerp
+       }
+       else if((self.iflags & IFLAG_VELOCITY) && (vlen(self.ivelocity2 - self.ivelocity1) > 1000))
+       {
+               self.itime1 = self.itime2 = time; // don't lerp
+       }
+       else if(dt >= 0.2)
+       {
+               self.itime1 = self.itime2 = time;
+       }
+       else
+       {
+               self.itime1 = serverprevtime;
+               self.itime2 = time;
+       }
+}
+void InterpolateOrigin_Do()
+{
+       vector forward, up;
+       if(self.itime1 && self.itime2 && self.itime1 != self.itime2)
+       {
+               float f;
+               f = bound(0, (time - self.itime1) / (self.itime2 - self.itime1), 1 + autocvar_cl_lerpexcess);
+               self.origin = (1 - f) * self.iorigin1 + f * self.iorigin2;
+               if(self.iflags & IFLAG_ANGLES)
+               {
+                       forward = (1 - f) * self.iforward1 + f * self.iforward2;
+                       up = (1 - f) * self.iup1 + f * self.iup2;
+                       self.angles = fixedvectoangles2(forward, up);
+               }
+               if(self.iflags & IFLAG_VELOCITY)
+                       self.velocity = (1 - f) * self.ivelocity1 + f * self.ivelocity2;
+       }
+}
+void InterpolateOrigin_Undo()
+{
+       self.origin = self.iorigin2;
+       if(self.iflags & IFLAG_ANGLES)
+               self.angles = fixedvectoangles2(self.iforward2, self.iup2);
+       if(self.iflags & IFLAG_VELOCITY)
+               self.velocity = self.ivelocity2;
+}
+
diff --git a/qcsrc/csqcmodel/interpolate.qh b/qcsrc/csqcmodel/interpolate.qh
new file mode 100644 (file)
index 0000000..8254fae
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+.float iflags;
+#define IFLAG_VELOCITY 1
+#define IFLAG_ANGLES 2
+#define IFLAG_AUTOANGLES 4
+#define IFLAG_VALID 8
+#define IFLAG_PREVALID 16
+#define IFLAG_TELEPORTED 32
+#define IFLAG_INTERNALMASK (IFLAG_VALID | IFLAG_PREVALID)
+
+// call this BEFORE reading an entity update
+void InterpolateOrigin_Undo();
+
+// call this AFTER receiving an entity update
+void InterpolateOrigin_Note();
+
+// call this when the entity got teleported, before InterpolateOrigin_Note
+void InterpolateOrigin_Reset();
+
+// call this BEFORE drawing
+void InterpolateOrigin_Do();
diff --git a/qcsrc/csqcmodel/settings.qh b/qcsrc/csqcmodel/settings.qh
new file mode 100644 (file)
index 0000000..a5f9c87
--- /dev/null
@@ -0,0 +1,80 @@
+// define this if svqc code wants to use .frame2 and .lerpfrac
+#define CSQCMODEL_HAVE_TWO_FRAMES
+
+// don't define this ever
+//#define CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
+
+// a hack for Xonotic
+#ifdef CSQC
+# define TAG_ENTITY_NAME tag_networkentity
+# define TAG_ENTITY_TYPE float
+.float tag_networkentity;
+#else
+# define TAG_ENTITY_NAME tag_entity
+# define TAG_ENTITY_TYPE entity
+#endif
+
+// add properties you want networked to CSQC here
+#define CSQCMODEL_EXTRAPROPERTIES \
+       CSQCMODEL_PROPERTY(1, float, ReadShort, WriteShort, colormap) \
+       CSQCMODEL_PROPERTY(2, float, ReadInt24_t, WriteInt24_t, effects) \
+       CSQCMODEL_PROPERTY(4, float, ReadByte, WriteByte, modelflags) \
+       CSQCMODEL_PROPERTY_SCALED(8, float, ReadByte, WriteByte, alpha, 255, 0, 255) \
+       CSQCMODEL_PROPERTY(16, float, ReadByte, WriteByte, skin) \
+       CSQCMODEL_IF(isplayer) \
+       CSQCMODEL_ENDIF \
+       CSQCMODEL_IF(!isplayer) \
+               CSQCMODEL_PROPERTY(32, TAG_ENTITY_TYPE, ReadShort, WriteEntity, TAG_ENTITY_NAME) \
+               CSQCMODEL_PROPERTY_SCALED(64, float, ReadByte, WriteByte, glowmod_x, 255, 0, 255) \
+               CSQCMODEL_PROPERTY_SCALED(64, float, ReadByte, WriteByte, glowmod_y, 255, 0, 255) \
+               CSQCMODEL_PROPERTY_SCALED(64, float, ReadByte, WriteByte, glowmod_z, 255, 0, 255) \
+       CSQCMODEL_ENDIF
+// TODO get rid of colormod/glowmod here, find good solution for nex charge glowmod hack; also get rid of some useless properties on non-players that only exist for CopyBody
+
+// add hook function calls here
+#define CSQCMODEL_HOOK_PREUPDATE \
+       CSQCModel_Hook_PreUpdate(isplayer, islocalplayer);
+#define CSQCMODEL_HOOK_POSTUPDATE \
+       CSQCModel_Hook_PostUpdate(isplayer, islocalplayer);
+#define CSQCMODEL_HOOK_PREDRAW \
+       CSQCModel_Hook_PreDraw(isplayer);
+#define CSQCPLAYER_HOOK_POSTCAMERASETUP
+
+// mod must define:
+//vector PL_MIN  = ...;
+//vector PL_MAX  = ...;
+//vector PL_VIEW_OFS  = ...;
+//vector PL_CROUCH_MIN  = ...;
+//vector PL_CROUCH_MAX  = ...;
+//vector PL_CROUCH_VIEW_OFS  = ...;
+
+#ifdef SVQC
+# ifdef NO_LEGACY_NETWORKING
+#  define CSQCMODEL_AUTOINIT() CSQCModel_LinkEntity()
+#  define CSQCMODEL_AUTOUPDATE() CSQCModel_CheckUpdate()
+# else
+.float iscsqcmodel;
+float autocvar_sv_use_csqc_players;
+#  define CSQCMODEL_AUTOINIT() \
+       if(autocvar_sv_use_csqc_players) \
+       { \
+               CSQCModel_LinkEntity(); \
+               self.iscsqcmodel = 1; \
+       } \
+       else \
+               self.iscsqcmodel = 0
+#  define CSQCMODEL_AUTOUPDATE() \
+       if(autocvar_sv_use_csqc_players && !self.iscsqcmodel) \
+       { \
+               CSQCModel_LinkEntity(); \
+               self.iscsqcmodel = 1; \
+       } \
+       if(!autocvar_sv_use_csqc_players && self.iscsqcmodel) \
+       { \
+               CSQCModel_UnlinkEntity(); \
+               self.iscsqcmodel = 0; \
+       } \
+       if(self.iscsqcmodel) \
+               CSQCModel_CheckUpdate()
+# endif
+#endif
diff --git a/qcsrc/csqcmodel/sv_model.qc b/qcsrc/csqcmodel/sv_model.qc
new file mode 100644 (file)
index 0000000..164c547
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+// generic CSQC model code
+
+float CSQCModel_Send(entity to, float sf)
+{
+       // some nice flags for CSQCMODEL_IF
+       float isplayer = (self.flags & FL_CLIENT);
+       float islocalplayer = (self == to);
+       float isnolocalplayer = (isplayer && (self != to));
+
+       WriteByte(MSG_ENTITY, ENT_CLIENT_MODEL);
+       WriteShort(MSG_ENTITY, sf);
+
+#define CSQCMODEL_IF(cond) if(cond) {
+#define CSQCMODEL_ENDIF }
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       if(sf & flag) \
+       { \
+               w(MSG_ENTITY, self.csqcmodel_##f); \
+       }
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+
+       return TRUE;
+}
+
+void CSQCModel_CheckUpdate()
+{
+       // some nice flags for CSQCMODEL_IF
+       float isplayer = (self.flags & FL_CLIENT);
+       float islocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
+       float isnolocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
+
+       if(self.effects & EF_RESTARTANIM_BIT)
+       {
+               self.SendFlags |= CSQCMODEL_PROPERTY_FRAME | CSQCMODEL_PROPERTY_FRAME2; // full anim resend please
+               self.effects &~= EF_RESTARTANIM_BIT;
+       }
+
+       if(self.effects & EF_TELEPORT_BIT)
+       {
+               self.SendFlags |= CSQCMODEL_PROPERTY_TELEPORTED; // no interpolation please
+               self.effects &~= EF_TELEPORT_BIT;
+       }
+
+#define CSQCMODEL_IF(cond) if(cond) {
+#define CSQCMODEL_ENDIF }
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       { \
+               t tmp = self.f; \
+               if(tmp != self.csqcmodel_##f) \
+               { \
+                       self.csqcmodel_##f = tmp; \
+                       self.SendFlags |= flag; \
+               } \
+       }
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
+       { \
+               t tmp = bound(mi, s * self.f, ma); \
+               if(tmp != self.csqcmodel_##f) \
+               { \
+                       self.csqcmodel_##f = tmp; \
+                       self.SendFlags |= flag; \
+               } \
+       }
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+}
+
+void CSQCModel_LinkEntity()
+{
+       self.SendEntity = CSQCModel_Send;
+       self.SendFlags = 0xFFFFFF;
+}
+
+void CSQCModel_UnlinkEntity()
+{
+       self.SendEntity = func_null;
+}
diff --git a/qcsrc/csqcmodel/sv_model.qh b/qcsrc/csqcmodel/sv_model.qh
new file mode 100644 (file)
index 0000000..3c4ce2b
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+// generic CSQC model code
+
+void CSQCModel_CheckUpdate();
+void CSQCModel_LinkEntity();
+void CSQCModel_UnlinkEntity();
+
+#define CSQCMODEL_IF(cond)
+#define CSQCMODEL_ENDIF
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       .t f; \
+       .t csqcmodel_##f;
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
index 8f45f5367e2ae88756d0fef15a65ea961cb5ab87..c210f848a2955e9b0aaa17cf52af6b92fe8c21c5 100644 (file)
@@ -779,7 +779,6 @@ float autocvar_g_ctf_shield_max_ratio;
 float autocvar_g_ctf_shield_min_negscore;
 float autocvar_g_cts_finish_kill_delay;
 float autocvar_g_cts_selfdamage;
-float autocvar_g_deathglow;
 float autocvar_g_debug_bot_commands;
 float autocvar_g_domination_default_teams;
 float autocvar_g_domination_disable_frags;
@@ -1129,13 +1128,6 @@ float autocvar_sv_maxairspeed;
 float autocvar_sv_maxairstrafespeed;
 float autocvar_sv_maxspeed;
 string autocvar_sv_motd;
-string autocvar_sv_player_crouch_maxs;
-string autocvar_sv_player_crouch_mins;
-string autocvar_sv_player_crouch_viewoffset;
-string autocvar_sv_player_headsize;
-string autocvar_sv_player_maxs;
-string autocvar_sv_player_mins;
-string autocvar_sv_player_viewoffset;
 float autocvar_sv_player_jumpanim_minfall;
 float autocvar_sv_precacheplayermodels;
 float autocvar_sv_precacheweapons;
index fc484066d5d7a0268dec4bf971fa8402239f20ba..57a09fe3808ac8997b2a557010fb442e24827dc8 100644 (file)
@@ -228,7 +228,7 @@ float CheatImpulse(float i)
                        IS_CHEAT(i, 0, 0);
                        FOR_EACH_PLAYER(e)
                        {
-                               get_model_parameters(e.playermodel, e.skinindex);
+                               get_model_parameters(e.playermodel, e.skin);
                                if(get_model_parameters_sex == "Female")
                                {
                                        makevectors(e.angles);
index 3d393755a0f3749d33793dc7b6de1e574c1284c2..171fcf35b27e28a021acb742494e311debd0e0c1 100644 (file)
@@ -341,160 +341,36 @@ string CheckPlayerModel(string plyermodel) {
                // to change a cvar default, we'll have a small leak here.
                FallbackPlayerModel = strzone(cvar_defstring("_cl_playermodel"));
        }
-       if(strlen(plyermodel) < 4)
-               return FallbackPlayerModel;
+       // only in right path
        if( substring(plyermodel,0,14) != "models/player/")
                return FallbackPlayerModel;
-       else if(autocvar_sv_servermodelsonly)
+       // only good file extensions
+       if(substring(plyermodel,-4,4) != ".zym")
+       if(substring(plyermodel,-4,4) != ".dpm")
+       if(substring(plyermodel,-4,4) != ".iqm")
+       if(substring(plyermodel,-4,4) != ".md3")
+       if(substring(plyermodel,-4,4) != ".psk")
+               return FallbackPlayerModel;
+       // forbid the LOD models
+       if(substring(plyermodel, -9,5) == "_lod1")
+               return FallbackPlayerModel;
+       if(substring(plyermodel, -9,5) == "_lod2")
+               return FallbackPlayerModel;
+       if(plyermodel != strtolower(plyermodel))
+               return FallbackPlayerModel;
+       // also, restrict to server models
+       if(autocvar_sv_servermodelsonly)
        {
-               if(substring(plyermodel,-4,4) != ".zym")
-               if(substring(plyermodel,-4,4) != ".dpm")
-               if(substring(plyermodel,-4,4) != ".iqm")
-               if(substring(plyermodel,-4,4) != ".md3")
-               if(substring(plyermodel,-4,4) != ".psk")
-                       return FallbackPlayerModel;
-               // forbid the LOD models
-               if(substring(plyermodel, -9,5) == "_lod1")
-                       return FallbackPlayerModel;
-               if(substring(plyermodel, -9,5) == "_lod2")
-                       return FallbackPlayerModel;
-               if(plyermodel != strtolower(plyermodel))
-                       return FallbackPlayerModel;
                if(!fexists(plyermodel))
                        return FallbackPlayerModel;
        }
        return plyermodel;
 }
 
-/*
-=============
-Client_customizeentityforclient
-
-LOD reduction
-=============
-*/
-void Client_uncustomizeentityforclient()
-{
-       if(self.modelindex == 0) // no need to uncustomize then
-               return;
-       self.modelindex = self.modelindex_lod0;
-       self.skin = self.skinindex;
-}
-
-float Client_customizeentityforclient()
+void setplayermodel(entity e, string modelname)
 {
-       entity modelsource;
-
-       if(self.modelindex == 0)
-               return TRUE;
-
-       // forcemodel stuff
-
-#ifdef PROFILING
-       float t0;
-       t0 = gettime(GETTIME_HIRES); // reference
-#endif
-
-       modelsource = self;
-
-#ifdef ALLOW_FORCEMODELS
-       if(other.cvar_cl_forceplayermodelsfromxonotic)
-               if not(self.modelindex_lod0_from_xonotic)
-                       modelsource = other;
-       if(other.cvar_cl_forceplayermodels && sv_clforceplayermodels)
-               modelsource = other;
-#endif
-
-       self.skin = modelsource.skinindex;
-
-#if 0
-       if(modelsource == self)
-               self.skin = modelsource.skinindex;
-       else
-               self.skin = mod(modelsource.skinindex, 3); // forbid the fbskins as forced skins
-#endif
-
-       // self: me
-       // other: the player viewing me
-       float distance;
-       float f;
-
-       if(other.cvar_cl_playerdetailreduction <= 0)
-       {
-               if(other.cvar_cl_playerdetailreduction <= -2)
-                       self.modelindex = modelsource.modelindex_lod2;
-               else if(other.cvar_cl_playerdetailreduction <= -1)
-                       self.modelindex = modelsource.modelindex_lod1;
-               else
-                       self.modelindex = modelsource.modelindex_lod0;
-       }
-       else
-       {
-               distance = vlen(self.origin - other.origin);
-               f = (distance + 100.0) * other.cvar_cl_playerdetailreduction;
-               if(f > sv_loddistance2)
-                       self.modelindex = modelsource.modelindex_lod2;
-               else if(f > sv_loddistance1)
-                       self.modelindex = modelsource.modelindex_lod1;
-               else
-                       self.modelindex = modelsource.modelindex_lod0;
-       }
-
-#ifdef PROFILING
-       float t1;
-       t1 = gettime(GETTIME_HIRES); // reference
-       client_cefc_accumulator += (t1 - t0);
-#endif
-
-       return TRUE;
-}
-
-void setmodel_lod(entity e, string modelname)
-{
-       string s;
-
-       if(sv_loddistance1)
-       {
-               // FIXME: this only supports 3-letter extensions
-               s = strcat(substring(modelname, 0, strlen(modelname)-4), "_lod1", substring(modelname, -4, 4));
-               if(fexists(s))
-               {
-                       setmodel(e, s); // players have high precision
-                       self.modelindex_lod1 = self.modelindex;
-               }
-               else
-                       self.modelindex_lod1 = -1;
-
-               s = strcat(substring(modelname, 0, strlen(modelname)-4), "_lod2", substring(modelname, -4, 4));
-               if(fexists(s))
-               {
-                       setmodel(e, s); // players have high precision
-                       self.modelindex_lod2 = self.modelindex;
-               }
-               else
-                       self.modelindex_lod2 = -1;
-
-               precache_model(modelname);
-               setmodel(e, modelname); // players have high precision
-               self.modelindex_lod0 = self.modelindex;
-
-               if(self.modelindex_lod1 < 0)
-                       self.modelindex_lod1 = self.modelindex;
-
-               if(self.modelindex_lod2 < 0)
-                       self.modelindex_lod2 = self.modelindex;
-       }
-       else
-       {
-               precache_model(modelname);
-               setmodel(e, modelname); // players have high precision
-               self.modelindex_lod0 = self.modelindex;
-                       // save it for possible player model forcing
-       }
-
-       s = whichpack(self.model);
-       self.modelindex_lod0_from_xonotic = ((s == "") || (substring(s, 0, 4) == "data"));
-
+       precache_model(modelname);
+       setmodel(e, modelname);
        player_setupanimsformodel();
        UpdatePlayerSounds();
 }
@@ -609,16 +485,18 @@ void PutObserverInServer (void)
        self.fixangle = TRUE;
        self.crouch = FALSE;
 
-       self.view_ofs = '0 0 0'; // so that your view doesn't go into the ceiling with MOVETYPE_FLY_WORLDONLY, previously "PL_VIEW_OFS"
        setorigin (self, spot.origin);
-       setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX); // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
        self.prevorigin = self.origin;
        self.items = 0;
        self.weapons = 0;
        self.model = "";
        FixPlayermodel();
-       self.model = "";
-       self.modelindex = 0;
+       setmodel(self, "null");
+       self.drawonlytoclient = self;
+
+       setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX); // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
+       self.view_ofs = '0 0 0'; // so that your view doesn't go into the ceiling with MOVETYPE_FLY_WORLDONLY, previously "PL_VIEW_OFS"
+
        self.weapon = 0;
        self.weaponname = "";
        self.switchingweapon = 0;
@@ -633,9 +511,6 @@ void PutObserverInServer (void)
        self.oldvelocity = self.velocity;
        self.fire_endtime = -1;
 
-       if(sv_loddistance1)
-               SetCustomizer(self, Client_customizeentityforclient, Client_uncustomizeentityforclient);
-
        if(g_arena)
        {
                if(self.version_mismatch)
@@ -722,29 +597,29 @@ void FixPlayermodel()
                {
                        m1 = self.mins;
                        m2 = self.maxs;
-                       setmodel_lod (self, defaultmodel);
+                       setplayermodel (self, defaultmodel);
                        setsize (self, m1, m2);
                        chmdl = TRUE;
                }
 
-               oldskin = self.skinindex;
-               self.skinindex = defaultskin;
+               oldskin = self.skin;
+               self.skin = defaultskin;
        } else {
                if (self.playermodel != self.model || self.playermodel == "")
                {
                        self.playermodel = CheckPlayerModel(self.playermodel); // this is never "", so no endless loop
                        m1 = self.mins;
                        m2 = self.maxs;
-                       setmodel_lod (self, self.playermodel);
+                       setplayermodel (self, self.playermodel);
                        setsize (self, m1, m2);
                        chmdl = TRUE;
                }
 
-               oldskin = self.skinindex;
-               self.skinindex = stof(self.playerskin);
+               oldskin = self.skin;
+               self.skin = stof(self.playerskin);
        }
 
-       if(chmdl || oldskin != self.skinindex)
+       if(chmdl || oldskin != self.skin)
                self.species = player_getspecies(); // model or skin has changed
 
        if(!teamplay)
@@ -849,6 +724,7 @@ void PutClientInServer (void)
                        self.effects = EF_FULLBRIGHT;
                else
                        self.effects = 0;
+               self.effects |= EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
                self.air_finished = time + 12;
                self.dmg = 2;
                if(autocvar_g_balance_nex_charge)
@@ -946,11 +822,9 @@ void PutClientInServer (void)
                        WriteByte(MSG_ONE, TE_CSQC_SPAWN);
                });
 
-               if(sv_loddistance1)
-                       SetCustomizer(self, Client_customizeentityforclient, Client_uncustomizeentityforclient);
-
                self.model = "";
                FixPlayermodel();
+               self.drawonlytoclient = world;
 
                self.crouch = FALSE;
                self.view_ofs = PL_VIEW_OFS;
@@ -1315,7 +1189,7 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2
                        self.clientkill_nexttime = time + killtime + autocvar_g_balance_kill_antispam;
                }
 
-               if(killtime <= 0 || !self.modelindex || self.deadflag != DEAD_NO)
+               if(killtime <= 0 || self.classname != "player" || self.deadflag != DEAD_NO)
                {
                        ClientKill_Now();
                }
@@ -1723,6 +1597,8 @@ void ClientConnect (void)
        if(!autocvar_g_campaign)
                Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0);
 
+       CSQCMODEL_AUTOINIT();
+
        self.model_randomizer = random();
 }
 
@@ -2743,42 +2619,26 @@ void PlayerPreThink (void)
 
                if(frametime)
                {
-                       if(self.health <= 0 && autocvar_g_deathglow)
-                       {
-                               if(self.glowmod_x > 0)
-                                       self.glowmod_x -= autocvar_g_deathglow * frametime;
-                               else
-                                       self.glowmod_x = -1;
-                               if(self.glowmod_y > 0)
-                                       self.glowmod_y -= autocvar_g_deathglow * frametime;
-                               else
-                                       self.glowmod_y = -1;
-                               if(self.glowmod_z > 0)
-                                       self.glowmod_z -= autocvar_g_deathglow * frametime;
-                               else
-                                       self.glowmod_z = -1;
-                       }
-                       else
+#ifndef NO_LEGACY_NETWORKING
+                       self.glowmod = colormapPaletteColor(self.clientcolors & 0x0F, TRUE) * 2;
+#endif
+
+                       if(self.weapon == WEP_NEX && autocvar_g_balance_nex_charge)
                        {
-                               // set weapon and player glowmod
-                               self.glowmod = colormapPaletteColor(self.clientcolors & 0x0F, TRUE) * 2;
+                               self.weaponentity_glowmod_x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
+                               self.weaponentity_glowmod_y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
+                               self.weaponentity_glowmod_z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
 
-                               if(self.weapon == WEP_NEX && autocvar_g_balance_nex_charge)
+                               if(self.nex_charge > autocvar_g_balance_nex_charge_animlimit)
                                {
-                                       self.weaponentity_glowmod_x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
-                                       self.weaponentity_glowmod_y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
-                                       self.weaponentity_glowmod_z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
-
-                                       if(self.nex_charge > autocvar_g_balance_nex_charge_animlimit)
-                                       {
-                                               self.weaponentity_glowmod_x = self.weaponentity_glowmod_x + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
-                                               self.weaponentity_glowmod_y = self.weaponentity_glowmod_y + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
-                                               self.weaponentity_glowmod_z = self.weaponentity_glowmod_z + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
-                                       }
+                                       self.weaponentity_glowmod_x = self.weaponentity_glowmod_x + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
+                                       self.weaponentity_glowmod_y = self.weaponentity_glowmod_y + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
+                                       self.weaponentity_glowmod_z = self.weaponentity_glowmod_z + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
                                }
-                               else
-                                       self.weaponentity_glowmod = self.glowmod;
                        }
+                       else
+                               self.weaponentity_glowmod = colormapPaletteColor(self.clientcolors & 0x0F, TRUE) * 2;
+
                        player_powerups();
                }
 
@@ -3191,4 +3051,6 @@ void PlayerPostThink (void)
        if(g_race)
                dprint(sprintf("%f %.6f\n", time, race_GetFractionalLapCount(self)));
        */
+
+       CSQCMODEL_AUTOUPDATE();
 }
index 2b3e4d4db1995400d26feaeeaa73af814b8c8e74..0b1576eed152897ae80855fc9ad79b82da313451 100644 (file)
@@ -134,7 +134,6 @@ void CopyBody(float keepvelocity)
        self.enemy = oldself;
        self.lip = oldself.lip;
        self.colormap = oldself.colormap;
-       self.glowmod = oldself.glowmod;
        self.iscreature = oldself.iscreature;
        self.damagedbycontents = oldself.damagedbycontents;
        self.angles = oldself.angles;
@@ -142,6 +141,7 @@ void CopyBody(float keepvelocity)
        self.classname = "body";
        self.damageforcescale = oldself.damageforcescale;
        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;
@@ -158,11 +158,7 @@ void CopyBody(float keepvelocity)
        self.armortype = oldself.armortype;
        self.model = oldself.model;
        self.modelindex = oldself.modelindex;
-       self.modelindex_lod0 = oldself.modelindex_lod0;
-       self.modelindex_lod0_from_xonotic = oldself.modelindex_lod0_from_xonotic;
-       self.modelindex_lod1 = oldself.modelindex_lod1;
-       self.modelindex_lod2 = oldself.modelindex_lod2;
-       self.skinindex = oldself.skinindex;
+       self.skin = oldself.skin;
        self.species = oldself.species;
        self.movetype = oldself.movetype;
        self.nextthink = oldself.nextthink;
@@ -195,7 +191,7 @@ void CopyBody(float keepvelocity)
 float player_getspecies()
 {
        float s;
-       get_model_parameters(self.model, self.skinindex);
+       get_model_parameters(self.model, self.skin);
        s = get_model_parameters_species;
        get_model_parameters(string_null, 0);
        if(s < 0)
@@ -1170,18 +1166,18 @@ float LoadPlayerSounds(string f, float first)
 }
 
 .float modelindex_for_playersound;
-.float skinindex_for_playersound;
+.float skin_for_playersound;
 void UpdatePlayerSounds()
 {
        if(self.modelindex == self.modelindex_for_playersound)
-       if(self.skinindex == self.skinindex_for_playersound)
+       if(self.skin == self.skin_for_playersound)
                return;
        self.modelindex_for_playersound = self.modelindex;
-       self.skinindex_for_playersound = self.skinindex;
+       self.skin_for_playersound = self.skin;
        ClearPlayerSounds();
        LoadPlayerSounds("sound/player/default.sounds", 1);
        if(!autocvar_g_debug_defaultsounds)
-               if(!LoadPlayerSounds(get_model_datafilename(self.model, self.skinindex, "sounds"), 0))
+               if(!LoadPlayerSounds(get_model_datafilename(self.model, self.skin, "sounds"), 0))
                        LoadPlayerSounds(get_model_datafilename(self.model, 0, "sounds"), 0);
 }
 
index 4acb8da891fa4fa4158b5ef01b7026a176cced5e..ae275ac679b6786a094f380577d602ea1d37388a 100644 (file)
@@ -681,6 +681,8 @@ void CL_ExteriorWeaponentity_Think()
 
        self.glowmod = self.owner.weaponentity_glowmod;
        self.colormap = self.owner.colormap;
+
+       CSQCMODEL_AUTOUPDATE();
 }
 
 // spawning weaponentity for client
@@ -708,6 +710,13 @@ void CL_SpawnWeaponentity()
        self.exteriorweaponentity.angles = '0 0 0';
        self.exteriorweaponentity.think = CL_ExteriorWeaponentity_Think;
        self.exteriorweaponentity.nextthink = time;
+
+       {
+               entity oldself = self;
+               self = self.exteriorweaponentity;
+               CSQCMODEL_AUTOINIT();
+               self = oldself;
+       }
 }
 
 void Send_WeaponComplain (entity e, float wpn, string wpnname, float type)
index 5e18a5cc60c55bb4936887ab9fab6f8b80153105..7cefb530d9f14be48ec3fb4f657fd1a07b0bbe3f 100644 (file)
@@ -125,13 +125,6 @@ float      MSG_ALL                                 = 2; // reliable
 float  MSG_INIT                                = 3; // initialization
 float  MSG_ENTITY                              = 5; // csqc
 
-vector PL_VIEW_OFS                             = '0 0 35';
-vector PL_MIN                                  = '-16 -16 -24';
-vector PL_MAX                                  = '16 16 45';
-vector PL_CROUCH_VIEW_OFS                      = '0 0 15';
-vector PL_CROUCH_MIN                           = '-16 -16 -24';
-vector PL_CROUCH_MAX                           = '16 16 25';
-
 // Sajt - added these, just as constants. Not sure how you want them actually put in the game, but I just
 // did this so at least they worked
 // NOTE: instagib IS NOT compatible with rocket-arena, so make sure to prevent selecting both in a menu
index ae8be3f9d609a26668c4b855490475e583abe4c5..0c06958af30d6de3baf411d5ba5308495894227f 100644 (file)
@@ -327,7 +327,6 @@ float default_weapon_alpha;
 
 .float() customizeentityforclient;
 .float cvar_cl_handicap;
-.float cvar_cl_playerdetailreduction;
 .float cvar_cl_clippedspectating;
 .float cvar_cl_autoscreenshot;
 .float cvar_cl_movement_track_canjump;
@@ -341,8 +340,6 @@ float default_weapon_alpha;
 .float cvar_cl_forceplayermodelsfromxonotic;
 float sv_clforceplayermodels;
 #endif
-float sv_loddistance1;
-float sv_loddistance2;
 .float cvar_cl_gunalign;
 .float cvar_cl_noantilag;
 
@@ -357,12 +354,6 @@ void AnnounceTo(entity e, string snd);
 
 .float version_nagtime;
 
-.float modelindex_lod0;
-.float modelindex_lod0_from_xonotic;
-.float skinindex;
-.float modelindex_lod1;
-.float modelindex_lod2;
-
 #define NUM_JUMPPADSUSED 3
 .float jumppadcount;
 .entity jumppadsused[NUM_JUMPPADSUSED];
index d0474b8ed4e92633c8ee3a83747db22eff59ea99..79641ed70eb130a7c292ecd8e4c3c9b754b85be6 100644 (file)
@@ -935,8 +935,17 @@ void spawnfunc_worldspawn (void)
                s = "";
                n = tokenize_console(cvar_string("sv_curl_serverpackages"));
                for(i = 0; i < n; ++i)
-                       if(substring(argv(i), -14, -1) != ".serverpackage")
+                       if(substring(argv(i), -14, -1) != "-serverpackage.txt")
+                       if(substring(argv(i), -14, -1) != ".serverpackage") // OLD legacy
                                s = strcat(s, " ", argv(i));
+               fd = search_begin("*-serverpackage.txt", TRUE, FALSE);
+               if(fd >= 0)
+               {
+                       j = search_getsize(fd);
+                       for(i = 0; i < j; ++i)
+                               s = strcat(s, " ", search_getfilename(fd, i));
+                       search_end(fd);
+               }
                fd = search_begin("*.serverpackage", TRUE, FALSE);
                if(fd >= 0)
                {
index 60644e6f20a4c1e6fda54f09532602865e1b36e5..0c47526a581ac46da23dbf2bcc393686bd1a6c3d 100644 (file)
@@ -151,25 +151,9 @@ void GameLogClose()
     }
 }
 
-vector PL_VIEW_OFS;
-vector PL_MIN;
-vector PL_MAX;
-vector PL_HEAD;
-vector PL_CROUCH_VIEW_OFS;
-vector PL_CROUCH_MIN;
-vector PL_CROUCH_MAX;
-
 float spawnpoint_nag;
 void relocate_spawnpoint()
 {
-    PL_VIEW_OFS                             = stov(autocvar_sv_player_viewoffset);
-    PL_MIN                                  = stov(autocvar_sv_player_mins);
-    PL_MAX                                  = stov(autocvar_sv_player_maxs);
-    PL_HEAD                                 = stov(autocvar_sv_player_headsize);
-    PL_CROUCH_VIEW_OFS                      = stov(autocvar_sv_player_crouch_viewoffset);
-    PL_CROUCH_MIN                           = stov(autocvar_sv_player_crouch_mins);
-    PL_CROUCH_MAX                           = stov(autocvar_sv_player_crouch_maxs);
-
     // nudge off the floor
     setorigin(self, self.origin + '0 0 1');
 
@@ -552,7 +536,6 @@ void GetCvars(float f)
        MUTATOR_CALLHOOK(GetCvars);
        GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
        GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot");
-       GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
        GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
        GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
        GetCvars_handleFloat(s, f, cvar_cl_clippedspectating, "cl_clippedspectating");
@@ -1136,11 +1119,6 @@ void readlevelcvars(void)
 #ifdef ALLOW_FORCEMODELS
        sv_clforceplayermodels = cvar("sv_clforceplayermodels");
 #endif
-       sv_loddistance1 = cvar("sv_loddistance1");
-       sv_loddistance2 = cvar("sv_loddistance2");
-
-       if(sv_loddistance2 <= sv_loddistance1)
-               sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
 
        sv_clones = cvar("sv_clones");
        sv_gentle = cvar("sv_gentle");
@@ -1466,15 +1444,12 @@ void precache_playermodel(string m)
        if(substring(m, -9,5) == "_lod2")
                return;
        precache_model(m);
-       if(sv_loddistance1)
-       {
-               f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
-               if(fexists(f))
-                       precache_model(f);
-               f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1));
-               if(fexists(f))
-                       precache_model(f);
-       }
+       f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
+       if(fexists(f))
+               precache_model(f);
+       f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1));
+       if(fexists(f))
+               precache_model(f);
 
        globhandle = search_begin(strcat(m, "_*.sounds"), TRUE, FALSE);
        if (globhandle < 0)
index 461f475c7818787f113386378b1a4e09159fa46d..bf50c9d3cada867c7d4d2034244a5a75a0d8caa4 100644 (file)
@@ -7,6 +7,7 @@
 .vector portal_safe_origin;
 .float portal_wants_to_vanish;
 .float portal_activatetime;
+.float savemodelindex;
 
 float PlayerEdgeDistance(entity p, vector v)
 {
@@ -479,7 +480,7 @@ float Portal_Customize()
                other = other.enemy;
        if(other == self.aiment)
        {
-               self.modelindex = self.modelindex_lod0;
+               self.modelindex = self.savemodelindex;
        }
        else if(IS_INDEPENDENT_PLAYER(other) || IS_INDEPENDENT_PLAYER(self.aiment))
        {
@@ -487,7 +488,7 @@ float Portal_Customize()
        }
        else
        {
-               self.modelindex = self.modelindex_lod0;
+               self.modelindex = self.savemodelindex;
        }
        return TRUE;
 }
@@ -617,7 +618,7 @@ entity Portal_Spawn(entity own, vector org, vector ang)
        portal.fade_time = time + autocvar_g_balance_portal_lifetime;
        portal.health = autocvar_g_balance_portal_health;
        setmodel(portal, "models/portal.md3");
-       portal.modelindex_lod0 = portal.modelindex;
+       portal.savemodelindex = portal.modelindex;
        portal.customizeentityforclient = Portal_Customize;
 
        if(!Portal_FindSafeOrigin(portal))
index 6dd08bb1bcab2f0cee10cb2963da90edd8475478..45d83116f46295b910aadfb84c0d1ceb694f3dfd 100644 (file)
@@ -38,6 +38,9 @@ campaign.qh
 
 accuracy.qh
 csqcprojectile.qh
+../csqcmodel/settings.qh
+../csqcmodel/common.qh
+../csqcmodel/sv_model.qh
 csqceffects.qc
 
 anticheat.qh
@@ -176,6 +179,7 @@ target_music.qc
 
 
 accuracy.qc
+../csqcmodel/sv_model.qc
 csqcprojectile.qc
 
 playerdemo.qc