summaryrefslogtreecommitdiffstats
path: root/trunk/source/skills.cc
diff options
context:
space:
mode:
authorpeterb12 <peterb12@c06c8d41-db1a-0410-9941-cceddc491573>2005-07-21 02:34:44 +0000
committerpeterb12 <peterb12@c06c8d41-db1a-0410-9941-cceddc491573>2005-07-21 02:34:44 +0000
commit673bdae75485d14f759af597c3c62b99601f9a43 (patch)
tree368103f29fe0ce5dcf98060d9b5faa04590085fb /trunk/source/skills.cc
parent7e900be770db24b0405fd2162491c405a425873e (diff)
downloadcrawl-ref-673bdae75485d14f759af597c3c62b99601f9a43.tar.gz
crawl-ref-673bdae75485d14f759af597c3c62b99601f9a43.zip
Initial revision
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'trunk/source/skills.cc')
-rw-r--r--trunk/source/skills.cc438
1 files changed, 438 insertions, 0 deletions
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 <string.h>
+#include <stdlib.h>
+
+#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()