added inventory, updated DB

This commit is contained in:
erik 2025-06-10 19:21:21 +00:00
parent f218350959
commit 10c51f6825
16528 changed files with 147743 additions and 79 deletions

View file

@ -15,7 +15,8 @@ RUN python -m pip install --upgrade pip && \
databases[postgresql] \
sqlalchemy \
alembic \
psycopg2-binary
psycopg2-binary \
httpx
## Copy application source code and migration scripts into container
COPY static/ /app/static/

View file

@ -13,6 +13,7 @@ services:
- "./main.py:/app/main.py"
- "./db_async.py:/app/db_async.py"
- "./static:/app/static"
- "./icons:/app/icons"
- "./alembic:/app/alembic"
- "./alembic.ini:/app/alembic.ini"
environment:
@ -56,6 +57,49 @@ services:
options:
max-size: "10m"
max-file: "3"
# Inventory Service: Separate microservice for item data processing
inventory-service:
build: ./inventory-service
ports:
- "127.0.0.1:8766:8000"
depends_on:
- inventory-db
volumes:
- "./inventory-service:/app"
environment:
DATABASE_URL: "postgresql://inventory_user:${INVENTORY_DB_PASSWORD}@inventory-db:5432/inventory_db"
LOG_LEVEL: "${LOG_LEVEL:-INFO}"
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Separate database for inventory service
inventory-db:
image: postgres:14
container_name: inventory-db
environment:
POSTGRES_DB: inventory_db
POSTGRES_USER: inventory_user
POSTGRES_PASSWORD: "${INVENTORY_DB_PASSWORD}"
volumes:
- inventory-data:/var/lib/postgresql/data
ports:
- "5433:5432"
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U inventory_user"]
interval: 30s
timeout: 5s
retries: 5
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Grafana service for visualization and dashboards
grafana:
image: grafana/grafana:latest
@ -91,3 +135,4 @@ services:
volumes:
timescale-data:
inventory-data:

View file

@ -0,0 +1,22 @@
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements first for better caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Create non-root user
RUN useradd -m -u 1000 inventory && chown -R inventory:inventory /app
USER inventory
# Default command
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,179 @@
"""
Database models and setup for Inventory Service.
Normalized schema designed around actual item JSON structure with proper enum translation.
"""
import sqlalchemy as sa
from sqlalchemy import (
Column, Integer, String, Float, Boolean, DateTime, BigInteger, Text, JSON,
ForeignKey, Index, UniqueConstraint, CheckConstraint, create_engine, MetaData
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import relationship
from datetime import datetime
Base = declarative_base()
class Item(Base):
"""Core item identification and basic properties."""
__tablename__ = 'items'
id = Column(Integer, primary_key=True)
character_name = Column(String(50), nullable=False, index=True)
item_id = Column(BigInteger, nullable=False) # Game item instance ID
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow)
# Basic properties (always present)
name = Column(String(200), nullable=False, index=True)
icon = Column(Integer, nullable=False)
object_class = Column(Integer, nullable=False, index=True)
# Core stats
value = Column(Integer, default=0)
burden = Column(Integer, default=0)
# Metadata flags
has_id_data = Column(Boolean, default=False)
last_id_time = Column(BigInteger, default=0)
# Unique constraint per character
__table_args__ = (
UniqueConstraint('character_name', 'item_id', name='uq_char_item'),
Index('ix_items_name_char', 'character_name', 'name'),
Index('ix_items_class_char', 'character_name', 'object_class'),
)
class ItemCombatStats(Base):
"""Combat-related properties for weapons and armor."""
__tablename__ = 'item_combat_stats'
item_id = Column(Integer, ForeignKey('items.id'), primary_key=True)
# Damage properties
max_damage = Column(Integer)
damage = Column(Integer)
damage_type = Column(Integer)
damage_bonus = Column(Float)
elemental_damage_bonus = Column(Integer)
elemental_damage_vs_monsters = Column(Float)
variance = Column(Float)
# Attack properties
attack_bonus = Column(Float)
weapon_time = Column(Integer)
weapon_skill = Column(Integer)
# Defense properties
armor_level = Column(Integer, index=True)
shield_value = Column(Integer)
melee_defense_bonus = Column(Float)
missile_defense_bonus = Column(Float)
magic_defense_bonus = Column(Float)
# Resistances
resist_magic = Column(Integer)
# Mana properties
mana_conversion_bonus = Column(Float)
class ItemRequirements(Base):
"""Wield requirements and skill prerequisites."""
__tablename__ = 'item_requirements'
item_id = Column(Integer, ForeignKey('items.id'), primary_key=True)
wield_level = Column(Integer, index=True)
wield_requirement = Column(Integer)
skill_level = Column(Integer)
lore_requirement = Column(Integer)
# String-based requirements (parsed from StringValues)
equip_skill = Column(String(50))
mastery = Column(String(50))
class ItemEnhancements(Base):
"""Enhancements, materials, and modifications."""
__tablename__ = 'item_enhancements'
item_id = Column(Integer, ForeignKey('items.id'), primary_key=True)
material = Column(String(50), index=True)
imbue = Column(String(50))
tinks = Column(Integer)
workmanship = Column(Float)
salvage_workmanship = Column(Float)
# Set information
item_set = Column(String(100), index=True)
class ItemRatings(Base):
"""Modern rating system properties."""
__tablename__ = 'item_ratings'
item_id = Column(Integer, ForeignKey('items.id'), primary_key=True)
# Damage ratings
damage_rating = Column(Integer)
damage_resist_rating = Column(Integer)
crit_rating = Column(Integer)
crit_resist_rating = Column(Integer)
crit_damage_rating = Column(Integer)
crit_damage_resist_rating = Column(Integer)
# Utility ratings
heal_boost_rating = Column(Integer)
vitality_rating = Column(Integer)
mana_conversion_rating = Column(Integer)
# Calculated totals
total_rating = Column(Integer)
class ItemSpells(Base):
"""Spell information for items."""
__tablename__ = 'item_spells'
item_id = Column(Integer, ForeignKey('items.id'), primary_key=True)
spell_id = Column(Integer, primary_key=True)
is_active = Column(Boolean, default=False)
class ItemRawData(Base):
"""Preserve original raw enum data for completeness."""
__tablename__ = 'item_raw_data'
item_id = Column(Integer, ForeignKey('items.id'), primary_key=True)
# Raw enum collections
int_values = Column(JSONB)
double_values = Column(JSONB)
string_values = Column(JSONB)
bool_values = Column(JSONB)
# Original full JSON for reference
original_json = Column(JSONB)
# Database URL configuration
import os
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://inventory_user:inventory_pass@inventory-db:5432/inventory_db")
# Create all indexes for performance
def create_indexes(engine):
"""Create additional performance indexes."""
# Item search indexes
sa.Index('ix_items_search', Item.character_name, Item.name, Item.object_class).create(engine, checkfirst=True)
# Combat stats indexes for filtering
sa.Index('ix_combat_damage', ItemCombatStats.max_damage).create(engine, checkfirst=True)
sa.Index('ix_combat_armor', ItemCombatStats.armor_level).create(engine, checkfirst=True)
# Requirements indexes for filtering
sa.Index('ix_req_level', ItemRequirements.wield_level).create(engine, checkfirst=True)
# Enhancement indexes
sa.Index('ix_enh_material_set', ItemEnhancements.material, ItemEnhancements.item_set).create(engine, checkfirst=True)
# JSONB indexes for raw data querying
sa.Index('ix_raw_int_gin', ItemRawData.int_values, postgresql_using='gin').create(engine, checkfirst=True)
sa.Index('ix_raw_original_gin', ItemRawData.original_json, postgresql_using='gin').create(engine, checkfirst=True)

View file

@ -0,0 +1,147 @@
{
"BoolValueKey": {
"type": "int",
"values": {
"0": "Undef",
"1": "Stuck",
"2": "Open",
"3": "Locked",
"4": "RotProof",
"5": "AllegianceUpdateRequest",
"6": "AiUsesMana",
"7": "AiUseHumanMagicAnimations",
"8": "AllowGive",
"9": "CurrentlyAttacking",
"10": "AttackerAi",
"11": "IgnoreCollisions",
"12": "ReportCollisions",
"13": "Ethereal",
"14": "GravityStatus",
"15": "LightsStatus",
"16": "ScriptedCollision",
"17": "Inelastic",
"18": "Visibility",
"19": "Attackable",
"20": "SafeSpellComponents",
"21": "AdvocateState",
"22": "Inscribable",
"23": "DestroyOnSell",
"24": "UiHidden",
"25": "IgnoreHouseBarriers",
"26": "HiddenAdmin",
"27": "PkWounder",
"28": "PkKiller",
"29": "NoCorpse",
"30": "UnderLifestoneProtection",
"31": "ItemManaUpdatePending",
"32": "GeneratorStatus",
"33": "ResetMessagePending",
"34": "DefaultOpen",
"35": "DefaultLocked",
"36": "DefaultOn",
"37": "OpenForBusiness",
"38": "IsFrozen",
"39": "DealMagicalItems",
"40": "LogoffImDead",
"41": "ReportCollisionsAsEnvironment",
"42": "AllowEdgeSlide",
"43": "AdvocateQuest",
"44": "IsAdmin",
"45": "IsArch",
"46": "IsSentinel",
"47": "IsAdvocate",
"48": "CurrentlyPoweringUp",
"49": "GeneratorEnteredWorld",
"50": "NeverFailCasting",
"51": "VendorService",
"52": "AiImmobile",
"53": "DamagedByCollisions",
"54": "IsDynamic",
"55": "IsHot",
"56": "IsAffecting",
"57": "AffectsAis",
"58": "SpellQueueActive",
"59": "GeneratorDisabled",
"60": "IsAcceptingTells",
"61": "LoggingChannel",
"62": "OpensAnyLock",
"63": "UnlimitedUse",
"64": "GeneratedTreasureItem",
"65": "IgnoreMagicResist",
"66": "IgnoreMagicArmor",
"67": "AiAllowTrade",
"68": "SpellComponentsRequired",
"69": "IsSellable",
"70": "IgnoreShieldsBySkill",
"71": "NoDraw",
"72": "ActivationUntargeted",
"73": "HouseHasGottenPriorityBootPos",
"74": "GeneratorAutomaticDestruction",
"75": "HouseHooksVisible",
"76": "HouseRequiresMonarch",
"77": "HouseHooksEnabled",
"78": "HouseNotifiedHudOfHookCount",
"79": "AiAcceptEverything",
"80": "IgnorePortalRestrictions",
"81": "RequiresBackpackSlot",
"82": "DontTurnOrMoveWhenGiving",
"83": "NpcLooksLikeObject",
"84": "IgnoreCloIcons",
"85": "AppraisalHasAllowedWielder",
"86": "ChestRegenOnClose",
"87": "LogoffInMinigame",
"88": "PortalShowDestination",
"89": "PortalIgnoresPkAttackTimer",
"90": "NpcInteractsSilently",
"91": "Retained",
"92": "IgnoreAuthor",
"93": "Limbo",
"94": "AppraisalHasAllowedActivator",
"95": "ExistedBeforeAllegianceXpChanges",
"96": "IsDeaf",
"97": "IsPsr",
"98": "Invincible",
"99": "Ivoryable",
"100": "Dyable",
"101": "CanGenerateRare",
"102": "CorpseGeneratedRare",
"103": "NonProjectileMagicImmune",
"104": "ActdReceivedItems",
"105": "Unknown105",
"106": "FirstEnterWorldDone",
"107": "RecallsDisabled",
"108": "RareUsesTimer",
"109": "ActdPreorderReceivedItems",
"110": "Afk",
"111": "IsGagged",
"112": "ProcSpellSelfTargeted",
"113": "IsAllegianceGagged",
"114": "EquipmentSetTriggerPiece",
"115": "Uninscribe",
"116": "WieldOnUse",
"117": "ChestClearedWhenClosed",
"118": "NeverAttack",
"119": "SuppressGenerateEffect",
"120": "TreasureCorpse",
"121": "EquipmentSetAddLevel",
"122": "BarberActive",
"123": "TopLayerPriority",
"124": "NoHeldItemShown",
"125": "LoginAtLifestone",
"126": "OlthoiPk",
"127": "Account15Days",
"128": "HadNoVitae",
"129": "NoOlthoiTalk",
"130": "AutowieldLeft",
"9001": "LinkedPortalOneSummon",
"9002": "LinkedPortalTwoSummon",
"9003": "HouseEvicted",
"9004": "UntrainedSkills",
"201326592": "Lockable_Decal",
"201326593": "Inscribable_Decal"
},
"comments": {},
"attributes": {},
"source_file": "BoolValueKey.cs"
}
}

View file

@ -0,0 +1,33 @@
{
"CoverageMask": {
"type": "int",
"values": {
"0": "None",
"1": "Unknown",
"2": "UnderwearUpperLegs",
"4": "UnderwearLowerLegs",
"8": "UnderwearChest",
"16": "UnderwearAbdomen",
"32": "UnderwearUpperArms",
"64": "UnderwearLowerArms",
"256": "OuterwearUpperLegs",
"512": "OuterwearLowerLegs",
"1024": "OuterwearChest",
"2048": "OuterwearAbdomen",
"4096": "OuterwearUpperArms",
"8192": "OuterwearLowerArms",
"16384": "Head",
"32768": "Hands",
"65536": "Feet",
"131072": "Cloak"
},
"comments": {
"Unknown": "Original pants abdomen?",
"UnderwearUpperLegs": "I think... 0x13 = Abdomen/UpperLegs",
"UnderwearLowerLegs": "I think... 0x16 = Abdomen/UpperLegs/LowerLegs",
"UnderwearAbdomen": "Original shirt abdomen?"
},
"attributes": {},
"source_file": "CoverageMask.cs"
}
}

View file

