1 | /* |
1 | /* |
2 | * CrossFire, A Multiplayer game |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
3 | * |
3 | * |
4 | * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team |
4 | * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copryight (C) 2002 Mark Wedel & Crossfire Development Team |
5 | * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team |
6 | * Copyright (C) 1992 Frank Tore Johansen |
6 | * Copyright (©) 1992,2007 Frank Tore Johansen |
7 | * |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify |
8 | * Deliantra is free software: you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by |
9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or |
10 | * the Free Software Foundation, either version 3 of the License, or |
11 | * (at your option) any later version. |
11 | * (at your option) any later version. |
12 | * |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
16 | * GNU General Public License for more details. |
17 | * |
17 | * |
18 | * You should have received a copy of the GNU General Public License |
18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software |
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
|
21 | * |
20 | * |
22 | * The author can be reached via e-mail to <crossfire@schmorp.de> |
21 | * The authors can be reached via e-mail to <support@deliantra.net> |
23 | */ |
22 | */ |
24 | |
23 | |
25 | /* Created July 95 to separate skill utilities from actual skills -b.t. */ |
24 | /* Created July 95 to separate skill utilities from actual skills -b.t. */ |
26 | |
25 | |
27 | /* Reconfigured skills code to allow linking of skills to experience |
26 | /* Reconfigured skills code to allow linking of skills to experience |
… | |
… | |
61 | * subtypes. |
60 | * subtypes. |
62 | */ |
61 | */ |
63 | void |
62 | void |
64 | init_skills (void) |
63 | init_skills (void) |
65 | { |
64 | { |
66 | for (archetype *at = first_archetype; at; at = at->next) |
65 | for_all_archetypes (at) |
67 | if (at->clone.type == SKILL) |
66 | if (at->type == SKILL) |
68 | { |
67 | { |
69 | if (skill_names[at->clone.subtype]) |
68 | if (skill_names[at->subtype]) |
70 | LOG (llevError, "init_skills: multiple skill using same subtype %d, %s, %s\n", |
69 | LOG (llevError, "init_skills: multiple skill using same subtype %d, %s, %s\n", |
71 | at->clone.subtype, &skill_names[at->clone.subtype], &at->clone.skill); |
70 | at->subtype, &skill_names[at->subtype], &at->skill); |
72 | else |
71 | else |
73 | skill_names[at->clone.subtype] = at->clone.skill; |
72 | skill_names[at->subtype] = at->skill; |
74 | } |
73 | } |
75 | |
74 | |
76 | /* This isn't really an error if there is no skill subtype set, but |
75 | /* This isn't really an error if there is no skill subtype set, but |
77 | * checking for this may catch some user errors. |
76 | * checking for this may catch some user errors. |
78 | */ |
77 | */ |
… | |
… | |
132 | for (object *tmp = who->inv; tmp; tmp = tmp->below) |
131 | for (object *tmp = who->inv; tmp; tmp = tmp->below) |
133 | if (tmp->skill == sh) |
132 | if (tmp->skill == sh) |
134 | { |
133 | { |
135 | if (tmp->type == SKILL && (tmp->flag [FLAG_CAN_USE_SKILL] || tmp->flag [FLAG_APPLIED])) |
134 | if (tmp->type == SKILL && (tmp->flag [FLAG_CAN_USE_SKILL] || tmp->flag [FLAG_APPLIED])) |
136 | /* If this is a skill that can be used without applying tool, return it */ |
135 | /* If this is a skill that can be used without applying tool, return it */ |
137 | return tmp->inv_splay (); |
136 | return splay (tmp); |
138 | /* Try to find appropriate skilltool. If the player has one already |
137 | /* Try to find appropriate skilltool. If the player has one already |
139 | * applied, we try to keep using that one. |
138 | * applied, we try to keep using that one. |
140 | */ |
139 | */ |
141 | else if (tmp->type == SKILL_TOOL && !skill_tool) |
140 | else if (tmp->type == SKILL_TOOL && !skill_tool) |
142 | skill_tool = tmp; |
141 | skill_tool = tmp; |
… | |
… | |
155 | { |
154 | { |
156 | skill = give_skill_by_name (who, skill_tool->skill); |
155 | skill = give_skill_by_name (who, skill_tool->skill); |
157 | link_player_skills (who); |
156 | link_player_skills (who); |
158 | } |
157 | } |
159 | |
158 | |
160 | skill->inv_splay (); |
|
|
161 | |
|
|
162 | if (!skill_tool->flag [FLAG_APPLIED]) |
159 | if (!skill_tool->flag [FLAG_APPLIED]) |
163 | if (apply_special (who, skill_tool, AP_APPLY | AP_NO_READY)) |
160 | if (apply_special (who, splay (skill_tool), AP_APPLY | AP_NO_READY)) |
164 | return 0; |
161 | return 0; |
165 | |
162 | |
166 | return skill; |
163 | return splay (skill); |
167 | } |
164 | } |
168 | |
165 | |
169 | object * |
166 | object * |
170 | find_skill_by_name (object *who, const char *name) |
167 | find_skill_by_name (object *who, const char *name) |
171 | { |
168 | { |
… | |
… | |
226 | |
223 | |
227 | if (chosen_skill) |
224 | if (chosen_skill) |
228 | { |
225 | { |
229 | chosen_skill->flag [FLAG_APPLIED] = true; |
226 | chosen_skill->flag [FLAG_APPLIED] = true; |
230 | change_abil (this, chosen_skill); |
227 | change_abil (this, chosen_skill); |
231 | chosen_skill->inv_splay (); |
|
|
232 | } |
228 | } |
233 | |
229 | |
234 | // always clear current weapon, as the selected skill could |
230 | // always clear current weapon, as the selected skill could |
235 | // conflict with the current weapon skill, which would go |
231 | // conflict with the current weapon skill, which would go |
236 | // undetected and exp would be given to the wrong skill. |
232 | // undetected and exp would be given to the wrong skill. |
… | |
… | |
551 | /* if skill really is a skill, then we can look at the skill archetype for |
547 | /* if skill really is a skill, then we can look at the skill archetype for |
552 | * bse reward value (exp) and level multiplier factor. |
548 | * bse reward value (exp) and level multiplier factor. |
553 | */ |
549 | */ |
554 | if (skill->type == SKILL) |
550 | if (skill->type == SKILL) |
555 | { |
551 | { |
556 | base += skill->arch->clone.stats.exp; |
552 | base += skill->arch->stats.exp; |
557 | if (settings.simple_exp) |
553 | if (settings.simple_exp) |
558 | { |
554 | { |
559 | if (skill->arch->clone.level) |
555 | if (skill->arch->level) |
560 | lvl_mult = (float) skill->arch->clone.level / 100.0; |
556 | lvl_mult = (float) skill->arch->level / 100.0; |
561 | else |
557 | else |
562 | lvl_mult = 1.0; /* no adjustment */ |
558 | lvl_mult = 1.0; /* no adjustment */ |
563 | } |
559 | } |
564 | else |
560 | else |
565 | { |
561 | { |
566 | if (skill->level) |
562 | if (skill->level) |
567 | lvl_mult = ((float) skill->arch->clone.level * (float) op_lvl) / ((float) skill->level * 100.0); |
563 | lvl_mult = ((float) skill->arch->level * (float) op_lvl) / ((float) skill->level * 100.0); |
568 | else |
564 | else |
569 | lvl_mult = 1.0; |
565 | lvl_mult = 1.0; |
570 | } |
566 | } |
571 | } |
567 | } |
572 | else |
568 | else |
… | |
… | |
660 | * Note this function is a bit more complicated becauase we |
656 | * Note this function is a bit more complicated becauase we |
661 | * we want ot sort the skills before printing them. If we |
657 | * we want ot sort the skills before printing them. If we |
662 | * just dumped this as we found it, this would be a bit |
658 | * just dumped this as we found it, this would be a bit |
663 | * simpler. |
659 | * simpler. |
664 | */ |
660 | */ |
665 | |
661 | //TODO: egad, do it in perl, do not suffer from the big buffer on stack, make it one single drawinfo. |
666 | void |
662 | void |
667 | show_skills (object *op, const char *search) |
663 | show_skills (object *op, const char *search) |
668 | { |
664 | { |
669 | object *tmp = NULL; |
665 | object *tmp = NULL; |
670 | char buf[MAX_BUF]; |
666 | char buf[MAX_BUF]; |
… | |
… | |
672 | int i, num_skills_found = 0; |
668 | int i, num_skills_found = 0; |
673 | static const char *const periods = "........................................"; |
669 | static const char *const periods = "........................................"; |
674 | |
670 | |
675 | /* Need to have a pointer and use strdup for qsort to work properly */ |
671 | /* Need to have a pointer and use strdup for qsort to work properly */ |
676 | char skills[NUM_SKILLS][MAX_BUF]; |
672 | char skills[NUM_SKILLS][MAX_BUF]; |
677 | |
|
|
678 | |
673 | |
679 | for (tmp = op->inv; tmp != NULL; tmp = tmp->below) |
674 | for (tmp = op->inv; tmp != NULL; tmp = tmp->below) |
680 | { |
675 | { |
681 | if (tmp->type == SKILL) |
676 | if (tmp->type == SKILL) |
682 | { |
677 | { |
… | |
… | |
685 | /* Basically want to fill this out to 40 spaces with periods */ |
680 | /* Basically want to fill this out to 40 spaces with periods */ |
686 | sprintf (buf, "%s%s", &tmp->name, periods); |
681 | sprintf (buf, "%s%s", &tmp->name, periods); |
687 | buf[40] = 0; |
682 | buf[40] = 0; |
688 | |
683 | |
689 | if (settings.permanent_exp_ratio) |
684 | if (settings.permanent_exp_ratio) |
690 | { |
|
|
691 | sprintf (skills[num_skills_found++], "%slvl:%3d (xp:%" PRId64 "/%" PRId64 "/%d%%)", |
685 | sprintf (skills[num_skills_found++], "%slvl:%3d (xp:%" PRId64 "/%" PRId64 "/%d%%)", |
692 | buf, tmp->level, tmp->stats.exp, |
686 | buf, tmp->level, tmp->stats.exp, |
693 | level_exp (tmp->level + 1, op->expmul), clipped_percent (tmp->perm_exp, tmp->stats.exp)); |
687 | level_exp (tmp->level + 1, op->expmul), clipped_percent (tmp->perm_exp, tmp->stats.exp)); |
694 | } |
|
|
695 | else |
688 | else |
696 | { |
|
|
697 | sprintf (skills[num_skills_found++], "%slvl:%3d (xp:%" PRId64 "/%" PRId64 ")", |
689 | sprintf (skills[num_skills_found++], "%slvl:%3d (xp:%" PRId64 "/%" PRId64 ")", |
698 | buf, tmp->level, tmp->stats.exp, level_exp (tmp->level + 1, op->expmul)); |
690 | buf, tmp->level, tmp->stats.exp, level_exp (tmp->level + 1, op->expmul)); |
699 | } |
691 | |
700 | /* I don't know why some characters get a bunch of skills, but |
692 | /* I don't know why some characters get a bunch of skills, but |
701 | * it sometimes happens (maybe a leftover from bugier earlier code |
693 | * it sometimes happens (maybe a leftover from bugier earlier code |
702 | * and those character are still about). In any case, lets handle |
694 | * and those character are still about). In any case, lets handle |
703 | * it so it doesn't crash the server - otherwise, one character may |
695 | * it so it doesn't crash the server - otherwise, one character may |
704 | * crash the server numerous times. |
696 | * crash the server numerous times. |
… | |
… | |
710 | break; |
702 | break; |
711 | } |
703 | } |
712 | } |
704 | } |
713 | } |
705 | } |
714 | |
706 | |
715 | clear_win_info (op); |
|
|
716 | new_draw_info (NDI_UNIQUE, 0, op, "Player skills:"); |
707 | new_draw_info (NDI_UNIQUE, 0, op, "Player skills:"); |
717 | if (num_skills_found > 1) |
708 | if (num_skills_found > 1) |
718 | qsort (skills, num_skills_found, MAX_BUF, (int (*)(const void *, const void *)) std::strcmp); |
709 | qsort (skills, num_skills_found, MAX_BUF, (int (*)(const void *, const void *)) std::strcmp); |
719 | |
710 | |
720 | for (i = 0; i < num_skills_found; i++) |
711 | for (i = 0; i < num_skills_found; i++) |
… | |
… | |
861 | if (!skill) |
852 | if (!skill) |
862 | new_draw_info (NDI_BLACK, 0, op, "You have no unarmed combat skills!"); |
853 | new_draw_info (NDI_BLACK, 0, op, "You have no unarmed combat skills!"); |
863 | } |
854 | } |
864 | } |
855 | } |
865 | |
856 | |
|
|
857 | if (skill) |
|
|
858 | { |
866 | op->change_skill (0); |
859 | op->change_skill (0); |
867 | apply_special (op, skill, AP_APPLY); |
860 | apply_special (op, skill, AP_APPLY); |
|
|
861 | } |
868 | } |
862 | } |
869 | |
863 | |
870 | if (!pl->combat_ob) |
864 | if (!pl->combat_ob) |
871 | { |
865 | { |
872 | LOG (llevError, "Could not find anything to attack on %s\n", &op->name); |
866 | LOG (llevError, "Could not find anything to attack on %s\n", &op->name); |