From 673bdae75485d14f759af597c3c62b99601f9a43 Mon Sep 17 00:00:00 2001 From: peterb12 Date: Thu, 21 Jul 2005 02:34:44 +0000 Subject: Initial revision git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3 c06c8d41-db1a-0410-9941-cceddc491573 --- trunk/source/skills.cc | 438 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 438 insertions(+) create mode 100644 trunk/source/skills.cc (limited to 'trunk/source/skills.cc') diff --git a/trunk/source/skills.cc b/trunk/source/skills.cc new file mode 100644 index 0000000000..af7d88f49a --- /dev/null +++ b/trunk/source/skills.cc @@ -0,0 +1,438 @@ +/* + * File: skills.cc + * Summary: Skill exercising functions. + * Written by: Linley Henzell + * + * Change History (most recent first): + * + * <3> 8/08/99 BWR Increased skill cost in midgame + * + * <2> 7/31/99 BWR Inc skill_point granularity, + * added MAX_SPENDING_LIMIT + * <1> -/--/-- LRH Created + */ + +#include "AppHdr.h" +#include "skills.h" + +#include +#include + +#include "externs.h" + +#include "macro.h" +#include "player.h" +#include "skills2.h" +#include "stuff.h" + + +// MAX_COST_LIMIT is the maximum XP amount it will cost to raise a skill +// by 10 skill points (ie one standard practice). +// +// MAX_SPENDING_LIMIT is the maximum XP amount we allow the player to +// spend on a skill in a single raise. +// +// Note that they don't have to be equal, but it is important to make +// sure that they're set so that the spending limit will always allow +// for 1 skill point to be earned. +#define MAX_COST_LIMIT 250 +#define MAX_SPENDING_LIMIT 250 + +static void exercise2( char exsk ); + +// These values were calculated by running a simulation of gaining skills. +// The goal is to try and match the old cost system which used the player's +// experience level (which has a number of problems) so things shouldn't +// seem too different to the player... but we still try to err on the +// high side for the lower levels. -- bwr +int skill_cost_needed( int level ) +{ + // The average starting skill total is actually lower, but + // some classes get about 2200, and they would probably be + // start around skill cost level 3 if we used the average. -- bwr + int ret = 2200; + + switch (level) + { + case 1: ret = 0; break; + + case 2: ret += 250; break; // 250 -- big because of initial 25 pool + case 3: ret += 350; break; // 100 + case 4: ret += 550; break; // 200 + case 5: ret += 900; break; // 350 + case 6: ret += 1300; break; // 400 + case 7: ret += 1900; break; // 600 + case 8: ret += 2800; break; // 900 + case 9: ret += 4200; break; // 1400 + case 10: ret += 5900; break; // 1700 + case 11: ret += 9000; break; // 3100 + + default: + ret += 9000 + (4000 * (level - 11)); + break; + } + + return (ret); +} + +void calc_total_skill_points( void ) +{ + int i; + + you.total_skill_points = 0; + + for (i = 0; i < NUM_SKILLS; i++) + { + you.total_skill_points += you.skill_points[i]; + } + + for (i = 1; i <= 27; i++) + { + if (you.total_skill_points < skill_cost_needed(i)) + break; + } + + you.skill_cost_level = i - 1; + +#if DEBUG_DIAGNOSTICS + you.redraw_experience = 1; +#endif +} + +// skill_cost_level makes skills more expensive for more experienced characters +// skill_level makes higher skills more expensive +static int calc_skill_cost( int skill_cost_level, int skill_level ) +{ + int ret = 1 + skill_level; + + // does not yet allow for loss of skill levels. + if (skill_level > 9) + { + ret *= (skill_level - 7); + ret /= 3; + } + + if (skill_cost_level > 4) + ret += skill_cost_level - 4; + if (skill_cost_level > 7) + ret += skill_cost_level - 7; + if (skill_cost_level > 10) + ret += skill_cost_level - 10; + if (skill_cost_level > 13) + ret += skill_cost_level - 13; + if (skill_cost_level > 16) + ret += skill_cost_level - 16; + + if (skill_cost_level > 10) + { + ret *= (skill_cost_level - 5); + ret /= 5; + } + + if (skill_level > 7) + ret += 1; + if (skill_level > 9) + ret += 2; + if (skill_level > 11) + ret += 3; + if (skill_level > 13) + ret += 4; + if (skill_level > 15) + ret += 5; + + if (ret > MAX_COST_LIMIT) + ret = MAX_COST_LIMIT; + + return (ret); +} + +void exercise(char exsk, int deg) +{ + if (you.exp_available > 0 && you.skills[exsk] < 27) + { + while (deg > 0) + { + if (!you.practise_skill[exsk] && !one_chance_in(4)) + break; + + exercise2( exsk ); + deg--; + } + } + + return; +} // end exercise() + +static void exercise2( char exsk ) +{ + int deg = 1; + int bonus = 0; + char old_best_skill = best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99); + + int skill_change = calc_skill_cost(you.skill_cost_level, you.skills[exsk]); + int i; + + // being good at some weapons makes others easier to learn: + if (exsk < SK_SLINGS) + { + /* blades to blades */ + if ((exsk == SK_SHORT_BLADES || exsk == SK_LONG_SWORDS) + && (you.skills[SK_SHORT_BLADES] > you.skills[exsk] + || you.skills[SK_LONG_SWORDS] > you.skills[exsk])) + { + bonus += random2(3); + } + + /* Axes and Polearms */ + if ((exsk == SK_AXES || exsk == SK_POLEARMS) + && (you.skills[SK_AXES] > you.skills[exsk] + || you.skills[SK_POLEARMS] > you.skills[exsk])) + { + bonus += random2(3); + } + + /* Polearms and Staves */ + if ((exsk == SK_POLEARMS || exsk == SK_STAVES) + && (you.skills[SK_POLEARMS] > you.skills[exsk] + || you.skills[SK_STAVES] > you.skills[exsk])) + { + bonus += random2(3); + } + + /* Axes and Maces */ + if ((exsk == SK_AXES || exsk == SK_MACES_FLAILS) + && (you.skills[SK_AXES] > you.skills[exsk] + || you.skills[SK_MACES_FLAILS] > you.skills[exsk])) + { + bonus += random2(3); + } + } + + // Quick fix for the fact that stealth can't be gained fast enough to + // keep up with the monster levels, this should speed its advancement + if (exsk == SK_STEALTH) + bonus += random2(3); + + // spell casting is cheaper early on, and elementals hinder each other + if (exsk >= SK_SPELLCASTING) + { + if (you.skill_cost_level < 5) + { + skill_change /= 2; + } + else if (you.skill_cost_level < 15) + { + skill_change *= (10 + (you.skill_cost_level - 5)); + skill_change /= 20; + } + + // being good at elemental magic makes other elements harder to learn: + if (exsk >= SK_FIRE_MAGIC && exsk <= SK_EARTH_MAGIC + && (you.skills[SK_FIRE_MAGIC] > you.skills[exsk] + || you.skills[SK_ICE_MAGIC] > you.skills[exsk] + || you.skills[SK_AIR_MAGIC] > you.skills[exsk] + || you.skills[SK_EARTH_MAGIC] > you.skills[exsk])) + { + if (one_chance_in(3)) + return; + } + + // some are direct opposites + if ((exsk == SK_FIRE_MAGIC || exsk == SK_ICE_MAGIC) + && (you.skills[SK_FIRE_MAGIC] > you.skills[exsk] + || you.skills[SK_ICE_MAGIC] > you.skills[exsk])) + { + // of course, this is cumulative with the one above. + if (!one_chance_in(3)) + return; + } + + if ((exsk == SK_AIR_MAGIC || exsk == SK_EARTH_MAGIC) + && (you.skills[SK_AIR_MAGIC] > you.skills[exsk] + || you.skills[SK_EARTH_MAGIC] > you.skills[exsk])) + { + if (!one_chance_in(3)) + return; + } + + // experimental restriction (too many spell schools) -- bwr + int skill_rank = 1; + + for (i = SK_CONJURATIONS; i <= SK_DIVINATIONS; i++) + { + if (you.skills[exsk] < you.skills[i]) + skill_rank++; + } + + // Things get progressively harder, but not harder than + // the Fire-Air or Ice-Earth level. + if (skill_rank > 3 && one_chance_in(10 - skill_rank)) + return; + } + + int fraction = 0; + int spending_limit = (you.exp_available < MAX_SPENDING_LIMIT) + ? you.exp_available : MAX_SPENDING_LIMIT; + + // handle fractional learning + if (skill_change > spending_limit) + { + // This system is a bit hard on missile weapons in the late game + // since they require expendable ammo in order to practise. + // Increasing the "deg"ree of exercise would make missile + // weapons too easy earlier on, so instead we're giving them + // a special case here. + if ((exsk != SK_DARTS && exsk != SK_BOWS && exsk != SK_CROSSBOWS) + || skill_change > you.exp_available) + { + fraction = (spending_limit * 10) / skill_change; + skill_change = (skill_change * fraction) / 10; + + deg = (deg * fraction) / 10; + + if (deg == 0) + bonus = (bonus * fraction) / 10; + } + else + { + if ((skill_change / 2) > MAX_SPENDING_LIMIT) + { + deg = 0; + fraction = 5; + } + else + { + deg = 1; + } + + skill_change = spending_limit; + } + } + + skill_change -= random2(5); + + if (skill_change < 1) + { + // No free lunch, this is a problem now that we don't + // have overspending. + if (deg > 0 || fraction > 0 || bonus > 0) + skill_change = 1; + else + skill_change = 0; + } + + // Can safely return at any stage before this + int skill_inc = (deg + bonus) * 10 + fraction; + + // Starting to learn skills is easier if the appropriate stat is high + if (you.skills[exsk] == 0) + { + if ((exsk >= SK_FIGHTING && exsk <= SK_STAVES) || exsk == SK_ARMOUR) + { + // These skills are easier for the strong + skill_inc *= ((you.strength < 5) ? 5 : you.strength); + skill_inc /= 10; + } + else if (exsk >= SK_SLINGS && exsk <= SK_UNARMED_COMBAT) + { + // These skills are easier for the dexterous + // Note: Armour is handled above. + skill_inc *= ((you.dex < 5) ? 5 : you.dex); + skill_inc /= 10; + } + else if (exsk >= SK_SPELLCASTING && exsk <= SK_POISON_MAGIC) + { + // These skills are easier for the smart + skill_inc *= ((you.intel < 5) ? 5 : you.intel); + skill_inc /= 10; + } + } + + you.skill_points[exsk] += skill_inc; + you.exp_available -= skill_change; + + you.total_skill_points += skill_inc; + if (you.skill_cost_level < 27 + && you.total_skill_points >= skill_cost_needed(you.skill_cost_level + 1)) + { + you.skill_cost_level++; + } + + if (you.exp_available < 0) + you.exp_available = 0; + + you.redraw_experience = 1; + +/* + New (LH): debugging bit: when you exercise a skill, displays the skill + exercised and how much you spent on it. Too irritating to be a regular + WIZARD feature. + +#if DEBUG_DIAGNOSTICS + snprintf( info, INFO_SIZE, "Exercised %s * %d for %d xp.", + skill_name(exsk), skill_inc, skill_change ); + mpr( info, MSGCH_DIAGNOSTICS ); +#endif +*/ + + if (you.skill_points[exsk] > + (skill_exp_needed(you.skills[exsk] + 2) + * species_skills(exsk, you.species) / 100)) + { + strcpy(info, "Your "); + strcat(info, skill_name(exsk)); + strcat(info, " skill increases!"); + mpr(info, MSGCH_INTRINSIC_GAIN); + + you.skills[exsk]++; + + // Recalculate this skill's order for tie breaking skills + // at its new level. See skills2.cc::init_skill_order() + // for more details. -- bwr + you.skill_order[exsk] = 0; + for (i = SK_FIGHTING; i < NUM_SKILLS; i++) + { + if (i == exsk) + continue; + + if (you.skills[i] >= you.skills[exsk]) + you.skill_order[exsk]++; + } + + if (exsk == SK_FIGHTING) + calc_hp(); + + if (exsk == SK_INVOCATIONS || exsk == SK_EVOCATIONS + || exsk == SK_SPELLCASTING) + { + calc_mp(); + } + + if (exsk == SK_DODGING || exsk == SK_ARMOUR) + you.redraw_evasion = 1; + + if (exsk == SK_ARMOUR || exsk == SK_SHIELDS + || exsk == SK_ICE_MAGIC || exsk == SK_EARTH_MAGIC + || you.duration[ DUR_TRANSFORMATION ] > 0) + { + you.redraw_armour_class = 1; + } + + const unsigned char best = best_skill( SK_FIGHTING, + (NUM_SKILLS - 1), 99 ); + + const unsigned char best_spell = best_skill( SK_SPELLCASTING, + SK_POISON_MAGIC, 99 ); + + if ((exsk == SK_SPELLCASTING) + && (you.skills[exsk] == 1 && best_spell == SK_SPELLCASTING)) + { + mpr("You're starting to get the hang of this magic thing."); + } + + if (best != old_best_skill || old_best_skill == exsk) + { + redraw_skill( you.your_name, player_title() ); + } + } +} // end exercise2() -- cgit v1.2.3-54-g00ecf