@ -0,0 +1,207 @@
{
"DoubleValueKey": {
"type": "int",
"values": {
"0": "Undef",
"1": "HeartbeatInterval",
"2": "HeartbeatTimestamp",
"3": "HealthRate",
"4": "StaminaRate",
"5": "ManaRate",
"6": "HealthUponResurrection",
"7": "StaminaUponResurrection",
"8": "ManaUponResurrection",
"9": "StartTime",
"10": "StopTime",
"11": "ResetInterval",
"12": "Shade",
"13": "ArmorModVsSlash",
"14": "ArmorModVsPierce",
"15": "ArmorModVsBludgeon",
"16": "ArmorModVsCold",
"17": "ArmorModVsFire",
"18": "ArmorModVsAcid",
"19": "ArmorModVsElectric",
"20": "CombatSpeed",
"21": "WeaponLength",
"22": "DamageVariance",
"23": "CurrentPowerMod",
"24": "AccuracyMod",
"25": "StrengthMod",
"26": "MaximumVelocity",
"27": "RotationSpeed",
"28": "MotionTimestamp",
"29": "WeaponDefense",
"30": "WimpyLevel",
"31": "VisualAwarenessRange",
"32": "AuralAwarenessRange",
"33": "PerceptionLevel",
"34": "PowerupTime",
"35": "MaxChargeDistance",
"36": "ChargeSpeed",
"37": "BuyPrice",
"38": "SellPrice",
"39": "DefaultScale",
"40": "LockpickMod",
"41": "RegenerationInterval",
"42": "RegenerationTimestamp",
"43": "GeneratorRadius",
"44": "TimeToRot",
"45": "DeathTimestamp",
"46": "PkTimestamp",
"47": "VictimTimestamp",
"48": "LoginTimestamp",
"49": "CreationTimestamp",
"50": "MinimumTimeSincePk",
"51": "DeprecatedHousekeepingPriority",
"52": "AbuseLoggingTimestamp",
"53": "LastPortalTeleportTimestamp",
"54": "UseRadius",
"55": "HomeRadius",
"56": "ReleasedTimestamp",
"57": "MinHomeRadius",
"58": "Facing",
"59": "ResetTimestamp",
"60": "LogoffTimestamp",
"61": "EconRecoveryInterval",
"62": "WeaponOffense",
"63": "DamageMod",
"64": "ResistSlash",
"65": "ResistPierce",
"66": "ResistBludgeon",
"67": "ResistFire",
"68": "ResistCold",
"69": "ResistAcid",
"70": "ResistElectric",
"71": "ResistHealthBoost",
"72": "ResistStaminaDrain",
"73": "ResistStaminaBoost",
"74": "ResistManaDrain",
"75": "ResistManaBoost",
"76": "Translucency",
"77": "PhysicsScriptIntensity",
"78": "Friction",
"79": "Elasticity",
"80": "AiUseMagicDelay",
"81": "ItemMinSpellcraftMod",
"82": "ItemMaxSpellcraftMod",
"83": "ItemRankProbability",
"84": "Shade2",
"85": "Shade3",
"86": "Shade4",
"87": "ItemEfficiency",
"88": "ItemManaUpdateTimestamp",
"89": "SpellGestureSpeedMod",
"90": "SpellStanceSpeedMod",
"91": "AllegianceAppraisalTimestamp",
"92": "PowerLevel",
"93": "AccuracyLevel",
"94": "AttackAngle",
"95": "AttackTimestamp",
"96": "CheckpointTimestamp",
"97": "SoldTimestamp",
"98": "UseTimestamp",
"99": "UseLockTimestamp",
"100": "HealkitMod",
"101": "FrozenTimestamp",
"102": "HealthRateMod",
"103": "AllegianceSwearTimestamp",
"104": "ObviousRadarRange",
"105": "HotspotCycleTime",
"106": "HotspotCycleTimeVariance",
"107": "SpamTimestamp",
"108": "SpamRate",
"109": "BondWieldedTreasure",
"110": "BulkMod",
"111": "SizeMod",
"112": "GagTimestamp",
"113": "GeneratorUpdateTimestamp",
"114": "DeathSpamTimestamp",
"115": "DeathSpamRate",
"116": "WildAttackProbability",
"117": "FocusedProbability",
"118": "CrashAndTurnProbability",
"119": "CrashAndTurnRadius",
"120": "CrashAndTurnBias",
"121": "GeneratorInitialDelay",
"122": "AiAcquireHealth",
"123": "AiAcquireStamina",
"124": "AiAcquireMana",
"125": "ResistHealthDrain",
"126": "LifestoneProtectionTimestamp",
"127": "AiCounteractEnchantment",
"128": "AiDispelEnchantment",
"129": "TradeTimestamp",
"130": "AiTargetedDetectionRadius",
"131": "EmotePriority",
"132": "LastTeleportStartTimestamp",
"133": "EventSpamTimestamp",
"134": "EventSpamRate",
"135": "InventoryOffset",
"136": "CriticalMultiplier",
"137": "ManaStoneDestroyChance",
"138": "SlayerDamageBonus",
"139": "AllegianceInfoSpamTimestamp",
"140": "AllegianceInfoSpamRate",
"141": "NextSpellcastTimestamp",
"142": "AppraisalRequestedTimestamp",
"143": "AppraisalHeartbeatDueTimestamp",
"144": "ManaConversionMod",
"145": "LastPkAttackTimestamp",
"146": "FellowshipUpdateTimestamp",
"147": "CriticalFrequency",
"148": "LimboStartTimestamp",
"149": "WeaponMissileDefense",
"150": "WeaponMagicDefense",
"151": "IgnoreShield",
"152": "ElementalDamageMod",
"153": "StartMissileAttackTimestamp",
"154": "LastRareUsedTimestamp",
"155": "IgnoreArmor",
"156": "ProcSpellRate",
"157": "ResistanceModifier",
"158": "AllegianceGagTimestamp",
"159": "AbsorbMagicDamage",
"160": "CachedMaxAbsorbMagicDamage",
"161": "GagDuration",
"162": "AllegianceGagDuration",
"163": "GlobalXpMod",
"164": "HealingModifier",
"165": "ArmorModVsNether",
"166": "ResistNether",
"167": "CooldownDuration",
"168": "WeaponAuraOffense",
"169": "WeaponAuraDefense",
"170": "WeaponAuraElemental",
"171": "WeaponAuraManaConv",
"8004": "PCAPRecordedWorkmanship",
"8010": "PCAPRecordedVelocityX",
"8011": "PCAPRecordedVelocityY",
"8012": "PCAPRecordedVelocityZ",
"8013": "PCAPRecordedAccelerationX",
"8014": "PCAPRecordedAccelerationY",
"8015": "PCAPRecordedAccelerationZ",
"8016": "PCAPRecordeOmegaX",
"8017": "PCAPRecordeOmegaY",
"8018": "PCAPRecordeOmegaZ",
"167772160": "SlashProt_Decal",
"167772161": "PierceProt_Decal",
"167772162": "BludgeonProt_Decal",
"167772163": "AcidProt_Decal",
"167772164": "LightningProt_Decal",
"167772165": "FireProt_Decal",
"167772166": "ColdProt_Decal",
"167772167": "Heading_Decal",
"167772168": "ApproachDistance_Decal",
"167772169": "SalvageWorkmanship_Decal",
"167772170": "Scale_Decal",
"167772171": "Variance_Decal",
"167772172": "AttackBonus_Decal",
"167772173": "Range_Decal",
"167772174": "DamageBonus_Decal"
},
"comments": {},
"attributes": {},
"source_file": "DoubleValueKey.cs"
}
}

View file

@ -0,0 +1,60 @@
{
"EquipMask": {
"type": "uint",
"values": {
"0": "None",
"1": "HeadWear",
"2": "ChestWear",
"4": "AbdomenWear",
"8": "UpperArmWear",
"16": "LowerArmWear",
"32": "HandWear",
"64": "UpperLegWear",
"128": "LowerLegWear",
"256": "FootWear",
"512": "ChestArmor",
"1024": "AbdomenArmor",
"2048": "UpperArmArmor",
"4096": "LowerArmArmor",
"8192": "UpperLegArmor",
"16384": "LowerLegArmor",
"32768": "NeckWear",
"65536": "WristWearLeft",
"131072": "WristWearRight",
"262144": "FingerWearLeft",
"524288": "FingerWearRight",
"1048576": "MeleeWeapon",
"2097152": "Shield",
"4194304": "MissileWeapon",
"8388608": "MissileAmmo",
"16777216": "Held",
"33554432": "TwoHanded",
"67108864": "TrinketOne",
"134217728": "Cloak",
"268435456": "SigilOne",
"536870912": "SigilTwo",
"1073741824": "SigilThree",
"EXPR:0x80000000 | HeadWear | ChestWear | AbdomenWear | UpperArmWear | LowerArmWear | HandWear | UpperLegWear | LowerLegWear | FootWear": "Clothing",
"EXPR:ChestArmor | AbdomenArmor | UpperArmArmor | LowerArmArmor | UpperLegArmor | LowerLegArmor | FootWear": "Armor",
"EXPR:ChestArmor | AbdomenArmor | UpperArmArmor | LowerArmArmor | UpperLegArmor | LowerLegArmor": "ArmorExclusive",
"EXPR:HeadWear | HandWear | FootWear": "Extremity",
"EXPR:NeckWear | WristWearLeft | WristWearRight | FingerWearLeft | FingerWearRight | TrinketOne | Cloak | SigilOne | SigilTwo | SigilThree": "Jewelry",
"EXPR:WristWearLeft | WristWearRight": "WristWear",
"EXPR:FingerWearLeft | FingerWearRight": "FingerWear",
"EXPR:SigilOne | SigilTwo | SigilThree": "Sigil",
"EXPR:Held | TwoHanded | TrinketOne | Cloak | SigilOne | SigilTwo": "ReadySlot",
"EXPR:SigilTwo | TrinketOne | Held": "Weapon",
"EXPR:SigilOne | SigilTwo | TrinketOne | Held": "WeaponReadySlot",
"EXPR:MeleeWeapon | Shield | MissileWeapon | Held | TwoHanded": "Selectable",
"EXPR:Selectable | MissileAmmo": "SelectablePlusAmmo",
"2147483647": "CanGoInReadySlot"
},
"comments": {
"SigilOne": "Blue",
"SigilTwo": "Yellow",
"SigilThree": "Red"
},
"attributes": {},
"source_file": "EquipMask.cs"
}
}

View file

@ -0,0 +1,463 @@
{
"IntValueKey": {
"type": "int",
"values": {
"0": "Undef",
"1": "ItemType",
"2": "CreatureType",
"3": "PaletteTemplate",
"4": "ClothingPriority",
"5": "EncumbranceVal",
"6": "ItemsCapacity",
"7": "ContainersCapacity",
"8": "Mass",
"9": "ValidLocations",
"10": "CurrentWieldedLocation",
"11": "MaxStackSize",
"12": "StackSize",
"13": "StackUnitEncumbrance",
"14": "StackUnitMass",
"15": "StackUnitValue",
"16": "ItemUseable",
"17": "RareId",
"18": "UiEffects",
"19": "Value",
"20": "CoinValue",
"21": "TotalExperience",
"22": "AvailableCharacter",
"23": "TotalSkillCredits",
"24": "AvailableSkillCredits",
"25": "Level",
"26": "AccountRequirements",
"27": "ArmorType",
"28": "ArmorLevel",
"29": "AllegianceCpPool",
"30": "AllegianceRank",
"31": "ChannelsAllowed",
"32": "ChannelsActive",
"33": "Bonded",
"34": "MonarchsRank",
"35": "AllegianceFollowers",
"36": "ResistMagic",
"37": "ResistItemAppraisal",
"38": "ResistLockpick",
"39": "DeprecatedResistRepair",
"40": "CombatMode",
"41": "CurrentAttackHeight",
"42": "CombatCollisions",
"43": "NumDeaths",
"44": "Damage",
"45": "DamageType",
"46": "DefaultCombatStyle",
"47": "AttackType",
"48": "WeaponSkill",
"49": "WeaponTime",
"50": "AmmoType",
"51": "CombatUse",
"52": "ParentLocation",
"53": "PlacementPosition",
"54": "WeaponEncumbrance",
"55": "WeaponMass",
"56": "ShieldValue",
"57": "ShieldEncumbrance",
"58": "MissileInventoryLocation",
"59": "FullDamageType",
"60": "WeaponRange",
"61": "AttackersSkill",
"62": "DefendersSkill",
"63": "AttackersSkillValue",
"64": "AttackersClass",
"65": "Placement",
"66": "CheckpointStatus",
"67": "Tolerance",
"68": "TargetingTactic",
"69": "CombatTactic",
"70": "HomesickTargetingTactic",
"71": "NumFollowFailures",
"72": "FriendType",
"73": "FoeType",
"74": "MerchandiseItemTypes",
"75": "MerchandiseMinValue",
"76": "MerchandiseMaxValue",
"77": "NumItemsSold",
"78": "NumItemsBought",
"79": "MoneyIncome",
"80": "MoneyOutflow",
"81": "MaxGeneratedObjects",
"82": "InitGeneratedObjects",
"83": "ActivationResponse",
"84": "OriginalValue",
"85": "NumMoveFailures",
"86": "MinLevel",
"87": "MaxLevel",
"88": "LockpickMod",
"89": "BoosterEnum",
"90": "BoostValue",
"91": "MaxStructure",
"92": "Structure",
"93": "PhysicsState",
"94": "TargetType",
"95": "RadarBlipColor",
"96": "EncumbranceCapacity",
"97": "LoginTimestamp",
"98": "CreationTimestamp",
"99": "PkLevelModifier",
"100": "GeneratorType",
"101": "AiAllowedCombatStyle",
"102": "LogoffTimestamp",
"103": "GeneratorDestructionType",
"104": "ActivationCreateClass",
"105": "ItemWorkmanship",
"106": "ItemSpellcraft",
"107": "ItemCurMana",
"108": "ItemMaxMana",
"109": "ItemDifficulty",
"110": "ItemAllegianceRankLimit",
"111": "PortalBitmask",
"112": "AdvocateLevel",
"113": "Gender",
"114": "Attuned",
"115": "ItemSkillLevelLimit",
"116": "GateLogic",
"117": "ItemManaCost",
"118": "Logoff",
"119": "Active",
"120": "AttackHeight",
"121": "NumAttackFailures",
"122": "AiCpThreshold",
"123": "AiAdvancementStrategy",
"124": "Version",
"125": "Age",
"126": "VendorHappyMean",
"127": "VendorHappyVariance",
"128": "CloakStatus",
"129": "VitaeCpPool",
"130": "NumServicesSold",
"131": "MaterialType",
"132": "NumAllegianceBreaks",
"133": "ShowableOnRadar",
"134": "PlayerKillerStatus",
"135": "VendorHappyMaxItems",
"136": "ScorePageNum",
"137": "ScoreConfigNum",
"138": "ScoreNumScores",
"139": "DeathLevel",
"140": "AiOptions",
"141": "OpenToEveryone",
"142": "GeneratorTimeType",
"143": "GeneratorStartTime",
"144": "GeneratorEndTime",
"145": "GeneratorEndDestructionType",
"146": "XpOverride",
"147": "NumCrashAndTurns",
"148": "ComponentWarningThreshold",
"149": "HouseStatus",
"150": "HookPlacement",
"151": "HookType",
"152": "HookItemType",
"153": "AiPpThreshold",
"154": "GeneratorVersion",
"155": "HouseType",
"156": "PickupEmoteOffset",
"157": "WeenieIteration",
"158": "WieldRequirements",
"159": "WieldSkillType",
"160": "WieldDifficulty",
"161": "HouseMaxHooksUsable",
"162": "HouseCurrentHooksUsable",
"163": "AllegianceMinLevel",
"164": "AllegianceMaxLevel",
"165": "HouseRelinkHookCount",
"166": "SlayerCreatureType",
"167": "ConfirmationInProgress",
"168": "ConfirmationTypeInProgress",
"169": "TsysMutationData",
"170": "NumItemsInMaterial",
"171": "NumTimesTinkered",
"172": "AppraisalLongDescDecoration",
"173": "AppraisalLockpickSuccessPercent",
"174": "AppraisalPages",
"175": "AppraisalMaxPages",
"176": "AppraisalItemSkill",
"177": "GemCount",
"178": "GemType",
"179": "ImbuedEffect",
"180": "AttackersRawSkillValue",
"181": "ChessRank",
"182": "ChessTotalGames",
"183": "ChessGamesWon",
"184": "ChessGamesLost",
"185": "TypeOfAlteration",
"186": "SkillToBeAltered",
"187": "SkillAlterationCount",
"188": "HeritageGroup",
"189": "TransferFromAttribute",
"190": "TransferToAttribute",
"191": "AttributeTransferCount",
"192": "FakeFishingSkill",
"193": "NumKeys",
"194": "DeathTimestamp",
"195": "PkTimestamp",
"196": "VictimTimestamp",
"197": "HookGroup",
"198": "AllegianceSwearTimestamp",
"199": "HousePurchaseTimestamp",
"200": "RedirectableEquippedArmorCount",
"201": "MeleeDefenseImbuedEffectTypeCache",
"202": "MissileDefenseImbuedEffectTypeCache",
"203": "MagicDefenseImbuedEffectTypeCache",
"204": "ElementalDamageBonus",
"205": "ImbueAttempts",
"206": "ImbueSuccesses",
"207": "CreatureKills",
"208": "PlayerKillsPk",
"209": "PlayerKillsPkl",
"210": "RaresTierOne",
"211": "RaresTierTwo",
"212": "RaresTierThree",
"213": "RaresTierFour",
"214": "RaresTierFive",
"215": "AugmentationStat",
"216": "AugmentationFamilyStat",
"217": "AugmentationInnateFamily",
"218": "AugmentationInnateStrength",
"219": "AugmentationInnateEndurance",
"220": "AugmentationInnateCoordination",
"221": "AugmentationInnateQuickness",
"222": "AugmentationInnateFocus",
"223": "AugmentationInnateSelf",
"224": "AugmentationSpecializeSalvaging",
"225": "AugmentationSpecializeItemTinkering",
"226": "AugmentationSpecializeArmorTinkering",
"227": "AugmentationSpecializeMagicItemTinkering",
"228": "AugmentationSpecializeWeaponTinkering",
"229": "AugmentationExtraPackSlot",
"230": "AugmentationIncreasedCarryingCapacity",
"231": "AugmentationLessDeathItemLoss",
"232": "AugmentationSpellsRemainPastDeath",
"233": "AugmentationCriticalDefense",
"234": "AugmentationBonusXp",
"235": "AugmentationBonusSalvage",
"236": "AugmentationBonusImbueChance",
"237": "AugmentationFasterRegen",
"238": "AugmentationIncreasedSpellDuration",
"239": "AugmentationResistanceFamily",
"240": "AugmentationResistanceSlash",
"241": "AugmentationResistancePierce",
"242": "AugmentationResistanceBlunt",
"243": "AugmentationResistanceAcid",
"244": "AugmentationResistanceFire",
"245": "AugmentationResistanceFrost",
"246": "AugmentationResistanceLightning",
"247": "RaresTierOneLogin",
"248": "RaresTierTwoLogin",
"249": "RaresTierThreeLogin",
"250": "RaresTierFourLogin",
"251": "RaresTierFiveLogin",
"252": "RaresLoginTimestamp",
"253": "RaresTierSix",
"254": "RaresTierSeven",
"255": "RaresTierSixLogin",
"256": "RaresTierSevenLogin",
"257": "ItemAttributeLimit",
"258": "ItemAttributeLevelLimit",
"259": "ItemAttribute2ndLimit",
"260": "ItemAttribute2ndLevelLimit",
"261": "CharacterTitleId",
"262": "NumCharacterTitles",
"263": "ResistanceModifierType",
"264": "FreeTinkersBitfield",
"265": "EquipmentSetId",
"266": "PetClass",
"267": "Lifespan",
"268": "RemainingLifespan",
"269": "UseCreateQuantity",
"270": "WieldRequirements2",
"271": "WieldSkillType2",
"272": "WieldDifficulty2",
"273": "WieldRequirements3",
"274": "WieldSkillType3",
"275": "WieldDifficulty3",
"276": "WieldRequirements4",
"277": "WieldSkillType4",
"278": "WieldDifficulty4",
"279": "Unique",
"280": "SharedCooldown",
"281": "Faction1Bits",
"282": "Faction2Bits",
"283": "Faction3Bits",
"284": "Hatred1Bits",
"285": "Hatred2Bits",
"286": "Hatred3Bits",
"287": "SocietyRankCelhan",
"288": "SocietyRankEldweb",
"289": "SocietyRankRadblo",
"290": "HearLocalSignals",
"291": "HearLocalSignalsRadius",
"292": "Cleaving",
"293": "AugmentationSpecializeGearcraft",
"294": "AugmentationInfusedCreatureMagic",
"295": "AugmentationInfusedItemMagic",
"296": "AugmentationInfusedLifeMagic",
"297": "AugmentationInfusedWarMagic",
"298": "AugmentationCriticalExpertise",
"299": "AugmentationCriticalPower",
"300": "AugmentationSkilledMelee",
"301": "AugmentationSkilledMissile",
"302": "AugmentationSkilledMagic",
"303": "ImbuedEffect2",
"304": "ImbuedEffect3",
"305": "ImbuedEffect4",
"306": "ImbuedEffect5",
"307": "DamageRating",
"308": "DamageResistRating",
"309": "AugmentationDamageBonus",
"310": "AugmentationDamageReduction",
"311": "ImbueStackingBits",
"312": "HealOverTime",
"313": "CritRating",
"314": "CritDamageRating",
"315": "CritResistRating",
"316": "CritDamageResistRating",
"317": "HealingResistRating",
"318": "DamageOverTime",
"319": "ItemMaxLevel",
"320": "ItemXpStyle",
"321": "EquipmentSetExtra",
"322": "AetheriaBitfield",
"323": "HealingBoostRating",
"324": "HeritageSpecificArmor",
"325": "AlternateRacialSkills",
"326": "AugmentationJackOfAllTrades",
"327": "AugmentationResistanceNether",
"328": "AugmentationInfusedVoidMagic",
"329": "WeaknessRating",
"330": "NetherOverTime",
"331": "NetherResistRating",
"332": "LuminanceAward",
"333": "LumAugDamageRating",
"334": "LumAugDamageReductionRating",
"335": "LumAugCritDamageRating",
"336": "LumAugCritReductionRating",
"337": "LumAugSurgeEffectRating",
"338": "LumAugSurgeChanceRating",
"339": "LumAugItemManaUsage",
"340": "LumAugItemManaGain",
"341": "LumAugVitality",
"342": "LumAugHealingRating",
"343": "LumAugSkilledCraft",
"344": "LumAugSkilledSpec",
"345": "LumAugNoDestroyCraft",
"346": "RestrictInteraction",
"347": "OlthoiLootTimestamp",
"348": "OlthoiLootStep",
"349": "UseCreatesContractId",
"350": "DotResistRating",
"351": "LifeResistRating",
"352": "CloakWeaveProc",
"353": "WeaponType",
"354": "MeleeMastery",
"355": "RangedMastery",
"356": "SneakAttackRating",
"357": "RecklessnessRating",
"358": "DeceptionRating",
"359": "CombatPetRange",
"360": "WeaponAuraDamage",
"361": "WeaponAuraSpeed",
"362": "SummoningMastery",
"363": "HeartbeatLifespan",
"364": "UseLevelRequirement",
"365": "LumAugAllSkills",
"366": "UseRequiresSkill",
"367": "UseRequiresSkillLevel",
"368": "UseRequiresSkillSpec",
"369": "UseRequiresLevel",
"370": "GearDamage",
"371": "GearDamageResist",
"372": "GearCrit",
"373": "GearCritResist",
"374": "GearCritDamage",
"375": "GearCritDamageResist",
"376": "GearHealingBoost",
"377": "GearNetherResist",
"378": "GearLifeResist",
"379": "GearMaxHealth",
"380": "Unknown380",
"381": "PKDamageRating",
"382": "PKDamageResistRating",
"383": "GearPKDamageRating",
"384": "GearPKDamageResistRating",
"385": "Unknown385",
"386": "Overpower",
"387": "OverpowerResist",
"388": "GearOverpower",
"389": "GearOverpowerResist",
"390": "Enlightenment",
"8007": "PCAPRecordedAutonomousMovement",
"8030": "PCAPRecordedMaxVelocityEstimated",
"8041": "PCAPRecordedPlacement",
"8042": "PCAPRecordedAppraisalPages",
"8043": "PCAPRecordedAppraisalMaxPages",
"9008": "CurrentLoyaltyAtLastLogoff",
"9009": "CurrentLeadershipAtLastLogoff",
"9010": "AllegianceOfficerRank",
"9011": "HouseRentTimestamp",
"9012": "Hairstyle",
"9013": "VisualClothingPriority",
"9014": "SquelchGlobal",
"9015": "InventoryOrder",
"218103808": "WeenieClassId_Decal",
"218103809": "Icon_Decal_DID",
"218103810": "Container_Decal_IID",
"218103811": "Landblock_Decal",
"218103812": "ItemSlots_Decal",
"218103813": "PackSlots_Decal",
"218103814": "StackCount_Decal",
"218103815": "StackMax_Decal",
"218103816": "Spell_Decal_DID",
"218103817": "SlotLegacy_Decal",
"218103818": "Wielder_Decal_IID",
"218103819": "WieldingSlot_Decal",
"218103820": "Monarch_Decal_IID",
"218103821": "Coverage_Decal",
"218103822": "EquipableSlots_Decal",
"218103823": "EquipType_Decal",
"218103824": "IconOutline_Decal",
"218103825": "MissileType_Decal",
"218103826": "UsageMask_Decal",
"218103827": "HouseOwner_Decal_IID",
"218103828": "HookMask_Decal",
"218103829": "HookType_Decal",
"218103830": "Setup_Decal_DID",
"218103831": "ObjectDescriptionFlags_Decal",
"218103832": "CreateFlags1_Decal",
"218103833": "CreateFlags2_Decal",
"218103834": "Category_Decal",
"218103835": "Behavior_Decal",
"218103836": "MagicDef_Decal",
"218103837": "SpecialProps_Decal",
"218103838": "SpellCount_Decal",
"218103839": "WeapSpeed_Decal",
"218103840": "EquipSkill_Decal",
"218103841": "DamageType_Decal",
"218103842": "MaxDamage_Decal",
"218103843": "Unknown10_Decal",
"218103844": "Unknown100000_Decal",
"218103845": "Unknown800000_Decal",
"218103846": "Unknown8000000_Decal",
"218103847": "PhysicsDataFlags_Decal",
"218103848": "ActiveSpellCount_Decal",
"218103849": "IconOverlay_Decal_DID",
"218103850": "IconUnderlay_Decal_DID",
"231735296": "Slot_Decal"
},
"comments": {
"EncumbranceVal": "ENCUMB_VAL_INT,",
"ValidLocations": "LOCATIONS_INT",
"Unknown10_Decal": "CurrentWieldLocation?",
"Unknown100000_Decal": "RadarBlipColor ???"
},
"attributes": {},
"source_file": "IntValueKey.cs"
}
}

