Atrinik Client 2.5
gui/spells.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 
00035 enum
00036 {
00038     SPELLS_FILTER_SPELL,
00040     SPELLS_FILTER_PRAYER,
00042     SPELLS_FILTER_ALL
00043 };
00044 
00053 static spell_entry_struct **spell_list[SPELL_PATH_NUM];
00055 static size_t spell_list_num[SPELL_PATH_NUM];
00057 static size_t spell_list_path = 0;
00059 static uint8 spell_list_filter_known;
00061 static uint8 spell_list_filter_type;
00062 
00064 static const char *const filter_names[SPELLS_FILTER_ALL + 1] =
00065 {
00066     "Spells", "Prayers", "All"
00067 };
00068 
00070 static button_struct button_path_left, button_path_right, button_close, button_filter_left, button_filter_right, button_filter_known, button_help;
00071 
00075 static void list_handle_enter(list_struct *list)
00076 {
00077     /* Ready the selected spell, if any. */
00078     if (list->text)
00079     {
00080         char buf[MAX_BUF];
00081 
00082         snprintf(buf, sizeof(buf), "/ready_spell %s", list->text[list->row_selected - 1][0]);
00083         client_command_check(buf);
00084     }
00085 }
00086 
00089 static const char *list_text_color_hook(list_struct *list, const char *default_color, uint32 row, uint32 col)
00090 {
00091     size_t spell_id;
00092     spell_entry_struct *spell;
00093 
00094     /* If the spell is not known, use gray instead of the default color. */
00095     if (spell_find_path_selected(list->text[row][col], &spell_id))
00096     {
00097         spell = spell_get(spell_list_path, spell_id);
00098 
00099         if (!spell->known)
00100         {
00101             return COLOR_GRAY;
00102         }
00103     }
00104 
00105     return default_color;
00106 }
00107 
00111 static void spell_list_reload()
00112 {
00113     list_struct *list;
00114     size_t i;
00115     uint32 offset, rows, selected;
00116 
00117     list = list_exists(LIST_SPELLS);
00118 
00119     if (!list)
00120     {
00121         return;
00122     }
00123 
00124     offset = list->row_offset;
00125     selected = list->row_selected;
00126     rows = list->rows;
00127     list_clear(list);
00128 
00129     for (i = 0; i < spell_list_num[spell_list_path]; i++)
00130     {
00131         if (spell_list_filter_known && !spell_list[spell_list_path][i]->known)
00132         {
00133             continue;
00134         }
00135 
00136         if (spell_list_filter_type != SPELLS_FILTER_ALL)
00137         {
00138             if (spell_list_filter_type == SPELLS_FILTER_SPELL && spell_list[spell_list_path][i]->type != SPELLS_FILTER_SPELL)
00139             {
00140                 continue;
00141             }
00142 
00143             if (spell_list_filter_type == SPELLS_FILTER_PRAYER && spell_list[spell_list_path][i]->type != SPELLS_FILTER_PRAYER)
00144             {
00145                 continue;
00146             }
00147         }
00148 
00149         list_add(list, list->rows, 0, spell_list[spell_list_path][i]->name);
00150     }
00151 
00152     list_sort(list, LIST_SORT_ALPHA);
00153 
00154     if (list->rows == rows)
00155     {
00156         list->row_offset = offset;
00157         list->row_selected = selected;
00158     }
00159 
00160     cur_widget[SPELLS_ID]->redraw = 1;
00161 }
00162 
00166 static void button_repeat_func(button_struct *button)
00167 {
00168     int path = spell_list_path;
00169 
00170     if (button == &button_path_left)
00171     {
00172         path--;
00173     }
00174     else
00175     {
00176         path++;
00177     }
00178 
00179     if (path < 0)
00180     {
00181         path = SPELL_PATH_NUM - 1;
00182     }
00183     else if (path > SPELL_PATH_NUM - 1)
00184     {
00185         path = 0;
00186     }
00187 
00188     spell_list_path = path;
00189     spell_list_reload();
00190 }
00191 
00196 static void button_filter_adjust(int adj)
00197 {
00198     int type = spell_list_filter_type + adj;
00199 
00200     if (type < 0)
00201     {
00202         type = SPELLS_FILTER_ALL;
00203     }
00204     else if (type > SPELLS_FILTER_ALL)
00205     {
00206         type = 0;
00207     }
00208 
00209     spell_list_filter_type = type;
00210     spell_list_reload();
00211 }
00212 
00216 void widget_spells_render(widgetdata *widget)
00217 {
00218     list_struct *list;
00219     SDL_Rect box, box2;
00220 
00221     /* Create the surface. */
00222     if (!widget->widgetSF)
00223     {
00224         widget->widgetSF = SDL_ConvertSurface(Bitmaps[BITMAP_CONTENT]->bitmap, Bitmaps[BITMAP_CONTENT]->bitmap->format, Bitmaps[BITMAP_CONTENT]->bitmap->flags);
00225     }
00226 
00227     list = list_exists(LIST_SPELLS);
00228 
00229     /* Create the spell list. */
00230     if (!list)
00231     {
00232         spell_list_filter_known = 0;
00233         spell_list_filter_type = SPELLS_FILTER_ALL;
00234 
00235         list = list_create(LIST_SPELLS, 12, 1, 8);
00236         list->handle_enter_func = list_handle_enter;
00237         list->text_color_hook = list_text_color_hook;
00238         list->surface = widget->widgetSF;
00239         list_scrollbar_enable(list);
00240         list_set_column(list, 0, 130, 7, NULL, -1);
00241         list_set_font(list, FONT_ARIAL10);
00242         spell_list_reload();
00243 
00244         /* Create various buttons... */
00245         button_create(&button_path_left);
00246         button_create(&button_path_right);
00247         button_create(&button_close);
00248         button_create(&button_filter_left);
00249         button_create(&button_filter_right);
00250         button_create(&button_filter_known);
00251         button_create(&button_help);
00252         button_path_left.repeat_func = button_path_right.repeat_func = button_repeat_func;
00253         button_close.bitmap = button_path_left.bitmap = button_path_right.bitmap = button_filter_left.bitmap = button_filter_right.bitmap = button_help.bitmap = BITMAP_BUTTON_ROUND;
00254         button_close.bitmap_pressed = button_path_left.bitmap_pressed = button_path_right.bitmap_pressed = button_filter_left.bitmap_pressed = button_filter_right.bitmap_pressed = button_help.bitmap_pressed = BITMAP_BUTTON_ROUND_DOWN;
00255     }
00256 
00257     if (widget->redraw)
00258     {
00259         _BLTFX bltfx;
00260         size_t spell_id;
00261 
00262         bltfx.surface = widget->widgetSF;
00263         bltfx.flags = 0;
00264         bltfx.alpha = 0;
00265         sprite_blt(Bitmaps[BITMAP_CONTENT], 0, 0, NULL, &bltfx);
00266 
00267         widget->redraw = 0;
00268 
00269         box.h = 0;
00270         box.w = widget->wd;
00271         string_blt(widget->widgetSF, FONT_SERIF12, "Spells", 0, 3, COLOR_HGOLD, TEXT_ALIGN_CENTER, &box);
00272         list->focus = 1;
00273         list_set_parent(list, widget->x1, widget->y1);
00274         list_show(list, 10, 2);
00275 
00276         box.w = 160;
00277         string_blt(widget->widgetSF, FONT_SERIF12, s_settings->spell_paths[spell_list_path], 0, widget->ht - FONT_HEIGHT(FONT_SERIF12) - 7, COLOR_HGOLD, TEXT_ALIGN_CENTER, &box);
00278 
00279         box.w = 80;
00280         string_blt(widget->widgetSF, FONT_ARIAL10, filter_names[spell_list_filter_type], 160, 24, COLOR_WHITE, TEXT_ALIGN_CENTER, &box);
00281 
00282         /* Show the spell's description. */
00283         if (list->text && spell_find_path_selected(list->text[list->row_selected - 1][0], &spell_id))
00284         {
00285             box.h = 120;
00286             box.w = 150;
00287             string_blt(widget->widgetSF, FONT_ARIAL10, spell_list[spell_list_path][spell_id]->desc, 160, 40, COLOR_WHITE, TEXT_WORD_WRAP, &box);
00288         }
00289 
00290         /* Show info such as the spell cost, path status, etc if there is
00291          * a selected spell and it's a known one. */
00292         if (list->text && spell_list[spell_list_path][spell_id]->known)
00293         {
00294             _Sprite *icon = FaceList[spell_list[spell_list_path][spell_id]->icon].sprite;
00295             const char *status;
00296 
00297             string_blt_format(widget->widgetSF, FONT_ARIAL10, 160, widget->ht - 30, COLOR_WHITE, TEXT_MARKUP, NULL, "<b>Cost</b>: %d", spell_list[spell_list_path][spell_id]->cost);
00298 
00299             switch (spell_list[spell_list_path][spell_id]->path)
00300             {
00301                 case 'a':
00302                     status = "Attuned";
00303                     break;
00304 
00305                 case 'r':
00306                     status = "Repelled";
00307                     break;
00308 
00309                 case 'd':
00310                     status = "Denied";
00311                     break;
00312 
00313                 default:
00314                     status = "Normal";
00315                     break;
00316             }
00317 
00318             string_blt_format(widget->widgetSF, FONT_ARIAL10, 160, widget->ht - 18, COLOR_WHITE, TEXT_MARKUP, NULL, "<b>Status</b>: %s", status);
00319             draw_frame(widget->widgetSF, widget->wd - 6 - icon->bitmap->w, widget->ht - 6 - icon->bitmap->h, icon->bitmap->w + 1, icon->bitmap->h + 1);
00320             sprite_blt(icon, widget->wd - 5 - icon->bitmap->w, widget->ht - 5 - icon->bitmap->h, NULL, &bltfx);
00321         }
00322     }
00323 
00324     box2.x = widget->x1;
00325     box2.y = widget->y1;
00326     SDL_BlitSurface(widget->widgetSF, NULL, ScreenSurface, &box2);
00327 
00328     /* Render the various buttons. */
00329     button_close.x = widget->x1 + widget->wd - Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->w - 4;
00330     button_close.y = widget->y1 + 4;
00331     button_render(&button_close, "X");
00332 
00333     button_help.x = widget->x1 + widget->wd - Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->w * 2 - 4;
00334     button_help.y = widget->y1 + 4;
00335     button_render(&button_help, "?");
00336 
00337     button_path_left.x = widget->x1 + 6;
00338     button_path_left.y = widget->y1 + widget->ht - Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->h - 5;
00339     button_render(&button_path_left, "<");
00340 
00341     button_path_right.x = widget->x1 + 6 + 130;
00342     button_path_right.y = widget->y1 + widget->ht - Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->h - 5;
00343     button_render(&button_path_right, ">");
00344 
00345     button_filter_left.x = widget->x1 + 160;
00346     button_filter_left.y = widget->y1 + 24;
00347     button_render(&button_filter_left, "<");
00348 
00349     button_filter_right.x = widget->x1 + 220;
00350     button_filter_right.y = widget->y1 + 24;
00351     button_render(&button_filter_right, ">");
00352 
00353     if (spell_list_filter_known)
00354     {
00355         button_filter_known.pressed = 1;
00356     }
00357 
00358     button_filter_known.x = widget->x1 + 243;
00359     button_filter_known.y = widget->y1 + 22;
00360     button_render(&button_filter_known, "Known");
00361 }
00362 
00367 void widget_spells_mevent(widgetdata *widget, SDL_Event *event)
00368 {
00369     list_struct *list = list_exists(LIST_SPELLS);
00370 
00371     /* If the list has handled the mouse event, we need to redraw the
00372      * widget. */
00373     if (list && list_handle_mouse(list, event->motion.x - widget->x1, event->motion.y - widget->y1, event))
00374     {
00375         widget->redraw = 1;
00376     }
00377 
00378     if (button_event(&button_path_left, event))
00379     {
00380         button_repeat_func(&button_path_left);
00381     }
00382     else if (button_event(&button_path_right, event))
00383     {
00384         button_repeat_func(&button_path_right);
00385     }
00386     else if (button_event(&button_close, event))
00387     {
00388         widget->show = 0;
00389         button_close.pressed = 0;
00390     }
00391     else if (button_event(&button_filter_left, event))
00392     {
00393         button_filter_adjust(-1);
00394     }
00395     else if (button_event(&button_filter_right, event))
00396     {
00397         button_filter_adjust(1);
00398     }
00399     else if (button_event(&button_filter_known, event))
00400     {
00401         spell_list_filter_known = !spell_list_filter_known;
00402         spell_list_reload();
00403     }
00404     else if (button_event(&button_help, event))
00405     {
00406         show_help("spell list");
00407     }
00408     else if (list->text && event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_LEFT && !draggingInvItem(DRAG_GET_STATUS))
00409     {
00410         size_t spell_id;
00411         _Sprite *icon;
00412 
00413         if (!spell_find_path_selected(list->text[list->row_selected - 1][0], &spell_id) || !spell_list[spell_list_path][spell_id]->known)
00414         {
00415             return;
00416         }
00417 
00418         icon = FaceList[spell_list[spell_list_path][spell_id]->icon].sprite;
00419 
00420         if (event->motion.x >= widget->x1 + widget->wd - 5 - icon->bitmap->w && event->motion.x <= widget->x1 + widget->wd - 5 && event->motion.y >= widget->y1 + widget->ht - 5 - icon->bitmap->h && event->motion.y <= widget->y1 + widget->ht - 5)
00421         {
00422             cpl.dragging.spell = spell_get(spell_list_path, spell_id);
00423             draggingInvItem(DRAG_QUICKSLOT_SPELL);
00424         }
00425     }
00426 }
00427 
00436 int spell_find(const char *name, size_t *spell_path, size_t *spell_id)
00437 {
00438     for (*spell_path = 0; *spell_path < SPELL_PATH_NUM - 1; *spell_path += 1)
00439     {
00440         for (*spell_id = 0; *spell_id < spell_list_num[*spell_path]; *spell_id += 1)
00441         {
00442             if (!strncasecmp(spell_list[*spell_path][*spell_id]->name, name, strlen(name)))
00443             {
00444                 return 1;
00445             }
00446         }
00447     }
00448 
00449     return 0;
00450 }
00451 
00460 int spell_find_path_selected(const char *name, size_t *spell_id)
00461 {
00462     for (*spell_id = 0; *spell_id < spell_list_num[spell_list_path]; *spell_id += 1)
00463     {
00464         if (!strncasecmp(spell_list[spell_list_path][*spell_id]->name, name, strlen(name)))
00465         {
00466             return 1;
00467         }
00468     }
00469 
00470     return 0;
00471 }
00472 
00478 spell_entry_struct *spell_get(size_t spell_path, size_t spell_id)
00479 {
00480     return spell_list[spell_path][spell_id];
00481 }
00482 
00485 void spells_init()
00486 {
00487     FILE *fp;
00488     char line[HUGE_BUF];
00489     size_t i, j, num_spells;
00490 
00491     /* Free previously allocated spells. */
00492     for (i = 0; i < SPELL_PATH_NUM; i++)
00493     {
00494         if (spell_list[i])
00495         {
00496             if (i != SPELL_PATH_NUM - 1)
00497             {
00498                 for (j = 0; j < spell_list_num[i]; j++)
00499                 {
00500                     free(spell_list[i][j]);
00501                 }
00502             }
00503 
00504             free(spell_list[i]);
00505         }
00506     }
00507 
00508     memset(&spell_list, 0, sizeof(*spell_list) * SPELL_PATH_NUM);
00509     memset(&spell_list_num, 0, sizeof(*spell_list_num) * SPELL_PATH_NUM);
00510     spell_list_path = 0;
00511     num_spells = 0;
00512 
00513     fp = server_file_open(SERVER_FILE_SPELLS);
00514 
00515     if (!fp)
00516     {
00517         return;
00518     }
00519 
00520     while (fgets(line, sizeof(line) - 1, fp))
00521     {
00522         char *spell_name, *icon, desc[HUGE_BUF];
00523         int spell_type, spell_path;
00524 
00525         line[strlen(line) - 1] = '\0';
00526         spell_name = strdup(line);
00527 
00528         if (!fgets(line, sizeof(line) - 1, fp))
00529         {
00530             LOG(llevBug, "  Got unexpected EOF reading spells file.\n");
00531             break;
00532         }
00533 
00534         spell_type = atoi(line);
00535 
00536         if (!fgets(line, sizeof(line) - 1, fp))
00537         {
00538             LOG(llevBug, "  Got unexpected EOF reading spells file.\n");
00539             break;
00540         }
00541 
00542         spell_path = atoi(line);
00543 
00544         if (!fgets(line, sizeof(line) - 1, fp))
00545         {
00546             LOG(llevBug, "  Got unexpected EOF reading spells file.\n");
00547             break;
00548         }
00549 
00550         line[strlen(line) - 1] = '\0';
00551         icon = strdup(line);
00552         desc[0] = '\0';
00553 
00554         while (fgets(line, sizeof(line) - 1, fp))
00555         {
00556             if (!strcmp(line, "end\n"))
00557             {
00558                 spell_entry_struct *entry;
00559 
00560                 /* Resize the spell list array for this spell path. */
00561                 spell_list[spell_path] = realloc(spell_list[spell_path], sizeof(*spell_list[spell_path]) * (spell_list_num[spell_path] + 1));
00562                 entry = spell_list[spell_path][spell_list_num[spell_path]] = malloc(sizeof(**spell_list[spell_path]));
00563                 spell_list_num[spell_path]++;
00564 
00565                 /* Store the data. */
00566                 strncpy(entry->name, spell_name, sizeof(entry->name) - 1);
00567                 entry->name[sizeof(entry->name) - 1] = '\0';
00568                 strncpy(entry->desc, desc, sizeof(entry->desc) - 1);
00569                 entry->desc[sizeof(entry->desc) - 1] = '\0';
00570                 strncpy(entry->icon_name, icon, sizeof(entry->icon_name) - 1);
00571                 entry->icon_name[sizeof(entry->icon_name) - 1] = '\0';
00572                 entry->icon = get_bmap_id(entry->icon_name);
00573                 entry->known = '\0';
00574                 entry->path = 0;
00575                 entry->type = spell_type - 1;
00576 
00577                 free(icon);
00578                 free(spell_name);
00579                 num_spells++;
00580                 break;
00581             }
00582 
00583             strncat(desc, line, sizeof(desc) - strlen(desc) - 1);
00584         }
00585     }
00586 
00587     fclose(fp);
00588 
00589     if (num_spells)
00590     {
00591         spell_list[SPELL_PATH_NUM - 1] = malloc(sizeof(*spell_list[SPELL_PATH_NUM - 1]) * num_spells);
00592 
00593         for (i = 0; i < SPELL_PATH_NUM - 1; i++)
00594         {
00595             for (j = 0; j < spell_list_num[i]; j++)
00596             {
00597                 spell_list[SPELL_PATH_NUM - 1][spell_list_num[SPELL_PATH_NUM - 1]] = spell_list[i][j];
00598                 spell_list_num[SPELL_PATH_NUM - 1]++;
00599             }
00600         }
00601     }
00602 }
00603 
00606 void spells_reload()
00607 {
00608     size_t spell_path, spell_id;
00609 
00610     for (spell_path = 0; spell_path < SPELL_PATH_NUM - 1; spell_path++)
00611     {
00612         for (spell_id = 0; spell_id < spell_list_num[spell_path]; spell_id++)
00613         {
00614             spell_list[spell_path][spell_id]->icon = get_bmap_id(spell_list[spell_path][spell_id]->icon_name);
00615         }
00616     }
00617 }
00618 
00622 void SpelllistCmd(char *data)
00623 {
00624     char *tmp_data, *cp;
00625     size_t spell_path, spell_id;
00626     int mode;
00627 
00628     tmp_data = strdup(data);
00629     cp = strtok(tmp_data, "/");
00630 
00631     mode = atoi(data);
00632 
00633     while (cp)
00634     {
00635         char *tmp[3];
00636 
00637         if (split_string(cp, tmp, sizeof(tmp) / sizeof(*tmp), ':') != 3)
00638         {
00639             cp = strtok(NULL, "/");
00640             continue;
00641         }
00642 
00643         /* If the spell exists, mark it as known, and store the path
00644          * status and casting cost. */
00645         if (spell_find(tmp[0], &spell_path, &spell_id))
00646         {
00647             spell_entry_struct *spell = spell_get(spell_path, spell_id);
00648 
00649             if (mode == SPLIST_MODE_REMOVE)
00650             {
00651                 spell->known = 0;
00652             }
00653             else
00654             {
00655                 spell->known = 1;
00656                 spell->path = tmp[2][0];
00657                 spell->cost = atoi(tmp[1]);
00658             }
00659         }
00660 
00661         cp = strtok(NULL, "/");
00662     }
00663 
00664     free(tmp_data);
00665     spell_list_reload();
00666 }