Merge branch 'master' into mirceakitsune/damage_effects
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / Main.qc
index 7e480ad..b2a2170 100644 (file)
@@ -4,27 +4,6 @@
 
 #define DP_CSQC_ENTITY_REMOVE_IS_B0RKED
 
-void cvar_clientsettemp(string cv, string val)
-{
-       entity e;
-       for(e = world; (e = find(e, classname, "saved_cvar_value")); )
-               if(e.netname == cv)
-                       goto saved;
-       e = spawn();
-       e.classname = "saved_cvar_value";
-       e.netname = strzone(cv);
-       e.message = strzone(cvar_string(cv));
-:saved
-       cvar_set(cv, val);
-}
-
-void cvar_clientsettemp_restore()
-{
-       entity e;
-       for(e = world; (e = find(e, classname, "saved_cvar_value")); )
-                       cvar_set(e.netname, e.message);
-}
-
 void menu_show_error()
 {
        drawstring('0 200 0', _("ERROR - MENU IS VISIBLE BUT NO MENU WAS DEFINED!"), '8 8 0', '1 0 0', 1, 0);
@@ -41,8 +20,56 @@ 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;
-string cl_announcer_prev;
 void WaypointSprite_Load();
 void CSQC_Init(void)
 {
@@ -68,6 +95,11 @@ void CSQC_Init(void)
 
        float i;
 
+#ifdef COMPAT_XON050_ENGINE
+       // old engine lacks implementation of player_localnum
+       player_localnum = player_localentnum - 1;
+#endif
+
        binddb = db_create();
        tempdb = db_create();
        ClientProgsDB = db_load("client.db");
@@ -79,38 +111,34 @@ void CSQC_Init(void)
        menu_action = menu_sub_null;
 
        for(i = 0; i < 255; ++i)
-               if(getplayerkey(i, "viewentity") == "")
+               if(getplayerkeyvalue(i, "viewentity") == "")
                        break;
        maxclients = i;
 
-       //ctf_temp_1 = "";
-       // localcmd("alias order \"cmd order $*\""); enable if ctf-command thingy is used
-       //registercmd("ctf_menu");
-       registercmd("ons_map");
-       registercmd("hud_configure");
-       registercmd("hud_save");
-       //registercmd("menu_action");
+       registercommand("hud_configure");
+       registercommand("hud_save");
+       //registercommand("menu_action");
 
-       registercmd("+showscores");registercmd("-showscores");
-       registercmd("+showaccuracy");registercmd("-showaccuracy");
+       registercommand("+showscores");registercommand("-showscores");
+       registercommand("+showaccuracy");registercommand("-showaccuracy");
 
 #ifndef CAMERATEST
        if(isdemo())
        {
 #endif
-               registercmd("+forward");registercmd("-forward");
-               registercmd("+back");registercmd("-back");
-               registercmd("+moveup");registercmd("-moveup");
-               registercmd("+movedown");registercmd("-movedown");
-               registercmd("+moveright");registercmd("-moveright");
-               registercmd("+moveleft");registercmd("-moveleft");
-               registercmd("+roll_right");registercmd("-roll_right");
-               registercmd("+roll_left");registercmd("-roll_left");
+               registercommand("+forward");registercommand("-forward");
+               registercommand("+back");registercommand("-back");
+               registercommand("+moveup");registercommand("-moveup");
+               registercommand("+movedown");registercommand("-movedown");
+               registercommand("+moveright");registercommand("-moveright");
+               registercommand("+moveleft");registercommand("-moveleft");
+               registercommand("+roll_right");registercommand("-roll_right");
+               registercommand("+roll_left");registercommand("-roll_left");
 #ifndef CAMERATEST
        }
 #endif
        registercvar("hud_usecsqc", "1");
-       registercvar("scoreboard_columns", "default", CVAR_SAVE);
+       registercvar("scoreboard_columns", "default");
 
        gametype = 0;
 
@@ -127,13 +155,25 @@ void CSQC_Init(void)
 
        GetTeam(COLOR_SPECTATOR, true); // add specs first
 
+       // needs to be done so early because of the constants they create
        RegisterWeapons();
+       RegisterGametypes();
 
        WaypointSprite_Load();
 
        // precaches
+       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();
@@ -141,18 +181,15 @@ void CSQC_Init(void)
        DamageInfo_Precache();
        Vehicles_Precache();
        turrets_precache();
-
-       if(autocvar_cl_announcer != cl_announcer_prev) {
-               Announcer_Precache();
-               if(cl_announcer_prev)
-                       strunzone(cl_announcer_prev);
-               cl_announcer_prev = strzone(autocvar_cl_announcer);
-       }
+  Announcer_Precache();
        Tuba_Precache();
-
-       if(autocvar_cl_reticle_item_normal) precache_pic("gfx/reticle_normal");
-       if(autocvar_cl_reticle_item_nex) precache_pic("gfx/reticle_nex");
-
+       
+       if(autocvar_cl_reticle)
+       {
+               if(autocvar_cl_reticle_item_normal) { precache_pic("gfx/reticle_normal"); }
+               if(autocvar_cl_reticle_item_nex) { precache_pic("gfx/reticle_nex"); }
+       }
+       
        get_mi_min_max_texcoords(1); // try the CLEVER way first
        minimapname = strcat("gfx/", mi_shortname, "_radar.tga");
        shortmapname = mi_shortname;
@@ -178,7 +215,7 @@ void CSQC_Init(void)
 }
 
 // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc)
-void CSQC_Shutdown(void)
+void Shutdown(void)
 {
 #ifdef USE_FTE
 #pragma TARGET id
@@ -199,8 +236,6 @@ void CSQC_Shutdown(void)
                db_save(ClientProgsDB, "client.db");
        db_close(ClientProgsDB);
 
-       cvar_clientsettemp_restore();
-
        if(camera_active)
                cvar_set("chase_active",ftos(chase_active_backup));
 
@@ -232,7 +267,7 @@ float SetTeam(entity o, float Team)
                        case COLOR_TEAM4:
                                break;
                        default:
-                               if(GetTeam(Team, false) == NULL)
+                               if(GetTeam(Team, false) == world)
                                {
                                        print(sprintf(_("trying to switch to unsupported team %d\n"), Team));
                                        Team = COLOR_SPECTATOR;
@@ -248,7 +283,7 @@ float SetTeam(entity o, float Team)
                        case 0:
                                break;
                        default:
-                               if(GetTeam(Team, false) == NULL)
+                               if(GetTeam(Team, false) == world)
                                {
                                        print(sprintf(_("trying to switch to unsupported team %d\n"), Team));
                                        Team = COLOR_SPECTATOR;
@@ -345,7 +380,7 @@ void PostInit(void)
        postinit = true;
 }
 
-// CSQC_ConsoleCommand : Used to parse commands in the console that have been registered with the "registercmd" function
+// CSQC_ConsoleCommand : Used to parse commands in the console that have been registered with the "registercommand" function
 // Return value should be 1 if CSQC handled the command, otherwise return 0 to have the engine handle it.
 float button_zoom;
 void Cmd_HUD_SetFields(float);
@@ -354,7 +389,6 @@ float CSQC_ConsoleCommand(string strMessage)
 {
        float argc;
        // Tokenize String
-       //argc = tokenize(strMessage);
        argc = tokenize_console(strMessage);
 
        // Acquire Command
@@ -492,7 +526,6 @@ void GameCommand(string msg)
        if(argv(0) == "help" || argc == 0)
        {
                print(_("Usage: cl_cmd COMMAND..., where possible commands are:\n"));
-               print(_("  settemp cvar value\n"));
                print(_("  scoreboard_columns_set ...\n"));
                print(_("  scoreboard_columns_help\n"));
                GameCommand_Generic("help");
@@ -514,9 +547,6 @@ void GameCommand(string msg)
                else
                        hud_panel_radar_maximized = (stof(argv(1)) != 0);
        }
-       else if(cmd == "settemp") {
-               cvar_clientsettemp(argv(1), argv(2));
-       }
        else if(cmd == "scoreboard_columns_set") {
                Cmd_HUD_SetFields(argc);
        }
@@ -814,7 +844,7 @@ void Ent_ClientData()
        if(f & 2)
        {
                newspectatee_status = ReadByte();
-               if(newspectatee_status == player_localentnum)
+               if(newspectatee_status == player_localnum + 1)
                        newspectatee_status = -1; // observing
        }
        else
@@ -848,6 +878,8 @@ void Ent_ClientData()
                        prev_health = -1;
        }
        spectatee_status = newspectatee_status;
+
+       // non-COMPAT_XON050_ENGINE: we could get rid of spectatee_status, and derive it from player_localentnum and player_localnum
 }
 
 void Ent_Nagger()
@@ -965,13 +997,23 @@ void CSQC_Ent_Update(float bIsNewEntity)
 
 #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
        if(self.enttype)
-               if(t != self.enttype)
+       {
+               if(t != self.enttype || bIsNewEntity)
                {
                        //print(_("A CSQC entity changed its type!\n"));
-                       print(sprintf(_("A CSQC entity changed its type! (edict: %d, classname: %s)\n"), num_for_edict(self), self.classname));
+                       print(sprintf(_("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n"), num_for_edict(self), self.entnum, self.enttype, t));
                        Ent_Remove();
                        bIsNewEntity = 1;
                }
+       }
+       else
+       {
+               if(!bIsNewEntity)
+               {
+                       print(sprintf(_("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n"), num_for_edict(self), self.entnum, t));
+                       bIsNewEntity = 1;
+               }
+       }
 #endif
        self.enttype = t;
        switch(t)
@@ -1008,6 +1050,7 @@ void CSQC_Ent_Update(float bIsNewEntity)
                case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
                case ENT_CLIENT_TURRET: ent_turret(); break; 
                case ENT_CLIENT_DAMAGEEFFECT: Ent_DamageEffect(); break;
+               case ENT_CLIENT_MODEL: CSQCModel_Read(bIsNewEntity); 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));
@@ -1042,7 +1085,7 @@ void Gamemode_Init()
 {
        if not(isdemo())
        {
-               localcmd("\n_cl_hook_gamestart ", GametypeNameFromType(gametype), "\n");
+               localcmd("\n_cl_hook_gamestart ", MapInfo_Type_ToString(gametype), "\n");
                calledhooks |= HOOK_START;
        }
 }
