Morrowind: Alchemy, the most overpowered skill

Balancing a game with many skills is often a difficult undertaking. Developers try to prevent a skill from being too powerful by including limits to the ways where you can boost a skill or they might make leveling a powerful skill a hard or grindy task. Playtesters will try the play the game and see where the limits lie. They can help with finding the the ways in which the game is unbalanced. In Morrowind, the alchemy skill is the one skill where the balancing has simply failed as the skill to way to powerful. In this article I will explain the many reasons why Alchemy is very overpowered.

First the leveling. In Morrowind you have two ways of leveling your skills. You can either practice your skill by doing something that boosts your skill, alternatively you can buy training to level up your skill points by one. In case you didn’t know how leveling works, the principle is very easy. On level n you need n points to level up your skill. So at level 5, you need 5 points to level up your skill. At level 24, you need 24 points to level up your skill. So what gives points in alchemy? Creating a potion succesfully gives 2 points. Eating an ingredient gives you 0.5 points. At level five you would need to make 3(=2.5 rounded up) potions succesfully or you could eat 5/0.5=10 ingredients. Fortunately, the cheapest ingredients cost 1 gold so you can level up from level 5 to 6 for a grand total of 10 gold. Eating your way to lvl 100 would cost you about 5000 gold. Still sounds a bit expensive, right? Don’t worry, it gets better.

Let’s look at making potions to increase level and also try to recoup the ingredient losses. Let’s work with a batch of 100 potential potion creations with 100 Crab Meat and 100 Small Kwama Eggs, both costing 1 gold each. This batch will cost 200 gold in total. Hopefully we can make enough potions to recoup some of these losses. What are the chances of making a potion?
SuccessChance = (Alchemy + (Intelligence / 5) + (Luck / 10)) * (0.75 + 0.5 * CurrentFatigue / MaximumFatigue). For simplicity’s sake, consider bad Intelligence and Luck at 30 and a full fatigue bar. This reduces the the formula to
SuccessChance = (Alchemy + 9) * (1.25). At level 5 we would have a 17.5% chance. At level 30 we would have a 48.75% chance. Sounds a bit low right? Let’s do the math. How much is a potion worth anyway?
BasePotionValue = (Alchemy + (Intelligence / 10) + (Luck / 10)) * MortarQuality. Using an Apprentice’s Mortar and Pestle at MortarQuality 0.5 we get the following value:
BasePotionValue = (Alchemy + 6) * 0.5. At level 5, this means a potion is worth 5 gold. At level 30, the same potion is worth 18 gold. Let’s put all this data into a table to give a better overview of the Crab Meat and Kwama Egg batch example:

LevelExpenseIncomeResult
520087.5-112.5
10200190-10
15200330130
20200471.25271.25
Alchemy profits

How did this happen? How is it possible to turn a profit at level 15 of a skill? The answer is very simple, when your skill goes up both your chance of making a potion and the price of the potion goes up. As the price of the potion has nothing to do with the price of the ingredients it always pays financially to use the cheapest ingredients as it does not affect the price of the potions. Who can we sell the potions to? All alchemists, pawnbrokers and general salesmen. This means that a lot of Mages Guild members are now your own personal piggy bank. You can train your skills basically for free at anyone who accepts your potions as many ingredient sellers replenish their ingredients after you buy them.

You might be already convinced of the fact that Alchemy is overpowered. But we’re not done yet. How powerful are these potions anyway. Let’s look at a ‘Restore Fatigue’ potion made from Crab Meat and Kwama Egg. An expensive “Exclusive Restore Fatigue” potion restores 80 points of fatigue for 5 seconds. This sounds great, but we can compare this with our own fatigue potions.
BasePotionStrength = (Alchemy + (Intelligence / 10) + (Luck / 10)) * MortarQuality / (3 * EffectBaseCost). With Intelligence and Luck at 30,MortarQuality at 0.5 and Restore Fatigue BaseCost at 1.0 this can be reduced to BasePotionStrength = (Alchemy + 6) / (6). At level 30 this means a restore of 6 fatigue per second. How long does the potion last? BasePotionDuration = BasePotionStrength * 3. A potion of strength 6 lasts 18 seconds! This is quite good. With a journeyman’s Mortar and Pestle, you get 12 fatigue restored for 36 seconds! This is so much more useful than the regular potions you can buy at the shops or find in caves.