View file

@ -0,0 +1,52 @@
{
"ItemType": {
"type": "uint",
"values": {
"0": "None",
"1": "MeleeWeapon",
"2": "Armor",
"4": "Clothing",
"8": "Jewelry",
"16": "Creature",
"32": "Food",
"64": "Money",
"128": "Misc",
"256": "MissileWeapon",
"512": "Container",
"1024": "Useless",
"2048": "Gem",
"4096": "SpellComponents",
"8192": "Writable",
"16384": "Key",
"32768": "Caster",
"65536": "Portal",
"131072": "Lockable",
"262144": "PromissoryNote",
"524288": "ManaStone",
"1048576": "Service",
"2097152": "MagicWieldable",
"4194304": "CraftCookingBase",
"8388608": "CraftAlchemyBase",
"33554432": "CraftFletchingBase",
"67108864": "CraftAlchemyIntermediate",
"134217728": "CraftFletchingIntermediate",
"268435456": "LifeStone",
"536870912": "TinkeringTool",
"1073741824": "TinkeringMaterial",
"2147483648": "Gameboard",
"EXPR:Portal | LifeStone": "PortalMagicTarget",
"EXPR:Misc | Container": "LockableMagicTarget",
"EXPR:Armor | Clothing": "Vestements",
"EXPR:MeleeWeapon | MissileWeapon": "Weapon",
"EXPR:MeleeWeapon | MissileWeapon | Caster": "WeaponOrCaster",
"EXPR:MeleeWeapon | Armor | Clothing | Jewelry | Food | Money | Misc | MissileWeapon | Container |": "Item",
"EXPR:MeleeWeapon | Armor | Clothing | MissileWeapon | Caster": "RedirectableItemEnchantmentTarget",
"EXPR:MeleeWeapon | Armor | Clothing | Jewelry | Misc | MissileWeapon | Container | Gem | Caster | ManaStone": "ItemEnchantableTarget",
"EXPR:MeleeWeapon | Armor | Clothing | Food | Misc | MissileWeapon | Container | Useless | Writable | Key |": "VendorShopKeep",
"EXPR:Food | Container | Writable | Key | PromissoryNote | CraftCookingBase": "VendorGrocer"
},
"comments": {},
"attributes": {},
"source_file": "ItemType.cs"
}
}

View file

@ -0,0 +1,83 @@
{
"MaterialType": {
"type": "uint",
"values": {
"0": "Unknown",
"1": "Ceramic",
"2": "Porcelain",
"4": "Linen",
"5": "Satin",
"6": "Silk",
"7": "Velvet",
"8": "Wool",
"10": "Agate",
"11": "Amber",
"12": "Amethyst",
"13": "Aquamarine",
"14": "Azurite",
"15": "BlackGarnet",
"16": "BlackOpal",
"17": "Bloodstone",
"18": "Carnelian",
"19": "Citrine",
"20": "Diamond",
"21": "Emerald",
"22": "FireOpal",
"23": "GreenGarnet",
"24": "GreenJade",
"25": "Hematite",
"26": "ImperialTopaz",
"27": "Jet",
"28": "LapisLazuli",
"29": "LavenderJade",
"30": "Malachite",
"31": "Moonstone",
"32": "Onyx",
"33": "Opal",
"34": "Peridot",
"35": "RedGarnet",
"36": "RedJade",
"37": "RoseQuartz",
"38": "Ruby",
"39": "Sapphire",
"40": "SmokeyQuartz",
"41": "Sunstone",
"42": "TigerEye",
"43": "Tourmaline",
"44": "Turquoise",
"45": "WhiteJade",
"46": "WhiteQuartz",
"47": "WhiteSapphire",
"48": "YellowGarnet",
"49": "YellowTopaz",
"50": "Zircon",
"51": "Ivory",
"52": "Leather",
"53": "ArmoredilloHide",
"54": "GromnieHide",
"55": "ReedSharkHide",
"57": "Brass",
"58": "Bronze",
"59": "Copper",
"60": "Gold",
"61": "Iron",
"62": "Pyreal",
"63": "Silver",
"64": "Steel",
"66": "Alabaster",
"67": "Granite",
"68": "Marble",
"69": "Obsidian",
"70": "Sandstone",
"71": "Serpentine",
"73": "Ebony",
"74": "Mahogany",
"75": "Oak",
"76": "Pine",
"77": "Teak"
},
"comments": {},
"attributes": {},
"source_file": "MaterialType.cs"
}
}

View file

@ -0,0 +1,23 @@
{
"QuadValueKey": {
"type": "int",
"values": {
"0": "Undef",
"1": "TotalExperience",
"2": "AvailableExperience",
"3": "AugmentationCost",
"4": "ItemTotalXp",
"5": "ItemBaseXp",
"6": "AvailableLuminance",
"7": "MaximumLuminance",
"8": "InteractionReqs",
"9000": "AllegianceXPCached",
"9001": "AllegianceXPGenerated",
"9002": "AllegianceXPReceived",
"9003": "VerifyXp"
},
"comments": {},
"attributes": {},
"source_file": "QuadValueKey.cs"
}
}

View file

@ -0,0 +1,228 @@
{
"Skill": {
"type": "indexed",
"values": {
"0": {
"name": "None",
"status": "Active"
},
"1": {
"name": "Axe",
"status": "Retired"
},
"2": {
"name": "Bow",
"status": "Retired"
},
"3": {
"name": "Crossbow",
"status": "Retired"
},
"4": {
"name": "Dagger",
"status": "Retired"
},
"5": {
"name": "Mace",
"status": "Retired"
},
"6": {
"name": "MeleeDefense",
"status": "Active"
},
"7": {
"name": "MissileDefense",
"status": "Active"
},
"8": {
"name": "Sling",
"status": "Retired"
},
"9": {
"name": "Spear",
"status": "Retired"
},
"10": {
"name": "Staff",
"status": "Retired"
},
"11": {
"name": "Sword",
"status": "Retired"
},
"12": {
"name": "ThrownWeapon",
"status": "Retired"
},
"13": {
"name": "UnarmedCombat",
"status": "Retired"
},
"14": {
"name": "ArcaneLore",
"status": "Active"
},
"15": {
"name": "MagicDefense",
"status": "Active"
},
"16": {
"name": "ManaConversion",
"status": "Active"
},
"17": {
"name": "Spellcraft",
"status": "Unimplemented"
},
"18": {
"name": "ItemTinkering",
"status": "Active"
},
"19": {
"name": "AssessPerson",
"status": "Active"
},
"20": {
"name": "Deception",
"status": "Active"
},
"21": {
"name": "Healing",
"status": "Active"
},
"22": {
"name": "Jump",
"status": "Active"
},
"23": {
"name": "Lockpick",
"status": "Active"
},
"24": {
"name": "Run",
"status": "Active"
},
"25": {
"name": "Awareness",
"status": "Unimplemented"
},
"26": {
"name": "ArmsAndArmorRepair",
"status": "Unimplemented"
},
"27": {
"name": "AssessCreature",
"status": "Active"
},
"28": {
"name": "WeaponTinkering",
"status": "Active"
},
"29": {
"name": "ArmorTinkering",
"status": "Active"
},
"30": {
"name": "MagicItemTinkering",
"status": "Active"
},
"31": {
"name": "CreatureEnchantment",
"status": "Active"
},
"32": {
"name": "ItemEnchantment",
"status": "Active"
},
"33": {
"name": "LifeMagic",
"status": "Active"
},
"34": {
"name": "WarMagic",
"status": "Active"
},
"35": {
"name": "Leadership",
"status": "Active"
},
"36": {
"name": "Loyalty",
"status": "Active"
},
"37": {
"name": "Fletching",
"status": "Active"
},
"38": {
"name": "Alchemy",
"status": "Active"
},
"39": {
"name": "Cooking",
"status": "Active"
},
"40": {
"name": "Salvaging",
"status": "Active"
},
"41": {
"name": "TwoHandedCombat",
"status": "Active"
},
"42": {
"name": "Gearcraft",
"status": "Retired"
},
"43": {
"name": "VoidMagic",
"status": "Active"
},
"44": {
"name": "HeavyWeapons",
"status": "Active"
},
"45": {
"name": "LightWeapons",
"status": "Active"
},
"46": {
"name": "FinesseWeapons",
"status": "Active"
},
"47": {
"name": "MissileWeapons",
"status": "Active"
},
"48": {
"name": "Shield",
"status": "Active"
},
"49": {
"name": "DualWield",
"status": "Active"
},
"50": {
"name": "Recklessness",
"status": "Active"
},
"51": {
"name": "SneakAttack",
"status": "Active"
},
"52": {
"name": "DirtyFighting",
"status": "Active"
},
"53": {
"name": "Challenge",
"status": "Unimplemented"
},
"54": {
"name": "Summoning",
"status": "Active"
}
},
"source_file": "Skill.cs"
}
}

View file

