Research:Player Craft Skills: Difference between revisions

From OpenMW Wiki
Jump to navigation Jump to search
(Fixing top level headings.)
(→‎Alchemy: Added full mechanic for potions and wortcraft.)
Line 65: Line 65:


==Alchemy==
==Alchemy==
===Potions===
{{Formula
{{Formula
|On potion creation
|On potion creation
|Uses [[Research:Magic#Magic effects|magic effect flags]].
|
|
|
|{{StatusCol|orange|Requires regression testing}}}}
|{{StatusCol|red|Fatigue is not accounted for; all alchemy GMSTs are not accounted for}}}}


'''Creating potions'''
<syntaxhighlight lang="python">
consume ingredients on both success and failure


Positive attributes:
x = pcAlchemy + 0.1 * pcIntelligence + 0.1 * pcLuck
roll 100 vs x, succeed if roll <= x
x *= mortarQuality * fPotionStrengthMult


<syntaxhighlight lang="python">
for each ingredient:
duration = [(Alchemy + [(Intelligence + Luck) / 10]) / Cost] * quality_of_the_mortar
    for each effect in ingredient:
power = duration / 3
        if effect.id == -1: continue
</syntaxhighlight>
        magicEffect = lookupEffect(effect.id)
       
        check magicEffect for match with effects in all other ingredients:
            effect.id should match
            if magicEffect.flags & TARGET_SKILL: effect.targetSkill should match
            if magicEffect.flags & TARGET_ATTR: effect.targetAttribute should match
       
        if effect is matched:
            if magicEffect is not in effectList, add it
           
if effectList is empty: return with failure


''The cost is related to basic cost of effect.''
for each magicEffect in effectList:
    if not magicEffect.flags & NO_MAGNITUDE:
        if not magicEffect.flags & NO_DURATION:
            magnitude = (x / fPotionT1MagMult) / magicEffect.baseCost
            duration = (x / fPotionT1DurMult) / magicEffect.baseCost
            if not magicEffect.flags & NEGATIVE:
                if retort and calcinator: (magnitude, duration) += 2*retort + calcinator
                if only retort: (magnitude, duration) += retort
                if only calcinator: (magnitude, duration) += calcincator
            else:
                if alembic and calcinator: (magnitude, duration) /= 2*alembic + 3*calcinator
                if only alembic: (magnitude, duration) /= 1 + alembic
                if only calcinator: (magnitude, duration) += calcinator
           
        else:
            magnitude = (x / fPotionT1MagMult) / magicEffect.baseCost
            duration = 1
            if not magicEffect.flags & NEGATIVE:
                if retort and calcinator: magnitude += 2/3 * (retort + calcinator) + 0.5
                if only retort: magnitude *= retort + 0.5
                if only calcinator: magnitude *= calcincator + 0.5
            else:
                if alembic and calcinator: magnitude /= 2*alembic + 3*calcinator
                if only alembic: magnitude /= 1 + alembic
                if only calcinator: magnitude *= calcinator + 0.5
           
    else:
        if not magicEffect.flags & NO_DURATION:
            magnitude = 1
            duration =  (x / fPotionT1DurMult) / magicEffect.baseCost
            if not magicEffect.flags & NEGATIVE:
                if retort and calcinator: duration += 2/3 * (retort + calcinator) + 0.5
                if only retort: duration *= retort + 0.5
                if only calcinator: duration *= calcincator + 0.5
            else:
                if alembic and calcinator: duration /= 2*alembic + 3*calcinator
                if only alembic: duration /= 1 + alembic
                if only calcinator: duration *= calcinator + 0.5
        else:
            magnitude = 1
            duration = 1
       
    magnitude = floor(magnitude + 0.5)
    duration = floor(duration + 0.5);
    if magnitude > 0 and duration > 0: add potionEffect(magicEffect, magnitude, duration) else nullify effect


Negative attributes:
if all effects are nullified: return with failure


* Alembic reduces the time of negative effects:
price = int(iAlchemyMod * x)
<syntaxhighlight lang="python">
weight = sum of ingredient weights / total ingredients added
duration_with_alembic = duration_without_alembic / ( 1 + quality_of_alembic)
visual = roll { 'Bargin', 'Cheap', 'Exclusive', 'Fresh', 'Quality', 'Standard' }
pick model/icon { m/misc_potion_{visual}_01.nif, m/tx_potion_{visual}_01.tga }
exercise alchemy skill (potion creation)
</syntaxhighlight>
</syntaxhighlight>


* Power of negative effects:
<syntaxhighlight lang="python">
power = duration_with_alembic / 3
</syntaxhighlight>


====Comments====


The image of a created potion is picked at random among the available.
It is notable how effective a calcinator becomes when combined with a retort or alembic. One of the few mechanics unaffected by fatigue. Each code path is slightly different; the most common (effects with magnitude and duration) acts differently enough with only a calcinator that it may be consider a bug. GMSTs fPotionMinUsefulDuration, fPotionT4BaseStrengthMult, fPotionT4EquipStrengthMult are unused.


It stays the same until one of the following things occur:


1. Change of quality or amount of any/all apparatus.
===Wortcraft===
 
{{Formula
2. Adding or removing ingredients.
|On eating a raw ingredient
 
|Uses [[Research:Magic#Magic effects|magic effect flags]]. Uses common term [[Research:Common_Terms#fatigueTerm|fatigueTerm]].
3. Any skill gain.
|
 
|{{StatusCol|green|Verified}}}}
4. Loading a save.
 
 
'''Eating ingredients'''
 
Simply eating ingredients raw will improve your alchemy skill. (Though at 1/4 the rate of mixing potions.)
 
 
Eating has a chance to apply the first effect of an ingredient onto the player.


<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
Duration = (magnitude * 2) + 1
magicEffect is the first effect of ingredient eaten
</syntaxhighlight>
x = (pcAlchemy + 0.2 * pcIntelligence + 0.1 * pcLuck) * fatigueTerm
roll 100, succeed if roll <= x


Magnitude is a random value between 1 and max_magnitude.
y = roll / min(x, 100)
y *= 0.25 * x
if not magicEffect.flags & NO_DURATION:
    duration = int(y)
else:
    duration = 1
if not magicEffect.flags & NO_MAGNITUDE:
    if not magicEffect.flags & NO_DURATION:
        magnitude = int((0.05 * y) / (0.1 * baseCost));
    else:
        magnitude = int(y / (0.1 * baseCost))
    magnitude = max(1, magnitude)
else:
    magnitude = 1


<syntaxhighlight lang="python">
apply effect(magicEffect, magnitude, duration)
Max_magnitude = floor(0.152 * Alch + 0.0158 * Luck + 0.0324 * Int)
exercise alchemy skill (ingredient use)
</syntaxhighlight>
</syntaxhighlight>
The chance to fail is based on alchemy, intelligence and luck. The exact formula is to be determined.

Revision as of 20:26, 3 September 2012

Enchanting

Actions affected On PC enchant attempt
Description
Implementation status
Analysis status Self-enchanting formula ignores fatigue and some GMSTs

Self-enchanting

for a constant effect item:

chance = Enchant + 0.125 * Intelligence + 0.25 * Luck - 5 * [enchantment points]
note: last term in above formula is solved for default GMSTs, full version is:
7.5/(fEnchantmentChanceMult*fEnchantmentConstantChanceMult) * [enchantment points]


Enchanted item recharge

Actions affected On soulgem use
Description Recharging with a filled soulgem. Uses common term fatigueTerm.
Implementation status
Analysis status Verified
luckTerm = 0.1 * luck
if luckTerm < 1 or luckTerm > 10: luckTerm = 1

intelligenceTerm = 0.2 * intelligence
if intelligenceTerm > 20: intelligenceTerm = 20
if intelligenceTerm < 1: intelligenceTerm = 1

x = (pcEnchant + intelligenceTerm + luckTerm) * fatigueTerm
roll 100, success if roll < x
on success restore charge: soulgem charge * (roll / x)


Comments

Recharging for most characters has a good chance of wasting a soul gem, as the enchant skill is the dominant term used for success. You would require enchant skill of over 65 with average stats to have a 100% success rate. The amount restored is a uniform random percentage of the soul gem, except if you have over a 100% success rate, in which case you will never get the full charge range out of a gem. The missing range increases as your skill does, but the lost charge is no more than 25% at the natural stat limit. Finally, note the strange luck term capping behaviour.


Armorer

Actions affected On using a repair item
Description
Implementation status
Analysis status Verified, but original contains bugs
fatigueTerm = fFatigueBase - fFatigueMult*(1 - normalisedFatigue)
where normalisedFatigue is a function of fatigue. empty fatigue bar -> 0.0, full fatigue bar -> 1.0

x = (0.1 * pcStrength + 0.1 * pcLuck + armorerSkill) / fatigueTerm
roll 100, if roll <= x then repair continues

y = int(fRepairAmountMult * hammerQuality * roll)
y = max(1, y)
repair item by y points


Comments

Bug in original game: Being more tired makes it easier to repair an item. The game should have multiplied by fatigueTerm instead of dividing by it.


Alchemy

Potions

Actions affected On potion creation
Description Uses magic effect flags.
Implementation status
Analysis status Requires regression testing
consume ingredients on both success and failure

x = pcAlchemy + 0.1 * pcIntelligence + 0.1 * pcLuck
roll 100 vs x, succeed if roll <= x
x *= mortarQuality * fPotionStrengthMult

for each ingredient:
    for each effect in ingredient:
        if effect.id == -1: continue
        magicEffect = lookupEffect(effect.id)
        
        check magicEffect for match with effects in all other ingredients:
            effect.id should match
            if magicEffect.flags & TARGET_SKILL: effect.targetSkill should match
            if magicEffect.flags & TARGET_ATTR: effect.targetAttribute should match
        
        if effect is matched:
            if magicEffect is not in effectList, add it
            
if effectList is empty: return with failure

for each magicEffect in effectList:
    if not magicEffect.flags & NO_MAGNITUDE:
        if not magicEffect.flags & NO_DURATION:
            magnitude = (x / fPotionT1MagMult) / magicEffect.baseCost
            duration = (x / fPotionT1DurMult) / magicEffect.baseCost
            if not magicEffect.flags & NEGATIVE:
                if retort and calcinator: (magnitude, duration) += 2*retort + calcinator
                if only retort: (magnitude, duration) += retort
                if only calcinator: (magnitude, duration) += calcincator
            else:
                if alembic and calcinator: (magnitude, duration) /= 2*alembic + 3*calcinator
                if only alembic: (magnitude, duration) /= 1 + alembic
                if only calcinator: (magnitude, duration) += calcinator
            
        else:
            magnitude = (x / fPotionT1MagMult) / magicEffect.baseCost
            duration = 1
            if not magicEffect.flags & NEGATIVE:
                if retort and calcinator: magnitude += 2/3 * (retort + calcinator) + 0.5
                if only retort: magnitude *= retort + 0.5
                if only calcinator: magnitude *= calcincator + 0.5
            else:
                if alembic and calcinator: magnitude /= 2*alembic + 3*calcinator
                if only alembic: magnitude /= 1 + alembic
                if only calcinator: magnitude *= calcinator + 0.5
            
    else:
        if not magicEffect.flags & NO_DURATION:
            magnitude = 1
            duration =  (x / fPotionT1DurMult) / magicEffect.baseCost
            if not magicEffect.flags & NEGATIVE:
                if retort and calcinator: duration += 2/3 * (retort + calcinator) + 0.5
                if only retort: duration *= retort + 0.5
                if only calcinator: duration *= calcincator + 0.5
            else:
                if alembic and calcinator: duration /= 2*alembic + 3*calcinator
                if only alembic: duration /= 1 + alembic
                if only calcinator: duration *= calcinator + 0.5
        else:
            magnitude = 1
            duration = 1
        
    magnitude = floor(magnitude + 0.5)
    duration = floor(duration + 0.5);
    if magnitude > 0 and duration > 0: add potionEffect(magicEffect, magnitude, duration) else nullify effect

if all effects are nullified: return with failure

price = int(iAlchemyMod * x)
weight = sum of ingredient weights / total ingredients added
visual = roll { 'Bargin', 'Cheap', 'Exclusive', 'Fresh', 'Quality', 'Standard' }
pick model/icon { m/misc_potion_{visual}_01.nif, m/tx_potion_{visual}_01.tga }
exercise alchemy skill (potion creation)


Comments

It is notable how effective a calcinator becomes when combined with a retort or alembic. One of the few mechanics unaffected by fatigue. Each code path is slightly different; the most common (effects with magnitude and duration) acts differently enough with only a calcinator that it may be consider a bug. GMSTs fPotionMinUsefulDuration, fPotionT4BaseStrengthMult, fPotionT4EquipStrengthMult are unused.


Wortcraft

Actions affected On eating a raw ingredient
Description Uses magic effect flags. Uses common term fatigueTerm.
Implementation status
Analysis status Verified
magicEffect is the first effect of ingredient eaten
x = (pcAlchemy + 0.2 * pcIntelligence + 0.1 * pcLuck) * fatigueTerm
roll 100, succeed if roll <= x

y = roll / min(x, 100)
y *= 0.25 * x
if not magicEffect.flags & NO_DURATION:
    duration = int(y)
else:
    duration = 1
if not magicEffect.flags & NO_MAGNITUDE:
    if not magicEffect.flags & NO_DURATION:
        magnitude = int((0.05 * y) / (0.1 * baseCost));
    else:
        magnitude = int(y / (0.1 * baseCost))
    magnitude = max(1, magnitude)
else:
    magnitude = 1

apply effect(magicEffect, magnitude, duration)
exercise alchemy skill (ingredient use)