Atrinik Client 1.0
gui/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 <include.h>
00031 
00033 struct _dialog_list_set option_list_set;
00034 
00036 const char *opt_tab[] =
00037 {
00038     "General",
00039     "Client",
00040     "Map",
00041     "Sound",
00042     "Fullscreen flags",
00043     "Windowed flags",
00044     "Debug",
00045     NULL
00046 };
00047 
00049 enum
00050 {
00051     SEL_BUTTON,
00052     SEL_CHECKBOX,
00053     SEL_RANGE,
00054     SEL_TEXT
00055 };
00056 // get drop both
00058 _option opt[] =
00059 {
00060     /* General */
00061     {"Playerdoll:", "Whether to always show the playerdoll.\nIf unchecked, the playerdoll is only shown while the inventory is open.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.playerdoll, VAL_BOOL},
00062     {"Show yourself targeted:", "Show your name in the target area instead of blank.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.show_target_self, VAL_BOOL},
00063     {"Show Tooltips:", "Show tooltips when hovering with the mouse over items.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.show_tooltips, VAL_BOOL},
00064     {"Collect mode:", "If enabled, will get/drop all items in the stack instead of asking\nhow many to get/drop.", "None#Get#Drop#Both", SEL_RANGE, 0, 3, 1, 0, &options.collect_mode, VAL_INT},
00065     {"Exp display:", "The format key is: ~4nl~ = For next level; ~tnl~ = Till next level;\n~LExp~ = Level exp; ~TExp~ = Total exp;", "Level/LExp#LExp\\%#LExp/LExp 4nl#TExp/TExp 4nl#(LExp\\%) LExp tnl", SEL_RANGE, 0, 4, 1, 4, &options.expDisplay, VAL_INT},
00066     {"Chat Timestamps:", "Show a timestamp before each chat message.", "Disabled#HH:MM#HH:MM:SS#H:MM AM/PM#H:MM:SS AM/PM", SEL_RANGE, 0, 4, 1, 0, &options.chat_timestamp, VAL_INT},
00067     {"Font size in chat boxes:", "Font size used in chat boxes on left and right.", "10px#11px#12px#13px#14px#15px#16px", SEL_RANGE, 0, 6, 1, 1, &options.chat_font_size, VAL_INT},
00068     {"Maximum chat lines:", "Maximum number of lines in the chat boxes.", "", SEL_RANGE, 20, 1000, 10, 200, &options.chat_max_lines, VAL_INT},
00069     {"#", "", "", 0, 0, 0, 0, 0, 0, 0},
00070 
00071     /* Client */
00072     {"Fullscreen:", "Toggle fullscreen to windowed mode.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.fullscreen, VAL_BOOL},
00073     {"Resolution:", "The resolution of the screen/window.\nIf you change to lower resolutions your GUI-windows may be hidden.", "Custom#800x600#960x600#1024x768#1100x700#1280x720#1280x800#1280x960#1280x1024#1440x900#1400x1050#1600x1200#1680x1050#1920x1080#1920x1200#2048x1536#2560x1600", SEL_RANGE, 0, 15, 1, 0, &options.resolution, VAL_INT},
00074     {"Automatic bpp:", "Use always the same bits per pixel like your default windows.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.auto_bpp_flag, VAL_BOOL},
00075     {"Colordeep:", "Use this bpp for fullscreen mode. Overruled by automatic bpp.\nNOTE: You need to restart the client.", "8 bpp#16 bpp#32 bpp", SEL_RANGE, 0, 2, 1, 1, &options.video_bpp, VAL_INT},
00076     {"Textwindows alpha value:", "Transparent value of text windows. Higher = darker", "", SEL_RANGE, 0, 255, 5, 255, &options.textwin_alpha, VAL_INT},
00077     {"Use intelligent fps cap:", "Enables intelligent fps capping.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.intelligent_fps_cap, VAL_BOOL},
00078     {"Save CPU time with sleep():", "Client eats less CPU time when set.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.max_speed, VAL_BOOL},
00079     {"Sleep time in ms:", "Time the client will sleep. Used with Save CPU time.", "", SEL_RANGE, 0, 1000, 1, 25, &options.sleep, VAL_INT},
00080     {"Key repeat speed:", "How fast to repeat a held down key.", "Off#Slow#Medium#Fast", SEL_RANGE, 0, 3, 1, 2, &options.key_repeat, VAL_INT},
00081     {"Disable file updates:", "If on, will not update sound effects/background music/etc on server\nconnect. This may be useful for users with low bandwidth.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.disable_updates, VAL_BOOL},
00082     {"Minimize latency:", "Disables Nagle's Algorithm in order to minimize latency, at the expense\nof more outgoing bandwidth.\nRequires server re-connection.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.tcp_nodelay, VAL_BOOL},
00083     {"Allow off-screen widgets:", "Allows moving (parts of) widgets off-screen.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.allow_widgets_offscreen, VAL_BOOL},
00084     {"#", "", "", 0, 0, 0, 0, 0, 0, 0},
00085 
00086     /* Map */
00087     {"Player Names:", "Show names of players above their heads.", "show no names#show all names#show only other#show only your", SEL_RANGE, 0, 3,1, 2, &options.player_names, VAL_INT},
00088     {"Playfield zoom:", "The zoom percentage of the playfield.", "", SEL_RANGE, 50, 200, 5, 100, &options.zoom, VAL_INT},
00089     {"Smooth zoom:", "Whether to use smooth zoom on the playfield.\nWarning: Very CPU intensive.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.zoom_smooth, VAL_BOOL},
00090     {"Low health warning:", "Shows a low health warning above your head.\nActivated if health is less than the given percent value.", "", SEL_RANGE, 0, 100, 5, 0, &options.warning_hp, VAL_INT},
00091     {"Low food warning:", "Shows a low food warning above your head.\nActivated if food is less than the given percent value.", "", SEL_RANGE, 0, 100, 5, 5, &options.warning_food, VAL_INT},
00092     {"Map X size:", "The X size of the map. If you have very low bandwidth, you may\nwant to consider lowering this somewhat.", "", SEL_RANGE, 9, MAP_MAX_SIZE, 1, MAP_MAX_SIZE, &options.map_size_x, VAL_INT},
00093     {"Map Y size:", "The Y size of the map. If you have very low bandwidth, you may\nwant to consider lowering this somewhat.", "", SEL_RANGE, 9, MAP_MAX_SIZE, 1, MAP_MAX_SIZE, &options.map_size_y, VAL_INT},
00094     {"#", "", "", 0, 0, 0, 0, 0, 0, 0},
00095 
00096     /* Sound */
00097     {"Sound volume:", "Set sound volume for effects.", "", SEL_RANGE, 0, 100, 5, 100, &options.sound_volume, VAL_INT},
00098     {"Music volume:", "Set music volume for background.", "", SEL_RANGE, 0, 100, 5, 80, &options.music_volume, VAL_INT},
00099     {"#", "", "", 0, 0, 0, 0, 0, 0, 0},
00100 
00101     /* Fullscreen Flags */
00102     {"Hardware Surface:", "Don't change unless you know what you're doing\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.Full_HWSURFACE, VAL_BOOL},
00103     {"Software Surface:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.Full_SWSURFACE, VAL_BOOL},
00104     {"Hardware Accel:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "",SEL_CHECKBOX, 0, 1, 1, 1, &options.Full_HWACCEL, VAL_BOOL},
00105     {"Doublebuffer:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "",SEL_CHECKBOX, 0, 1, 1, 0, &options.Full_DOUBLEBUF, VAL_BOOL},
00106     {"Any format:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "",SEL_CHECKBOX, 0, 1, 1, 1, &options.Full_ANYFORMAT, VAL_BOOL},
00107     {"Async blit:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "",SEL_CHECKBOX, 0, 1, 1, 0, &options.Full_ASYNCBLIT, VAL_BOOL},
00108     {"Hardware Palette:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "",SEL_CHECKBOX, 0, 1, 1, 1, &options.Full_HWPALETTE, VAL_BOOL},
00109     {"Resizeable:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "",SEL_CHECKBOX, 0, 1, 1, 0, &options.Full_RESIZABLE, VAL_BOOL},
00110     {"No frame:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.Full_NOFRAME, VAL_BOOL},
00111     {"RLE accel:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.Full_RLEACCEL, VAL_BOOL},
00112     {"#", "", "", 0, 0, 0, 0, 0, 0, 0},
00113 
00114     /* Windowed flags */
00115     {"Window Hardware Surface:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.Win_HWSURFACE, VAL_BOOL},
00116     {"Window Software Surface:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.Win_SWSURFACE, VAL_BOOL},
00117     {"Window Hardware Accel:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.Win_HWACCEL, VAL_BOOL},
00118     {"Window Doublebuffer:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.Win_DOUBLEBUF, VAL_BOOL},
00119     {"Window Any format:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.Win_ANYFORMAT, VAL_BOOL},
00120     {"Window Async blit:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.Win_ASYNCBLIT, VAL_BOOL},
00121     {"Window Hardware Palette:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.Win_HWPALETTE, VAL_BOOL},
00122     {"Window Resizeable:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.Win_RESIZABLE, VAL_BOOL},
00123     {"Window No frame:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.Win_NOFRAME, VAL_BOOL},
00124     {"Window RLE accel:", "Don't change unless you know what you're doing.\nNOTE: You need to restart the client.", "", SEL_CHECKBOX, 0, 1, 1, 1, &options.Win_RLEACCEL, VAL_BOOL},
00125     {"#", "", "", 0, 0, 0, 0, 0, 0, 0},
00126 
00127     /* Debug */
00128     {"Show Framerate:", "Show the framerate.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.show_frame, VAL_BOOL},
00129     {"Force Redraw:", "Forces the system to redraw EVERY frame.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.force_redraw, VAL_BOOL},
00130     {"Use Update Rect:", "", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.use_rect, VAL_BOOL},
00131     {"Reload user's graphics", "If on, always try to reload faces from user's graphics (gfx_user)\ndirectory, even if they have been reloaded previously.\nThis is especially useful when creating new images and testing out how\nthey look in the game.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.reload_gfx_user, VAL_BOOL},
00132     {"Disable region map cache:", "Disables the region maps cache.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.disable_rm_cache, VAL_BOOL},
00133     {"Enable quickport:", "Enables using middle-click on the region map for instant teleportation.", "", SEL_CHECKBOX, 0, 1, 1, 0, &options.fastport, VAL_BOOL},
00134     {"#", "", "", 0, 0, 0, 0, 0, 0, 0},
00135 
00136     {0, "", "", 0, 0, 0, 0, 0, 0, 0},
00137 };
00138 
00144 static char *get_value(void *value, int type)
00145 {
00146     static char txt_value[20];
00147 
00148     switch (type)
00149     {
00150         case VAL_INT:
00151             snprintf(txt_value, sizeof(txt_value), "%d", *((int *) value));
00152             return txt_value;
00153 
00154         case VAL_U32:
00155             snprintf(txt_value, sizeof(txt_value), "%d", *((uint32 *) value));
00156             return txt_value;
00157 
00158         case VAL_CHAR:
00159             snprintf(txt_value, sizeof(txt_value), "%d", *((uint8 *) value));
00160             return txt_value;
00161 
00162         default:
00163             return NULL;
00164     }
00165 }
00166 
00171 void optwin_draw_options(int x, int y)
00172 {
00173 #define LEN_NAME 111
00174     int i = -1, pos = 0, max = 0;
00175     /* for info text */
00176     int y2 = y + 344;
00177     int mxy_opt = -1;
00178     int page = option_list_set.group_nr;
00179     int id = 0;
00180     int mx, my, mb, tmp;
00181 
00182     mb = SDL_GetMouseState(&mx, &my) & SDL_BUTTON(SDL_BUTTON_LEFT);
00183 
00184     /* Find actual page */
00185     while (page && opt[++i].name)
00186     {
00187         if (opt[i].name[0] == '#')
00188         {
00189             page--;
00190         }
00191     }
00192 
00193     /* Draw actual page */
00194     while (opt[++i].name && opt[i].name[0] != '#')
00195     {
00196         max++;
00197         StringBlt(ScreenSurface, &SystemFont, opt[i].name, x + 1, y + 3, COLOR_BLACK, NULL, NULL);
00198 
00199         switch (opt[i].sel_type)
00200         {
00201             case SEL_CHECKBOX:
00202                 tmp = COLOR_WHITE;
00203 
00204                 if (option_list_set.entry_nr == max - 1)
00205                 {
00206                     tmp = COLOR_HGOLD;
00207                     /* Remember this tab for later use */
00208                     if (mxy_opt == -1)
00209                     {
00210                         mxy_opt = i;
00211                     }
00212                 }
00213 
00214                 if (mx > x && mx < x + 280 && my > y && my < y + 20 )
00215                 {
00216                     tmp = COLOR_GREEN;
00217                     /* Remember this tab for later use */
00218                     mxy_opt = i;
00219                 }
00220 
00221                 StringBlt(ScreenSurface, &SystemFont, opt[i].name, x, y + 2, tmp, NULL, NULL);
00222 
00223                 sprite_blt(Bitmaps[BITMAP_DIALOG_CHECKER], x + LEN_NAME, y, NULL, NULL);
00224 
00225                 if (*((int *) opt[i].value) == 1)
00226                 {
00227                     StringBlt(ScreenSurface, &SystemFont, "X", x + LEN_NAME + 8, y + 2, COLOR_BLACK, NULL, NULL);
00228                     StringBlt(ScreenSurface, &SystemFont, "X", x + LEN_NAME + 7, y + 1, COLOR_WHITE, NULL, NULL);
00229                 }
00230 
00231                 if ((pos == option_list_set.entry_nr && option_list_set.key_change) || (mb && mb_clicked && active_button < 0 && mx > x + LEN_NAME && mx < x + LEN_NAME + 20 && my > y && my < y + 18))
00232                 {
00233                     mb_clicked = 0;
00234                     option_list_set.key_change = 0;
00235 
00236                     if (*((int *) opt[i].value) == 1)
00237                     {
00238                         *((int *) opt[i].value) = 0;
00239                     }
00240                     else
00241                     {
00242                         *((int *) opt[i].value) = 1;
00243                     }
00244                 }
00245                 break;
00246 
00247             case SEL_RANGE:
00248             {
00249 #define LEN_VALUE 100
00250                 SDL_Rect box;
00251                 box.x = x + LEN_NAME, box.y = y + 1;
00252                 box.h = 16, box.w = LEN_VALUE;
00253 
00254                 tmp = COLOR_WHITE;
00255 
00256                 if (option_list_set.entry_nr == max - 1)
00257                 {
00258                     tmp = COLOR_HGOLD;
00259 
00260                     /* Remember this tab for later use */
00261                     if (mxy_opt == -1)
00262                     {
00263                         mxy_opt = i;
00264                     }
00265                 }
00266 
00267                 if (mx > x && mx < x + 280 && my > y && my < y + 20)
00268                 {
00269                     tmp = COLOR_GREEN;
00270                     /* Remember this tab for later use */
00271                     mxy_opt = i;
00272                 }
00273 
00274                 StringBlt(ScreenSurface, &SystemFont, opt[i].name, x, y + 2, tmp, NULL, NULL);
00275                 SDL_FillRect(ScreenSurface, &box, 0);
00276 
00277                 if (*opt[i].val_text == '\0')
00278                 {
00279                     StringBlt(ScreenSurface, &SystemFont, get_value(opt[i].value, opt[i].value_type), box.x + 2, y + 2, COLOR_WHITE, NULL, NULL);
00280                 }
00281                 else
00282                 {
00283 #define MAX_LEN 40
00284                     char text[MAX_LEN + 1];
00285                     int o= *((int *) opt[i].value);
00286                     int p = 0, q = -1;
00287 
00288                     /* Find starting position of string */
00289                     while (o && opt[i].val_text[p])
00290                     {
00291                         if (opt[i].val_text[p++] == '#')
00292                         {
00293                             o--;
00294                         }
00295                     }
00296 
00297                     /* Find ending position of string */
00298                     while (q++ < MAX_LEN  && opt[i].val_text[p])
00299                     {
00300                         if ((text[q] = opt[i].val_text[p++]) == '#')
00301                         {
00302                             break;
00303                         }
00304                     }
00305 
00306                     text[q] = '\0';
00307                     StringBlt(ScreenSurface, &SystemFont,text, box.x + 2, y + 2, COLOR_WHITE, NULL, NULL);
00308 #undef MAX_LEN
00309                 }
00310 
00311                 sprite_blt(Bitmaps[BITMAP_DIALOG_RANGE_OFF], x + LEN_NAME + LEN_VALUE, y, NULL, NULL);
00312 
00313                 /* Keyboard event */
00314                 if (option_list_set.key_change && option_list_set.entry_nr == pos)
00315                 {
00316                     if (option_list_set.key_change == -1)
00317                     {
00318                         add_value(opt[i].value, opt[i].value_type,-opt[i].deltaRange, opt[i].minRange, opt[i].maxRange);
00319                     }
00320                     else if (option_list_set.key_change == 1)
00321                     {
00322                         add_value(opt[i].value, opt[i].value_type, opt[i].deltaRange, opt[i].minRange, opt[i].maxRange);
00323                     }
00324 
00325                     option_list_set.key_change = 0;
00326                 }
00327 
00328                 if (mx > x + LEN_NAME + LEN_VALUE && mx < x + LEN_NAME + LEN_VALUE + 14 && my > y && my < y + 18)
00329                 {
00330                     /* 2 buttons per row */
00331                     if (mb && active_button < 0)
00332                     {
00333                         active_button = id + 1;
00334                     }
00335 
00336                     if (active_button == id + 1)
00337                     {
00338                         sprite_blt(Bitmaps[BITMAP_DIALOG_RANGE_L], x + LEN_NAME + LEN_VALUE, y, NULL, NULL);
00339 
00340                         if (!mb)
00341                         {
00342                             add_value(opt[i].value, opt[i].value_type, -opt[i].deltaRange, opt[i].minRange, opt[i].maxRange);
00343                         }
00344                     }
00345                 }
00346                 else if (mx > x + LEN_NAME + LEN_VALUE + 14 && mx < x + LEN_NAME + LEN_VALUE + 28 && my > y && my < y + 18)
00347                 {
00348                     if (mb && active_button < 0)
00349                     {
00350                         active_button = id;
00351                     }
00352 
00353                     if (active_button == id)
00354                     {
00355                         sprite_blt(Bitmaps[BITMAP_DIALOG_RANGE_R], x + LEN_NAME+LEN_VALUE + 14, y, NULL, NULL);
00356 
00357                         if (!mb)
00358                         {
00359                             add_value(opt[i].value, opt[i].value_type, opt[i].deltaRange, opt[i].minRange, opt[i].maxRange);
00360                         }
00361                     }
00362                 }
00363 #undef LEN_VALUE
00364                 break;
00365             }
00366 
00367             case SEL_BUTTON:
00368                 sprite_blt(Bitmaps[BITMAP_DIALOG_BUTTON_UP], x, y, NULL, NULL);
00369                 break;
00370         }
00371 
00372         y += 20;
00373         pos++;
00374         id += 2;
00375     }
00376 
00377     if (option_list_set.entry_nr > max - 1)
00378     {
00379         option_list_set.entry_nr = max - 1;
00380     }
00381 
00382     /* Print the info text */
00383     x += 20;
00384 
00385     if (mxy_opt >= 0)
00386     {
00387         char *cp, buf[MAX_BUF];
00388         int y_tmp = 0;
00389 
00390         strncpy(buf, opt[mxy_opt].info, sizeof(buf) - 1);
00391         buf[sizeof(buf) - 1] = '\0';
00392         cp = strtok(buf, "\n");
00393 
00394         while (cp)
00395         {
00396             StringBlt(ScreenSurface, &SystemFont, cp, x + 11, y2 + 1 + y_tmp, COLOR_BLACK, NULL, NULL);
00397             StringBlt(ScreenSurface, &SystemFont, cp, x + 10, y2 + y_tmp, COLOR_WHITE, NULL, NULL);
00398             y_tmp += 12;
00399             cp = strtok(NULL, "\n");
00400         }
00401     }
00402 #undef LEN_NAME
00403 }
00404 
00407 void show_optwin()
00408 {
00409     char buf[128];
00410     int x, y;
00411     int mx, my, mb;
00412     int numButton = 0;
00413 
00414     mb = SDL_GetMouseState(&mx, &my) & SDL_BUTTON(SDL_BUTTON_LEFT);
00415     x = Screensize->x / 2 - Bitmaps[BITMAP_DIALOG_BG]->bitmap->w / 2;
00416     y = Screensize->y / 2 - Bitmaps[BITMAP_DIALOG_BG]->bitmap->h / 2;
00417     sprite_blt(Bitmaps[BITMAP_DIALOG_BG], x, y, NULL, NULL);
00418     sprite_blt(Bitmaps[BITMAP_DIALOG_TITLE_OPTIONS], x + 250 - Bitmaps[BITMAP_DIALOG_TITLE_OPTIONS]->bitmap->w / 2, y + 14, NULL, NULL);
00419     add_close_button(x, y, MENU_OPTION);
00420 
00421     draw_tabs(opt_tab, &option_list_set.group_nr, "Option Group", x + 8, y + 70);
00422     optwin_draw_options(x + 130, y + 90);
00423 
00424     sprintf(buf, "~SHIFT~ + ~%c%c~ to select group            ~%c%c~ to select option          ~%c%c~ to change option", ASCII_UP, ASCII_DOWN, ASCII_UP, ASCII_DOWN, ASCII_RIGHT, ASCII_LEFT);
00425     StringBlt(ScreenSurface, &SystemFont, buf, x + 135, y + 410, COLOR_WHITE, NULL, NULL);
00426 
00427     /* Mark active entry */
00428     StringBlt(ScreenSurface, &SystemFont, ">", x + TXT_START_NAME - 15, y + 10 + TXT_Y_START + option_list_set.entry_nr * 20, COLOR_HGOLD, NULL, NULL);
00429 
00430     /* save button */
00431     if (add_button(x + 25, y + 454, numButton++, BITMAP_DIALOG_BUTTON_UP, "Done", "~D~one"))
00432     {
00433         check_menu_keys(MENU_OPTION, SDLK_d);
00434     }
00435 
00436     if (!mb)
00437     {
00438         active_button = -1;
00439     }
00440 }
00441 
00443 enum
00444 {
00445     BUTTON_SETTINGS,
00446     BUTTON_KEY_SETTINGS,
00447     BUTTON_LOGOUT,
00448     BUTTON_BACK,
00449 
00450     BUTTON_NUM
00451 };
00452 
00454 static const char *const button_names[BUTTON_NUM] =
00455 {
00456     "Client Settings", "Key settings", "Logout", "Back to play"
00457 };
00458 
00460 static size_t button_selected;
00461 
00465 static void settings_popup_draw_func(popup_struct *popup)
00466 {
00467     SDL_Rect box;
00468     size_t i;
00469     int x, y, mx, my;
00470     char buf[MAX_BUF];
00471     uint64 flags;
00472 
00473     box.x = 0;
00474     box.y = 10;
00475     box.w = popup->surface->w;
00476     box.h = 0;
00477     string_blt(popup->surface, FONT_SERIF20, "<u>Settings</u>", box.x, box.y, COLOR_SIMPLE(COLOR_HGOLD), TEXT_ALIGN_CENTER | TEXT_MARKUP, &box);
00478     box.y += 50;
00479 
00480     SDL_GetMouseState(&mx, &my);
00481 
00482     for (i = 0; i < BUTTON_NUM; i++)
00483     {
00484         if (GameStatus != GAME_STATUS_PLAY && (i == BUTTON_BACK || i == BUTTON_LOGOUT))
00485         {
00486             continue;
00487         }
00488 
00489         flags = TEXT_ALIGN_CENTER;
00490         x = Screensize->x / 2 - popup->surface->w / 2 + box.x;
00491         y = Screensize->y / 2 - popup->surface->h / 2 + box.y;
00492 
00493         if (mx >= x && mx < x + popup->surface->w && my >= y && my < y + FONT_HEIGHT(FONT_SERIF40))
00494         {
00495             snprintf(buf, sizeof(buf), "<u>%s</u>", button_names[i]);
00496             flags |= TEXT_MARKUP;
00497         }
00498         else
00499         {
00500             strncpy(buf, button_names[i], sizeof(buf) - 1);
00501             buf[sizeof(buf) - 1] = '\0';
00502         }
00503 
00504         if (button_selected == i)
00505         {
00506             string_blt_shadow_format(popup->surface, FONT_SERIF40, box.x, box.y, COLOR_SIMPLE(COLOR_HGOLD), COLOR_SIMPLE(COLOR_BLACK), flags | TEXT_MARKUP, &box, "<c=#9f0408>&gt;</c> %s <c=#9f0408>&lt;</c>", buf);
00507         }
00508         else
00509         {
00510 
00511             string_blt_shadow(popup->surface, FONT_SERIF40, buf, box.x, box.y, COLOR_SIMPLE(COLOR_WHITE), COLOR_SIMPLE(COLOR_BLACK), flags, &box);
00512         }
00513 
00514         box.y += FONT_HEIGHT(FONT_SERIF40);
00515     }
00516 }
00517 
00521 static void settings_button_handle(size_t button)
00522 {
00523     if (button == BUTTON_KEY_SETTINGS)
00524     {
00525         keybind_status = KEYBIND_STATUS_NO;
00526         cpl.menustatus = MENU_KEYBIND;
00527     }
00528     else if (button == BUTTON_SETTINGS)
00529     {
00530         cpl.menustatus = MENU_OPTION;
00531     }
00532     else if (button == BUTTON_LOGOUT)
00533     {
00534         socket_close(&csocket);
00535         GameStatus = GAME_STATUS_INIT;
00536     }
00537 
00538     popup_destroy_visible();
00539 }
00540 
00543 static int settings_popup_event_func(popup_struct *popup, SDL_Event *event)
00544 {
00545     if (event->type == SDL_KEYDOWN)
00546     {
00547         /* Move the selected button up and down. */
00548         if (event->key.keysym.sym == SDLK_UP || event->key.keysym.sym == SDLK_DOWN)
00549         {
00550             int selected = button_selected, num_buttons;
00551 
00552             selected += event->key.keysym.sym == SDLK_DOWN ? 1 : -1;
00553             num_buttons = (GameStatus == GAME_STATUS_PLAY ? BUTTON_NUM : BUTTON_LOGOUT) - 1;
00554 
00555             if (selected < 0)
00556             {
00557                 selected = num_buttons;
00558             }
00559             else if (selected > num_buttons)
00560             {
00561                 selected = 0;
00562             }
00563 
00564             button_selected = selected;
00565             return 1;
00566         }
00567         else if (event->key.keysym.sym == SDLK_RETURN || event->key.keysym.sym == SDLK_KP_ENTER)
00568         {
00569             settings_button_handle(button_selected);
00570             return 1;
00571         }
00572     }
00573     else if (event->type == SDL_MOUSEBUTTONDOWN)
00574     {
00575         if (event->button.button == SDL_BUTTON_LEFT)
00576         {
00577             int x, y;
00578             size_t i;
00579 
00580             x = Screensize->x / 2 - popup->surface->w / 2;
00581             y = Screensize->y / 2 - popup->surface->h / 2 + 60;
00582 
00583             for (i = 0; i < BUTTON_NUM; i++)
00584             {
00585                 if (event->motion.x >= x && event->motion.x < x + popup->surface->w && event->motion.y >= y && event->motion.y < y + FONT_HEIGHT(FONT_SERIF40))
00586                 {
00587                     settings_button_handle(i);
00588                     break;
00589                 }
00590 
00591                 y += FONT_HEIGHT(FONT_SERIF40);
00592             }
00593         }
00594     }
00595 
00596     return -1;
00597 }
00598 
00601 void settings_open()
00602 {
00603     popup_struct *popup;
00604 
00605     popup = popup_create(BITMAP_POPUP);
00606     popup->draw_func = settings_popup_draw_func;
00607     popup->event_func = settings_popup_event_func;
00608 
00609     button_selected = GameStatus == GAME_STATUS_PLAY ? BUTTON_BACK : BUTTON_SETTINGS;
00610 }