Ok, so the potions you can make are not only financially a good idea, they are also way better than store-bought potions. We’re done now, right? No, one last thing. Remember that everything regarding Alchemy is partially dependent on Intelligence? This dependence is what turns Alchemy from an overpowered skill into a broken skill. Why? Because all these calculations are not based on the base Intelligence but on the modified Intelligence you have. What is the difference? The base Intelligence is the Intelligence you have based on your Attributes. The modified Intelligence is the base Intelligence with all modifications like damaged Intelligence or Intelligence boosts. This can be exploited by creating ‘Fortify Intelligence’ potions, consuming these potions, and then do Alchemy again. This creates cycle of potions getting better and better, while your Intelligence gets higher and higher. This trick can easily be used to get Intelligence in the thousands. You can use this Intelligence to create ultimate boost potions, super powered spells and 100% enchant chance.

Alchemy is overpowered? Yes it is.

Morrowind: Why leveling weapons is hard at low skill level

A lot of players here are veterans of the game and have played the game dozens or hundreds of hours. In their playthroughs they have encountered many aspects of the game, amongst which is the leveling system. Perhaps players have tried to manually train skills from the lowest level (5) to the highest level (100) by actually using the skills instead of buying it from a trainer. In this post I’m trying to explain why leveling weapon skills can be difficult when you are at both low and high skill levels using mathematics.

First things first, how do skills level? Every hit of the enemy gives you one progress point towards your next level. How many progress points do you need to increase your skill level? ProgresPointsRequired = (1 + SkillLevel)*SkillGroupBonus*SpecializationBonus. Basically, every level you need ‘level+1’ progress points or in this case hits. What are the SkillGroupBonus and the SpecializationBonus? The SkillGroupBonus is whether the Skill is Major, Minor or Miscellaneous. Major corresponds to SkillGroupBonus 0.75, Minor to 1.0 and Miscellaneous to 1.25. Basically, major skills level 25% faster and misc skills level 25%(actually 20%) slower. The SpecializationBonus means that you have chosen the skill group as a specialization (out of Combat, Magic and Stealth) and is 0.8 if the skill is in the right group and 1.0 otherwise. This also gives a 5 point bonus to all skills in the group.

Since the skill we are trying to level starts at 5, we know it is both misc and not in the specialization group. This gives us the following formula. ProgresPointsRequired = 1.25*(1 + SkillLevel). This means that at skill level 5, we need 1.25*(1+5)=7.5(=7 rounded down) hits to advance to the next level will at skill level 99 we need 125 hits to connect. In total, we would need 6294 hits to level from 5 to level 100 with each level become 1.25 points/hits harder.