@ -0,0 +1,710 @@
{
"SpellCategory": {
"type": "int",
"values": {
"0": "Undefined",
"1": "Strength_Raising",
"2": "Strength_Lowering",
"3": "Endurance_Raising",
"4": "Endurance_Lowering",
"5": "Quickness_Raising",
"6": "Quickness_Lowering",
"7": "Coordination_Raising",
"8": "Coordination_Lowering",
"9": "Focus_Raising",
"10": "Focus_Lowering",
"11": "Self_Raising",
"12": "Self_Lowering",
"13": "Focus_Concentration",
"14": "Focus_Disruption",
"15": "Focus_Brilliance",
"16": "Focus_Dullness",
"17": "Axe_Raising",
"18": "Axe_Lowering",
"19": "Bow_Raising",
"20": "Bow_Lowering",
"21": "Crossbow_Raising",
"22": "Crossbow_Lowering",
"23": "Dagger_Raising",
"24": "Dagger_Lowering",
"25": "Mace_Raising",
"26": "Mace_Lowering",
"27": "Spear_Raising",
"28": "Spear_Lowering",
"29": "Staff_Raising",
"30": "Staff_Lowering",
"31": "Sword_Raising",
"32": "Sword_Lowering",
"33": "Thrown_Weapons_Raising",
"34": "Thrown_Weapons_Lowering",
"35": "Unarmed_Combat_Raising",
"36": "Unarmed_Combat_Lowering",
"37": "Melee_Defense_Raising",
"38": "Melee_Defense_Lowering",
"39": "Missile_Defense_Raising",
"40": "Missile_Defense_Lowering",
"41": "Magic_Defense_Raising",
"42": "Magic_Defense_Lowering",
"43": "Creature_Enchantment_Raising",
"44": "Creature_Enchantment_Lowering",
"45": "Item_Enchantment_Raising",
"46": "Item_Enchantment_Lowering",
"47": "Life_Magic_Raising",
"48": "Life_Magic_Lowering",
"49": "War_Magic_Raising",
"50": "War_Magic_Lowering",
"51": "Mana_Conversion_Raising",
"52": "Mana_Conversion_Lowering",
"53": "Arcane_Lore_Raising",
"54": "Arcane_Lore_Lowering",
"55": "Appraise_Armor_Raising",
"56": "Appraise_Armor_Lowering",
"57": "Appraise_Item_Raising",
"58": "Appraise_Item_Lowering",
"59": "Appraise_Magic_Item_Raising",
"60": "Appraise_Magic_Item_Lowering",
"61": "Appraise_Weapon_Raising",
"62": "Appraise_Weapon_Lowering",
"63": "Assess_Monster_Raising",
"64": "Assess_Monster_Lowering",
"65": "Deception_Raising",
"66": "Deception_Lowering",
"67": "Healing_Raising",
"68": "Healing_Lowering",
"69": "Jump_Raising",
"70": "Jump_Lowering",
"71": "Leadership_Raising",
"72": "Leadership_Lowering",
"73": "Lockpick_Raising",
"74": "Lockpick_Lowering",
"75": "Loyalty_Raising",
"76": "Loyalty_Lowering",
"77": "Run_Raising",
"78": "Run_Lowering",
"79": "Health_Raising",
"80": "Health_Lowering",
"81": "Stamina_Raising",
"82": "Stamina_Lowering",
"83": "Mana_Raising",
"84": "Mana_Lowering",
"85": "Mana_Remedy",
"86": "Mana_Malediction",
"87": "Health_Transfer_to_caster",
"88": "Health_Transfer_from_caster",
"89": "Stamina_Transfer_to_caster",
"90": "Stamina_Transfer_from_caster",
"91": "Mana_Transfer_to_caster",
"92": "Mana_Transfer_from_caster",
"93": "Health_Accelerating",
"94": "Health_Decelerating",
"95": "Stamina_Accelerating",
"96": "Stamina_Decelerating",
"97": "Mana_Accelerating",
"98": "Mana_Decelerating",
"99": "Vitae_Raising",
"100": "Vitae_Lowering",
"101": "Acid_Protection",
"102": "Acid_Vulnerability",
"103": "Bludgeon_Protection",
"104": "Bludgeon_Vulnerability",
"105": "Cold_Protection",
"106": "Cold_Vulnerability",
"107": "Electric_Protection",
"108": "Electric_Vulnerability",
"109": "Fire_Protection",
"110": "Fire_Vulnerability",
"111": "Pierce_Protection",
"112": "Pierce_Vulnerability",
"113": "Slash_Protection",
"114": "Slash_Vulnerability",
"115": "Armor_Raising",
"116": "Armor_Lowering",
"117": "Acid_Missile",
"118": "Bludgeoning_Missile",
"119": "Cold_Missile",
"120": "Electric_Missile",
"121": "Fire_Missile",
"122": "Piercing_Missile",
"123": "Slashing_Missile",
"124": "Acid_Seeker",
"125": "Bludgeoning_Seeker",
"126": "Cold_Seeker",
"127": "Electric_Seeker",
"128": "Fire_Seeker",
"129": "Piercing_Seeker",
"130": "Slashing_Seeker",
"131": "Acid_Burst",
"132": "Bludgeoning_Burst",
"133": "Cold_Burst",
"134": "Electric_Burst",
"135": "Fire_Burst",
"136": "Piercing_Burst",
"137": "Slashing_Burst",
"138": "Acid_Blast",
"139": "Bludgeoning_Blast",
"140": "Cold_Blast",
"141": "Electric_Blast",
"142": "Fire_Blast",
"143": "Piercing_Blast",
"144": "Slashing_Blast",
"145": "Acid_Scatter",
"146": "Bludgeoning_Scatter",
"147": "Cold_Scatter",
"148": "Electric_Scatter",
"149": "Fire_Scatter",
"150": "Piercing_Scatter",
"151": "Slashing_Scatter",
"152": "Attack_Mod_Raising",
"153": "Attack_Mod_Lowering",
"154": "Damage_Raising",
"155": "Damage_Lowering",
"156": "Defense_Mod_Raising",
"157": "Defense_Mod_Lowering",
"158": "Weapon_Time_Raising",
"159": "Weapon_Time_Lowering",
"160": "Armor_Value_Raising",
"161": "Armor_Value_Lowering",
"162": "Acid_Resistance_Raising",
"163": "Acid_Resistance_Lowering",
"164": "Bludgeon_Resistance_Raising",
"165": "Bludgeon_Resistance_Lowering",
"166": "Cold_Resistance_Raising",
"167": "Cold_Resistance_Lowering",
"168": "Electric_Resistance_Raising",
"169": "Electric_Resistance_Lowering",
"170": "Fire_Resistance_Raising",
"171": "Fire_Resistance_Lowering",
"172": "Pierce_Resistance_Raising",
"173": "Pierce_Resistance_Lowering",
"174": "Slash_Resistance_Raising",
"175": "Slash_Resistance_Lowering",
"176": "Bludgeoning_Resistance_Raising",
"177": "Bludgeoning_Resistance_Lowering",
"178": "Slashing_Resistance_Raising",
"179": "Slashing_Resistance_Lowering",
"180": "Piercing_Resistance_Raising",
"181": "Piercing_Resistance_Lowering",
"182": "Electrical_Resistance_Raising",
"183": "Electrical_Resistance_Lowering",
"184": "Frost_Resistance_Raising",
"185": "Frost_Resistance_Lowering",
"186": "Flame_Resistance_Raising",
"187": "Flame_Resistance_Lowering",
"188": "Acidic_Resistance_Raising",
"189": "Acidic_Resistance_Lowering",
"190": "Armor_Level_Raising",
"191": "Armor_Level_Lowering",
"192": "Lockpick_Resistance_Raising",
"193": "Lockpick_Resistance_Lowering",
"194": "Appraisal_Resistance_Raising",
"195": "Appraisal_Resistance_Lowering",
"196": "Vision_Raising",
"197": "Vision_Lowering",
"198": "Transparency_Raising",
"199": "Transparency_Lowering",
"200": "Portal_Tie",
"201": "Portal_Recall",
"202": "Portal_Creation",
"203": "Portal_Item_Creation",
"204": "Vitae",
"205": "Assess_Person_Raising",
"206": "Assess_Person_Lowering",
"207": "Acid_Volley",
"208": "Bludgeoning_Volley",
"209": "Frost_Volley",
"210": "Lightning_Volley",
"211": "Flame_Volley",
"212": "Force_Volley",
"213": "Blade_Volley",
"214": "Portal_Sending",
"215": "Lifestone_Sending",
"216": "Cooking_Raising",
"217": "Cooking_Lowering",
"218": "Fletching_Raising",
"219": "Fletching_Lowering",
"220": "Alchemy_Lowering",
"221": "Alchemy_Raising",
"222": "Acid_Ring",
"223": "Bludgeoning_Ring",
"224": "Cold_Ring",
"225": "Electric_Ring",
"226": "Fire_Ring",
"227": "Piercing_Ring",
"228": "Slashing_Ring",
"229": "Acid_Wall",
"230": "Bludgeoning_Wall",
"231": "Cold_Wall",
"232": "Electric_Wall",
"233": "Fire_Wall",
"234": "Piercing_Wall",
"235": "Slashing_Wall",
"236": "Acid_Strike",
"237": "Bludgeoning_Strike",
"238": "Cold_Strike",
"239": "Electric_Strike",
"240": "Fire_Strike",
"241": "Piercing_Strike",
"242": "Slashing_Strike",
"243": "Acid_Streak",
"244": "Bludgeoning_Streak",
"245": "Cold_Streak",
"246": "Electric_Streak",
"247": "Fire_Streak",
"248": "Piercing_Streak",
"249": "Slashing_Streak",
"250": "Dispel",
"251": "Creature_Mystic_Raising",
"252": "Creature_Mystic_Lowering",
"253": "Item_Mystic_Raising",
"254": "Item_Mystic_Lowering",
"255": "War_Mystic_Raising",
"256": "War_Mystic_Lowering",
"257": "Health_Restoring",
"258": "Health_Depleting",
"259": "Mana_Restoring",
"260": "Mana_Depleting",
"261": "Strength_Increase",
"262": "Strength_Decrease",
"263": "Endurance_Increase",
"264": "Endurance_Decrease",
"265": "Quickness_Increase",
"266": "Quickness_Decrease",
"267": "Coordination_Increase",
"268": "Coordination_Decrease",
"269": "Focus_Increase",
"270": "Focus_Decrease",
"271": "Self_Increase",
"272": "Self_Decrease",
"273": "GreatVitality_Raising",
"274": "PoorVitality_Lowering",
"275": "GreatVigor_Raising",
"276": "PoorVigor_Lowering",
"277": "GreaterIntellect_Raising",
"278": "LessorIntellect_Lowering",
"279": "LifeGiver_Raising",
"280": "LifeTaker_Lowering",
"281": "StaminaGiver_Raising",
"282": "StaminaTaker_Lowering",
"283": "ManaGiver_Raising",
"284": "ManaTaker_Lowering",
"285": "Acid_Ward_Protection",
"286": "Acid_Ward_Vulnerability",
"287": "Fire_Ward_Protection",
"288": "Fire_Ward_Vulnerability",
"289": "Cold_Ward_Protection",
"290": "Cold_Ward_Vulnerability",
"291": "Electric_Ward_Protection",
"292": "Electric_Ward_Vulnerability",
"293": "Leadership_Obedience_Raising",
"294": "Leadership_Obedience_Lowering",
"295": "Melee_Defense_Shelter_Raising",
"296": "Melee_Defense_Shelter_Lowering",
"297": "Missile_Defense_Shelter_Raising",
"298": "Missile_Defense_Shelter_Lowering",
"299": "Magic_Defense_Shelter_Raising",
"300": "Magic_Defense_Shelter_Lowering",
"301": "HuntersAcumen_Raising",
"302": "HuntersAcumen_Lowering",
"303": "StillWater_Raising",
"304": "StillWater_Lowering",
"305": "StrengthofEarth_Raising",
"306": "StrengthofEarth_Lowering",
"307": "Torrent_Raising",
"308": "Torrent_Lowering",
"309": "Growth_Raising",
"310": "Growth_Lowering",
"311": "CascadeAxe_Raising",
"312": "CascadeAxe_Lowering",
"313": "CascadeDagger_Raising",
"314": "CascadeDagger_Lowering",
"315": "CascadeMace_Raising",
"316": "CascadeMace_Lowering",
"317": "CascadeSpear_Raising",
"318": "CascadeSpear_Lowering",
"319": "CascadeStaff_Raising",
"320": "CascadeStaff_Lowering",
"321": "StoneCliffs_Raising",
"322": "StoneCliffs_Lowering",
"323": "MaxDamage_Raising",
"324": "MaxDamage_Lowering",
"325": "Bow_Damage_Raising",
"326": "Bow_Damage_Lowering",
"327": "Bow_Range_Raising",
"328": "Bow_Range_Lowering",
"329": "Extra_Defense_Mod_Raising",
"330": "Extra_Defense_Mod_Lowering",
"331": "Extra_Bow_Skill_Raising",
"332": "Extra_Bow_Skill_Lowering",
"333": "Extra_Alchemy_Skill_Raising",
"334": "Extra_Alchemy_Skill_Lowering",
"335": "Extra_Arcane_Lore_Skill_Raising",
"336": "Extra_Arcane_Lore_Skill_Lowering",
"337": "Extra_Appraise_Armor_Skill_Raising",
"338": "Extra_Appraise_Armor_Skill_Lowering",
"339": "Extra_Cooking_Skill_Raising",
"340": "Extra_Cooking_Skill_Lowering",
"341": "Extra_Crossbow_Skill_Raising",
"342": "Extra_Crossbow_Skill_Lowering",
"343": "Extra_Deception_Skill_Raising",
"344": "Extra_Deception_Skill_Lowering",
"345": "Extra_Loyalty_Skill_Raising",
"346": "Extra_Loyalty_Skill_Lowering",
"347": "Extra_Fletching_Skill_Raising",
"348": "Extra_Fletching_Skill_Lowering",
"349": "Extra_Healing_Skill_Raising",
"350": "Extra_Healing_Skill_Lowering",
"351": "Extra_Melee_Defense_Skill_Raising",
"352": "Extra_Melee_Defense_Skill_Lowering",
"353": "Extra_Appraise_Item_Skill_Raising",
"354": "Extra_Appraise_Item_Skill_Lowering",
"355": "Extra_Jumping_Skill_Raising",
"356": "Extra_Jumping_Skill_Lowering",
"357": "Extra_Life_Magic_Skill_Raising",
"358": "Extra_Life_Magic_Skill_Lowering",
"359": "Extra_Lockpick_Skill_Raising",
"360": "Extra_Lockpick_Skill_Lowering",
"361": "Extra_Appraise_Magic_Item_Skill_Raising",
"362": "Extra_Appraise_Magic_Item_Skill_Lowering",
"363": "Extra_Mana_Conversion_Skill_Raising",
"364": "Extra_Mana_Conversion_Skill_Lowering",
"365": "Extra_Assess_Creature_Skill_Raising",
"366": "Extra_Assess_Creature_Skill_Lowering",
"367": "Extra_Assess_Person_Skill_Raising",
"368": "Extra_Assess_Person_Skill_Lowering",
"369": "Extra_Run_Skill_Raising",
"370": "Extra_Run_Skill_Lowering",
"371": "Extra_Sword_Skill_Raising",
"372": "Extra_Sword_Skill_Lowering",
"373": "Extra_Thrown_Weapons_Skill_Raising",
"374": "Extra_Thrown_Weapons_Skill_Lowering",
"375": "Extra_Unarmed_Combat_Skill_Raising",
"376": "Extra_Unarmed_Combat_Skill_Lowering",
"377": "Extra_Appraise_Weapon_Skill_Raising",
"378": "Extra_Appraise_Weapon_Skill_Lowering",
"379": "Armor_Increase",
"380": "Armor_Decrease",
"381": "Extra_Acid_Resistance_Raising",
"382": "Extra_Acid_Resistance_Lowering",
"383": "Extra_Bludgeon_Resistance_Raising",
"384": "Extra_Bludgeon_Resistance_Lowering",
"385": "Extra_Fire_Resistance_Raising",
"386": "Extra_Fire_Resistance_Lowering",
"387": "Extra_Cold_Resistance_Raising",
"388": "Extra_Cold_Resistance_Lowering",
"389": "Extra_Attack_Mod_Raising",
"390": "Extra_Attack_Mod_Lowering",
"391": "Extra_Armor_Value_Raising",
"392": "Extra_Armor_Value_Lowering",
"393": "Extra_Pierce_Resistance_Raising",
"394": "Extra_Pierce_Resistance_Lowering",
"395": "Extra_Slash_Resistance_Raising",
"396": "Extra_Slash_Resistance_Lowering",
"397": "Extra_Electric_Resistance_Raising",
"398": "Extra_Electric_Resistance_Lowering",
"399": "Extra_Weapon_Time_Raising",
"400": "Extra_Weapon_Time_Lowering",
"401": "Bludgeon_Ward_Protection",
"402": "Bludgeon_Ward_Vulnerability",
"403": "Slash_Ward_Protection",
"404": "Slash_Ward_Vulnerability",
"405": "Pierce_Ward_Protection",
"406": "Pierce_Ward_Vulnerability",
"407": "Stamina_Restoring",
"408": "Stamina_Depleting",
"409": "Fireworks",
"410": "Health_Divide",
"411": "Stamina_Divide",
"412": "Mana_Divide",
"413": "Coordination_Increase2",
"414": "Strength_Increase2",
"415": "Focus_Increase2",
"416": "Endurance_Increase2",
"417": "Self_Increase2",
"418": "Melee_Defense_Multiply",
"419": "Missile_Defense_Multiply",
"420": "Magic_Defense_Multiply",
"421": "Attributes_Decrease",
"422": "LifeGiver_Raising2",
"423": "Item_Enchantment_Raising2",
"424": "Skills_Decrease",
"425": "Extra_Mana_Conversion_Bonus",
"426": "War_Mystic_Raising2",
"427": "War_Mystic_Lowering2",
"428": "Magic_Defense_Shelter_Raising2",
"429": "Extra_Life_Magic_Skill_Raising2",
"430": "Creature_Mystic_Raising2",
"431": "Item_Mystic_Raising2",
"432": "Mana_Raising2",
"433": "Self_Raising2",
"434": "CreatureEnchantment_Raising2",
"435": "Salvaging_Raising",
"436": "Extra_Salvaging_Raising",
"437": "Extra_Salvaging_Raising2",
"438": "CascadeAxe_Raising2",
"439": "Extra_Bow_Skill_Raising2",
"440": "Extra_Thrown_Weapons_Skill_Raising2",
"441": "Extra_Crossbow_Skill_Raising2",
"442": "CascadeDagger_Raising2",
"443": "CascadeMace_Raising2",
"444": "Extra_Unarmed_Combat_Skill_Raising2",
"445": "CascadeSpear_Raising2",
"446": "CascadeStaff_Raising2",
"447": "Extra_Sword_Skill_Raising2",
"448": "Acid_Protection_Rare",
"449": "Acid_Resistance_Raising_Rare",
"450": "Alchemy_Raising_Rare",
"451": "Appraisal_Resistance_Lowering_Rare",
"452": "Appraise_Armor_Raising_Rare",
"453": "Appraise_Item_Raising_Rare",
"454": "Appraise_Magic_Item_Raising_Rare",
"455": "Appraise_Weapon_Raising_Rare",
"456": "Arcane_Lore_Raising_Rare",
"457": "Armor_Raising_Rare",
"458": "Armor_Value_Raising_Rare",
"459": "Assess_Monster_Raising_Rare",
"460": "Assess_Person_Raising_Rare",
"461": "Attack_Mod_Raising_Rare",
"462": "Axe_Raising_Rare",
"463": "Bludgeon_Protection_Rare",
"464": "Bludgeon_Resistance_Raising_Rare",
"465": "Bow_Raising_Rare",
"466": "Cold_Protection_Rare",
"467": "Cold_Resistance_Raising_Rare",
"468": "Cooking_Raising_Rare",
"469": "Coordination_Raising_Rare",
"470": "Creature_Enchantment_Raising_Rare",
"471": "Crossbow_Raising_Rare",
"472": "Dagger_Raising_Rare",
"473": "Damage_Raising_Rare",
"474": "Deception_Raising_Rare",
"475": "Defense_Mod_Raising_Rare",
"476": "Electric_Protection_Rare",
"477": "Electric_Resistance_Raising_Rare",
"478": "Endurance_Raising_Rare",
"479": "Fire_Protection_Rare",
"480": "Fire_Resistance_Raising_Rare",
"481": "Fletching_Raising_Rare",
"482": "Focus_Raising_Rare",
"483": "Healing_Raising_Rare",
"484": "Health_Accelerating_Rare",
"485": "Item_Enchantment_Raising_Rare",
"486": "Jump_Raising_Rare",
"487": "Leadership_Raising_Rare",
"488": "Life_Magic_Raising_Rare",
"489": "Lockpick_Raising_Rare",
"490": "Loyalty_Raising_Rare",
"491": "Mace_Raising_Rare",
"492": "Magic_Defense_Raising_Rare",
"493": "Mana_Accelerating_Rare",
"494": "Mana_Conversion_Raising_Rare",
"495": "Melee_Defense_Raising_Rare",
"496": "Missile_Defense_Raising_Rare",
"497": "Pierce_Protection_Rare",
"498": "Pierce_Resistance_Raising_Rare",
"499": "Quickness_Raising_Rare",
"500": "Run_Raising_Rare",
"501": "Self_Raising_Rare",
"502": "Slash_Protection_Rare",
"503": "Slash_Resistance_Raising_Rare",
"504": "Spear_Raising_Rare",
"505": "Staff_Raising_Rare",
"506": "Stamina_Accelerating_Rare",
"507": "Strength_Raising_Rare",
"508": "Sword_Raising_Rare",
"509": "Thrown_Weapons_Raising_Rare",
"510": "Unarmed_Combat_Raising_Rare",
"511": "War_Magic_Raising_Rare",
"512": "Weapon_Time_Raising_Rare",
"513": "Armor_Increase_Inky_Armor",
"514": "Magic_Defense_Shelter_Raising_Fiun",
"515": "Extra_Run_Skill_Raising_Fiun",
"516": "Extra_Mana_Conversion_Skill_Raising_Fiun",
"517": "Attributes_Increase_Cantrip1",
"518": "Extra_Melee_Defense_Skill_Raising2",
"519": "ACTDPurchaseRewardSpell",
"520": "ACTDPurchaseRewardSpellHealth",
"521": "SaltAsh_Attack_Mod_Raising",
"522": "Quickness_Increase2",
"523": "Extra_Alchemy_Skill_Raising2",
"524": "Extra_Cooking_Skill_Raising2",
"525": "Extra_Fletching_Skill_Raising2",
"526": "Extra_Lockpick_Skill_Raising2",
"527": "MucorManaWell",
"528": "Stamina_Restoring2",
"529": "Allegiance_Raising",
"530": "Health_DoT",
"531": "Health_DoT_Secondary",
"532": "Health_DoT_Tertiary",
"533": "Health_HoT",
"534": "Health_HoT_Secondary",
"535": "Health_HoT_Tertiary",
"536": "Health_Divide_Secondary",
"537": "Health_Divide_Tertiary",
"538": "SetSword_Raising",
"539": "SetAxe_Raising",
"540": "SetDagger_Raising",
"541": "SetMace_Raising",
"542": "SetSpear_Raising",
"543": "SetStaff_Raising",
"544": "SetUnarmed_Raising",
"545": "SetBow_Raising",
"546": "SetCrossbow_Raising",
"547": "SetThrown_Raising",
"548": "SetItemEnchantment_Raising",
"549": "SetCreatureEnchantment_Raising",
"550": "SetWarMagic_Raising",
"551": "SetLifeMagic_Raising",
"552": "SetMeleeDefense_Raising",
"553": "SetMissileDefense_Raising",
"554": "SetMagicDefense_Raising",
"555": "SetStamina_Accelerating",
"556": "SetCooking_Raising",
"557": "SetFletching_Raising",
"558": "SetLockpick_Raising",
"559": "SetAlchemy_Raising",
"560": "SetSalvaging_Raising",
"561": "SetArmorExpertise_Raising",
"562": "SetWeaponExpertise_Raising",
"563": "SetItemTinkering_Raising",
"564": "SetMagicItemExpertise_Raising",
"565": "SetLoyalty_Raising",
"566": "SetStrength_Raising",
"567": "SetEndurance_Raising",
"568": "SetCoordination_Raising",
"569": "SetQuickness_Raising",
"570": "SetFocus_Raising",
"571": "SetWillpower_Raising",
"572": "SetHealth_Raising",
"573": "SetStamina_Raising",
"574": "SetMana_Raising",
"575": "SetSprint_Raising",
"576": "SetJumping_Raising",
"577": "SetSlashResistance_Raising",
"578": "SetBludgeonResistance_Raising",
"579": "SetPierceResistance_Raising",
"580": "SetFlameResistance_Raising",
"581": "SetAcidResistance_Raising",
"582": "SetFrostResistance_Raising",
"583": "SetLightningResistance_Raising",
"584": "Crafting_LockPick_Raising",
"585": "Crafting_Fletching_Raising",
"586": "Crafting_Cooking_Raising",
"587": "Crafting_Alchemy_Raising",
"588": "Crafting_ArmorTinkering_Raising",
"589": "Crafting_WeaponTinkering_Raising",
"590": "Crafting_MagicTinkering_Raising",
"591": "Crafting_ItemTinkering_Raising",
"592": "SkillPercent_Alchemy_Raising",
"593": "TwoHanded_Raising",
"594": "TwoHanded_Lowering",
"595": "Extra_TwoHanded_Skill_Raising",
"596": "Extra_TwoHanded_Skill_Lowering",
"597": "Extra_TwoHanded_Skill_Raising2",
"598": "TwoHanded_Raising_Rare",
"599": "SetTwoHanded_Raising",
"600": "GearCraft_Raising",
"601": "GearCraft_Lowering",
"602": "Extra_GearCraft_Skill_Raising",
"603": "Extra_GearCraft_Skill_Lowering",
"604": "Extra_GearCraft_Skill_Raising2",
"605": "GearCraft_Raising_Rare",
"606": "SetGearCraft_Raising",
"607": "LoyaltyMana_Raising",
"608": "LoyaltyStamina_Raising",
"609": "LeadershipHealth_Raising",
"610": "TrinketDamage_Raising",
"611": "TrinketDamage_Lowering",
"612": "TrinketHealth_Raising",
"613": "TrinketStamina_Raising",
"614": "TrinketMana_Raising",
"615": "TrinketXP_Raising",
"616": "DeceptionArcaneLore_Raising",
"617": "HealOverTime_Raising",
"618": "DamageOverTime_Raising",
"619": "HealingResistRating_Raising",
"620": "AetheriaDamageRating_Raising",
"621": "AetheriaDamageReduction_Raising",
"622": "SKIPPED",
"623": "AetheriaHealth_Raising",
"624": "AetheriaStamina_Raising",
"625": "AetheriaMana_Raising",
"626": "AetheriaCriticalDamage_Raising",
"627": "AetheriaHealingAmplification_Raising",
"628": "AetheriaProcDamageRating_Raising",
"629": "AetheriaProcDamageReduction_Raising",
"630": "AetheriaProcHealthOverTime_Raising",
"631": "AetheriaProcDamageOverTime_Raising",
"632": "AetheriaProcHealingReduction_Raising",
"633": "RareDamageRating_Raising",
"634": "RareDamageReductionRating_Raising",
"635": "AetheriaEndurance_Raising",
"636": "NetherDamageOverTime_Raising",
"637": "NetherDamageOverTime_Raising2",
"638": "NetherDamageOverTime_Raising3",
"639": "Nether_Streak",
"640": "Nether_Missile",
"641": "Nether_Ring",
"642": "NetherDamageRating_Lowering",
"643": "NetherDamageHealingReduction_Raising",
"644": "Void_Magic_Lowering",
"645": "Void_Magic_Raising",
"646": "Void_Mystic_Raising",
"647": "SetVoidMagic_Raising",
"648": "Void_Magic_Raising_Rare",
"649": "Void_Mystic_Raising2",
"650": "LuminanceDamageRating_Raising",
"651": "LuminanceDamageReduction_Raising",
"652": "LuminanceHealth_Raising",
"653": "AetheriaCriticalReduction_Raising",
"654": "Extra_Missile_Defense_Skill_Raising",
"655": "Extra_Missile_Defense_Skill_Lowering",
"656": "Extra_Missile_Defense_Skill_Raising2",
"657": "AetheriaHealthResistance_Raising",
"658": "AetheriaDotResistance_Raising",
"659": "Cloak_Skill_Raising",
"660": "Cloak_All_Skill_Raising",
"661": "Cloak_Magic_Defense_Lowering",
"662": "Cloak_Melee_Defense_Lowering",
"663": "Cloak_Missile_Defense_Lowering",
"664": "DirtyFighting_Lowering",
"665": "DirtyFighting_Raising",
"666": "Extra_DirtyFighting_Raising",
"667": "DualWield_Lowering",
"668": "DualWield_Raising",
"669": "Extra_DualWield_Raising",
"670": "Recklessness_Lowering",
"671": "Recklessness_Raising",
"672": "Extra_Recklessness_Raising",
"673": "Shield_Lowering",
"674": "Shield_Raising",
"675": "Extra_Shield_Raising",
"676": "SneakAttack_Lowering",
"677": "SneakAttack_Raising",
"678": "Extra_SneakAttack_Raising",
"679": "Rare_DirtyFighting_Raising",
"680": "Rare_DualWield_Raising",
"681": "Rare_Recklessness_Raising",
"682": "Rare_Shield_Raising",
"683": "Rare_SneakAttack_Raising",
"684": "DF_Attack_Skill_Debuff",
"685": "DF_Bleed_Damage",
"686": "DF_Defense_Skill_Debuff",
"687": "DF_Healing_Debuff",
"688": "SetDirtyFighting_Raising",
"689": "SetDualWield_Raising",
"690": "SetRecklessness_Raising",
"691": "SetShield_Raising",
"692": "SetSneakAttack_Raising",
"693": "LifeGiver_Mhoire",
"694": "RareDamageRating_Raising2",
"695": "Spell_Damage_Raising",
"696": "Summoning_Raising",
"697": "Summoning_Lowering",
"698": "Extra_Summoning_Skill_Raising",
"699": "SetSummoning_Raising"
},
"comments": {},
"attributes": {},
"source_file": "SpellCategory.cs"
}
}

