Atrinik Client 2.5
gui/skills.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 skill_entry_struct **skill_list[SKILL_LIST_TYPES];
00035 static size_t skill_list_num[SKILL_LIST_TYPES];
00036 
00038 static size_t skill_list_type = 0;
00040 static uint8 skill_list_filter_known;
00042 static button_struct button_type_left, button_type_right, button_close, button_filter_known, button_help;
00043 
00047 static void list_handle_enter(list_struct *list)
00048 {
00049     /* Ready the selected skill, if any. */
00050     if (list->text)
00051     {
00052         char buf[MAX_BUF];
00053 
00054         snprintf(buf, sizeof(buf), "/ready_skill %s", list->text[list->row_selected - 1][0]);
00055         client_command_check(buf);
00056     }
00057 }
00058 
00061 static const char *list_text_color_hook(list_struct *list, const char *default_color, uint32 row, uint32 col)
00062 {
00063     size_t id;
00064 
00065     /* If the skill is not known, use gray instead of the default color. */
00066     if (skill_find_type_selected(list->text[row][col], &id) && !skill_list[skill_list_type][id]->known)
00067     {
00068         return COLOR_GRAY;
00069     }
00070 
00071     return default_color;
00072 }
00073 
00076 static void skill_list_reload()
00077 {
00078     list_struct *list;
00079     size_t i;
00080     uint32 offset, rows, selected;
00081 
00082     list = list_exists(LIST_SKILLS);
00083 
00084     if (!list)
00085     {
00086         return;
00087     }
00088 
00089     offset = list->row_offset;
00090     selected = list->row_selected;
00091     rows = list->rows;
00092     list_clear(list);
00093 
00094     for (i = 0; i < skill_list_num[skill_list_type]; i++)
00095     {
00096         if (skill_list_filter_known && !skill_list[skill_list_type][i]->known)
00097         {
00098             continue;
00099         }
00100 
00101         list_add(list, list->rows, 0, skill_list[skill_list_type][i]->name);
00102     }
00103 
00104     list_sort(list, LIST_SORT_ALPHA);
00105 
00106     if (list->rows == rows)
00107     {
00108         list->row_offset = offset;
00109         list->row_selected = selected;
00110     }
00111 
00112     cur_widget[SKILLS_ID]->redraw = 1;
00113 }
00114 
00118 static void button_repeat_func(button_struct *button)
00119 {
00120     int path = skill_list_type;
00121 
00122     if (button == &button_type_left)
00123     {
00124         path--;
00125     }
00126     else
00127     {
00128         path++;
00129     }
00130 
00131     if (path < 0)
00132     {
00133         path = SKILL_LIST_TYPES - 1;
00134     }
00135     else if (path > SKILL_LIST_TYPES - 1)
00136     {
00137         path = 0;
00138     }
00139 
00140     skill_list_type = path;
00141     skill_list_reload();
00142 }
00143 
00147 void widget_skills_render(widgetdata *widget)
00148 {
00149     list_struct *list;
00150     SDL_Rect box, box2;
00151 
00152     /* Create the surface. */
00153     if (!widget->widgetSF)
00154     {
00155         widget->widgetSF = SDL_ConvertSurface(Bitmaps[BITMAP_CONTENT]->bitmap, Bitmaps[BITMAP_CONTENT]->bitmap->format, Bitmaps[BITMAP_CONTENT]->bitmap->flags);
00156     }
00157 
00158     list = list_exists(LIST_SKILLS);
00159 
00160     /* Create the skill list. */
00161     if (!list)
00162     {
00163         skill_list_filter_known = 0;
00164 
00165         list = list_create(LIST_SKILLS, 12, 1, 8);
00166         list->handle_enter_func = list_handle_enter;
00167         list->text_color_hook = list_text_color_hook;
00168         list->surface = widget->widgetSF;
00169         list_scrollbar_enable(list);
00170         list_set_column(list, 0, 130, 7, NULL, -1);
00171         list_set_font(list, FONT_ARIAL10);
00172         skill_list_reload();
00173 
00174         /* Create various buttons... */
00175         button_create(&button_type_left);
00176         button_create(&button_type_right);
00177         button_create(&button_close);
00178         button_create(&button_filter_known);
00179         button_create(&button_help);
00180         button_type_left.repeat_func = button_type_right.repeat_func = button_repeat_func;
00181         button_close.bitmap = button_type_left.bitmap = button_type_right.bitmap = button_help.bitmap = BITMAP_BUTTON_ROUND;
00182         button_close.bitmap_pressed = button_type_left.bitmap_pressed = button_type_right.bitmap_pressed = button_help.bitmap_pressed = BITMAP_BUTTON_ROUND_DOWN;
00183     }
00184 
00185     if (widget->redraw)
00186     {
00187         _BLTFX bltfx;
00188         size_t skill_id;
00189 
00190         bltfx.surface = widget->widgetSF;
00191         bltfx.flags = 0;
00192         bltfx.alpha = 0;
00193         sprite_blt(Bitmaps[BITMAP_CONTENT], 0, 0, NULL, &bltfx);
00194 
00195         widget->redraw = 0;
00196 
00197         box.h = 0;
00198         box.w = widget->wd;
00199         string_blt(widget->widgetSF, FONT_SERIF12, "Skills", 0, 3, COLOR_HGOLD, TEXT_ALIGN_CENTER, &box);
00200         list->focus = 1;
00201         list_set_parent(list, widget->x1, widget->y1);
00202         list_show(list, 10, 2);
00203 
00204         box.w = 160;
00205         string_blt(widget->widgetSF, FONT_SERIF12, s_settings->skill_types[skill_list_type], 0, widget->ht - FONT_HEIGHT(FONT_SERIF12) - 7, COLOR_HGOLD, TEXT_ALIGN_CENTER, &box);
00206 
00207         /* Show the skill's description. */
00208         if (list->text && skill_find_type_selected(list->text[list->row_selected - 1][0], &skill_id))
00209         {
00210             box.h = 120;
00211             box.w = 150;
00212             string_blt(widget->widgetSF, FONT_ARIAL10, skill_list[skill_list_type][skill_id]->desc, 160, 40, COLOR_WHITE, TEXT_WORD_WRAP | TEXT_MARKUP, &box);
00213         }
00214 
00215         /* Show the skill's icon, if it's known. */
00216         if (list->text && skill_list[skill_list_type][skill_id]->known)
00217         {
00218             _Sprite *icon = FaceList[skill_list[skill_list_type][skill_id]->icon].sprite;
00219             char level_buf[MAX_BUF], exp_buf[MAX_BUF];
00220 
00221             if (skill_list[skill_list_type][skill_id]->exp == -1)
00222             {
00223                 strncpy(level_buf, "<b>Level</b>: n/a", sizeof(level_buf) - 1);
00224                 level_buf[sizeof(level_buf) - 1] = '\0';
00225             }
00226             else
00227             {
00228                 snprintf(level_buf, sizeof(level_buf), "<b>Level</b>: %d", skill_list[skill_list_type][skill_id]->level);
00229             }
00230 
00231             if (skill_list[skill_list_type][skill_id]->exp >= 0)
00232             {
00233                 snprintf(exp_buf, sizeof(exp_buf), "<b>Exp</b>: %"FMT64, skill_list[skill_list_type][skill_id]->exp);
00234             }
00235             else
00236             {
00237                 strncpy(exp_buf, "<b>Exp</b>: n/a", sizeof(exp_buf) - 1);
00238                 exp_buf[sizeof(exp_buf) - 1] = '\0';
00239             }
00240 
00241             string_blt(widget->widgetSF, FONT_ARIAL10, level_buf, 160, widget->ht - 30, COLOR_WHITE, TEXT_MARKUP, NULL);
00242             string_blt(widget->widgetSF, FONT_ARIAL10, exp_buf, 160, widget->ht - 18, COLOR_WHITE, TEXT_MARKUP, NULL);
00243 
00244             draw_frame(widget->widgetSF, widget->wd - 6 - icon->bitmap->w, widget->ht - 6 - icon->bitmap->h, icon->bitmap->w + 1, icon->bitmap->h + 1);
00245             sprite_blt(icon, widget->wd - 5 - icon->bitmap->w, widget->ht - 5 - icon->bitmap->h, NULL, &bltfx);
00246         }
00247     }
00248 
00249     box2.x = widget->x1;
00250     box2.y = widget->y1;
00251     SDL_BlitSurface(widget->widgetSF, NULL, ScreenSurface, &box2);
00252 
00253     /* Render the various buttons. */
00254     button_close.x = widget->x1 + widget->wd - Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->w - 4;
00255     button_close.y = widget->y1 + 4;
00256     button_render(&button_close, "X");
00257 
00258     button_help.x = widget->x1 + widget->wd - Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->w * 2 - 4;
00259     button_help.y = widget->y1 + 4;
00260     button_render(&button_help, "?");
00261 
00262     button_type_left.x = widget->x1 + 6;
00263     button_type_left.y = widget->y1 + widget->ht - Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->h - 5;
00264     button_render(&button_type_left, "<");
00265 
00266     button_type_right.x = widget->x1 + 6 + 130;
00267     button_type_right.y = widget->y1 + widget->ht - Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->h - 5;
00268     button_render(&button_type_right, ">");
00269 
00270     if (skill_list_filter_known)
00271     {
00272         button_filter_known.pressed = 1;
00273     }
00274 
00275     button_filter_known.x = widget->x1 + 158;
00276     button_filter_known.y = widget->y1 + 22;
00277     button_render(&button_filter_known, "Known");
00278 }
00279 
00284 void widget_skills_mevent(widgetdata *widget, SDL_Event *event)
00285 {
00286     list_struct *list = list_exists(LIST_SKILLS);
00287 
00288     /* If the list has handled the mouse event, we need to redraw the
00289      * widget. */
00290     if (list && list_handle_mouse(list, event->motion.x - widget->x1, event->motion.y - widget->y1, event))
00291     {
00292         widget->redraw = 1;
00293     }
00294 
00295     if (button_event(&button_type_left, event))
00296     {
00297         button_repeat_func(&button_type_left);
00298     }
00299     else if (button_event(&button_type_right, event))
00300     {
00301         button_repeat_func(&button_type_right);
00302     }
00303     else if (button_event(&button_close, event))
00304     {
00305         widget->show = 0;
00306         button_close.pressed = 0;
00307     }
00308     else if (button_event(&button_filter_known, event))
00309     {
00310         skill_list_filter_known = !skill_list_filter_known;
00311         skill_list_reload();
00312     }
00313     else if (button_event(&button_help, event))
00314     {
00315         show_help("skill list");
00316     }
00317 }
00318 
00327 int skill_find(const char *name, size_t *type, size_t *id)
00328 {
00329     for (*type = 0; *type < SKILL_LIST_TYPES - 1; *type += 1)
00330     {
00331         for (*id = 0; *id < skill_list_num[*type]; *id += 1)
00332         {
00333             if (!strncasecmp(skill_list[*type][*id]->name, name, strlen(name)))
00334             {
00335                 return 1;
00336             }
00337         }
00338     }
00339 
00340     return 0;
00341 }
00342 
00351 int skill_find_type_selected(const char *name, size_t *id)
00352 {
00353     for (*id = 0; *id < skill_list_num[skill_list_type]; *id += 1)
00354     {
00355         if (!strncasecmp(skill_list[skill_list_type][*id]->name, name, strlen(name)))
00356         {
00357             return 1;
00358         }
00359     }
00360 
00361     return 0;
00362 }
00363 
00369 skill_entry_struct *skill_get(size_t type, size_t id)
00370 {
00371     return skill_list[type][id];
00372 }
00373 
00376 void skills_init()
00377 {
00378     FILE *fp;
00379     char line[HUGE_BUF];
00380     size_t i, j, num_skills;
00381 
00382     /* Free previously allocated skills. */
00383     for (i = 0; i < SKILL_LIST_TYPES; i++)
00384     {
00385         if (skill_list[i])
00386         {
00387             if (i != SKILL_LIST_TYPES - 1)
00388             {
00389                 for (j = 0; j < skill_list_num[i]; j++)
00390                 {
00391                     free(skill_list[i][j]);
00392                 }
00393             }
00394 
00395             free(skill_list[i]);
00396         }
00397     }
00398 
00399     memset(&skill_list, 0, sizeof(*skill_list) * SKILL_LIST_TYPES);
00400     memset(&skill_list_num, 0, sizeof(*skill_list_num) * SKILL_LIST_TYPES);
00401     skill_list_type = 0;
00402     num_skills = 0;
00403 
00404     fp = server_file_open(SERVER_FILE_SKILLS);
00405 
00406     if (!fp)
00407     {
00408         return;
00409     }
00410 
00411     while (fgets(line, sizeof(line) - 1, fp))
00412     {
00413         char *name, *icon, desc[HUGE_BUF];
00414         int type;
00415 
00416         line[strlen(line) - 1] = '\0';
00417         name = strdup(line);
00418 
00419         if (!fgets(line, sizeof(line) - 1, fp))
00420         {
00421             LOG(llevBug, "  Got unexpected EOF reading skills file.\n");
00422             break;
00423         }
00424 
00425         type = atoi(line);
00426 
00427         if (!fgets(line, sizeof(line) - 1, fp))
00428         {
00429             LOG(llevBug, "  Got unexpected EOF reading skills file.\n");
00430             break;
00431         }
00432 
00433         line[strlen(line) - 1] = '\0';
00434         icon = strdup(line);
00435         desc[0] = '\0';
00436 
00437         while (fgets(line, sizeof(line) - 1, fp))
00438         {
00439             if (!strcmp(line, "end\n"))
00440             {
00441                 skill_entry_struct *entry;
00442 
00443                 /* Resize the skill list array for this skill type. */
00444                 skill_list[type] = realloc(skill_list[type], sizeof(*skill_list[type]) * (skill_list_num[type] + 1));
00445                 entry = skill_list[type][skill_list_num[type]] = malloc(sizeof(**skill_list[type]));
00446                 skill_list_num[type]++;
00447 
00448                 /* Store the data. */
00449                 strncpy(entry->name, name, sizeof(entry->name) - 1);
00450                 entry->name[sizeof(entry->name) - 1] = '\0';
00451                 strncpy(entry->desc, desc, sizeof(entry->desc) - 1);
00452                 entry->desc[sizeof(entry->desc) - 1] = '\0';
00453                 strncpy(entry->icon_name, icon, sizeof(entry->icon_name) - 1);
00454                 entry->icon_name[sizeof(entry->icon_name) - 1] = '\0';
00455                 entry->icon = get_bmap_id(entry->icon_name);
00456                 entry->known = 0;
00457 
00458                 free(icon);
00459                 free(name);
00460                 num_skills++;
00461                 break;
00462             }
00463 
00464             strncat(desc, line, sizeof(desc) - strlen(desc) - 1);
00465         }
00466     }
00467 
00468     fclose(fp);
00469 
00470     if (num_skills)
00471     {
00472         skill_list[SKILL_LIST_TYPES - 1] = malloc(sizeof(*skill_list[SKILL_LIST_TYPES - 1]) * num_skills);
00473 
00474         for (i = 0; i < SKILL_LIST_TYPES - 1; i++)
00475         {
00476             for (j = 0; j < skill_list_num[i]; j++)
00477             {
00478                 skill_list[SKILL_LIST_TYPES - 1][skill_list_num[SKILL_LIST_TYPES - 1]] = skill_list[i][j];
00479                 skill_list_num[SKILL_LIST_TYPES - 1]++;
00480             }
00481         }
00482     }
00483 }
00484 
00487 void skills_reload()
00488 {
00489     size_t type, id;
00490 
00491     for (type = 0; type < SKILL_LIST_TYPES - 1; type++)
00492     {
00493         for (id = 0; id < skill_list_num[type]; id++)
00494         {
00495             skill_list[type][id]->icon = get_bmap_id(skill_list[type][id]->icon_name);
00496         }
00497     }
00498 }
00499 
00503 void SkilllistCmd(char *data)
00504 {
00505     char *tmp_data, *cp;
00506     size_t skill_type, skill_id;
00507     int mode;
00508 
00509     tmp_data = strdup(data);
00510     cp = strtok(tmp_data, "/");
00511 
00512     mode = atoi(data);
00513 
00514     while (cp)
00515     {
00516         char *tmp[3];
00517 
00518         if (split_string(cp, tmp, sizeof(tmp) / sizeof(*tmp), '|') != 3)
00519         {
00520             cp = strtok(NULL, "/");
00521             continue;
00522         }
00523 
00524         /* If the skill exists, mark it as known, and store the level/exp. */
00525         if (skill_find(tmp[0], &skill_type, &skill_id))
00526         {
00527             skill_entry_struct *skill = skill_get(skill_type, skill_id);
00528 
00529             if (mode == SPLIST_MODE_REMOVE)
00530             {
00531                 skill->known = 0;
00532             }
00533             else
00534             {
00535                 skill->known = 1;
00536                 skill->level = atoi(tmp[1]);
00537                 skill->exp = atoll(tmp[2]);
00538                 WIDGET_REDRAW_ALL(SKILL_EXP_ID);
00539             }
00540         }
00541 
00542         cp = strtok(NULL, "/");
00543     }
00544 
00545     free(tmp_data);
00546     skill_list_reload();
00547 }