Atrinik Client 2.5
client/settings.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00033 static const char *const opt_types[OPT_TYPE_NUM] =
00034 {
00035     "bool", "input_num", "input_text", "range", "select", "int"
00036 };
00037 
00039 setting_category **setting_categories = NULL;
00041 size_t setting_categories_num = 0;
00045 static uint8 setting_update_mapsize = 0;
00046 
00051 static void setting_load_value(setting_struct *setting, const char *str)
00052 {
00053     switch (setting->type)
00054     {
00055         case OPT_TYPE_BOOL:
00056             if (KEYWORD_IS_TRUE(str))
00057             {
00058                 setting->val.i = 1;
00059             }
00060             else if (KEYWORD_IS_FALSE(str))
00061             {
00062                 setting->val.i = 0;
00063             }
00064             else
00065             {
00066                 setting->val.i = atoi(str);
00067             }
00068 
00069             break;
00070 
00071         case OPT_TYPE_INPUT_NUM:
00072         case OPT_TYPE_RANGE:
00073         case OPT_TYPE_INT:
00074         case OPT_TYPE_SELECT:
00075             setting->val.i = atoi(str);
00076             break;
00077 
00078         case OPT_TYPE_INPUT_TEXT:
00079             if (setting->val.str)
00080             {
00081                 free(setting->val.str);
00082             }
00083 
00084             setting->val.str = strdup(str);
00085             break;
00086     }
00087 }
00088 
00091 void settings_init()
00092 {
00093     FILE *fp;
00094     char buf[HUGE_BUF], *cp;
00095     setting_category *category;
00096     setting_struct *setting;
00097 
00098     fp = fopen_wrapper(FILE_SETTINGS_TXT, "r");
00099 
00100     if (!fp)
00101     {
00102         LOG(llevError, "settings_init(): Missing "FILE_SETTINGS_TXT", cannot continue.\n");
00103     }
00104 
00105     category = NULL;
00106     setting = NULL;
00107     setting_categories = NULL;
00108     setting_categories_num = 0;
00109 
00110     while (fgets(buf, sizeof(buf) - 1, fp))
00111     {
00112         cp = strchr(buf, '\n');
00113 
00114         if (cp)
00115         {
00116             *cp = '\0';
00117         }
00118 
00119         cp = buf;
00120 
00121         while (*cp != '\0')
00122         {
00123             if (isspace(*cp))
00124             {
00125                 cp++;
00126             }
00127             else
00128             {
00129                 break;
00130             }
00131         }
00132 
00133         if (*cp == '#' || *cp == '\0')
00134         {
00135             continue;
00136         }
00137 
00138         if (!strcmp(cp, "end"))
00139         {
00140             if (setting)
00141             {
00142                 category->settings = realloc(category->settings, sizeof(category->settings) * (category->settings_num + 1));
00143                 category->settings[category->settings_num] = setting;
00144                 category->settings_num++;
00145                 setting = NULL;
00146             }
00147             else if (category)
00148             {
00149                 setting_categories = realloc(setting_categories, sizeof(*setting_categories) * (setting_categories_num + 1));
00150                 setting_categories[setting_categories_num] = category;
00151                 setting_categories_num++;
00152                 category = NULL;
00153             }
00154         }
00155         else if (setting)
00156         {
00157             if (!strncmp(cp, "type ", 5))
00158             {
00159                 size_t type_id;
00160 
00161                 for (type_id = 0; type_id < OPT_TYPE_NUM; type_id++)
00162                 {
00163                     if (!strcmp(cp + 5, opt_types[type_id]))
00164                     {
00165                         setting->type = type_id;
00166                         break;
00167                     }
00168                 }
00169 
00170                 if (type_id == OPT_TYPE_NUM)
00171                 {
00172                     LOG(llevError, "Invalid type: %s\n", cp + 5);
00173                 }
00174                 else if (type_id == OPT_TYPE_SELECT)
00175                 {
00176                     setting->custom_attrset = calloc(1, sizeof(setting_select));
00177                 }
00178                 else if (type_id == OPT_TYPE_RANGE)
00179                 {
00180                     setting->custom_attrset = calloc(1, sizeof(setting_range));
00181                 }
00182             }
00183             else if (!strncmp(cp, "default ", 8))
00184             {
00185                 setting_load_value(setting, cp + 8);
00186             }
00187             else if (!strncmp(cp, "desc ", 5))
00188             {
00189                 setting->desc = strdup(cp + 5);
00190                 convert_newline(setting->desc);
00191             }
00192             else if (!strncmp(cp, "internal ", 9))
00193             {
00194                 setting->internal = KEYWORD_IS_TRUE(cp + 9) ? 1 : 0;
00195             }
00196             else if (setting->type == OPT_TYPE_SELECT && !strncmp(cp, "option ", 7))
00197             {
00198                 setting_select *s_select = SETTING_SELECT(setting);
00199 
00200                 s_select->options = realloc(s_select->options, sizeof(*s_select->options) * (s_select->options_len + 1));
00201                 s_select->options[s_select->options_len] = strdup(cp + 7);
00202                 s_select->options_len++;
00203             }
00204             else if (setting->type == OPT_TYPE_RANGE && !strncmp(cp, "range ", 6))
00205             {
00206                 setting_range *range = SETTING_RANGE(setting);
00207                 sint64 min, max;
00208 
00209                 if (sscanf(cp + 6, "%"FMT64" - %"FMT64, &min, &max) == 2)
00210                 {
00211                     range->min = min;
00212                     range->max = max;
00213                 }
00214                 else
00215                 {
00216                     LOG(llevBug, "settings_init(): Invalid line: %s\n", cp);
00217                 }
00218             }
00219             else if (setting->type == OPT_TYPE_RANGE && !strncmp(cp, "advance ", 8))
00220             {
00221                 SETTING_RANGE(setting)->advance = atoi(cp + 8);
00222             }
00223             else
00224             {
00225                 LOG(llevBug, "settings_init(): Invalid line: %s\n", cp);
00226             }
00227         }
00228         else if (category)
00229         {
00230             if (!strncmp(cp, "setting ", 8))
00231             {
00232                 setting = calloc(1, sizeof(*setting));
00233                 setting->name = strdup(cp + 8);
00234             }
00235             else
00236             {
00237                 LOG(llevBug, "settings_init(): Invalid line: %s\n", cp);
00238             }
00239         }
00240         else if (!strncmp(cp, "category ", 9))
00241         {
00242             category = calloc(1, sizeof(*category));
00243             category->name = strdup(cp + 9);
00244         }
00245     }
00246 
00247     fclose(fp);
00248 
00249     /* Now load the user's settings (if any). */
00250     settings_load();
00251 }
00252 
00255 void settings_load()
00256 {
00257     FILE *fp;
00258     char buf[HUGE_BUF], *cp;
00259     size_t cat = 0, setting = 0;
00260     uint8 is_setting_name = 1;
00261 
00262     fp = fopen_wrapper(FILE_SETTINGS_DAT, "r");
00263 
00264     /* No user settings yet. */
00265     if (!fp)
00266     {
00267         return;
00268     }
00269 
00270     while (fgets(buf, sizeof(buf) - 1, fp))
00271     {
00272         cp = strchr(buf, '\n');
00273 
00274         if (cp)
00275         {
00276             *cp = '\0';
00277         }
00278 
00279         cp = buf;
00280 
00281         while (*cp != '\0')
00282         {
00283             if (isspace(*cp))
00284             {
00285                 cp++;
00286             }
00287             else
00288             {
00289                 break;
00290             }
00291         }
00292 
00293         if (*cp == '#' || *cp == '\0')
00294         {
00295             continue;
00296         }
00297 
00298         if (!strncmp(cp, "category ", 9))
00299         {
00300             cat = category_from_name(cp + 9);
00301         }
00302         else
00303         {
00304             if (is_setting_name)
00305             {
00306                 setting = setting_from_name(cp);
00307             }
00308             else
00309             {
00310                 setting_load_value(setting_categories[cat]->settings[setting], cp);
00311             }
00312 
00313             is_setting_name = !is_setting_name;
00314         }
00315     }
00316 
00317     fclose(fp);
00318 }
00319 
00322 void settings_save()
00323 {
00324     FILE *fp;
00325     size_t cat, set;
00326     setting_struct *setting;
00327 
00328     fp = fopen_wrapper(FILE_SETTINGS_DAT, "w");
00329 
00330     if (!fp)
00331     {
00332         LOG(llevBug, "Could not open settings file ("FILE_SETTINGS_DAT").\n");
00333         return;
00334     }
00335 
00336     for (cat = 0; cat < setting_categories_num; cat++)
00337     {
00338         fprintf(fp, "category %s\n", setting_categories[cat]->name);
00339 
00340         for (set = 0; set < setting_categories[cat]->settings_num; set++)
00341         {
00342             setting = setting_categories[cat]->settings[set];
00343 
00344             fprintf(fp, "%s\n", setting->name);
00345 
00346             if (setting_is_text(setting))
00347             {
00348                 fprintf(fp, "%s\n", setting->val.str);
00349             }
00350             else
00351             {
00352                 fprintf(fp, "%"FMT64"\n", setting->val.i);
00353             }
00354         }
00355     }
00356 
00357     fclose(fp);
00358 }
00359 
00364 void settings_deinit()
00365 {
00366     size_t cat, setting;
00367 
00368     /* Save the user's settings first. */
00369     settings_save();
00370 
00371     /* Start deinitializing. */
00372     for (cat = 0; cat < setting_categories_num; cat++)
00373     {
00374         for (setting = 0; setting < setting_categories[cat]->settings_num; setting++)
00375         {
00376             if (setting_is_text(setting_categories[cat]->settings[setting]))
00377             {
00378                 free(setting_categories[cat]->settings[setting]->val.str);
00379             }
00380 
00381             free(setting_categories[cat]->settings[setting]->name);
00382 
00383             if (setting_categories[cat]->settings[setting]->desc)
00384             {
00385                 free(setting_categories[cat]->settings[setting]->desc);
00386             }
00387 
00388             if (setting_categories[cat]->settings[setting]->type == OPT_TYPE_SELECT)
00389             {
00390                 setting_select *s_select = SETTING_SELECT(setting_categories[cat]->settings[setting]);
00391                 size_t option;
00392 
00393                 for (option = 0; option < s_select->options_len; option++)
00394                 {
00395                     free(s_select->options[option]);
00396                 }
00397 
00398                 if (s_select->options)
00399                 {
00400                     free(s_select->options);
00401                 }
00402             }
00403 
00404             if (setting_categories[cat]->settings[setting]->custom_attrset)
00405             {
00406                 free(setting_categories[cat]->settings[setting]->custom_attrset);
00407             }
00408         }
00409 
00410         if (setting_categories[cat]->settings)
00411         {
00412             free(setting_categories[cat]->settings);
00413         }
00414 
00415         free(setting_categories[cat]->name);
00416         free(setting_categories[cat]);
00417     }
00418 
00419     if (setting_categories)
00420     {
00421         free(setting_categories);
00422         setting_categories = NULL;
00423     }
00424 
00425     setting_categories_num = 0;
00426 }
00427 
00432 void *setting_get(setting_struct *setting)
00433 {
00434     switch (setting->type)
00435     {
00436         case OPT_TYPE_BOOL:
00437         case OPT_TYPE_INPUT_NUM:
00438         case OPT_TYPE_RANGE:
00439         case OPT_TYPE_INT:
00440         case OPT_TYPE_SELECT:
00441             return &setting->val.i;
00442 
00443         case OPT_TYPE_INPUT_TEXT:
00444             return setting->val.str;
00445     }
00446 
00447     return NULL;
00448 }
00449 
00455 const char *setting_get_str(int cat, int setting)
00456 {
00457     return (const char *) setting_get(setting_categories[cat]->settings[setting]);
00458 }
00459 
00465 sint64 setting_get_int(int cat, int setting)
00466 {
00467     return *(sint64 *) setting_get(setting_categories[cat]->settings[setting]);
00468 }
00469 
00476 static int setting_apply_always(int cat, int setting)
00477 {
00478     switch (cat)
00479     {
00480         case OPT_CAT_GENERAL:
00481             switch (setting)
00482             {
00483                 /* Need to hide/show the playerdoll widget. */
00484                 case OPT_PLAYERDOLL:
00485                     cur_widget[PDOLL_ID]->show = setting_get_int(cat, setting);
00486                     return 1;
00487             }
00488 
00489             break;
00490 
00491         case OPT_CAT_DEVEL:
00492             switch (setting)
00493             {
00494                 /* Need to hide/show the fps widget. */
00495                 case OPT_SHOW_FPS:
00496                     cur_widget[FPS_ID]->show = setting_get_int(cat, setting);
00497                     return 1;
00498             }
00499     }
00500 
00501     return 0;
00502 }
00503 
00508 static void setting_apply_runtime(int cat, int setting)
00509 {
00510     /* Try both run-time and startup-time changes first. */
00511     if (setting_apply_always(cat, setting))
00512     {
00513         return;
00514     }
00515 
00516     switch (cat)
00517     {
00518         case OPT_CAT_GENERAL:
00519             switch (setting)
00520             {
00521                 /* Changed how exp display shows its data, redraw the
00522                  * widget. */
00523                 case OPT_EXP_DISPLAY:
00524                     WIDGET_REDRAW_ALL(SKILL_EXP_ID);
00525                     break;
00526             }
00527 
00528             break;
00529 
00530         case OPT_CAT_CLIENT:
00531             switch (setting)
00532             {
00533                 /* Resolution change. */
00534                 case OPT_RESOLUTION:
00535                 {
00536                     int w, h;
00537 
00538                     if (sscanf(SETTING_SELECT(setting_categories[cat]->settings[setting])->options[setting_get_int(cat, setting)], "%dx%d", &w, &h) == 2 && (ScreenSurface->w != w || ScreenSurface->h != h))
00539                     {
00540                         resize_window(w, h);
00541                         video_set_size();
00542                     }
00543 
00544                     break;
00545                 }
00546 
00547                 /* Fullscreen change. */
00548                 case OPT_FULLSCREEN:
00549                     if ((setting_get_int(cat, setting) && !(ScreenSurface->flags & SDL_FULLSCREEN)) || (!setting_get_int(cat, setting) && ScreenSurface->flags & SDL_FULLSCREEN))
00550                     {
00551                         video_fullscreen_toggle(&ScreenSurface, NULL);
00552                     }
00553 
00554                     break;
00555             }
00556 
00557             break;
00558 
00559         case OPT_CAT_MAP:
00560             switch (setting)
00561             {
00562                 /* Map width/height change. */
00563                 case OPT_MAP_WIDTH:
00564                 case OPT_MAP_HEIGHT:
00565                     if (setting_update_mapsize)
00566                     {
00567                         char buf[MAX_BUF];
00568 
00569                         snprintf(buf, sizeof(buf), "setup mapsize %"FMT64"x%"FMT64, setting_get_int(cat, OPT_MAP_WIDTH), setting_get_int(cat, OPT_MAP_HEIGHT));
00570                         cs_write_string(buf, strlen(buf));
00571                         setting_update_mapsize = 0;
00572                     }
00573 
00574                     break;
00575             }
00576 
00577             break;
00578 
00579         case OPT_CAT_SOUND:
00580             switch (setting)
00581             {
00582                 /* Music volume change. */
00583                 case OPT_VOLUME_MUSIC:
00584                     sound_update_volume();
00585                     break;
00586             }
00587 
00588             break;
00589     }
00590 }
00591 
00595 void settings_apply()
00596 {
00597     size_t i, j;
00598 
00599     for (i = 0; i < setting_categories_num; i++)
00600     {
00601         for (j = 0; j < setting_categories[i]->settings_num; j++)
00602         {
00603             setting_apply_always(i, j);
00604         }
00605     }
00606 }
00607 
00611 void settings_apply_change()
00612 {
00613     size_t cat, setting;
00614 
00615     for (cat = 0; cat < setting_categories_num; cat++)
00616     {
00617         for (setting = 0; setting < setting_categories[cat]->settings_num; setting++)
00618         {
00619             setting_apply_runtime(cat, setting);
00620         }
00621     }
00622 }
00623 
00629 void setting_set_int(int cat, int setting, sint64 val)
00630 {
00631     void *dst = setting_get(setting_categories[cat]->settings[setting]);
00632 
00633     (*(sint64 *) dst) = val;
00634 
00635     /* Map width/height, mark for update. */
00636     if (cat == OPT_CAT_MAP && (setting == OPT_MAP_WIDTH || setting == OPT_MAP_HEIGHT))
00637     {
00638         setting_update_mapsize = 1;
00639     }
00640 }
00641 
00646 int setting_is_text(setting_struct *setting)
00647 {
00648     switch (setting->type)
00649     {
00650         case OPT_TYPE_INPUT_TEXT:
00651             return 1;
00652     }
00653 
00654     return 0;
00655 }
00656 
00661 sint64 category_from_name(const char *name)
00662 {
00663     size_t cat;
00664 
00665     for (cat = 0; cat < setting_categories_num; cat++)
00666     {
00667         if (!strcmp(setting_categories[cat]->name, name))
00668         {
00669             return cat;
00670         }
00671     }
00672 
00673     return -1;
00674 }
00675 
00682 sint64 setting_from_name(const char *name)
00683 {
00684     size_t cat, setting;
00685 
00686     for (cat = 0; cat < setting_categories_num; cat++)
00687     {
00688         for (setting = 0; setting < setting_categories[cat]->settings_num; setting++)
00689         {
00690             if (!strcmp(setting_categories[cat]->settings[setting]->name, name))
00691             {
00692                 return setting;
00693             }
00694         }
00695     }
00696 
00697     return -1;
00698 }