View file

@ -0,0 +1,74 @@
{
"StringValueKey": {
"type": "int",
"values": {
"0": "Undef",
"1": "Name",
"2": "Title",
"3": "Sex",
"4": "HeritageGroup",
"5": "Template",
"6": "AttackersName",
"7": "Inscription",
"8": "ScribeName",
"9": "VendorsName",
"10": "Fellowship",
"11": "MonarchsName",
"12": "LockCode",
"13": "KeyCode",
"14": "Use",
"15": "ShortDesc",
"16": "LongDesc",
"17": "ActivationTalk",
"18": "UseMessage",
"19": "ItemHeritageGroupRestriction",
"20": "PluralName",
"21": "MonarchsTitle",
"22": "ActivationFailure",
"23": "ScribeAccount",
"24": "TownName",
"25": "CraftsmanName",
"26": "UsePkServerError",
"27": "ScoreCachedText",
"28": "ScoreDefaultEntryFormat",
"29": "ScoreFirstEntryFormat",
"30": "ScoreLastEntryFormat",
"31": "ScoreOnlyEntryFormat",
"32": "ScoreNoEntry",
"33": "Quest",
"34": "GeneratorEvent",
"35": "PatronsTitle",
"36": "HouseOwnerName",
"37": "QuestRestriction",
"38": "AppraisalPortalDestination",
"39": "TinkerName",
"40": "ImbuerName",
"41": "HouseOwnerAccount",
"42": "DisplayName",
"43": "DateOfBirth",
"44": "ThirdPartyApi",
"45": "KillQuest",
"46": "Afk",
"47": "AllegianceName",
"48": "AugmentationAddQuest",
"49": "KillQuest2",
"50": "KillQuest3",
"51": "UseSendsSignal",
"52": "GearPlatingName",
"8006": "PCAPRecordedCurrentMotionState",
"8031": "PCAPRecordedServerName",
"8032": "PCAPRecordedCharacterName",
"9001": "AllegianceMotd",
"9002": "AllegianceMotdSetBy",
"9003": "AllegianceSpeakerTitle",
"9004": "AllegianceSeneschalTitle",
"9005": "AllegianceCastellanTitle",
"9006": "GodState",
"9007": "TinkerLog",
"184549376": "SecondaryName_Decal"
},
"comments": {},
"attributes": {},
"source_file": "StringValueKey.cs"
}
}

View file

@ -0,0 +1,84 @@
{
"WeenieType": {
"type": "uint",
"values": {
"0": "Undef",
"1": "Generic",
"2": "Clothing",
"3": "MissileLauncher",
"4": "Missile",
"5": "Ammunition",
"6": "MeleeWeapon",
"7": "Portal",
"8": "Book",
"9": "Coin",
"10": "Creature",
"11": "Admin",
"12": "Vendor",
"13": "HotSpot",
"14": "Corpse",
"15": "Cow",
"16": "AI",
"17": "Machine",
"18": "Food",
"19": "Door",
"20": "Chest",
"21": "Container",
"22": "Key",
"23": "Lockpick",
"24": "PressurePlate",
"25": "LifeStone",
"26": "Switch",
"27": "PKModifier",
"28": "Healer",
"29": "LightSource",
"30": "Allegiance",
"31": "UNKNOWN__GUESSEDNAME32",
"32": "SpellComponent",
"33": "ProjectileSpell",
"34": "Scroll",
"35": "Caster",
"36": "Channel",
"37": "ManaStone",
"38": "Gem",
"39": "AdvocateFane",
"40": "AdvocateItem",
"41": "Sentinel",
"42": "GSpellEconomy",
"43": "LSpellEconomy",
"44": "CraftTool",
"45": "LScoreKeeper",
"46": "GScoreKeeper",
"47": "GScoreGatherer",
"48": "ScoreBook",
"49": "EventCoordinator",
"50": "Entity",
"51": "Stackable",
"52": "HUD",
"53": "House",
"54": "Deed",
"55": "SlumLord",
"56": "Hook",
"57": "Storage",
"58": "BootSpot",
"59": "HousePortal",
"60": "Game",
"61": "GamePiece",
"62": "SkillAlterationDevice",
"63": "AttributeTransferDevice",
"64": "Hooker",
"65": "AllegianceBindstone",
"66": "InGameStatKeeper",
"67": "AugmentationDevice",
"68": "SocialManager",
"69": "Pet",
"70": "PetDevice",
"71": "CombatPet"
},
"comments": {
"UNKNOWN__GUESSEDNAME32": "NOTE: Missing 1"
},
"attributes": {},
"source_file": "WeenieType.cs"
}
}