It looks like we’re done now, right? The problem is, we’ve forgotten to add in the hit chance, which makes leveling from lower skill levels an issue. How does hit chance work in Morrowind. It’s quite a simple idea as the hit chance is (Attacker's Hit Rate - Defender's Evasion)%. How are both stats calculated? With the following formulas: HitRate = (Weapon Skill + (Agility / 5) + (Luck / 10)) * (0.75 + 0.5 * Current Fatigue / Maximum Fatigue) + Fortify Attack Magnitude + Blind Magnitude and EvasionRate = ((Agility / 5) + (Luck / 10)) * (0.75 + 0.5 * Current Fatigue / Maximum Fatigue) + Sanctuary Magnitude. Let’s assume no special situations(Fortify Attack, Blind and Sanctuary are 0). We get the reduced HitRate = (Weapon Skill + (Agility / 5) + (Luck / 10)) * (0.75 + 0.5 * Current Fatigue / Maximum Fatigue) and EvasionRate = ((Agility / 5) + (Luck / 10)) * (0.75 + 0.5 * Current Fatigue / Maximum Fatigue). Let’s assume that both the player and the enemy NPC are about evenly matched and at full fatigue, we can get an actual hit chance HitChance = 1.25*(SkillLevel)/100%. This is a bit of a simplification as the player will later on be a lot more powerful and have much higher stats than a random enemy NPC but this will suffice for this explanation. We can see that at low skill levels, the chance to hit is often abysmal (e.g 6.25% at level 5). We now deduce the number of strikes on average to produce a hit. Using the expected value, we get StrikesRequiredForOneHit=1/HitChance=100/1.25*SkillLevel. Combining this into the final formula we get StrikesRequiredForOneLevel=(100/1.25*SkillLevel)*1.25(1+SkillLevel) which reduces to StrikesRequiredForOneLevel= 100 + (100/SkillLevel).

This implies what we may have noticed ourselves when playing, leveling a weapons skill actually becomes easier when we are at a high level since we miss less too. Note that after level 80, since you are guaranteed to hit, HitsRequired simply becomes ProgressPointsRequired again and leveling becomes harder as the player becomes more skillful.

Morrowind: Analysing the Dark Brotherhood attacks

The Tribunal expansion of Morrowind has an interesting way of starting. Lots of game expansions offer a new place you can explore. You can usually visit these places by talking to a random NPC with an updated conversation tree or by talking to specific NPCs who are able to take you to the new place.

By contrast, Tribunal throws you into the expansion content by throwing assassins at you! How does this mechanic work? In this article I will explain the finer details of this mission and I will also address misconceptions that still float around.

Let’s consider the “journal” for this mission.

IndexFinishes QuestJournal Entry(TR_DBAttack)
10An attempt was made on my life as I tried to rest. I do not know who wishes me dead, but the attack should probably be reported to a guard.
20One of the assassins had an odd dart on his body, the look of which I’ve never seen before.
30A guard has told me that my attackers were likely members of the Dark Brotherhood, and that I have been targeted for assassination. He suggests I speak with Apelles Matius in Ebonheart for more information.
40Apparently, the Dark Brotherhood does not have a large base of operations here on Vvardenfell, but has a very large contingent in Mournhold. Due to the Blight, no residents are allowed to travel to the capital city, and all visits are made only by the special order of Duke Dren.
50I’ve been told to speak to Asciene Rane in the Grand Council Chambers about transport to Mournhold.
60Asciene Rane has agreed to transport me to Mournhold. If I wish to return to the mainland, I should speak to Effe-Tei, an Argonian Mage in the Royal Palace. When I arrive, I should speak with one of the Royal Guard for more information about the Dark Brotherhood.
100☑I’ve been told that the Dark Brotherhood is rumored to have a base in the ruins of Old Mournhold, accessible through the sewer system in the Great Bazaar. I’ve been warned that I enter there at my own peril.

As you can see, the mission starts when you are attacked by an assassin. To complete the mission you need to do the following:

  • Talk to a guard
  • Talk to Apelles Matius
  • Talk to Asciene Rane
  • Talk to a Royal Guard

Talking to a (generic) Royal Guardsman and talking about the topic of the Dark Brotherhood attack ends the mission. This will also end the Dark Brotherhood attacks. But how does the attack mechanic work? Let’s look at the (big) relevant script in question “dbAttackScript”.

Begin dbattackScript

float dbchance
short journalOnce
short attackOnce
short playerLevel
short attackmod
short othermod
short dbnumber
short temp
short sleepOnce

if ( GetJournalIndex TR_dbAttack >= 50 )
	return
endif