@@ -1057,10 +1100,10 @@ void CSQC_Parse_Print(string strMessage)
        print(ColorTranslateRGB(strMessage));
 }
 
-// CSQC_Parse_CenterPrint : Provides the centerprint string in the first parameter that the server provided.
+// CSQC_Parse_CenterPrint : Provides the centerprint_hud string in the first parameter that the server provided.
 void CSQC_Parse_CenterPrint(string strMessage)
 {
-       centerprint(strMessage);
+       centerprint_hud(strMessage);
 }
 
 string notranslate_fogcmd1 = "\nfog ";
@@ -1078,7 +1121,7 @@ void Ent_ScoresInfo()
 {
        float i;
        self.classname = "ent_client_scores_info";
-       gametype = ReadByte();
+       gametype = ReadInt24_t();
        for(i = 0; i < MAX_SCORE; ++i)
        {
                scores_label[i] = strzone(ReadString());
@@ -1285,7 +1328,7 @@ void Net_ReadRace()
                                strunzone(grecordholder[pos-1]);
                        grecordholder[pos-1] = strzone(ReadString());
                        grecordtime[pos-1] = ReadInt24_t();
-                       if(grecordholder[pos-1] == GetPlayerName(player_localentnum -1))
+                       if(grecordholder[pos-1] == GetPlayerName(player_localnum))
                                race_myrank = pos;
                        break;
                case RACE_NET_SERVER_STATUS:
@@ -1385,7 +1428,7 @@ float CSQC_Parse_TempEntity()
                        bHandled = true;
                        break;
                case TE_CSQC_ANNOUNCE:
-                       announce_snd = strzone(ReadString());
+                       Announcer_Play(ReadString());
                        bHandled = true;
                        break;
                case TE_CSQC_KILLNOTIFY:
@@ -1411,10 +1454,10 @@ float CSQC_Parse_TempEntity()
                        Net_WeaponComplain();
                        bHandled = true;
                        break;
-        case TE_CSQC_VEHICLESETUP:
-            Net_VehicleSetup();
-            bHandled = true;
-            break;
+               case TE_CSQC_VEHICLESETUP:
+                       Net_VehicleSetup();
+                       bHandled = true;
+                       break;
                default:
                        // No special logic for this temporary entity; return 0 so the engine can handle it
                        bHandled = false;
@@ -1435,7 +1478,7 @@ string getcommandkey(string text, string command)
        keys = db_get(binddb, command);
        if (!keys)
        {
-               n = tokenize(findkeysforcommand(command)); // uses '...' strings
+               n = tokenize(findkeysforcommand(command, 0)); // uses '...' strings
                for(j = 0; j < n; ++j)
                {
                        k = stof(argv(j));