Research:Security and Crime
Security
Actions affected | On lockpicking and probing |
Description | Affects doors and containers. |
Implementation status | Implemented |
Analysis status | Verified |
On picking a lock
x = 0.2 * pcAgility + 0.1 * pcLuck + securitySkill
x *= pickQuality * fatigueTerm
x += fPickLockMult * lockStrength
if x <= 0: fail and report impossible
roll 100, if roll <= x then open lock else report failure
On probing a trap
x = 0.2 * pcAgility + 0.1 * pcLuck + securitySkill
x += fTrapCostMult * trapSpellPoints
x *= probeQuality * fatigueTerm
if x <= 0: fail and report impossible
roll 100, if roll <= x then untrap else report failure
Pickpocketing
Actions affected | On pickpocket (activate while sneaking) |
Description | |
Implementation status | Implemented |
Analysis status | Mechanic is broken and shouldn't be used as it is, but verified |
Pickpocketing is a multi-stage process. Not all items in the NPC's inventory are available, depending on the initial rolls. There are checks on a steal attempt, and when the window is closed.
On initiating
for each item stack:
roll 100, stack is visible if roll <= pcSneak
On picking an item
fatigueTerm = fFatigueBase - fFatigueMult*(1 - normalisedFatigue)
#where normalisedFatigue is a function of fatigue. empty fatigue bar -> 0.0, full fatigue bar -> 1.0
#note fatigueTerm is normally 1.25 at full fatigue.
#checks the whole stack no matter how many you try to take
#note: filled soulgems have the value of an empty soulgem due to a missing calculation
stackValue = itemValue * itemsInStack
valueTerm = 10 * fPickPocketMod * stackValue
x = (0.2 * pcAgility + 0.1 * pcLuck + pcSneak) * fatigueTerm
y = (valueTerm + npcSneak + 0.2 * npcAgilityTerm + 0.1 * npcLuckTerm) * npcFatigueTerm
t = x - y + x # yes, that is what it does
if t < pcSneak / iPickMinChance:
roll 100, win if roll <= int(pcSneak / iPickMinChance)
else:
t = min(iPickMaxChance, t)
roll 100, win if roll <= int(t)
On closing the pickpocket window
Same calculation as taking an item, but with valueTerm = 0.
Comments
The stealing process is highly broken for most items; any item or stack of items worth over 100 septims has such a negative result that it is picked at minimum chance, and this is at maximum all stats. A player with stats around 50 is picking at minimum for anything valuable. The available items window is not reset after every successful steal, only when you close the window and retry the pickpocket.
Bounties and Reporting
Bounties
Actions affected | On being observed committing crimes |
Description | |
Implementation status | Implemented |
Analysis status | Being researched |
killing: iCrimeKilling
assault: iCrimeAttack
pickpocket: iCrimePickpocket
trespass: iCrimeTrespass
theft: fCrimeStealing * stack value
werewolf transformation: iWerewolfBounty
Trespass includes activating, picking, and using Open magic on an owned door. Normal faction ownership rules apply.
NPC reactions
Actions affected | On being observed committing crimes |
Description | |
Implementation status | |
Analysis status | Being researched |
for each observer in the cell: # NPCs only, range unknown
alarmTerm = 0.01 * observer.alarm
if crime is killing:
fightTerm, dispTerm = iFightKilling, iDispKilling
if crime is assault, observed:
fightTerm, dispTerm = iFightAttack, fDispAttacking
if crime is assault, victim:
fightTerm, dispTerm = iFightAttacking, iDispAttackMod
if crime is theft:
fightTerm, dispTerm = fFightStealing * stack value, fDispStealing * stack value
if crime is pickpocket, observed:
fightTerm, dispTerm = iFightPickpocket, fDispPickpocketMod
if crime is pickpocket, victim:
fightTerm, dispTerm = 4 * iFightPickpocket, fDispPickpocketMod
if alarmTerm > 0: alarmTerm = 1.0
if crime is trespass:
fightTerm, dispTerm = iFightTrespass, iDispTrespass
if observer is not victim or observer.isGuard:
dispTerm *= alarmTerm
fightTerm += fFightDispMult * (50 - dispTerm)
x = iFightDistanceBase - fFightDistanceMultiplier * distance(player, observer)
fightTerm = alarmTerm * (fightTerm + x)
if observer.fight + fightTerm > 100:
fightTerm = 100 - observer.fight
fightTerm = max(0, fightTerm)
observer.fight += int(fightTerm)
observer.disposition += int(dispTerm)
- lots more crime system stuff occurs here -
if (observer.alarm < 100 or not observer.isGuard) and observer.fight < 100:
observer.fight is reset to the original value
if observer is not victim: observer.disposition is reset to the original value
Guard reactions
Actions affected | Checked by "Guard" class NPCs every 1.0 seconds |
Description | |
Implementation status | Implemented |
Analysis status | Being researched |
if bounty >= iCrimeThreshold:
if bounty >= iCrimeThreshold * iCrimeThresholdMultiplier:
guards will immediately initiate combat and cannot be engaged in dialogue
else:
guards in range will run to the player and initiate dialogue
Comments
Note that the crime level that prompts the "death warrant" dialogue from the guards (5000 gold) is coded through dialogue conditions, not here.
Thieves Guild reductions
Actions affected | On initiating any dialogue |
Description | |
Implementation status | Implemented |
Analysis status | Verified |
Interacts with dialogue through global script variables, which are set every time the player enters dialogue with an NPC.
CrimeGoldDiscount
if bounty == 0: CrimeGoldDiscount = 0
else: CrimeGoldDiscount = max(1, fCrimeGoldDiscountMult * bounty)
CrimeGoldTurnIn
if bounty == 0: CrimeGoldTurnIn = 0
else: CrimeGoldTurnIn = max(1, fCrimeGoldTurnInMult * bounty)
PCHasCrimeGold
PCHasCrimeGold = 1 if player can afford bounty (before any discount), 0 if not
PCHasGoldDiscount
PCHasGoldDiscount = 1 if player can afford bounty (with thief discount), 0 if not
PCHasTurnIn
PCHasTurnIn = 1 if player can afford bounty (with turn-in discount), 0 if not
Prison
Prison time is proportional to the bounty. Skills can be lost during time spent in prison, except Security which can improve.