if ( player->GetLevel >= 30 )
	set playerLevel to 5
else
	if ( player->GetLevel >=20 )
		set playerLevel to 4
	else
		if ( player->GetLevel >= 10 )
			set playerLevel to 3
		else
			if ( player->GetLevel >=4 )
				set playerLevel to 2
			else
				set playerLevel to 1
			endif
		endif
	endif
endif

if ( GetPCCell "Seyda Neen, Census and Excise Office" == 1 )
	return
endif

if ( journalOnce == 1 )
	;Journal TR_DBAttack 10
	set journalOnce to -1
endif

if ( GetPCSleep == 1 )
	if ( sleepOnce == 1 )
		return
	endif
	set sleepOnce to 1
	set dbchance to Random 100
	set attackmod to ( attackonce * 10 )
	if ( playerlevel == 5 )
		set othermod to ( 90- attackmod )
		if ( dbchance <= othermod )
			WakeUpPC
			MessageBox "You are awakened by a loud noise."
			set dbnumber to ( dbnumber + 1 )
			if ( dbnumber > 2 )
				set dbnumber to 2
			endif
			set temp to dbnumber
			while ( temp != 0 )
				PlaceAtPC "db_assassin4" 1 128 1
				set temp to ( temp - 1 )
			endwhile
			set attackonce to ( attackonce + 1 )
				if ( journalOnce == -1 )
					return
				endif
				set journalOnce to 1
				set DBAttack to 1
		endif
	else
		if ( playerLevel == 4 )
			set othermod to ( 70 - attackmod )
			if ( dbchance <= othermod )
				WakeUpPC
				MessageBox "You are awakened by a loud noise."
				set dbnumber to ( dbnumber + 1 )
				if ( dbnumber > 2 )
					set dbnumber to 2
				endif
				set temp to dbnumber
				while ( temp != 0 )
					PlaceAtPC "db_assassin3" 1 128 1
					set temp to ( temp - 1 )
				endwhile
				set attackonce to ( attackonce + 1 )
					if ( journalOnce == -1 )
						return
					endif
					set journalOnce to 1
					set DBAttack to 1
			endif
		else
			if ( playerLevel == 3 )
				set othermod to ( 50 - attackmod )
				if ( dbchance <= othermod )
					WakeUpPC
					MessageBox "You are awakened by a loud noise."
					PlaceAtPC "db_assassin2" 1 128 1
					set attackonce to ( attackonce + 1 )
						if ( journalOnce == -1 )
							return
						endif
						set journalOnce to 1
						set DBAttack to 1
				endif
			else
				if ( playerLevel == 2 )
					set othermod to ( 40 - attackmod )
					if ( dbchance <= othermod )
						WakeUpPC
						MessageBox "You are awakened by a loud noise."
						PlaceAtPC "db_assassin1" 1 128 1
						set attackonce to ( attackonce + 1 )
							if ( journalOnce == -1 )
								return
							endif
							set journalOnce to 1
							set DBAttack to 1
					endif
				else
					if ( playerLevel == 1 )
						set othermod to ( 20 - attackmod )
						if ( dbchance <= othermod )
							WakeUpPC
							MessageBox "You are awakened by a loud noise."
							PlaceAtPC "db_assassin1b" 1 128 1
							set attackonce to ( attackonce + 1 )
								if ( journalOnce == -1 )
									return
								endif
								set journalOnce to 1
								set DBAttack to 1
						endif
					endif
				endif	
			endif
		endif
	endif
else
	set sleepOnce to 0
endif



End

That’s a lot to take in all at once! Let’s analyze the code blocks one by one.

Begin dbattackScript

float dbchance
short journalOnce
short attackOnce
short playerLevel
short attackmod
short othermod
short dbnumber
short temp
short sleepOnce

if ( GetJournalIndex TR_dbAttack >= 50 )
	return
endif

