Research:Trading and Services: Difference between revisions
Jump to navigation
Jump to search
(→Trading and services: Improved a few descriptions.) |
(→Trading and services: Updated spellmaking and enchanting.) |
||
Line 127: | Line 127: | ||
y = 0 | y = 0 | ||
for each effect in spell: | for each effect in spell: | ||
x = 0.5 * (effect.magnitudeMin + effect.magnitudeMax) | x = 0.5 * (max(1, effect.magnitudeMin) + max(1, effect.magnitudeMax)) | ||
x *= 0.1 * effect.magicEffect.baseMagickaCost | x *= 0.1 * effect.magicEffect.baseMagickaCost | ||
x *= 1 + effect.duration | x *= 1 + effect.duration | ||
Line 144: | Line 144: | ||
|On purchasing an enchantment | |On purchasing an enchantment | ||
| | | | ||
|{{StatusCol| | |{{StatusCol|orange|Changes since last implementation}} | ||
|{{StatusCol|orange| | |{{StatusCol|orange|Requires verification}}}} | ||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
cost of enchanting service = barterOffer(npc, | y = 0 | ||
enchantPoints = 0 | |||
for each effect in spell: | |||
x = 0.5 * (max(1, effect.magnitudeMin) + max(1, effect.magnitudeMax)) | |||
x *= 0.1 * effect.magicEffect.baseMagickaCost | |||
x *= effect.duration # note difference from spellmaking | |||
x += 0.05 * max(1, spell.radius) * effect.magicEffect.baseMagickaCost | |||
y += x * fEffectCostMult | |||
y = max(1, y) | |||
if effect.rangeType & CAST_TARGET: y *= 1.5 | |||
enchantPoints += int(y) | |||
# note enchantPoints not used for cost | |||
cost of enchanting service = barterOffer(npc, y * fEnchantmentValueMult, buying) | |||
</syntaxhighlight> | </syntaxhighlight> | ||
====Comments==== | |||
Multiple enchantments stack in a expensive manner, as both variables y and enchantPoints are accumulators. Strangely, the cost is based on the equivalent to the spellmaking accumulator rather than the enchantment points used. | |||
===Travel costs=== | ===Travel costs=== |
Revision as of 19:57, 8 January 2015
Trading and services
Common mechanics
Barter function
All bartering and services use a common function to evaluate costs. Uses common formula fatigueTerm for each side of a transaction.
defining a function barterOffer :: (Actor npc, int basePrice, bool buyingSelling) -> int offerPrice
if npc is a creature: return basePrice
clampedDisposition = clamp int(npcDisposition) to [0..100]
a = min(pcMercantile, 100)
b = min(0.1 * pcLuck, 10)
c = min(0.2 * pcPersonality, 10)
d = min(npcMercantile, 100)
e = min(0.1 * npcLuck, 10)
f = min(0.2 * npcPersonality, 10)
pcTerm = (clampedDisposition - 50 + a + b + c) * pcFatigueTerm
npcTerm = (d + e + f) * npcFatigueTerm
buyTerm = 0.01 * (100 - 0.5 * (pcTerm - npcTerm))
sellTerm = 0.01 * (50 - 0.5 * (npcTerm - pcTerm))
if buying: x = buyTerm
if selling: x = min(buyTerm, sellTerm)
if x < 1: offerPrice = int(x * basePrice)
if x >= 1: offerPrice = basePrice + int((x - 1) * basePrice)
offerPrice = max(1, offerPrice)
Bartering
Actions affected | On choosing/offering an item to buy/sell |
Description | Determining item/stack base prices and adjusted prices. |
Implementation status | Implemented |
Analysis status | Verified |
basePrice = price of prototype item of the same kind, enchanted items have prices set at enchant time and saved with the object
stackSize = number of items in selected stack
if item is a weapon or armor: x = basePrice * (remainingDurability / maxDurability)
if item is lockpick, probe or repair hammer: x = basePrice * (remainingUses / maxUses)
if item is a filled soul gem: basePrice = soul points contained * empty soul gem price
otherwise: x = basePrice
if buying: merchant offer is adjusted by -barterOffer(merchant, x * stackSize, buying)
if selling: merchant offer is adjusted by +barterOffer(merchant, x * stackSize, selling)
Actions affected | On finalizing a transaction. |
Description | Includes haggling mechanic. Uses common formula fatigueTerm. |
Implementation status | Implemented |
Analysis status | Verified |
all prices are negative when player is buying, positive when player is selling
accept if playerOffer <= merchantOffer (same for buy and sell)
if npc is a creature: reject (no haggle)
a = abs(merchantOffer)
b = abs(playerOffer)
if buying: d = int(100 * (a - b) / a)
if selling: d = int(100 * (b - a) / a)
clampedDisposition = clamp int(npcDisposition) to [0..100]
dispositionTerm = fDispositionMod * (clampedDisposition - 50)
pcTerm = (dispositionTerm + pcMercantile + 0.1 * pcLuck + 0.2 * pcPersonality) * pcFatigueTerm
npcTerm = (npcMercantile + 0.1 * npcLuck + 0.2 * npcPersonality) * npcFatigueTerm
x = fBargainOfferMulti * d + fBargainOfferBase
if buying: x += abs(int(pcTerm - npcTerm))
if selling: x += abs(int(npcTerm - pcTerm))
roll 100, if roll <= x then trade is accepted
adjust npc temporary disposition by iBarterSuccessDisposition or iBarterFailDisposition
Merchant repair
Actions affected | On opening the repair service window |
Description | |
Implementation status | Implemented |
Analysis status | Verified |
p = max(1, basePrice)
r = max(1, int(maxDurability / p))
x = int((maxDurability - durability) / r)
x = int(fRepairMult * x)
cost = barterOffer(npc, x, buying)
Trainers
Actions affected | On purchasing training |
Description | |
Implementation status | Implemented |
Analysis status | Verified, but buggy. See notes for solution. |
cost of training a skill = barterOffer(npc, pcSkill * iTrainingMod, buying)
Standard Morrowind uses the current skill value, including fortifies and drains, which allows cheap training exploits with drain spells. A new implementation should use the skill's base value.
Spell merchant
Actions affected | On purchasing a spell |
Description | |
Implementation status | Implemented |
Analysis status | Verified |
cost of purchasing existing spell = barterOffer(npc, spell.magickaCost * fSpellValueMult, buying)
Actions affected | On purchasing from a spellmaking service |
Description | |
Implementation status | Implemented |
Analysis status | Needs testing |
y = 0
for each effect in spell:
x = 0.5 * (max(1, effect.magnitudeMin) + max(1, effect.magnitudeMax))
x *= 0.1 * effect.magicEffect.baseMagickaCost
x *= 1 + effect.duration
x += 0.05 * max(1, spell.radius) * effect.magicEffect.baseMagickaCost
y += x * fEffectCostMult
y = max(1, y)
if effect.rangeType & CAST_TARGET: y *= 1.5
magickaCost = int(y)
cost of spellmaking = barterOffer(npc, magickaCost * fSpellMakingValueMult, buying)
Enchanting merchant
Actions affected | On purchasing an enchantment |
Description | |
Implementation status | Changes since last implementation |
Analysis status | Requires verification |
y = 0
enchantPoints = 0
for each effect in spell:
x = 0.5 * (max(1, effect.magnitudeMin) + max(1, effect.magnitudeMax))
x *= 0.1 * effect.magicEffect.baseMagickaCost
x *= effect.duration # note difference from spellmaking
x += 0.05 * max(1, spell.radius) * effect.magicEffect.baseMagickaCost
y += x * fEffectCostMult
y = max(1, y)
if effect.rangeType & CAST_TARGET: y *= 1.5
enchantPoints += int(y)
# note enchantPoints not used for cost
cost of enchanting service = barterOffer(npc, y * fEnchantmentValueMult, buying)
Comments
Multiple enchantments stack in a expensive manner, as both variables y and enchantPoints are accumulators. Strangely, the cost is based on the equivalent to the spellmaking accumulator rather than the enchantment points used.
Travel costs
Physical travel
Actions affected | On travelling via silt strider, boat or similar travel service AI |
Description | |
Implementation status | Implemented |
Analysis status | Requires independent testing |
dist = distance from player to destination
cost = barterOffer(npc, int(dist / fTravelMult), buying)
time = int(dist / fTravelTimeMult)
Guild guide
Actions affected | On travelling via Mages' Guild teleport service |
Description | |
Implementation status | Implemented |
Analysis status | Verified |
cost = barterOffer(npc, fMagesGuildTravel, buying)