View file

@ -0,0 +1,23 @@
{
"WieldRequirement": {
"type": "int",
"values": {
"0": "Invalid",
"1": "Skill",
"2": "RawSkill",
"3": "Attrib",
"4": "RawAttrib",
"5": "SecondaryAttrib",
"6": "RawSecondaryAttrib",
"7": "Level",
"8": "Training",
"9": "IntStat",
"10": "BoolStat",
"11": "CreatureType",
"12": "HeritageType"
},
"comments": {},
"attributes": {},
"source_file": "WieldRequirement.cs"
}
}

View file

@ -0,0 +1,294 @@
#!/usr/bin/env python3
"""
Comprehensive enum extraction from Mag-Plugins/Shared/Constants directory.
This script extracts ALL enum definitions from the Mag-Plugins source code
and creates structured JSON mappings for the inventory service.
"""
import re
import json
import os
from pathlib import Path
from typing import Dict, List, Any, Tuple, Optional
def extract_enum_from_file(file_path: Path) -> Tuple[str, Dict[str, Any]]:
"""Extract enum definition from a C# file."""
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# Find enum declaration
enum_match = re.search(r'public enum (\w+)(?:\s*:\s*(\w+))?\s*{', content)
if not enum_match:
return None, {}
enum_name = enum_match.group(1)
enum_type = enum_match.group(2) or 'int'
print(f"Extracting {enum_name} from {file_path.name}")
# Extract enum entries
entries = {}
comments = {}
attributes = {}
# Pattern to match enum entries with various formats
# Supports: Name = Value, Name, Name = 0x12345, etc.
pattern = r'^\s*(?:\[([^\]]+)\])?\s*(?:/// <summary>\s*([^<]*?)\s*/// </summary>\s*)?(?:\[([^\]]+)\])?\s*(\w+)(?:\s*=\s*([^,]+?))?\s*,?\s*(?://\s*(.*))?$'
lines = content.split('\n')
in_enum = False
current_value = 0
for line in lines:
# Check if we're entering the enum
if f'enum {enum_name}' in line:
in_enum = True
continue
# Check if we're exiting the enum
if in_enum and '}' in line and not line.strip().startswith('//'):
break
if in_enum:
match = re.match(pattern, line)
if match:
attr1, summary, attr2, name, value, comment = match.groups()
# Parse value
if value:
value = value.strip()
if value.startswith('0x') and ' ' not in value:
# Simple hex value
parsed_value = int(value, 16)
elif value.isdigit():
# Simple integer
parsed_value = int(value)
elif '|' in value or '<<' in value or '+' in value:
# Complex expression - store as string for now
parsed_value = f"EXPR:{value}"
else:
# Try simple conversion
try:
parsed_value = int(value)
except ValueError:
parsed_value = f"VALUE:{value}"
else:
parsed_value = current_value
entries[parsed_value] = name
# Update current_value for auto-increment
if isinstance(parsed_value, int):
current_value = parsed_value + 1
else:
# For non-numeric values, increment anyway for next entry
current_value += 1
# Store metadata
if summary:
comments[name] = summary.strip()
if comment:
comments[name] = comment.strip()
if attr1 or attr2:
attributes[name] = (attr1 or '') + ' ' + (attr2 or '')
return enum_name, {
'type': enum_type,
'values': entries,
'comments': comments,
'attributes': attributes,
'source_file': file_path.name
}
def extract_skill_names():
"""Extract skill names with their indices from Skill.cs"""
skill_file = Path('/home/erik/MosswartOverlord/Mag-Plugins/Shared/Constants/Skill.cs')
with open(skill_file, 'r') as f:
content = f.read()
skills = {}
lines = content.split('\n')
in_enum = False
index = 0
for line in lines:
if 'enum Skill' in line:
in_enum = True
continue
if in_enum and '}' in line:
break
if in_enum:
# Match skill entries like "None," or "Axe, /* Retired */"
match = re.match(r'^\s*(\w+),?\s*(?:/\*\s*([^*]*)\s*\*/)?', line)
if match:
skill_name = match.group(1)
status = match.group(2) or "Active"
skills[index] = {
'name': skill_name,
'status': status.strip()
}
index += 1
return skills
def categorize_enums():
"""Create logical categories for different enum types."""
return {
'item_properties': {
'description': 'Item property value keys for different data types',
'enums': ['IntValueKey', 'DoubleValueKey', 'StringValueKey', 'BoolValueKey', 'QuadValueKey']
},
'item_classification': {
'description': 'Item type and material classification',
'enums': ['ItemType', 'MaterialType', 'WeenieType']
},
'game_mechanics': {
'description': 'Skills, spells, and game system enums',
'enums': ['Skill', 'SpellCategory', 'WieldRequirement']
},
'technical': {
'description': 'Technical flags and masks for game engine',
'enums': ['CoverageMask', 'EquipMask']
}
}
def create_translation_mappings():
"""Create user-friendly translations for important enum values."""
# Map IntValueKey values to more descriptive names
int_value_translations = {
5: 'Encumbrance',
19: 'Value (Pyreals)',
25: 'Level',
28: 'Armor Level',
44: 'Base Damage',
45: 'Damage Type',
48: 'Weapon Skill',
158: 'Wield Requirements',
160: 'Wield Difficulty',
218103842: 'Maximum Damage',
218103849: 'Icon Overlay',
218103850: 'Icon Underlay'
}
# Material type friendly names
material_translations = {
0: 'Unknown',
1: 'Ceramic',
20: 'Diamond',
21: 'Emerald',
31: 'Ruby',
32: 'Sapphire'
}
return {
'int_values': int_value_translations,
'materials': material_translations
}
def main():
"""Main extraction process."""
constants_dir = Path('/home/erik/MosswartOverlord/Mag-Plugins/Shared/Constants')
output_dir = Path('/home/erik/MosswartOverlord/inventory-service')
# Ensure output directory exists
output_dir.mkdir(exist_ok=True)
print("Starting comprehensive enum extraction from Mag-Plugins/Shared/Constants...")
# Extract all enum files
all_enums = {}
enum_files = list(constants_dir.glob('*.cs'))
for enum_file in enum_files:
if enum_file.name == 'Dictionaries.cs': # Skip non-enum files
continue
enum_name, enum_data = extract_enum_from_file(enum_file)
if enum_name and enum_data:
all_enums[enum_name] = enum_data
# Special handling for Skills (has complex structure)
skill_data = extract_skill_names()
all_enums['Skill'] = {
'type': 'indexed',
'values': skill_data,
'source_file': 'Skill.cs'
}
# Create categorized structure
categories = categorize_enums()
translations = create_translation_mappings()
# Save complete enum database
complete_data = {
'metadata': {
'extracted_at': '2025-06-10',
'source': 'Mag-Plugins/Shared/Constants',
'total_enums': len(all_enums),
'version': '1.0.0'
},
'categories': categories,
'translations': translations,
'enums': all_enums
}
# Save main database
main_output = output_dir / 'complete_enum_database.json'
with open(main_output, 'w') as f:
json.dump(complete_data, f, indent=2)
print(f"Saved complete enum database to {main_output}")
# Save individual enum files for backward compatibility
individual_dir = output_dir / 'enums'
individual_dir.mkdir(exist_ok=True)
for enum_name, enum_data in all_enums.items():
enum_file = individual_dir / f'{enum_name}.json'
with open(enum_file, 'w') as f:
json.dump({enum_name: enum_data}, f, indent=2)
# Update existing files for backward compatibility
if 'IntValueKey' in all_enums:
legacy_int_file = output_dir / 'int_value_enums.json'
with open(legacy_int_file, 'w') as f:
json.dump(all_enums['IntValueKey']['values'], f, indent=2)
print(f"Updated legacy file: {legacy_int_file}")
# Create comprehensive summary
print("\n" + "="*60)
print("EXTRACTION SUMMARY")
print("="*60)
for enum_name, enum_data in all_enums.items():
value_count = len(enum_data.get('values', {}))
enum_type = enum_data.get('type', 'unknown')
print(f"{enum_name:20} | {value_count:4} values | Type: {enum_type}")
print(f"\nTotal enums extracted: {len(all_enums)}")
print(f"Files created:")
print(f" - {main_output}")
print(f" - {len(all_enums)} individual enum files in {individual_dir}/")
# Show sample translations
print("\nSample enum translations:")
for enum_name in ['IntValueKey', 'MaterialType', 'ItemType', 'Skill']:
if enum_name in all_enums:
values = all_enums[enum_name]['values']
if isinstance(values, dict):
sample_keys = list(values.keys())[:3]
for key in sample_keys:
if isinstance(values[key], dict):
print(f" {enum_name}[{key}] = {values[key].get('name', values[key])}")
else:
print(f" {enum_name}[{key}] = {values[key]}")
if __name__ == '__main__':
main()

View file

@ -0,0 +1,268 @@
#!/usr/bin/env python3
"""
Comprehensive enum extraction from Mag-Plugins/Shared directory.
Extracts all enums, dictionaries, and data needed for rich tooltip display.
"""
import json
import re
import csv
from pathlib import Path
from typing import Dict, Any
def extract_csharp_enum(file_path: Path) -> Dict[str, Any]:
"""Extract enum definition from C# file."""
try:
content = file_path.read_text(encoding='utf-8')
# Find enum declaration
enum_match = re.search(r'public enum (\w+)(?:\s*:\s*\w+)?\s*{([^}]+)}', content, re.DOTALL)
if not enum_match:
return {}
enum_name = enum_match.group(1)
enum_body = enum_match.group(2)
values = {}
for line in enum_body.split('\n'):
line = line.strip()
if not line or line.startswith('//'):
continue
# Parse enum values (handle various formats)
if '=' in line:
parts = line.split('=')
if len(parts) >= 2:
name = parts[0].strip().rstrip(',')
value_part = parts[1].strip().rstrip(',')
# Handle hex values
if value_part.startswith('0x'):
try:
value = int(value_part, 16)
values[str(value)] = name
except ValueError:
pass
# Handle decimal values
elif value_part.isdigit():
values[value_part] = name
# Handle expressions (for flags)
elif '|' in value_part:
values[f"EXPR:{value_part}"] = name
else:
# Auto-increment enum
name = line.rstrip(',').strip()
if name and not name.startswith('//'):
values[str(len(values))] = name
return {
'name': enum_name,
'values': values,
'source_file': str(file_path.name)
}
except Exception as e:
print(f"Error extracting enum from {file_path}: {e}")
return {}
def extract_dictionaries_cs(file_path: Path) -> Dict[str, Any]:
"""Extract dictionary mappings from Dictionaries.cs file."""
try:
content = file_path.read_text(encoding='utf-8')
dictionaries = {}
# Look for dictionary definitions with various patterns
dict_patterns = [
r'public static readonly Dictionary<int, string> (\w+) = new Dictionary<int, string>\s*\n\s*{([^}]+)}',
r'public static readonly Dictionary<int, string> (\w+) = new Dictionary<int, string>\(\)\s*\n\s*{([^}]+)}'
]
for pattern in dict_patterns:
for match in re.finditer(pattern, content, re.DOTALL):
dict_name = match.group(1)
dict_body = match.group(2)
values = {}
for line in dict_body.split('\n'):
line = line.strip()
if not line or line.startswith('//'):
continue
# Parse dictionary entries: { 0x1, "value" } or { 1, "value" }
entry_patterns = [
r'{\s*0x([0-9A-Fa-f]+),\s*"([^"]+)"\s*}', # Hex format
r'{\s*(\d+),\s*"([^"]+)"\s*}' # Decimal format
]
for entry_pattern in entry_patterns:
entry_match = re.search(entry_pattern, line)
if entry_match:
key_str = entry_match.group(1)
value = entry_match.group(2)
# Convert hex to decimal if needed
if 'x' in entry_pattern:
key = str(int(key_str, 16))
else:
key = key_str
values[key] = value
break
if values:
dictionaries[dict_name] = {
'name': dict_name,
'values': values,
'source_file': 'Dictionaries.cs'
}
return dictionaries
except Exception as e:
print(f"Error extracting dictionaries: {e}")
return {}
def extract_spells_csv(file_path: Path) -> Dict[str, Any]:
"""Extract spell data from Spells.csv."""
try:
spells = {}
# Try different encodings
for encoding in ['utf-8', 'latin1', 'cp1252']:
try:
with open(file_path, 'r', encoding=encoding) as f:
reader = csv.DictReader(f)
for row in reader:
spell_id = row.get('Id', '').strip()
if spell_id and spell_id.isdigit():
spells[spell_id] = {
'id': int(spell_id),
'name': row.get('Name', '').strip(),
'description': row.get('Description', '').strip(),
'school': row.get('School', '').strip(),
'difficulty': row.get('Difficulty', '').strip(),
'duration': row.get('Duration', '').strip(),
'mana': row.get('Mana', '').strip(),
'family': row.get('Family', '').strip(),
'speed': row.get('Speed', '').strip(),
'target_effect': row.get('TargetEffect', '').strip(),
'target_mask': row.get('TargetMask', '').strip()
}
break
except UnicodeDecodeError:
continue
return {
'name': 'Spells',
'values': spells,
'source_file': 'Spells.csv'
}
except Exception as e:
print(f"Error extracting spells: {e}")
return {}
def extract_object_class_cs(file_path: Path) -> Dict[str, Any]:
"""Extract ObjectClass enum specifically."""
try:
content = file_path.read_text(encoding='utf-8')
# Find ObjectClass enum
enum_match = re.search(r'public enum ObjectClass\s*{([^}]+)}', content, re.DOTALL)
if not enum_match:
return {}
enum_body = enum_match.group(1)
values = {}
current_value = 0
for line in enum_body.split('\n'):
line = line.strip()
if not line or line.startswith('//'):
continue
if '=' in line:
parts = line.split('=')
if len(parts) >= 2:
name = parts[0].strip().rstrip(',')
value_str = parts[1].strip().rstrip(',')
try:
current_value = int(value_str)
values[str(current_value)] = name
current_value += 1
except ValueError:
pass
else:
name = line.rstrip(',').strip()
if name and not name.startswith('//'):
values[str(current_value)] = name
current_value += 1
return {
'name': 'ObjectClass',
'values': values,
'source_file': 'ObjectClass.cs'
}
except Exception as e:
print(f"Error extracting ObjectClass: {e}")
return {}
def main():
base_path = Path('/home/erik/MosswartOverlord/Mag-Plugins/Shared')
constants_path = base_path / 'Constants'
spells_path = base_path / 'Spells'
comprehensive_database = {
'metadata': {
'extracted_at': '2025-06-10',
'source': 'Mag-Plugins/Shared (comprehensive)',
'version': '2.0.0'
},
'enums': {},
'dictionaries': {},
'spells': {},
'object_classes': {}
}
# Extract all constant enums
for cs_file in constants_path.glob('*.cs'):
if cs_file.name in ['Dictionaries.cs']:
continue # Handle separately
enum_data = extract_csharp_enum(cs_file)
if enum_data:
comprehensive_database['enums'][enum_data['name']] = enum_data
print(f"✓ Extracted enum: {enum_data['name']} ({len(enum_data['values'])} values)")
# Extract ObjectClass enum
object_class_file = base_path / 'ObjectClass.cs'
if object_class_file.exists():
object_class_data = extract_object_class_cs(object_class_file)
if object_class_data:
comprehensive_database['object_classes'] = object_class_data
print(f"✓ Extracted ObjectClass: {len(object_class_data['values'])} values")
# Extract dictionaries
dict_file = constants_path / 'Dictionaries.cs'
if dict_file.exists():
dict_data = extract_dictionaries_cs(dict_file)
comprehensive_database['dictionaries'] = dict_data
print(f"✓ Extracted dictionaries: {len(dict_data)} dictionaries")
# Extract spells
spells_file = spells_path / 'Spells.csv'
if spells_file.exists():
spell_data = extract_spells_csv(spells_file)
if spell_data:
comprehensive_database['spells'] = spell_data
print(f"✓ Extracted spells: {len(spell_data['values'])} spells")
# Save comprehensive database
output_file = Path('/home/erik/MosswartOverlord/inventory-service/comprehensive_enum_database_v2.json')
with open(output_file, 'w') as f:
json.dump(comprehensive_database, f, indent=2)
print(f"\n✅ Comprehensive enum database saved to: {output_file}")
print(f"📊 Total enums: {len(comprehensive_database['enums'])}")
print(f"📊 Total dictionaries: {len(comprehensive_database['dictionaries'])}")
print(f"📊 Total spells: {len(comprehensive_database['spells'].get('values', {}))}")
print(f"📊 Object classes: {len(comprehensive_database['object_classes'].get('values', {}))}")
if __name__ == '__main__':
main()

View file