We see a large amount of defined variables, some ending with “Once”. This is the way of the Bethesda-team to define booleans or “counters” as the scripting language used is quite limited.
playerLevel seems evident but isn’t, other variables aren’t clear yet from this context. The first “active” code checks if the journal has state 50 or greater. This corresponds to the conversation with Apelles Matius. In that case, the script stops.

if ( player->GetLevel >= 30 )
	set playerLevel to 5
else
	if ( player->GetLevel >=20 )
		set playerLevel to 4
	else
		if ( player->GetLevel >= 10 )
			set playerLevel to 3
		else
			if ( player->GetLevel >=4 )
				set playerLevel to 2
			else
				set playerLevel to 1
			endif
		endif
	endif
endif

So the playerLevel is an estimation of the power of player, capping at lvl 30+ players. The minimum playerLevel is designated to be ‘1’.

if ( GetPCCell "Seyda Neen, Census and Excise Office" == 1 )
	return
endif

if ( journalOnce == 1 )
	;Journal TR_DBAttack 10
	set journalOnce to -1
endif

The script stops if we are in the Seyda Neen Census and Excise Office, the “tutorial building” of Morrowind.
If the journalOnce is equal to 1, we set it to -1.

if ( GetPCSleep == 1 )
	if ( sleepOnce == 1 )
		return
	endif
	set sleepOnce to 1
	set dbchance to Random 100
	set attackmod to ( attackonce * 10 )
[cut code]
else
	set sleepOnce to 0
endif

This code looks a bit weird but it is one of the effects of the weird Morrowind scripting engine. The DB attack script is a “global script” which means it is run many times per second. The check for GetPCSleep checks if the player is asleep. If he is, we change the sleepOnce in such a way that the inner block is validated only once per player sleep. Now, the code gets interesting. The dbchange is a random number from 0-100. attackmod is set to be 10 times attackonce. Since we haven’t updated attackonce, we can assume it to be 0.
We get 5 somewhat equal blocks of code depending on the “strength” of the player. I will discuss the highest player level as it seems the most complex.

if ( playerlevel == 5 )
		set othermod to ( 90- attackmod )
		if ( dbchance <= othermod )
			WakeUpPC
			MessageBox "You are awakened by a loud noise."
			set dbnumber to ( dbnumber + 1 )
			if ( dbnumber > 2 )
				set dbnumber to 2
			endif
			set temp to dbnumber
			while ( temp != 0 )
				PlaceAtPC "db_assassin4" 1 128 1
				set temp to ( temp - 1 )
			endwhile
			set attackonce to ( attackonce + 1 )
				if ( journalOnce == -1 )
					return
				endif
				set journalOnce to 1
				set DBAttack to 1
		endif

The variable othermode is defined as 90 - attackmod. We know that attackmod is 10 times attackOnce. If the random dbchance is smaller than or equal to othermode, the assassin attack happens. dbnumber is increased by 1 with a maximum value of 2. Then, dbnumber of assassins are spawned of “quality” db_assassin4. This means that you will be attacked by one assassin the first time and two every time after that when level 30+. Then attackOnce is increased by one. This means that every attack decreases the othermod by 10. After 9 attacks on this playerLevel, the attack mechanism will not trigger! Afterwards, journalOnce is set to 1/true and DBAttack as well. Other playerLevel values have a lower othermod, weaker assassins and limit the amount of attackers to 1.

Which conclusions can we draw from this analysis?

  • Talking to Appeles Matius about the attacks stops the attacks
  • You will not be attacked in the Census Office
  • Being a higher level means you will be attacked by higher level assassins
  • Being a high enough level will spawn more assassins after the first attempt
  • The assassin attacks dry up after while on their own

This addresses some misconceptions that are held about the attacks. You can be attacked while being any level (though this is changed on the Xbox version). Talking to Appeles Matius is enough although some believe you need to travel to Mournhold. The attacks will end when “enough” assassins have been sent your way.