1 /* $Id$ */
2 /* File: skills.c */
3
4 /* Purpose: player skills */
5
6 /*
7 * Copyright (c) 2001 DarkGod
8 *
9 * This software may be copied and distributed for educational, research, and
10 * not for profit purposes provided that this copyright and statement are
11 * included in all such copies.
12 */
13
14 /* added this for consistency in some (unrelated) header-inclusion,
15 it IS a server file, isn't it? */
16 #define SERVER
17 #include "angband.h"
18
19 #if 0
20 /* Initialze the s_info array at server start */
21 bool init_s_info()
22 {
23 int i;
24 int order = 1;
25
26 for (i = 0; i < MAX_SKILLS; i++)
27 {
28 /* Is there a skill to process here ? */
29 if (skill_tree_init[i][1] > 0)
30 {
31 /* Set it's father and order in the tree */
32 s_info[skill_tree_init[i][1]].father = skill_tree_init[i][0];
33 s_info[skill_tree_init[i][1]].order = order++;
34 }
35 }
36 return FALSE;
37 }
38 #endif // 0
39
40 /*
41 * Initialize a skill with given values
42 */
init_skill(player_type * p_ptr,u32b value,s16b mod,int i)43 void init_skill(player_type *p_ptr, u32b value, s16b mod, int i) {
44 p_ptr->s_info[i].base_value = value;
45 p_ptr->s_info[i].value = value;
46 p_ptr->s_info[i].mod = mod;
47 p_ptr->s_info[i].touched = TRUE;
48 #if 0 //SMOOTHSKILLS
49 if (s_info[i].flags1 & SKF1_HIDDEN)
50 p_ptr->s_info[i].hidden = TRUE;
51 else
52 p_ptr->s_info[i].hidden = FALSE;
53 if (s_info[i].flags1 & SKF1_DUMMY)
54 p_ptr->s_info[i].dummy = TRUE;
55 else
56 p_ptr->s_info[i].dummy = FALSE;
57 #else
58 p_ptr->s_info[i].flags1 = (char)(s_info[i].flags1 & 0xFF);
59
60 /* hack: Rangers can train limited Archery skill */
61 if (p_ptr->pclass == CLASS_RANGER && i == SKILL_ARCHERY)
62 p_ptr->s_info[i].flags1 |= SKF1_MAX_10;
63 /* hack: Druids/Vampires can't train Mimicry skill */
64 if ((p_ptr->pclass == CLASS_DRUID || p_ptr->prace == RACE_VAMPIRE)
65 && i == SKILL_MIMIC)
66 p_ptr->s_info[i].flags1 |= SKF1_MAX_1;
67 #endif
68 }
69
70 /*
71 *
72 */
get_skill(player_type * p_ptr,int skill)73 s16b get_skill(player_type *p_ptr, int skill)
74 {
75 #if 0
76 /* prevent breaking the +2 limit */
77 int s;
78 s = (p_ptr->s_info[skill].value / SKILL_STEP);
79 if (s > p_ptr->lev + 2) s = p_ptr->lev + 2;
80 return s;
81 #else
82 return (p_ptr->s_info[skill].value / SKILL_STEP);
83 #endif
84 }
85
86
87 /*
88 *
89 */
get_skill_scale(player_type * p_ptr,int skill,u32b scale)90 s16b get_skill_scale(player_type *p_ptr, int skill, u32b scale)
91 {
92 #if 0
93 /* prevent breaking the +2 limit */
94 int s;
95 /* s = ((p_ptr->s_info[skill].value * 1000) / SKILL_STEP);
96 if (s > (p_ptr->lev * 1000) + 2000) s = (p_ptr->lev * 1000) + 2000;
97 s = (s * SKILL_STEP) / 1000;
98 return (((s / 10) * (scale * (SKILL_STEP / 10)) / (SKILL_MAX / 10)) / (SKILL_STEP / 10)); */
99
100 /* Cleaning up this mess too... - mikaelh */
101 s = p_ptr->s_info[skill].value;
102 if (s > (p_ptr->lev + 2) * SKILL_STEP) s = (p_ptr->lev + 2) * SKILL_STEP;
103 return ((s * scale) / SKILL_MAX);
104
105 #else
106 /* XXX XXX XXX */
107 /* return (((p_ptr->s_info[skill].value / 10) * (scale * (SKILL_STEP / 10)) /
108 (SKILL_MAX / 10)) /
109 (SKILL_STEP / 10)); */
110 /* Simpler formula suggested by Potter - mikaelh */
111 return ((p_ptr->s_info[skill].value * scale) / SKILL_MAX);
112
113 #endif
114 }
115
116 /* Allow very rough resolution of skills into very small scaled values
117 (Added this for minus_... in dungeon.c - C. Blue) */
get_skill_scale_fine(player_type * p_ptr,int skill,u32b scale)118 s16b get_skill_scale_fine(player_type *p_ptr, int skill, u32b scale)
119 {
120 return (((p_ptr->s_info[skill].value * scale) / SKILL_MAX) +
121 (magik(((p_ptr->s_info[skill].value * scale * 100) / SKILL_MAX) % 100) ? 1 : 0));
122 }
123
124 /* Will add, sub, .. */
modify_aux(s32b a,s32b b,char mod)125 static s32b modify_aux(s32b a, s32b b, char mod)
126 {
127 switch (mod)
128 {
129 case '+':
130 return (a + b);
131 break;
132 case '-':
133 return (a - b);
134 break;
135 case '=':
136 return (b);
137 break;
138 case '%':
139 return ((a * b) / 100);
140 break;
141 default:
142 return (0);
143 }
144 }
145
146
147 /*
148 * Gets the base value of a skill, given a race/class/...
149 */
compute_skills(player_type * p_ptr,s32b * v,s32b * m,int i)150 void compute_skills(player_type *p_ptr, s32b *v, s32b *m, int i)
151 {
152 s32b value = 0, mod = 0, j;
153
154 /***** class skills *****/
155
156 /* find the skill mods for that class */
157 for (j = 0; j < MAX_SKILLS; j++) {
158 if (p_ptr->cp_ptr->skills[j].skill == i) {
159 value = p_ptr->cp_ptr->skills[j].value;
160 mod = p_ptr->cp_ptr->skills[j].mod;
161
162 *v = modify_aux(*v,
163 value, p_ptr->cp_ptr->skills[j].vmod);
164 *m = modify_aux(*m,
165 mod, p_ptr->cp_ptr->skills[j].mmod);
166 }
167 }
168
169 /* Race later (b/c of its modificative nature) */
170 for (j = 0; j < MAX_SKILLS; j++) {
171 if (p_ptr->rp_ptr->skills[j].skill == i) {
172 value = p_ptr->rp_ptr->skills[j].value;
173 mod = p_ptr->rp_ptr->skills[j].mod;
174
175 *v = modify_aux(*v,
176 value, p_ptr->rp_ptr->skills[j].vmod);
177 *m = modify_aux(*m,
178 mod, p_ptr->rp_ptr->skills[j].mmod);
179 }
180 }
181 }
182
183 /* Display messages to the player, telling him about newly gained abilities
184 from increasing a skill */
msg_gained_abilities(int Ind,int old_value,int i)185 void msg_gained_abilities(int Ind, int old_value, int i) {
186 player_type *p_ptr = Players[Ind];
187 int new_value = get_skill_scale(p_ptr, i, 500);
188
189 // int as = get_archery_skill(p_ptr);
190 // int ws = get_weaponmastery_skill(p_ptr);
191
192 /* Tell the player about new abilities that he gained from the skill increase */
193 if (old_value == new_value) return;
194 switch (i) {
195 case SKILL_CLIMB: if (new_value == 10) msg_print(Ind, "\374\377GYou learn how to climb mountains!");
196 break;
197 case SKILL_LEVITATE: if (new_value == 10) msg_print(Ind, "\374\377GYou learn how to levitate!");
198 break;
199 case SKILL_FREEACT: if (new_value == 10) msg_print(Ind, "\374\377GYou learn how to resist paralysis and move freely!");
200 break;
201 case SKILL_RESCONF: if (new_value == 10) msg_print(Ind, "\374\377GYou learn how to keep a focussed mind and avoid confusion!");
202 break;
203 case SKILL_DODGE:
204 if (old_value == 0 && new_value > 0 &&
205 p_ptr->inventory[INVEN_ARM].k_idx && p_ptr->inventory[INVEN_ARM].tval == TV_SHIELD)
206 msg_print(Ind, "\377oYou cannot dodge attacks while wielding a shield!");
207 break;
208 case SKILL_MARTIAL_ARTS:
209 if (old_value == 0 && new_value > 0) {
210 bool warn_takeoff = FALSE;
211 /* display some warnings if an item will severely conflict with Martial Arts skill */
212 if (p_ptr->inventory[INVEN_WIELD].k_idx ||
213 is_weapon(p_ptr->inventory[INVEN_ARM].tval) || /* for dual-wielders */
214 #ifndef ENABLE_MA_BOOMERANG
215 p_ptr->inventory[INVEN_BOW].k_idx) {
216 #else
217 p_ptr->inventory[INVEN_BOW].tval == TV_BOW) {
218 #endif
219 #ifndef ENABLE_MA_BOOMERANG
220 msg_print(Ind, "\374\377RWarning: Using any sort of weapon renders Martial Arts skill effectless.");
221 #else
222 msg_print(Ind, "\374\377RWarning: Using any melee weapon or bow renders Martial Arts skill effectless.");
223 #endif
224 warn_takeoff = TRUE;
225 }
226 if (p_ptr->inventory[INVEN_ARM].k_idx && p_ptr->inventory[INVEN_ARM].tval == TV_SHIELD) {
227 msg_print(Ind, "\377RWarning: You cannot use special martial art styles with a shield!");
228 warn_takeoff = TRUE;
229 }
230 if (warn_takeoff) msg_print(Ind, "\374\377R Press 't' key to take off your weapons or shield.");
231
232 /* Martial artists shouldn't get a weapon-wield warning */
233 p_ptr->warning_wield = 1;
234 /* also don't send any weapon-bpr related warnings since their
235 suggested remedies don't work for us as MA user */
236 p_ptr->warning_bpr = 1;
237 p_ptr->warning_bpr2 = 1;
238 p_ptr->warning_bpr3 = 1;
239 }
240 if (old_value < 10 && new_value >= 10) { /* the_sandman */
241 // msg_print(Ind, "\374\377GYou feel as if you could take on the world!");
242 msg_print(Ind, "\374\377GYou learn to use punching techniques.");
243 msg_print(Ind, "\374\377GYour attack speed has become faster due to your training!");
244 }
245 if (old_value < 20 && new_value >= 20)
246 msg_print(Ind, "\374\377GYou get the hang of using kicks.");
247 if (old_value < 30 && new_value >= 30)
248 msg_print(Ind, "\374\377GYou get the hang of using hand side strikes.");
249 if (old_value < 50 && new_value >= 50)
250 msg_print(Ind, "\374\377GYou get the hang of knee-based attacks.");
251 if (old_value < 70 && new_value >= 70)
252 msg_print(Ind, "\374\377GYou get the hang of elbow-based attacks.");
253 if (old_value < 90 && new_value >= 90)
254 msg_print(Ind, "\374\377GYou get the hang of butting techniques.");
255 if (old_value < 100 && new_value >= 100) {
256 msg_print(Ind, "\374\377GYou learn how to fall safely!");
257 msg_print(Ind, "\374\377GYour attack speed has become faster due to your training!");
258 }
259 if (old_value < 110 && new_value >= 110)
260 msg_print(Ind, "\374\377GYour kicks have improved.");
261 if (old_value < 130 && new_value >= 130)
262 msg_print(Ind, "\374\377GYou get the hang of well-timed uppercuts.");
263 if (old_value < 150 && new_value >= 150)
264 msg_print(Ind, "\374\377GYou learn how to tame your fear!");
265 if (old_value < 160 && new_value >= 160)
266 msg_print(Ind, "\374\377GYou get the hang of difficult double-kicks.");
267 if (old_value < 200 && new_value >= 200) {
268 msg_print(Ind, "\374\377GYou learn to use the Cat's Claw technique.");
269 msg_print(Ind, "\374\377GYou learn how to keep your mind focussed and avoid confusion!");
270 msg_print(Ind, "\374\377GYour attack speed has become faster due to your training!");
271 }
272 if (old_value < 250 && new_value >= 250) {
273 msg_print(Ind, "\374\377GYou learn to use jump kicks effectively.");
274 msg_print(Ind, "\374\377GYou learn how to resist paralysis and move freely!");
275 }
276 if (old_value < 290 && new_value >= 290)
277 msg_print(Ind, "\374\377GYou learn to use the Eagle's Claw technique.");
278 if (old_value < 300 && new_value >= 300) {
279 msg_print(Ind, "\374\377GYou learn how to swim easily!");
280 msg_print(Ind, "\374\377GYour attack speed has become faster due to your training!");
281 }
282 if (old_value < 330 && new_value >= 330) {
283 msg_print(Ind, "\374\377GYou get the hang of circle kicks.");
284 }
285 /* } if (old_value < 350 && new_value >= 350) { <- this one is now at skill 1.000 already
286 msg_print(Ind, "\374\377GYour attack speed has become faster due to your training!"); */
287 if (old_value < 370 && new_value >= 370)
288 msg_print(Ind, "\374\377GYou learn the Iron Fist technique.");
289 if (old_value < 400 && new_value >= 400) {
290 msg_print(Ind, "\374\377GYou learn how to climb mountains!");
291 msg_print(Ind, "\374\377GYour attack speed has become faster due to your training!");
292 }
293 if (old_value < 410 && new_value >= 410)
294 msg_print(Ind, "\374\377GYou get the hang of difficult flying kicks.");
295 if (old_value < 450 && new_value >= 450) {
296 msg_print(Ind, "\374\377GYou learn the Dragon Fist technique.");
297 msg_print(Ind, "\374\377GYour attack speed has become faster due to your training!");
298 }
299 if (old_value < 480 && new_value >= 480) {
300 msg_print(Ind, "\374\377GYou get the hang of effective Crushing Blows.");
301 if (p_ptr->total_winner) {
302 msg_print(Ind, "\374\377GYou learn the Royal Titan's Fist technique.");
303 msg_print(Ind, "\374\377GYou learn the Royal Phoenix Claw technique.");
304 }
305 }
306 if (old_value < 500 && new_value >= 500) {
307 msg_print(Ind, "\374\377GYou learn the technique of Levitation!");
308 /* The final +ea has been moved down from lvl 50 to lvl 1 to boost MA a little - the_sandman - moved it to 350 - C. Blue */
309 msg_print(Ind, "\374\377GYour attack speed has become faster due to your training!");
310 }
311 break;
312 case SKILL_STANCE:
313 /* automatically upgrade currently taken stance power */
314 switch (p_ptr->pclass) {
315 case CLASS_WARRIOR:
316 if (old_value < 50 && new_value >= 50) msg_print(Ind, "\374\377GYou learn how to enter a defensive stance (rank I). ('\377gm\377G' key)");
317 if (old_value < 150 && new_value >= 150) {
318 msg_print(Ind, "\374\377GYou learn how to enter defensive stance rank II.");
319 if (p_ptr->combat_stance == 1) p_ptr->combat_stance_power = 1;
320 }
321 if (old_value < 350 && new_value >= 350) {
322 msg_print(Ind, "\374\377GYou learn how to enter defensive stance rank III.");
323 if (p_ptr->combat_stance == 1) p_ptr->combat_stance_power = 2;
324 }
325 if (old_value < 100 && new_value >= 100) msg_print(Ind, "\374\377GYou learn how to enter an offensive stance (rank I).");
326 if (old_value < 200 && new_value >= 200) {
327 msg_print(Ind, "\374\377GYou learn how to enter offensive stance rank II.");
328 if (p_ptr->combat_stance == 2) p_ptr->combat_stance_power = 1;
329 }
330 if (old_value < 400 && new_value >= 400) {
331 msg_print(Ind, "\374\377GYou learn how to enter offensive stance rank III.");
332 if (p_ptr->combat_stance == 2) p_ptr->combat_stance_power = 2;
333 }
334 break;
335 case CLASS_MIMIC:
336 if (old_value < 100 && new_value >= 100) msg_print(Ind, "\374\377GYou learn how to enter a defensive stance (rank I). ('\377gm\377G' key)");
337 if (old_value < 200 && new_value >= 200) {
338 msg_print(Ind, "\374\377GYou learn how to enter defensive stance rank II.");
339 if (p_ptr->combat_stance == 1) p_ptr->combat_stance_power = 1;
340 }
341 if (old_value < 400 && new_value >= 400) {
342 msg_print(Ind, "\374\377GYou learn how to enter defensive stance rank III.");
343 if (p_ptr->combat_stance == 1) p_ptr->combat_stance_power = 2;
344 }
345 if (old_value < 100 && new_value >= 150) msg_print(Ind, "\374\377GYou learn how to enter an offensive stance (rank I).");
346 if (old_value < 200 && new_value >= 250) {
347 msg_print(Ind, "\374\377GYou learn how to enter offensive stance rank II.");
348 if (p_ptr->combat_stance == 2) p_ptr->combat_stance_power = 1;
349 }
350 if (old_value < 400 && new_value >= 400) {
351 msg_print(Ind, "\374\377GYou learn how to enter offensive stance rank III.");
352 if (p_ptr->combat_stance == 2) p_ptr->combat_stance_power = 2;
353 }
354 break;
355 case CLASS_PALADIN:
356 if (old_value < 50 && new_value >= 50) msg_print(Ind, "\374\377GYou learn how to enter a defensive stance (rank I). ('\377gm\377G' key)");
357 if (old_value < 200 && new_value >= 200) {
358 msg_print(Ind, "\374\377GYou learn how to enter defensive stance rank II.");
359 if (p_ptr->combat_stance == 1) p_ptr->combat_stance_power = 1;
360 }
361 if (old_value < 350 && new_value >= 350) {
362 msg_print(Ind, "\374\377GYou learn how to enter defensive stance rank III.");
363 if (p_ptr->combat_stance == 1) p_ptr->combat_stance_power = 2;
364 }
365 if (old_value < 100 && new_value >= 150) msg_print(Ind, "\374\377GYou learn how to enter an offensive stance (rank I).");
366 if (old_value < 200 && new_value >= 250) {
367 msg_print(Ind, "\374\377GYou learn how to enter offensive stance rank II.");
368 if (p_ptr->combat_stance == 2) p_ptr->combat_stance_power = 1;
369 }
370 if (old_value < 400 && new_value >= 400) {
371 msg_print(Ind, "\374\377GYou learn how to enter offensive stance rank III.");
372 if (p_ptr->combat_stance == 2) p_ptr->combat_stance_power = 2;
373 }
374 break;
375 case CLASS_RANGER:
376 if (old_value < 50 && new_value >= 100) msg_print(Ind, "\374\377GYou learn how to enter a defensive stance (rank I). ('\377gm\377G' key)");
377 if (old_value < 150 && new_value >= 200) {
378 msg_print(Ind, "\374\377GYou learn how to enter defensive stance rank II.");
379 if (p_ptr->combat_stance == 1) p_ptr->combat_stance_power = 1;
380 }
381 if (old_value < 350 && new_value >= 400) {
382 msg_print(Ind, "\374\377GYou learn how to enter defensive stance rank III.");
383 if (p_ptr->combat_stance == 1) p_ptr->combat_stance_power = 2;
384 }
385 if (old_value < 100 && new_value >= 150) msg_print(Ind, "\374\377GYou learn how to enter an offensive stance (rank I).");
386 if (old_value < 200 && new_value >= 250) {
387 msg_print(Ind, "\374\377GYou learn how to enter offensive stance rank II.");
388 if (p_ptr->combat_stance == 2) p_ptr->combat_stance_power = 1;
389 }
390 if (old_value < 400 && new_value >= 400) {
391 msg_print(Ind, "\374\377GYou learn how to enter offensive stance rank III.");
392 if (p_ptr->combat_stance == 2) p_ptr->combat_stance_power = 2;
393 }
394 break;
395 }
396
397 /* learn royal stances at 45+ if winner */
398 if (old_value < 450 && new_value >= 450 && p_ptr->total_winner) {
399 msg_print(Ind, "\374\377GYou learn how to enter Royal Rank combat stances.");
400 if (p_ptr->combat_stance) p_ptr->combat_stance_power = 3;
401 }
402 break;
403 case SKILL_ARCHERY:
404 if (old_value < 40 && new_value >= 40)
405 msg_print(Ind, "\374\377GYou learn the shooting technique 'Flare missile'! (press '\377gm\377G')");
406 if (old_value < 80 && new_value >= 80)
407 msg_print(Ind, "\374\377GYou learn the shooting technique 'Precision shot'!");
408 if (old_value < 100 && new_value >= 100)
409 msg_print(Ind, "\374\377GYou learn how to create ammunition from bones and rubble!");
410 if (old_value < 110 && new_value >= 110)
411 msg_print(Ind, "\374\377GYou got better at recognizing the power of unknown ranged weapons and ammo!");
412 if (old_value < 160 && new_value >= 160)
413 msg_print(Ind, "\374\377GYou learn the shooting technique 'Double-shot'!");
414 if (old_value < 200 && new_value >= 200)
415 msg_print(Ind, "\374\377GYour ability to create ammunition improved remarkably!");
416 if (old_value < 250 && new_value >= 250)
417 msg_print(Ind, "\374\377GYou learn the shooting technique 'Barrage'!");
418 // if (old_value < 500 && new_value >= 500)
419 // msg_print(Ind, "\374\377GYour general shooting power gains extra might due to your training!");
420 break;
421 case SKILL_COMBAT:
422 if (old_value < 110 && new_value >= 110) {
423 msg_print(Ind, "\374\377GYou got better at recognizing the power of unknown weapons.");
424 #if 0
425 } if (old_value < 310 && new_value >= 310) {
426 msg_print(Ind, "\374\377GYou got better at recognizing the power of unknown ranged weapons and ammo.");
427 } if (old_value < 410 && new_value >= 410) {
428 msg_print(Ind, "\374\377GYou got better at recognizing the power of unknown magical items.");
429 #else /* more true messages: */
430 } if (old_value < 310 && new_value >= 310) {
431 if (get_skill(p_ptr, SKILL_ARCHERY) < 11)
432 msg_print(Ind, "\374\377GYou somewhat recognize the usefulness of unknown ranged weapons and ammo.");
433 } if (old_value < 410 && new_value >= 410) {
434 /* message somewhat redudant with classes/other skills which also give
435 ok_curse, but seems impractical to sort out really */
436 msg_print(Ind, "\374\377GYou feel able to sense curses on all types of items.");
437 #endif
438 }
439 break;
440 case SKILL_MAGIC:
441 if (old_value < 110 && new_value >= 110) msg_print(Ind, "\374\377GYou got better at recognizing the power of unknown magical items.");
442 break;
443 case SKILL_EARTH:
444 if (old_value < 300 && new_value >= 300) {
445 msg_print(Ind, "\374\377GYou feel able to prevent shards of rock from striking you.");
446 } if (old_value < 450 && new_value >= 450) {
447 msg_print(Ind, "\374\377GYou feel able to prevent large masses of rock from striking you.");
448 }
449 break;
450 case SKILL_AIR:
451 if (old_value < 300 && new_value >= 300) {
452 msg_print(Ind, "\374\377GYou feel light as a feather.");
453 } if (old_value < 400 && new_value >= 400) {
454 msg_print(Ind, "\374\377GYou feel able to breathe within poisoned air.");
455 } if (old_value < 500 && new_value >= 500) {
456 msg_print(Ind, "\374\377GYou feel levitating is easy.");
457 }
458 break;
459 case SKILL_WATER:
460 if (old_value < 300 && new_value >= 300) {
461 msg_print(Ind, "\374\377GYou feel able to prevent water streams from striking you.");
462 } if (old_value < 400 && new_value >= 400) {
463 msg_print(Ind, "\374\377GYou feel able to move through water easily.");
464 } if (old_value < 500 && new_value >= 500) {
465 msg_print(Ind, "\374\377GYou feel able to prevent tidal waves from striking you.");
466 }
467 break;
468 case SKILL_FIRE:
469 if (old_value < 300 && new_value >= 300) {
470 msg_print(Ind, "\374\377GYou feel able to resist fire easily.");
471 } if (old_value < 500 && new_value >= 500) {
472 msg_print(Ind, "\374\377GYou feel that fire cannot harm you anymore.");
473 }
474 break;
475 case SKILL_MANA:
476 if (old_value < 400 && new_value >= 400) {
477 msg_print(Ind, "\374\377GYou feel able to defend from mana attacks easily.");
478 }
479 break;
480 case SKILL_CONVEYANCE:
481 if (old_value < 300 && new_value >= 300 &&
482 get_skill(p_ptr, SKILL_UDUN) < 30) {
483 msg_print(Ind, "\374\377GYou are impervious to feeble teleportation attacks.");
484 }
485 break;
486 case SKILL_DIVINATION:
487 if (old_value < 500 && new_value >= 500) {
488 msg_print(Ind, "\374\377GYou find identifying items ridiculously easy.");
489 identify_pack(Ind);
490 }
491 break;
492 case SKILL_NATURE:
493 if (old_value < 300 && new_value >= 300) {
494 msg_print(Ind, "\374\377GYour magic allows you to pass trees and forests easily.");
495 } if (old_value < 400 && new_value >= 400) {
496 msg_print(Ind, "\374\377GYour magic allows you to pass water easily.");
497 }
498 /* + continuous effect */
499 break;
500 case SKILL_MIND:
501 if (old_value < 300 && new_value >= 300) {
502 msg_print(Ind, "\374\377GYou feel strong against confusion and hallucinations.");
503 } if (old_value < 400 && new_value >= 400) {
504 msg_print(Ind, "\374\377GYou learn to keep hold of your sanity.");
505 } if (old_value < 500 && new_value >= 500) {
506 msg_print(Ind, "\374\377GYou learn to keep strong hold of your sanity.");
507 }
508 break;
509 case SKILL_TEMPORAL:
510 if (old_value < 500 && new_value >= 500) {
511 msg_print(Ind, "\374\377GYou don't fear time attacks as much anymore.");
512 }
513 break;
514 case SKILL_UDUN:
515 if (old_value < 300 && new_value >= 300 &&
516 get_skill(p_ptr, SKILL_CONVEYANCE) < 30) {
517 msg_print(Ind, "\374\377GYou are impervious to feeble teleportation attacks.");
518 } if (old_value < 400 && new_value >= 400) {
519 msg_print(Ind, "\374\377GYou have strong control over your life force.");
520 }
521 break;
522 case SKILL_META: /* + continuous effect */
523 break;
524 case SKILL_HOFFENSE:
525 if (old_value < 300 && new_value >= 300) {
526 msg_print(Ind, "\374\377GYou fight against undead with holy wrath.");
527 } if (old_value < 400 && new_value >= 400) {
528 msg_print(Ind, "\374\377GYou fight against demons with holy wrath.");
529 } if (old_value < 500 && new_value >= 500) {
530 msg_print(Ind, "\374\377GYou fight against evil with holy fury.");
531 }
532 break;
533 case SKILL_HDEFENSE:
534 if (old_value < 300 && new_value >= 300) {
535 msg_print(Ind, "\374\377GYou stand fast against undead.");
536 } if (old_value < 400 && new_value >= 400) {
537 msg_print(Ind, "\374\377GYou stand fast against demons.");
538 } if (old_value < 500 && new_value >= 500) {
539 msg_print(Ind, "\374\377GYou stand fast against evil.");
540 }
541 break;
542 case SKILL_HCURING:
543 if (old_value < 300 && new_value >= 300) {
544 msg_print(Ind, "\374\377GYou feel strong against blindness and poison.");
545 } if (old_value < 400 && new_value >= 400) {
546 msg_print(Ind, "\374\377GYou feel strong against stun and cuts.");
547 } if (old_value < 500 && new_value >= 500) {
548 msg_print(Ind, "\374\377GYou feel strong against hallucination and black breath.");
549 msg_print(Ind, "\374\377GYour melee attacks inflict greater damage on undead.");
550 msg_print(Ind, "\374\377GYour soul escapes less quickly on death.");
551 }
552 /* + continuous effect */
553 break;
554 case SKILL_HSUPPORT:
555 if (old_value < 400 && new_value >= 400 && p_ptr->prace != RACE_MAIA) {
556 msg_print(Ind, "\374\377GYou don't feel hunger for worldly food anymore.");
557 } if (old_value < 500 && new_value >= 500) {
558 msg_print(Ind, "\374\377GYou feel superior to ancient curses.");
559 }
560 break;
561 case SKILL_SWORD: case SKILL_AXE: case SKILL_BLUNT: case SKILL_POLEARM:
562 if ((old_value < 250 && new_value >= 250) || (old_value < 500 && new_value >= 500)) {
563 msg_print(Ind, "\374\377GYour attack speed has become faster due to your training!");
564 }
565 break;
566 case SKILL_SLING:
567 if ((old_value < 100 && new_value >= 100) || (old_value < 200 && new_value >= 200) ||
568 (old_value < 300 && new_value >= 300) || (old_value < 400 && new_value >= 400) || (old_value < 500 && new_value >= 500)) {
569 msg_print(Ind, "\374\377GYour shooting speed with slings has become faster due to your training!");
570 }
571 if (old_value < 500 && new_value >= 500)
572 msg_print(Ind, "\374\377GYour shooting power with slings gains extra might due to your training!");
573 break;
574 case SKILL_BOW:
575 if ((old_value < 125 && new_value >= 125) || (old_value < 250 && new_value >= 250) ||
576 (old_value < 375 && new_value >= 375) || (old_value < 500 && new_value >= 500)) {
577 msg_print(Ind, "\374\377GYour shooting speed with bows has become faster due to your training!");
578 }
579 if (old_value < 500 && new_value >= 500)
580 msg_print(Ind, "\374\377GYour shooting power with bows gains extra might due to your training!");
581 break;
582 case SKILL_XBOW:
583 if ((old_value < 125 && new_value >= 125) || (old_value < 375 && new_value >= 375)) {
584 msg_print(Ind, "\374\377GYour shooting power with crossbows gains extra might due to your training!");
585 }
586 if ((old_value < 250 && new_value >= 250) || (old_value < 500 && new_value >= 500)) {
587 msg_print(Ind, "\374\377GYour shooting speed with crossbows has become faster due to your training!");
588 }
589 if (old_value < 500 && new_value >= 500)
590 msg_print(Ind, "\374\377GYour shooting power with crossbows gains extra might due to your training!");
591 break;
592 /* case SKILL_SLING:
593 case SKILL_BOW:
594 case SKILL_XBOW:
595 */ case SKILL_BOOMERANG:
596 if ((old_value < 166 && new_value >= 166) || (old_value < 333 && new_value >= 333) ||
597 (old_value < 500 && new_value >= 500)) {
598 msg_print(Ind, "\374\377GYour boomerang throwing speed has become faster due to your training!");
599 }
600 break;
601 case SKILL_AURA_FEAR: if (old_value == 0 && new_value > 0) p_ptr->aura[0] = TRUE; break; /* MAX_AURAS */
602 case SKILL_AURA_SHIVER: if (old_value == 0 && new_value > 0) p_ptr->aura[1] = TRUE; break;
603 case SKILL_AURA_DEATH: if (old_value == 0 && new_value > 0) p_ptr->aura[2] = TRUE; break;
604 #if 0 /* obsolete */
605 case SKILL_DIG:
606 if (old_value < 300 && new_value >= 300) {
607 msg_print(Ind, "\374\377GYou've become much better at prospecting.");
608 }
609 break;
610 #endif
611 case SKILL_HEALTH:
612 if (old_value < 100 && new_value >= 100) p_ptr->sanity_bar = 1;
613 else if (old_value < 200 && new_value >= 200) p_ptr->sanity_bar = 2;
614 else if (old_value < 400 && new_value >= 400) p_ptr->sanity_bar = 3;
615 break;
616 }
617 }
618
619 /* Hrm this can be nasty for Sorcery/Antimagic */
620 // void recalc_skills_theory(s16b *invest, s32b *base_val, u16b *base_mod, s32b *bonus)
621 static void increase_related_skills(int Ind, int i, bool quiet)
622 {
623 player_type *p_ptr = Players[Ind];
624 int j;
625
626 /* Modify related skills */
627 for (j = 0; j < MAX_SKILLS; j++) {
628 /* Ignore self */
629 if (j == i) continue;
630
631 /* Exclusive skills */
632 if (s_info[i].action[j] == SKILL_EXCLUSIVE) {
633 /* Turn it off */
634 p_ptr->s_info[j].value = 0;
635 }
636
637 /* Non-exclusive skills */
638 else {
639 /* Save previous value */
640 int old_value = get_skill_scale(p_ptr, j, 500);
641
642 /* Increase / decrease with a % */
643 s32b val = p_ptr->s_info[j].value +
644 (p_ptr->s_info[j].mod * s_info[i].action[j] / 100);
645
646 /* Skill value cannot be negative */
647 if (val < 0) val = 0;
648
649 /* It cannot exceed SKILL_MAX */
650 if ((p_ptr->s_info[j].flags1 & SKF1_MAX_1) && (val >= 1000)) val = 1000;
651 else if ((p_ptr->s_info[j].flags1 & SKF1_MAX_10) && (val >= 10000)) val = 10000;
652 else if ((p_ptr->s_info[j].flags1 & SKF1_MAX_20) && (val >= 20000)) val = 20000;
653 else if ((p_ptr->s_info[j].flags1 & SKF1_MAX_25) && (val >= 25000)) val = 25000;
654 else if (val > SKILL_MAX) val = SKILL_MAX;
655
656 /* Save the modified value */
657 p_ptr->s_info[j].value = val;
658
659 /* Update the client */
660 if (!quiet) {
661 calc_techniques(Ind);
662 Send_skill_info(Ind, j, TRUE);
663 }
664
665 /* Take care of gained abilities */
666 if (!quiet) msg_gained_abilities(Ind, old_value, j);
667 }
668 }
669 }
670
671
672 /*
673 * Advance the skill point of the skill specified by i and
674 * modify related skills
675 * note that we *MUST* send back a skill_info packet
676 */
677 void increase_skill(int Ind, int i, bool quiet)
678 {
679 player_type *p_ptr = Players[Ind];
680 int old_value;
681 // int as, ws, new_value;
682 // int can_regain;
683
684 /* Sanity check - mikaelh */
685 if (i < 0 || i >= MAX_SKILLS)
686 {
687 return;
688 }
689
690 /* No skill points to be allocated */
691 if (p_ptr->skill_points <= 0) {
692 if (!quiet) Send_skill_info(Ind, i, TRUE);
693 return;
694 }
695
696 /* The skill cannot be increased */
697 if (p_ptr->s_info[i].mod <= 0) {
698 if (!quiet) Send_skill_info(Ind, i, TRUE);
699 return;
700 }
701
702 /* The skill is already maxed */
703 if ((p_ptr->s_info[i].value >= SKILL_MAX) ||
704 /* Some extra ability skills don't go over 1 ('1' meaning 'learnt') */
705 ((p_ptr->s_info[i].flags1 & SKF1_MAX_1) && (p_ptr->s_info[i].value >= 1000)) ||
706 /* Hack: Archery for rangers doesn't go over 10 */
707 ((p_ptr->s_info[i].flags1 & SKF1_MAX_10) && (p_ptr->s_info[i].value >= 10000)) ||
708 /* unused: doesn't go over 20 */
709 ((p_ptr->s_info[i].flags1 & SKF1_MAX_20) && (p_ptr->s_info[i].value >= 20000)) ||
710 /* unused: doesn't go over 25 */
711 ((p_ptr->s_info[i].flags1 & SKF1_MAX_25) && (p_ptr->s_info[i].value >= 25000)))
712 {
713 if (!quiet) Send_skill_info(Ind, i, TRUE);
714 return;
715 }
716
717 /* Cannot allocate more than player level + 2 levels */
718 if ((p_ptr->s_info[i].value / SKILL_STEP) >= p_ptr->lev + 2) /* <- this allows limit breaks at very high step values -- handled in GET_SKILL now! */
719 // if ((((p_ptr->s_info[i].value + p_ptr->s_info[i].mod) * 10) / SKILL_STEP) > (p_ptr->lev * 10) + 20) /* <- this often doesn't allow proper increase to +2 at high step values */
720 {
721 if (!quiet) Send_skill_info(Ind, i, TRUE);
722 return;
723 }
724
725 /* Spend an unallocated skill point */
726 p_ptr->skill_points--;
727
728 /* Save previous value for telling the player about newly gained
729 abilities later on. Round down extra-safely (just paranoia). */
730 // old_value = (p_ptr->s_info[i].value - (p_ptr->s_info[i].value % SKILL_STEP)) / SKILL_STEP;
731 /*multiply by 10, so we get +1 digit*/
732 old_value = (p_ptr->s_info[i].value - (p_ptr->s_info[i].value % (SKILL_STEP / 10))) / (SKILL_STEP / 10);
733
734 /* Increase the skill */
735 p_ptr->s_info[i].value += p_ptr->s_info[i].mod;
736
737 /* extra abilities cap at 1000 */
738 if ((p_ptr->s_info[i].flags1 & SKF1_MAX_1) && (p_ptr->s_info[i].value >= 1000))
739 p_ptr->s_info[i].value = 1000;
740 /* hack: archery for rangers caps at 10000 */
741 else if ((p_ptr->s_info[i].flags1 & SKF1_MAX_10) && (p_ptr->s_info[i].value >= 10000))
742 p_ptr->s_info[i].value = 10000;
743 /* unused: */
744 else if ((p_ptr->s_info[i].flags1 & SKF1_MAX_20) && (p_ptr->s_info[i].value >= 20000))
745 p_ptr->s_info[i].value = 20000;
746 /* unused: */
747 else if ((p_ptr->s_info[i].flags1 & SKF1_MAX_25) && (p_ptr->s_info[i].value >= 25000))
748 p_ptr->s_info[i].value = 25000;
749 /* cap at SKILL_MAX */
750 else if (p_ptr->s_info[i].value >= SKILL_MAX) p_ptr->s_info[i].value = SKILL_MAX;
751
752 /* Increase the skill */
753 increase_related_skills(Ind, i, quiet);
754
755 /* Update the client */
756 if (!quiet) {
757 calc_techniques(Ind);
758 Send_skill_info(Ind, i, TRUE);
759 }
760
761 /* XXX updating is delayed till player leaves the skill screen */
762 p_ptr->update |= (PU_SKILL_MOD);
763
764 /* also update 'C' character screen live! */
765 p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA);
766 p_ptr->redraw |= (PR_SKILLS | PR_PLUSSES | PR_SANITY);
767
768 /* Take care of gained abilities */
769 if (!quiet) msg_gained_abilities(Ind, old_value, i);
770 }
771 /*
772 * Given the name of a skill, returns skill index or -1 if no
773 * such skill is found
774 */
775 s16b find_skill(cptr name)
776 {
777 u16b i;
778
779 /* Scan skill list */
780 // for (i = 1; i < max_s_idx; i++)
781 for (i = 0; i < MAX_SKILLS; i++)
782 {
783 /* The name matches */
784 if (streq(s_info[i].name + s_name, name)) return (i);
785 }
786
787 /* No match found */
788 return (-1);
789 }
790
791 /* return value by which a skill was auto-modified by related skills
792 instead of real point distribution by the player */
793 static s32b modified_by_related(player_type *p_ptr, int i) {
794 int j, points;
795 s32b val = 0, jv, jm;
796
797 for (j = 0; j < MAX_SKILLS; j++) {
798 /* Ignore self */
799 if (j == i) continue;
800
801 /* Ignore skills that aren't modified by related skills */
802 if ((s_info[j].action[i] != SKILL_EXCLUSIVE) &&
803 s_info[j].action[i] &&
804 /* hack against oscillation: only take care of increase atm '> 0': */
805 (s_info[j].action[i] > 0)) {
806 /* calc 'manual increase' of the increasing skill by excluding base value 'jv' */
807 jv = 0; jm = 0;
808 compute_skills(p_ptr, &jv, &jm, j);
809 /* calc amount of points the user spent into the increasing skill */
810 // if (jm)
811 if (p_ptr->s_info[j].mod)
812 // points = (p_ptr->s_info[j].value - p_ptr->s_info[j].base_value - modified_by_related(p_ptr, j)) / jm;
813 points = (p_ptr->s_info[j].value - p_ptr->s_info[j].base_value - modified_by_related(p_ptr, j)) / p_ptr->s_info[j].mod;
814 else
815 points = 0;
816 /* calc and stack up amount of the increase that skill 'i' experienced by that */
817 val += ((p_ptr->s_info[i].mod * s_info[j].action[i] / 100) * points);
818
819 /* Skill value cannot be negative */
820 if (val < 0) val = 0;
821 /* It cannot exceed SKILL_MAX */
822 if (val > SKILL_MAX) val = SKILL_MAX;
823 }
824 }
825
826 return (val);
827 }
828
829 /* Free all points spent into a certain skill and make them available again.
830 Note that it is actually impossible under current skill functionality
831 to reconstruct the exact points the user spent on all skills in all cases.
832 Reasons:
833 - If the skill in question for example is a skill that gets
834 increased as a result of increasing another skill, we won't
835 know how many points the player actually invested into it if
836 the skill is maxed out.
837 - Similarly, we wont know how many points to subtract from
838 related skills when we erase a specific skill, if that related
839 skill is maxed, because the player might have spent more points
840 into it than would be required to max it.
841 - Even if we start analyzing all skills, we won't know which one
842 got more 'overspent' points as soon as there are two ore more
843 maximized skills in question.
844 For a complete respec function see respec_skills() below.
845 This function is still possible though, if we agree that it may
846 'optimize' the skill point spending for the users. It can't return
847 more points than the user actually could spend in an 'ideal skill chart'.
848 So it wouldn't hurt really, if we allow this to correct any waste
849 of skill points the user did. - C. Blue
850 update_skills: Change base values and base mods to up-to-date values. */
851 void respec_skill(int Ind, int i, bool update_skill, bool polymorph) {
852 player_type *p_ptr = Players[Ind];
853 int j;
854 s32b v = 0, m = 0; /* base starting skill value, skill modifier */
855 s32b jv, jm;
856 s32b real_user_increase = 0, val;
857 int spent_points;
858
859 compute_skills(p_ptr, &v, &m, i);
860
861 /* Calculate amount of 'manual increase' to this skill.
862 Manual meaning either direct increases or indirect
863 increases from related skills. */
864 real_user_increase = p_ptr->s_info[i].value - p_ptr->s_info[i].base_value;
865 /* Now get rid of amount of indirect increases we got
866 from related skills. */
867 real_user_increase = real_user_increase - modified_by_related(p_ptr, i); /* recursive */
868 /* catch overflow cap (example: skill starts at 1.000,
869 but is modified by a theoretical total of 50.000 from
870 various other skills -> would end at -1.000) */
871 if (real_user_increase < 0) real_user_increase = 0;
872 /* calculate skill points spent into this skill */
873 // spent_points = real_user_increase / m;
874 if (p_ptr->s_info[i].mod)
875 spent_points = real_user_increase / p_ptr->s_info[i].mod;
876 else
877 spent_points = 0;
878
879 /* modify related skills */
880 for (j = 0; j < MAX_SKILLS; j++) {
881 /* Ignore self */
882 if (j == i) continue;
883
884 /* Exclusive skills */
885 if (s_info[i].action[j] == SKILL_EXCLUSIVE) {
886 jv = 0; jm = 0;
887 compute_skills(p_ptr, &jv, &jm, j);
888 /* Turn it on again (!) */
889 // p_ptr->s_info[j].value = jv;
890 p_ptr->s_info[j].value = p_ptr->s_info[j].base_value;
891 } else { /* Non-exclusive skills */
892 /* Decrease with a % */
893 val = p_ptr->s_info[j].value -
894 ((p_ptr->s_info[j].mod * s_info[i].action[j] / 100) * spent_points);
895
896 /* Skill value cannot be negative */
897 if (val < 0) val = 0;
898 /* It cannot exceed SKILL_MAX */
899 if ((p_ptr->s_info[j].flags1 & SKF1_MAX_1) && (val > 1000)) val = 1000;
900 else if ((p_ptr->s_info[j].flags1 & SKF1_MAX_10) && (val > 10000)) val = 10000;
901 else if ((p_ptr->s_info[j].flags1 & SKF1_MAX_20) && (val > 10000)) val = 20000;
902 else if ((p_ptr->s_info[j].flags1 & SKF1_MAX_25) && (val > 10000)) val = 25000;
903 else if (val > SKILL_MAX) val = SKILL_MAX;
904
905 /* Save the modified value */
906 p_ptr->s_info[j].value = val;
907
908 /* Update the client */
909 Send_skill_info(Ind, j, FALSE);
910 }
911 }
912
913 /* Remove the points, ie set skill to its starting base value again
914 and just add synergy points it got from other related skills */
915 p_ptr->s_info[i].value -= real_user_increase;
916 /* Free the points, making them available */
917 p_ptr->skill_points += spent_points;
918
919 if (update_skill) { /* hack: fix skill.mod */
920 p_ptr->s_info[i].mod = m;
921 p_ptr->s_info[i].value = v;
922 p_ptr->s_info[i].base_value = v;
923 }
924 if (p_ptr->fruit_bat == 1) fruit_bat_skills(p_ptr);
925
926 /* in case we changed mimicry skill */
927 if (polymorph) do_mimic_change(Ind, 0, TRUE);
928
929 /* hack - fix SKILL_STANCE skill */
930 if (i == SKILL_STANCE && get_skill(p_ptr, SKILL_STANCE)) {
931 if (p_ptr->max_plv < 50) p_ptr->s_info[SKILL_STANCE].value = p_ptr->max_plv * 1000;
932 else p_ptr->s_info[SKILL_STANCE].value = 50000;
933 /* Update the client */
934 Send_skill_info(Ind, SKILL_STANCE, TRUE);
935 Send_skill_info(Ind, SKILL_TECHNIQUE, TRUE);
936 }
937
938 /* Update the client */
939 calc_techniques(Ind);
940 Send_skill_info(Ind, i, FALSE);
941 /* XXX updating is delayed till player leaves the skill screen */
942 p_ptr->update |= (PU_SKILL_MOD);
943 /* also update 'C' character screen live! */
944 p_ptr->update |= (PU_BONUS);
945 p_ptr->redraw |= (PR_SKILLS | PR_PLUSSES);
946
947 /* Discard old "save point" for /undoskills command */
948 memcpy(p_ptr->s_info_old, p_ptr->s_info, MAX_SKILLS * sizeof(skill_player));
949 p_ptr->skill_points_old = p_ptr->skill_points;
950 p_ptr->reskill_possible = TRUE;
951 }
952
953 /* Complete skill-chart reset (full respec) - C. Blue
954 update_skill: Change base value and base mod to up-to-date values. */
955 void respec_skills(int Ind, bool update_skills) {
956 player_type *p_ptr = Players[Ind];
957 int i;
958 s32b v, m; /* base starting skill value, skill modifier */
959
960 /* Remove the points, ie set skills to its starting base values again */
961 for (i = 0; i < MAX_SKILLS; i++) {
962 v = 0; m = 0;
963 if (update_skills) {
964 compute_skills(p_ptr, &v, &m, i);
965 p_ptr->s_info[i].base_value = v;
966 p_ptr->s_info[i].value = v;
967 p_ptr->s_info[i].mod = m;
968 } else {
969 p_ptr->s_info[i].value = p_ptr->s_info[i].base_value;
970 }
971 }
972 if (p_ptr->fruit_bat == 1) fruit_bat_skills(p_ptr);
973 /* Update the client */
974 for (i = 0; i < MAX_SKILLS; i++) Send_skill_info(Ind, i, FALSE);
975
976 /* Calculate amount of skill points that should be
977 available to the player depending on his level */
978 p_ptr->skill_points = (p_ptr->max_plv - 1) * SKILL_NB_BASE;
979
980 /* in case we changed mimicry skill */
981 do_mimic_change(Ind, 0, TRUE);
982
983 /* hack - fix SKILL_STANCE skill */
984 if (get_skill(p_ptr, SKILL_STANCE)) {
985 if (p_ptr->max_plv < 50) p_ptr->s_info[SKILL_STANCE].value = p_ptr->max_plv * 1000;
986 else p_ptr->s_info[SKILL_STANCE].value = 50000;
987 /* Update the client */
988 Send_skill_info(Ind, SKILL_STANCE, TRUE);
989 Send_skill_info(Ind, SKILL_TECHNIQUE, TRUE);
990 }
991
992 /* Update the client */
993 calc_techniques(Ind);
994 /* XXX updating is delayed till player leaves the skill screen */
995 p_ptr->update |= (PU_SKILL_MOD);
996 /* also update 'C' character screen live! */
997 p_ptr->update |= (PU_BONUS);
998 p_ptr->redraw |= (PR_SKILLS | PR_PLUSSES);
999
1000 /* Discard old "save point" for /undoskills command */
1001 memcpy(p_ptr->s_info_old, p_ptr->s_info, MAX_SKILLS * sizeof(skill_player));
1002 p_ptr->skill_points_old = p_ptr->skill_points;
1003 p_ptr->reskill_possible = TRUE;
1004 }
1005
1006 /* return amount of points that were invested into a skill */
1007 int invested_skill_points(int Ind, int i) {
1008 player_type *p_ptr = Players[Ind];
1009 s32b v = 0, m = 0; /* base starting skill value, skill modifier */
1010 s32b real_user_increase = 0;
1011
1012 compute_skills(p_ptr, &v, &m, i);
1013
1014 /* Calculate amount of 'manual increase' to this skill.
1015 Manual meaning either direct increases or indirect
1016 increases from related skills. */
1017 real_user_increase = p_ptr->s_info[i].value - p_ptr->s_info[i].base_value;
1018 /* Now get rid of amount of indirect increases we got
1019 from related skills. */
1020 real_user_increase = real_user_increase - modified_by_related(p_ptr, i); /* recursive */
1021 /* catch overflow cap (example: skill starts at 1.000,
1022 but is modified by a theoretical total of 50.000 from
1023 various other skills -> would end at -1.000) */
1024 if (real_user_increase < 0) real_user_increase = 0;
1025 /* calculate skill points spent into this skill */
1026 return(real_user_increase / m);
1027 }
1028
1029 /* Disable skills that fruit bats could not put to use anyway.
1030 This could be moved to tables.c to form a new type, aka body mod skills
1031 like racial/class skills currently do (applied by compute_skills()). */
1032 void fruit_bat_skills(player_type *p_ptr) {
1033 p_ptr->s_info[SKILL_MASTERY].value = p_ptr->s_info[SKILL_MASTERY].mod = 0;
1034 p_ptr->s_info[SKILL_SWORD].value = p_ptr->s_info[SKILL_SWORD].mod = 0;
1035 p_ptr->s_info[SKILL_CRITS].value = p_ptr->s_info[SKILL_CRITS].mod = 0;
1036 p_ptr->s_info[SKILL_BLUNT].value = p_ptr->s_info[SKILL_BLUNT].mod = 0;
1037 p_ptr->s_info[SKILL_AXE].value = p_ptr->s_info[SKILL_AXE].mod = 0;
1038 p_ptr->s_info[SKILL_POLEARM].value = p_ptr->s_info[SKILL_POLEARM].mod = 0;
1039 p_ptr->s_info[SKILL_DUAL].value = p_ptr->s_info[SKILL_DUAL].mod = 0;
1040
1041 p_ptr->s_info[SKILL_ARCHERY].value = p_ptr->s_info[SKILL_ARCHERY].mod = 0;
1042 p_ptr->s_info[SKILL_BOW].value = p_ptr->s_info[SKILL_BOW].mod = 0;
1043 p_ptr->s_info[SKILL_XBOW].value = p_ptr->s_info[SKILL_XBOW].mod = 0;
1044 p_ptr->s_info[SKILL_SLING].value = p_ptr->s_info[SKILL_SLING].mod = 0;
1045 p_ptr->s_info[SKILL_BOOMERANG].value = p_ptr->s_info[SKILL_BOOMERANG].mod = 0;
1046 }
1047