@ -0,0 +1,130 @@
#!/usr/bin/env python3
"""
Extract enum definitions from Mag-Plugins C# files into JSON mappings.
This script parses the IntValueKey.cs file to create a mapping between
numeric enum values and their human-readable names for inventory processing.
"""
import re
import json
import os
from pathlib import Path
def extract_int_value_enums(cs_file_path):
"""Extract IntValueKey enum definitions from C# file."""
with open(cs_file_path, 'r') as f:
content = f.read()
# Pattern to match enum entries: EnumName = Value,
pattern = r'^\s*(?:\[[^\]]+\])?\s*(\w+)\s*=\s*(\d+),?\s*(?://.*)?$'
enums = {}
in_enum = False
for line in content.split('\n'):
# Check if we're entering the enum
if 'enum IntValueKey' in line:
in_enum = True
continue
# Check if we're exiting the enum
if in_enum and line.strip() == '}':
break
# Parse enum entries
if in_enum:
match = re.match(pattern, line)
if match:
name = match.group(1)
value = int(match.group(2))
enums[value] = name
return enums
def create_property_mappings():
"""Create organized property mappings for different item aspects."""
# Based on analysis of the enum values and common item properties
property_categories = {
'basic': {
5: 'encumbrance', # EncumbranceVal
19: 'value', # Value
25: 'level', # Level
28: 'armor_level', # ArmorLevel
44: 'damage', # Damage
45: 'damage_type', # DamageType
},
'requirements': {
158: 'wield_requirement', # Common wield requirement key (from JSON data)
160: 'wield_level', # Common wield level key (from JSON data)
48: 'weapon_skill', # WeaponSkill
},
'combat': {
218103842: 'max_damage', # MaxDamage_Decal
36: 'resist_magic', # ResistMagic
56: 'shield_value', # ShieldValue
},
'display': {
218103809: 'icon', # Icon_Decal_DID
218103849: 'icon_overlay', # IconOverlay_Decal_DID
218103850: 'icon_underlay', # IconUnderlay_Decal_DID
},
'metadata': {
218103808: 'weenie_class_id', # WeenieClassId_Decal
218103847: 'physics_data_flags', # PhysicsDataFlags_Decal
218103831: 'object_desc_flags', # ObjectDescriptionFlags_Decal
}
}
return property_categories
def main():
"""Main extraction process."""
# Paths
mag_plugins_path = Path('/home/erik/MosswartOverlord/Mag-Plugins')
int_value_key_path = mag_plugins_path / 'Shared' / 'Constants' / 'IntValueKey.cs'
output_dir = Path('/home/erik/MosswartOverlord/inventory-service')
# Create output directory
output_dir.mkdir(exist_ok=True)
# Extract all enum values
print("Extracting IntValueKey enums...")
int_enums = extract_int_value_enums(int_value_key_path)
print(f"Found {len(int_enums)} enum definitions")
# Create property categories
property_categories = create_property_mappings()
# Save complete enum mapping
enum_output = output_dir / 'int_value_enums.json'
with open(enum_output, 'w') as f:
json.dump(int_enums, f, indent=2)
print(f"Saved complete enum mapping to {enum_output}")
# Save categorized mappings
categories_output = output_dir / 'property_categories.json'
with open(categories_output, 'w') as f:
json.dump(property_categories, f, indent=2)
print(f"Saved property categories to {categories_output}")
# Print some interesting findings
print("\nKey mappings found:")
interesting_keys = [5, 19, 28, 44, 158, 160, 218103809, 218103842, 218103847, 218103849]
for key in interesting_keys:
if key in int_enums:
print(f" {key}: {int_enums[key]}")
print(f"\nFiles created in {output_dir}/")
print("- int_value_enums.json: Complete enum mapping")
print("- property_categories.json: Organized property categories")
if __name__ == '__main__':
main()

View file

@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""
Extract spell names from Mag-Plugins/Shared/Spells/Spells.csv for spell ID translation.
"""
import csv
import json
from pathlib import Path
def extract_spell_names():
"""Extract spell ID to name mappings from Spells.csv."""
csv_path = Path('/home/erik/MosswartOverlord/Mag-Plugins/Shared/Spells/Spells.csv')
if not csv_path.exists():
print(f"❌ Spells.csv not found at {csv_path}")
return {}
spell_mappings = {}
# Try different encodings
encodings = ['utf-8', 'latin-1', 'windows-1252', 'utf-8-sig']
for encoding in encodings:
try:
with open(csv_path, 'r', encoding=encoding) as f:
reader = csv.DictReader(f)
print(f"✓ Successfully opened with {encoding} encoding")
for row in reader:
try:
spell_id = int(row['Id'])
spell_name = row['Name'].strip()
spell_description = row.get('Description', '').strip()
spell_school = row.get('School', '').strip()
spell_family = row.get('Family', '').strip()
spell_difficulty = row.get('Difficulty', '').strip()
spell_duration = row.get('Duration', '').strip()
spell_mana = row.get('Mana', '').strip()
# Create comprehensive spell data
spell_data = {
'name': spell_name,
'description': spell_description,
'school': spell_school,
'family': spell_family,
'difficulty': spell_difficulty,
'duration': spell_duration,
'mana': spell_mana
}
spell_mappings[spell_id] = spell_data
except (ValueError, KeyError) as e:
print(f"⚠️ Skipping invalid row: {e}")
continue
# If we get here successfully, we're done
break
except Exception as e:
print(f"❌ Error with {encoding} encoding: {e}")
continue
if spell_mappings:
print(f"✓ Extracted {len(spell_mappings)} spell entries")
else:
print("❌ Failed to extract spells with any encoding")
return spell_mappings
def save_spell_database(spell_mappings):
"""Save spell mappings to JSON file."""
output_path = Path('/home/erik/MosswartOverlord/inventory-service/spell_database.json')
spell_database = {
'metadata': {
'version': '1.0.0',
'source': 'Mag-Plugins/Shared/Spells/Spells.csv',
'total_spells': len(spell_mappings),
'description': 'Spell ID to name/data mappings for Asheron\'s Call'
},
'spells': spell_mappings
}
try:
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(spell_database, f, indent=2, ensure_ascii=False)
print(f"✓ Spell database saved to {output_path}")
return True
except Exception as e:
print(f"❌ Error saving spell database: {e}")
return False
def main():
"""Main extraction process."""
print("Extracting spell names from Spells.csv...")
# Extract spell mappings
spell_mappings = extract_spell_names()
if not spell_mappings:
print("❌ No spells extracted")
return
# Save to JSON file
if save_spell_database(spell_mappings):
# Show some sample spells
print("\nSample spell entries:")
for spell_id, spell_data in list(spell_mappings.items())[:5]:
print(f" {spell_id}: {spell_data['name']} ({spell_data['school']})")
print(f"\n✓ Successfully processed {len(spell_mappings)} spells")
else:
print("❌ Failed to save spell database")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,37 @@
#!/usr/bin/env python3
"""
Initialize the inventory service database.
Creates all tables and performs initial setup.
"""
import asyncio
import logging
import os
import sqlalchemy as sa
from database import Base, DATABASE_URL, create_indexes
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
async def init_database():
"""Initialize database tables and indexes."""
try:
# Create engine
engine = sa.create_engine(DATABASE_URL)
# Create all tables
logger.info("Creating database tables...")
Base.metadata.create_all(engine)
# Create indexes
logger.info("Creating performance indexes...")
create_indexes(engine)
logger.info("Database initialization completed successfully")
except Exception as e:
logger.error(f"Database initialization failed: {e}")
raise
if __name__ == "__main__":
asyncio.run(init_database())

View file

@ -0,0 +1,450 @@
{
"0": "Undef",
"1": "ItemType",
"2": "CreatureType",
"3": "PaletteTemplate",
"4": "ClothingPriority",
"5": "EncumbranceVal",
"6": "ItemsCapacity",
"7": "ContainersCapacity",
"8": "Mass",
"9": "ValidLocations",
"10": "CurrentWieldedLocation",
"11": "MaxStackSize",
"12": "StackSize",
"13": "StackUnitEncumbrance",
"14": "StackUnitMass",
"15": "StackUnitValue",
"16": "ItemUseable",
"17": "RareId",
"18": "UiEffects",
"19": "Value",
"20": "CoinValue",
"21": "TotalExperience",
"22": "AvailableCharacter",
"23": "TotalSkillCredits",
"24": "AvailableSkillCredits",
"25": "Level",
"26": "AccountRequirements",
"27": "ArmorType",
"28": "ArmorLevel",
"29": "AllegianceCpPool",
"30": "AllegianceRank",
"31": "ChannelsAllowed",
"32": "ChannelsActive",
"33": "Bonded",
"34": "MonarchsRank",
"35": "AllegianceFollowers",
"36": "ResistMagic",
"37": "ResistItemAppraisal",
"38": "ResistLockpick",
"39": "DeprecatedResistRepair",
"40": "CombatMode",
"41": "CurrentAttackHeight",
"42": "CombatCollisions",
"43": "NumDeaths",
"44": "Damage",
"45": "DamageType",
"46": "DefaultCombatStyle",
"47": "AttackType",
"48": "WeaponSkill",
"49": "WeaponTime",
"50": "AmmoType",
"51": "CombatUse",
"52": "ParentLocation",
"53": "PlacementPosition",
"54": "WeaponEncumbrance",
"55": "WeaponMass",
"56": "ShieldValue",
"57": "ShieldEncumbrance",
"58": "MissileInventoryLocation",
"59": "FullDamageType",
"60": "WeaponRange",
"61": "AttackersSkill",
"62": "DefendersSkill",
"63": "AttackersSkillValue",
"64": "AttackersClass",
"65": "Placement",
"66": "CheckpointStatus",
"67": "Tolerance",
"68": "TargetingTactic",
"69": "CombatTactic",
"70": "HomesickTargetingTactic",
"71": "NumFollowFailures",
"72": "FriendType",
"73": "FoeType",
"74": "MerchandiseItemTypes",
"75": "MerchandiseMinValue",
"76": "MerchandiseMaxValue",
"77": "NumItemsSold",
"78": "NumItemsBought",
"79": "MoneyIncome",
"80": "MoneyOutflow",
"81": "MaxGeneratedObjects",
"82": "InitGeneratedObjects",
"83": "ActivationResponse",
"84": "OriginalValue",
"85": "NumMoveFailures",
"86": "MinLevel",
"87": "MaxLevel",
"88": "LockpickMod",
"89": "BoosterEnum",
"90": "BoostValue",
"91": "MaxStructure",
"92": "Structure",
"93": "PhysicsState",
"94": "TargetType",
"95": "RadarBlipColor",
"96": "EncumbranceCapacity",
"97": "LoginTimestamp",
"98": "CreationTimestamp",
"99": "PkLevelModifier",
"100": "GeneratorType",
"101": "AiAllowedCombatStyle",
"102": "LogoffTimestamp",
"103": "GeneratorDestructionType",
"104": "ActivationCreateClass",
"105": "ItemWorkmanship",
"106": "ItemSpellcraft",
"107": "ItemCurMana",
"108": "ItemMaxMana",
"109": "ItemDifficulty",
"110": "ItemAllegianceRankLimit",
"111": "PortalBitmask",
"112": "AdvocateLevel",
"113": "Gender",
"114": "Attuned",
"115": "ItemSkillLevelLimit",
"116": "GateLogic",
"117": "ItemManaCost",
"118": "Logoff",
"119": "Active",
"120": "AttackHeight",
"121": "NumAttackFailures",
"122": "AiCpThreshold",
"123": "AiAdvancementStrategy",
"124": "Version",
"125": "Age",
"126": "VendorHappyMean",
"127": "VendorHappyVariance",
"128": "CloakStatus",
"129": "VitaeCpPool",
"130": "NumServicesSold",
"131": "MaterialType",
"132": "NumAllegianceBreaks",
"133": "ShowableOnRadar",
"134": "PlayerKillerStatus",
"135": "VendorHappyMaxItems",
"136": "ScorePageNum",
"137": "ScoreConfigNum",
"138": "ScoreNumScores",
"139": "DeathLevel",
"140": "AiOptions",
"141": "OpenToEveryone",
"142": "GeneratorTimeType",
"143": "GeneratorStartTime",
"144": "GeneratorEndTime",
"145": "GeneratorEndDestructionType",
"146": "XpOverride",
"147": "NumCrashAndTurns",
"148": "ComponentWarningThreshold",
"149": "HouseStatus",
"150": "HookPlacement",
"151": "HookType",
"152": "HookItemType",
"153": "AiPpThreshold",
"154": "GeneratorVersion",
"155": "HouseType",
"156": "PickupEmoteOffset",
"157": "WeenieIteration",
"158": "WieldRequirements",
"159": "WieldSkillType",
"160": "WieldDifficulty",
"161": "HouseMaxHooksUsable",
"162": "HouseCurrentHooksUsable",
"163": "AllegianceMinLevel",
"164": "AllegianceMaxLevel",
"165": "HouseRelinkHookCount",
"166": "SlayerCreatureType",
"167": "ConfirmationInProgress",
"168": "ConfirmationTypeInProgress",
"169": "TsysMutationData",
"170": "NumItemsInMaterial",
"171": "NumTimesTinkered",
"172": "AppraisalLongDescDecoration",
"173": "AppraisalLockpickSuccessPercent",
"174": "AppraisalPages",
"175": "AppraisalMaxPages",
"176": "AppraisalItemSkill",
"177": "GemCount",
"178": "GemType",
"179": "ImbuedEffect",
"180": "AttackersRawSkillValue",
"181": "ChessRank",
"182": "ChessTotalGames",
"183": "ChessGamesWon",
"184": "ChessGamesLost",
"185": "TypeOfAlteration",
"186": "SkillToBeAltered",
"187": "SkillAlterationCount",
"188": "HeritageGroup",
"189": "TransferFromAttribute",
"190": "TransferToAttribute",
"191": "AttributeTransferCount",
"192": "FakeFishingSkill",
"193": "NumKeys",
"194": "DeathTimestamp",
"195": "PkTimestamp",
"196": "VictimTimestamp",
"197": "HookGroup",
"198": "AllegianceSwearTimestamp",
"199": "HousePurchaseTimestamp",
"200": "RedirectableEquippedArmorCount",
"201": "MeleeDefenseImbuedEffectTypeCache",
"202": "MissileDefenseImbuedEffectTypeCache",
"203": "MagicDefenseImbuedEffectTypeCache",
"204": "ElementalDamageBonus",
"205": "ImbueAttempts",
"206": "ImbueSuccesses",
"207": "CreatureKills",
"208": "PlayerKillsPk",
"209": "PlayerKillsPkl",
"210": "RaresTierOne",
"211": "RaresTierTwo",
"212": "RaresTierThree",
"213": "RaresTierFour",
"214": "RaresTierFive",
"215": "AugmentationStat",
"216": "AugmentationFamilyStat",
"217": "AugmentationInnateFamily",
"218": "AugmentationInnateStrength",
"219": "AugmentationInnateEndurance",
"220": "AugmentationInnateCoordination",
"221": "AugmentationInnateQuickness",
"222": "AugmentationInnateFocus",
"223": "AugmentationInnateSelf",
"224": "AugmentationSpecializeSalvaging",
"225": "AugmentationSpecializeItemTinkering",
"226": "AugmentationSpecializeArmorTinkering",
"227": "AugmentationSpecializeMagicItemTinkering",
"228": "AugmentationSpecializeWeaponTinkering",
"229": "AugmentationExtraPackSlot",
"230": "AugmentationIncreasedCarryingCapacity",
"231": "AugmentationLessDeathItemLoss",
"232": "AugmentationSpellsRemainPastDeath",
"233": "AugmentationCriticalDefense",
"234": "AugmentationBonusXp",
"235": "AugmentationBonusSalvage",
"236": "AugmentationBonusImbueChance",
"237": "AugmentationFasterRegen",
"238": "AugmentationIncreasedSpellDuration",
"239": "AugmentationResistanceFamily",
"240": "AugmentationResistanceSlash",
"241": "AugmentationResistancePierce",
"242": "AugmentationResistanceBlunt",
"243": "AugmentationResistanceAcid",
"244": "AugmentationResistanceFire",
"245": "AugmentationResistanceFrost",
"246": "AugmentationResistanceLightning",
"247": "RaresTierOneLogin",
"248": "RaresTierTwoLogin",
"249": "RaresTierThreeLogin",
"250": "RaresTierFourLogin",
"251": "RaresTierFiveLogin",
"252": "RaresLoginTimestamp",
"253": "RaresTierSix",
"254": "RaresTierSeven",
"255": "RaresTierSixLogin",
"256": "RaresTierSevenLogin",
"257": "ItemAttributeLimit",
"258": "ItemAttributeLevelLimit",
"259": "ItemAttribute2ndLimit",
"260": "ItemAttribute2ndLevelLimit",
"261": "CharacterTitleId",
"262": "NumCharacterTitles",
"263": "ResistanceModifierType",
"264": "FreeTinkersBitfield",
"265": "EquipmentSetId",
"266": "PetClass",
"267": "Lifespan",
"268": "RemainingLifespan",
"269": "UseCreateQuantity",
"270": "WieldRequirements2",
"271": "WieldSkillType2",
"272": "WieldDifficulty2",
"273": "WieldRequirements3",
"274": "WieldSkillType3",
"275": "WieldDifficulty3",
"276": "WieldRequirements4",
"277": "WieldSkillType4",
"278": "WieldDifficulty4",
"279": "Unique",
"280": "SharedCooldown",
"281": "Faction1Bits",
"282": "Faction2Bits",
"283": "Faction3Bits",
"284": "Hatred1Bits",
"285": "Hatred2Bits",
"286": "Hatred3Bits",
"287": "SocietyRankCelhan",
"288": "SocietyRankEldweb",
"289": "SocietyRankRadblo",
"290": "HearLocalSignals",
"291": "HearLocalSignalsRadius",
"292": "Cleaving",
"293": "AugmentationSpecializeGearcraft",
"294": "AugmentationInfusedCreatureMagic",
"295": "AugmentationInfusedItemMagic",
"296": "AugmentationInfusedLifeMagic",
"297": "AugmentationInfusedWarMagic",
"298": "AugmentationCriticalExpertise",
"299": "AugmentationCriticalPower",
"300": "AugmentationSkilledMelee",
"301": "AugmentationSkilledMissile",
"302": "AugmentationSkilledMagic",
"303": "ImbuedEffect2",
"304": "ImbuedEffect3",
"305": "ImbuedEffect4",
"306": "ImbuedEffect5",
"307": "DamageRating",
"308": "DamageResistRating",
"309": "AugmentationDamageBonus",
"310": "AugmentationDamageReduction",
"311": "ImbueStackingBits",
"312": "HealOverTime",
"313": "CritRating",
"314": "CritDamageRating",
"315": "CritResistRating",
"316": "CritDamageResistRating",
"317": "HealingResistRating",
"318": "DamageOverTime",
"319": "ItemMaxLevel",
"320": "ItemXpStyle",
"321": "EquipmentSetExtra",
"322": "AetheriaBitfield",
"323": "HealingBoostRating",
"324": "HeritageSpecificArmor",
"325": "AlternateRacialSkills",
"326": "AugmentationJackOfAllTrades",
"327": "AugmentationResistanceNether",
"328": "AugmentationInfusedVoidMagic",
"329": "WeaknessRating",
"330": "NetherOverTime",
"331": "NetherResistRating",
"332": "LuminanceAward",
"333": "LumAugDamageRating",
"334": "LumAugDamageReductionRating",
"335": "LumAugCritDamageRating",
"336": "LumAugCritReductionRating",
"337": "LumAugSurgeEffectRating",
"338": "LumAugSurgeChanceRating",
"339": "LumAugItemManaUsage",
"340": "LumAugItemManaGain",
"341": "LumAugVitality",
"342": "LumAugHealingRating",
"343": "LumAugSkilledCraft",
"344": "LumAugSkilledSpec",
"345": "LumAugNoDestroyCraft",
"346": "RestrictInteraction",
"347": "OlthoiLootTimestamp",
"348": "OlthoiLootStep",
"349": "UseCreatesContractId",
"350": "DotResistRating",
"351": "LifeResistRating",
"352": "CloakWeaveProc",
"353": "WeaponType",
"354": "MeleeMastery",
"355": "RangedMastery",
"356": "SneakAttackRating",
"357": "RecklessnessRating",
"358": "DeceptionRating",
"359": "CombatPetRange",
"360": "WeaponAuraDamage",
"361": "WeaponAuraSpeed",
"362": "SummoningMastery",
"363": "HeartbeatLifespan",
"364": "UseLevelRequirement",
"365": "LumAugAllSkills",
"366": "UseRequiresSkill",
"367": "UseRequiresSkillLevel",
"368": "UseRequiresSkillSpec",
"369": "UseRequiresLevel",
"370": "GearDamage",
"371": "GearDamageResist",
"372": "GearCrit",
"373": "GearCritResist",
"374": "GearCritDamage",
"375": "GearCritDamageResist",
"376": "GearHealingBoost",
"377": "GearNetherResist",
"378": "GearLifeResist",
"379": "GearMaxHealth",
"380": "Unknown380",
"381": "PKDamageRating",
"382": "PKDamageResistRating",
"383": "GearPKDamageRating",
"384": "GearPKDamageResistRating",
"385": "Unknown385",
"386": "Overpower",
"387": "OverpowerResist",
"388": "GearOverpower",
"389": "GearOverpowerResist",
"390": "Enlightenment",
"8007": "PCAPRecordedAutonomousMovement",
"8030": "PCAPRecordedMaxVelocityEstimated",
"8041": "PCAPRecordedPlacement",
"8042": "PCAPRecordedAppraisalPages",
"8043": "PCAPRecordedAppraisalMaxPages",
"9008": "CurrentLoyaltyAtLastLogoff",
"9009": "CurrentLeadershipAtLastLogoff",
"9010": "AllegianceOfficerRank",
"9011": "HouseRentTimestamp",
"9012": "Hairstyle",
"9013": "VisualClothingPriority",
"9014": "SquelchGlobal",
"9015": "InventoryOrder",
"218103808": "WeenieClassId_Decal",
"218103809": "Icon_Decal_DID",
"218103810": "Container_Decal_IID",
"218103811": "Landblock_Decal",
"218103812": "ItemSlots_Decal",
"218103813": "PackSlots_Decal",
"218103814": "StackCount_Decal",
"218103815": "StackMax_Decal",
"218103816": "Spell_Decal_DID",
"218103817": "SlotLegacy_Decal",
"218103818": "Wielder_Decal_IID",
"218103819": "WieldingSlot_Decal",
"218103820": "Monarch_Decal_IID",
"218103821": "Coverage_Decal",
"218103822": "EquipableSlots_Decal",
"218103823": "EquipType_Decal",
"218103824": "IconOutline_Decal",
"218103825": "MissileType_Decal",
"218103826": "UsageMask_Decal",
"218103827": "HouseOwner_Decal_IID",
"218103828": "HookMask_Decal",
"218103829": "HookType_Decal",
"218103830": "Setup_Decal_DID",
"218103831": "ObjectDescriptionFlags_Decal",
"218103832": "CreateFlags1_Decal",
"218103833": "CreateFlags2_Decal",
"218103834": "Category_Decal",
"218103835": "Behavior_Decal",
"218103836": "MagicDef_Decal",
"218103837": "SpecialProps_Decal",
"218103838": "SpellCount_Decal",
"218103839": "WeapSpeed_Decal",
"218103840": "EquipSkill_Decal",
"218103841": "DamageType_Decal",
"218103842": "MaxDamage_Decal",
"218103843": "Unknown10_Decal",
"218103844": "Unknown100000_Decal",
"218103845": "Unknown800000_Decal",
"218103846": "Unknown8000000_Decal",
"218103847": "PhysicsDataFlags_Decal",
"218103848": "ActiveSpellCount_Decal",
"218103849": "IconOverlay_Decal_DID",
"218103850": "IconUnderlay_Decal_DID",
"231735296": "Slot_Decal"
}

1112
inventory-service/main.py Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
{
"basic": {
"5": "encumbrance",
"19": "value",
"25": "level",
"28": "armor_level",
"44": "damage",
"45": "damage_type"
},
"requirements": {
"158": "wield_requirement",
"160": "wield_level",
"48": "weapon_skill"
},
"combat": {
"218103842": "max_damage",
"36": "resist_magic",
"56": "shield_value"
},
"display": {
"218103809": "icon",
"218103849": "icon_overlay",
"218103850": "icon_underlay"
},
"metadata": {
"218103808": "weenie_class_id",
"218103847": "physics_data_flags",
"218103831": "object_desc_flags"
}
}

View file

@ -0,0 +1,9 @@
fastapi==0.104.1
uvicorn[standard]==0.24.0
sqlalchemy==1.4.53
asyncpg==0.29.0
databases[postgresql]==0.8.0
pydantic==2.5.0
python-multipart==0.0.6
python-json-logger==2.0.7
psycopg2-binary==2.9.9

File diff suppressed because it is too large Load diff

143
main.py
View file

@ -20,6 +20,7 @@ from fastapi.staticfiles import StaticFiles
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
from typing import Optional
import httpx
# Async database support
from sqlalchemy.dialects.postgresql import insert as pg_insert
@ -49,6 +50,9 @@ logger = logging.getLogger(__name__)
# Get log level from environment (DEBUG, INFO, WARNING, ERROR)
log_level = os.getenv('LOG_LEVEL', 'INFO').upper()
logger.setLevel(getattr(logging, log_level, logging.INFO))
# Inventory service configuration
INVENTORY_SERVICE_URL = os.getenv('INVENTORY_SERVICE_URL', 'http://inventory-service:8000')
# In-memory caches for REST endpoints
_cached_live: dict = {"players": []}
_cached_trails: dict = {"trails": []}
@ -293,29 +297,24 @@ async def get_trails(
# --- GET Inventory Endpoints ---------------------------------
@app.get("/inventory/{character_name}")
async def get_character_inventory(character_name: str):
"""Get the complete inventory for a specific character from the database."""
"""Get the complete inventory for a specific character - inventory service only."""
try:
query = """
SELECT name, icon, object_class, value, burden, has_id_data, item_data, timestamp
FROM character_inventories
WHERE character_name = :character_name
ORDER BY name
"""
rows = await database.fetch_all(query, {"character_name": character_name})
async with httpx.AsyncClient(timeout=10.0) as client:
response = await client.get(
f"{INVENTORY_SERVICE_URL}/inventory/{character_name}"
)
if not rows:
if response.status_code == 200:
return JSONResponse(content=response.json())
elif response.status_code == 404:
raise HTTPException(status_code=404, detail=f"No inventory found for character '{character_name}'")
else:
logger.error(f"Inventory service returned {response.status_code} for {character_name}")
raise HTTPException(status_code=502, detail="Inventory service error")
items = []
for row in rows:
item = dict(row)
items.append(item)
return JSONResponse(content=jsonable_encoder({
"character_name": character_name,
"item_count": len(items),
"items": items
}))
except httpx.RequestError as e:
logger.error(f"Could not reach inventory service: {e}")
raise HTTPException(status_code=503, detail="Inventory service unavailable")
except HTTPException:
raise
except Exception as e:
@ -458,18 +457,42 @@ async def _broadcast_to_browser_clients(snapshot: dict):
browser_conns.discard(ws)
async def _store_inventory(inventory_msg: FullInventoryMessage):
"""Store complete character inventory to database with extracted searchable fields.
Processes each item to extract key fields for indexing while preserving
complete item data in JSONB format. Uses UPSERT to handle item updates.
"""
async def _forward_to_inventory_service(inventory_msg: FullInventoryMessage):
"""Forward inventory data to the inventory microservice for processing."""
try:
# Create inventory directory if it doesn't exist
# Prepare data for inventory service
inventory_data = {
"character_name": inventory_msg.character_name,
"timestamp": inventory_msg.timestamp.isoformat(),
"items": inventory_msg.items
}
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post(
f"{INVENTORY_SERVICE_URL}/process-inventory",
json=inventory_data
)
if response.status_code == 200:
result = response.json()
logger.info(f"Inventory service processed {result['processed']} items for {inventory_msg.character_name}")
else:
logger.error(f"Inventory service error {response.status_code}: {response.text}")
except Exception as e:
logger.error(f"Failed to forward inventory to service: {e}")
# Don't raise - this shouldn't block the main storage
async def _store_inventory(inventory_msg: FullInventoryMessage):
"""Forward inventory data to inventory microservice for processing and storage."""
try:
# Forward to inventory microservice for enhanced processing and storage
await _forward_to_inventory_service(inventory_msg)
# Optional: Create JSON file for debugging (can be removed in production)
inventory_dir = Path("./inventory")
inventory_dir.mkdir(exist_ok=True)
# Store as JSON file for backwards compatibility / debugging
file_path = inventory_dir / f"{inventory_msg.character_name}_inventory.json"
inventory_data = {
"character_name": inventory_msg.character_name,
@ -481,50 +504,8 @@ async def _store_inventory(inventory_msg: FullInventoryMessage):
with open(file_path, 'w') as f:
json.dump(inventory_data, f, indent=2)
# Store items in database
for item in inventory_msg.items:
# Extract searchable fields
item_id = item.get("Id")
if item_id is None:
continue # Skip items without ID
name = item.get("Name", "")
icon = item.get("Icon", 0)
object_class = item.get("ObjectClass", 0)
value = item.get("Value", 0)
burden = item.get("Burden", 0)
has_id_data = item.get("HasIdData", False)
# UPSERT item into database
stmt = pg_insert(character_inventories).values(
character_name=inventory_msg.character_name,
item_id=item_id,
timestamp=inventory_msg.timestamp,
name=name,
icon=icon,
object_class=object_class,
value=value,
burden=burden,
has_id_data=has_id_data,
item_data=item
).on_conflict_do_update(
constraint="uq_char_item",
set_={
"timestamp": inventory_msg.timestamp,
"name": name,
"icon": icon,
"object_class": object_class,
"value": value,
"burden": burden,
"has_id_data": has_id_data,
"item_data": item
}
)
await database.execute(stmt)
except Exception as e:
logger.error(f"Failed to store inventory for {inventory_msg.character_name}: {e}", exc_info=True)
logger.error(f"Failed to forward inventory for {inventory_msg.character_name}: {e}", exc_info=True)
raise
@ -636,13 +617,13 @@ async def ws_receive_snapshots(
logger.debug(f"Updated kills for {snap.character_name}: +{delta} (total from {last} to {snap.kills})")
ws_receive_snapshots._last_kills[key] = snap.kills
except Exception as db_error:
logger.error(f"Database transaction failed for {snap.character_name}: {db_error}", exc_info=True)
logger.error(f"💾 Database transaction failed for {snap.character_name} (session: {snap.session_id[:8]}): {db_error}", exc_info=True)
continue
# Broadcast updated snapshot to all browser clients
await _broadcast_to_browser_clients(snap.dict())
logger.debug(f"Processed telemetry from {snap.character_name}")
logger.debug(f"Processed telemetry from {snap.character_name} (session: {snap.session_id[:8]}, kills: {snap.kills})")
except Exception as e:
logger.error(f"Failed to process telemetry event: {e}", exc_info=True)
logger.error(f"Failed to process telemetry event from {data.get('character_name', 'unknown')}: {e}", exc_info=True)
continue
# --- Rare event: update total and session counters and persist ---
if msg_type == "rare":
@ -892,6 +873,22 @@ async def get_stats(character_name: str):
raise HTTPException(status_code=500, detail="Internal server error")
# -------------------- static frontend ---------------------------
# Custom icon handler that prioritizes clean icons over originals
from fastapi.responses import FileResponse
@app.get("/icons/{icon_filename}")
async def serve_icon(icon_filename: str):
"""Serve icons from static/icons directory"""
# Serve from static/icons directory
icon_path = Path("static/icons") / icon_filename
if icon_path.exists():
return FileResponse(icon_path, media_type="image/png")
# Icon not found
raise HTTPException(status_code=404, detail="Icon not found")
# Icons are now served from static/icons directory
# Serve SPA files (catch-all for frontend routes)
# Mount the single-page application frontend (static assets) at root path
app.mount("/", StaticFiles(directory="static", html=True), name="static")

BIN
static/icons/06000133.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/icons/0600015D.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/0600015F.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

BIN
static/icons/06000160.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/06000162.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

BIN
static/icons/06000163.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/06000164.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/icons/06000165.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/icons/06000167.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/0600016A.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

BIN
static/icons/0600016B.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

BIN
static/icons/0600016D.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/0600016E.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/0600016F.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/06000170.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
static/icons/06000173.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

BIN
static/icons/06000178.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

BIN
static/icons/0600017B.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 B

BIN
static/icons/0600017C.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/06000261.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

BIN
static/icons/060002C4.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
static/icons/060002C5.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
static/icons/060002C6.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/icons/060002C7.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/icons/060002C8.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/icons/060002C9.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/icons/060004C6.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
static/icons/060004C8.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
static/icons/060004CA.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
static/icons/060004DA.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
static/icons/060004DB.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
static/icons/06000F50.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
static/icons/06000F52.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
static/icons/06000F53.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
static/icons/06000F54.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
static/icons/06000F5A.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/icons/06000F5D.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/icons/06000F5E.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
static/icons/06000F66.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
static/icons/06000F68.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/icons/06000F6A.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/icons/06000F6B.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/icons/06000F6C.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/icons/06000F6E.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/icons/06000F86.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
static/icons/06000F89.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
static/icons/06000F8A.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

BIN
static/icons/06000F90.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
static/icons/06000F93.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

BIN
static/icons/06000F98.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
static/icons/06000FAA.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
static/icons/06000FAC.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
static/icons/06000FAD.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
static/icons/06000FAE.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
static/icons/06000FB1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/icons/06000FB5.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
static/icons/06000FB7.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
static/icons/06000FB8.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
static/icons/06000FBB.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/icons/06000FBC.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/icons/06000FBD.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
static/icons/06000FBE.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/icons/06000FC2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/06000FC3.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/06000FC4.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/icons/06000FC6.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/06000FC7.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/icons/06000FCA.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/icons/06000FCB.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
static/icons/06000FCC.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Some files were not shown because too many files have changed in this diff Show more