Login
User Name:

Password:



Register

Forgot your password?
Object Reader for SmaugFUSS Created for 1.9.9
Nov 9, 2026 2:31 am
By camdenriley
Eldhamud code verses AI
Oct 8, 2026 7:23 pm
By eldhamud
do_advance
Jun 27, 2026 10:32 am
By Remcon
Time spamming LOP1.6
Jun 17, 2026 4:03 pm
By Remcon
A Bash Startup Script
Feb 7, 2026 3:49 pm
By eldhamud
SWFotEFUSS 1.5.4
Author: Various
Submitted by: Samson
SWRFUSS 1.4.4
Author: Various
Submitted by: Samson
SmaugFUSS 1.9.9
Author: Various
Submitted by: Samson
AFKMud 3.0.0
Author: AFKMud Team
Submitted by: Samson
SillyMUD 1.2a
Author: J. Brothers, J. Sievert, et al
Submitted by: Samson
Users Online
Anthropic, Amazonbot, DotBot

Members: 0
Guests: 99
Stats
Files
Topics
Posts
Members
Newest Member
518
3,815
19,734
595
camdenriley

» SmaugMuds » Codebases » SmaugFUSS » Object Reader for SmaugFUSS C...
Forum Rules | Mark all | Recent Posts

Object Reader for SmaugFUSS Created for 1.9.9
< Newer Topic :: Older Topic >

Pages:<< prev 1 next >>
Post is unread #1 Jul 31, 2026 6:40 pm   
Go to the top of the page
Go to the bottom of the page

Angst
Fledgling
GroupMembers
Posts2
JoinedJul 31, 2026

 
I created a python area directory parser that when run from the area directory, scans every .are file, pulls the objects and exports them to a .csv file. It translates bitvectors into human readable names as well. save the into a .py file, run it, and open the .csv that's created., that's it. Find the stats on all the stuff! I ran it against the default of 1.9.9 and it worked fine. Usage may very.

import os
import csv
import glob
import re

# --- EXACT AFFECT FLAGS FROM YOUR BUILD.C ---
AFFECT_FLAGS = [
    "blind", "invisible", "detect_evil", "detect_invis", "detect_magic",
    "detect_hidden", "hold", "sanctuary", "faerie_fire", "infrared", "curse",
    "_flaming", "poison", "protect", "_paralysis", "sneak", "hide", "sleep",
    "charm", "flying", "pass_door", "floating", "truesight", "detect_traps",
    "scrying", "fireshield", "shockshield", "r1", "iceshield", "possess",
    "berserk", "aqua_breath", "recurringspell", "contagious", "acidmist",
    "venomshield", "grapple"
]

ITEM_TYPES = {
    "light": "Light", "scroll": "Scroll", "wand": "Wand", "staff": "Staff", 
    "weapon": "Weapon", "treasure": "Treasure", "armor": "Armor", "potion": "Potion", 
    "furniture": "Furniture", "trash": "Trash", "container": "Container", 
    "drinkcon": "DrinkCon", "key": "Key", "food": "Food", "money": "Money", 
    "boat": "Boat", "corpsenpc": "CorpseNpc", "corpsepc": "CorpsePc", 
    "fountain": "Fountain", "pill": "Pill", "armortinkered": "ArmorTinkered"
}

WEAPON_TYPES = {
    0: "Hit/Buff", 1: "Slice", 2: "Stab", 3: "Slash", 4: "Whip", 
    5: "Claw", 6: "Blast", 7: "Pound", 8: "Crush", 9: "Grepe", 
    10: "Bite", 11: "Sting", 12: "Gouge"
}

AFFECT_LOCATIONS = {
    1: "Strength", 2: "Dexterity", 3: "Intelligence", 4: "Wisdom", 5: "Constitution",
    12: "Mana", 13: "HP", 14: "Move", 17: "AC", 18: "Hitroll", 19: "Damroll",
    24: "Saving_Spell"
}

LIQUID_TYPES = {
    0: "Water", 1: "Beer", 2: "Wine", 3: "Ale", 4: "Dark_Ale", 5: "Whisky",
    6: "Lemonade", 7: "Firebreather", 8: "Local_Specialty", 9: "Slime",
    10: "Milk", 11: "Tea", 12: "Coffee", 13: "Blood", 14: "Salt_Water", 15: "Juice"
}

def decode_specific_values(item_type, values, explicit_spells):
    readable = {"V0_Meaning": "", "V1_Meaning": "", "V2_Meaning": "", "V3_Meaning": "", "V4_Meaning": "", "V5_Meaning": ""}
    while len(values) < 6:
        values.append("0")
    v0, v1, v2, v3, v4, v5 = values[0], values[1], values[2], values[3], values[4], values[5]
    
    try:
        clean_type = item_type.lower().replace('~', '').strip()
        
        if clean_type == "weapon":
            readable["V3_Meaning"] = WEAPON_TYPES.get(int(v3), f"Unknown({v3})")
            readable["V1_Meaning"] = f"{v1} (Min Damage)"
            readable["V2_Meaning"] = f"{v2} (Max Damage)"
            
        elif clean_type in ["scroll", "potion", "pill"]:
            readable["V0_Meaning"] = f"Cast Level: {v0}"
            # 🛠️ CHOOSE EXPLICIT SPELLS INSTEAD OF VALUE INTEGERS
            s1 = explicit_spells[0] if len(explicit_spells) >= 1 else "None"
            s2 = explicit_spells[1] if len(explicit_spells) >= 2 else "None"
            s3 = explicit_spells[2] if len(explicit_spells) >= 3 else "None"
            readable["V1_Meaning"] = f"Spell 1: {s1}"
            readable["V2_Meaning"] = f"Spell 2: {s2}"
            readable["V3_Meaning"] = f"Spell 3: {s3}"
            
        elif clean_type in ["wand", "staff"]:
            readable["V0_Meaning"] = f"Cast Level: {v0}"
            readable["V1_Meaning"] = f"Max Charges: {v1}"
            readable["V2_Meaning"] = f"Current Charges: {v2}"
            s1 = explicit_spells[0] if explicit_spells else "None"
            readable["V3_Meaning"] = f"Spell: {s1}"
            
        elif clean_type == "container":
            readable["V0_Meaning"] = f"Max Weight Capacity: {v0}"
            flags = []
            val_v1 = int(v1)
            if val_v1 & 1: flags.append("Closeable")
            if val_v1 & 2: flags.append("Pickproof")
            if val_v1 & 4: flags.append("Closed")
            if val_v1 & 8: flags.append("Locked")
            readable["V1_Meaning"] = "|".join(flags) if flags else "None"
            readable["V2_Meaning"] = f"Key VNUM: {v2}" if int(v2) > 0 else "No Key"
            
        elif clean_type == "drinkcon":
            readable["V0_Meaning"] = f"Capacity: {v0}"
            readable["V1_Meaning"] = f"Current Quantity: {v1}"
            readable["V2_Meaning"] = LIQUID_TYPES.get(int(v2), f"Unknown Liquid({v2})")
            readable["V3_Meaning"] = "Poisoned!" if int(v3) != 0 else "Safe"
            
        elif clean_type == "light":
            readable["V2_Meaning"] = "Infinite Light" if int(v2) == -1 else f"Fuel: {v2} hours"
    except ValueError:
        pass
    return readable

def format_flag_string(raw_flags):
    if not raw_flags: return "None"
    clean = raw_flags.replace('~', '').strip()
    parts = [p.strip().capitalize() for p in clean.split() if p.strip()]
    return "; ".join(parts) if parts else "None"

class KeyedSmaugParser:
    def __init__(self, filepath):
        self.filepath = filepath
        self.filename = os.path.basename(filepath)
        self.object_rows = []

    def clean_val(self, val_str):
        return val_str.replace('~', '').strip()

    def parse(self):
        with open(self.filepath, 'r', encoding='latin-1', errors='ignore') as f:
            content = f.read()

        object_blocks = re.findall(r'#OBJECT\b(.*?)(?=#ENDOBJECT|#OBJECT|\Z)', content, re.DOTALL | re.IGNORECASE)

        for block in object_blocks:
            lines = [line.strip() for line in block.split('\n') if line.strip()]
            
            obj_data = {
                'Vnum': '', 'Keywords': '', 'Type': '', 'Short': '', 'Long': '',
                'WFlags': '', 'Flags': '', 'Values': ['0', '0', '0', '0', '0', '0'],
                'Weight': '0', 'Cost': '0', 'Level': '0', 'Layers': '0',
                'Spells': []
            }
            stats = {"Strength": 0, "Dexterity": 0, "Intelligence": 0, "Wisdom": 0, "Constitution": 0, "Mana": 0, "HP": 0, "Move": 0, "AC": 0, "Hitroll": 0, "Damroll": 0}

            for line in lines:
                parts = line.split(None, 1)
                if len(parts) < 2: continue
                
                key = parts[0].lower()
                val = parts[1]

                if key == 'vnum':
                    obj_data['Vnum'] = val
                elif key == 'keywords':
                    obj_data['Keywords'] = self.clean_val(val)
                elif key == 'type':
                    obj_data['Type'] = self.clean_val(val)
                elif key == 'short':
                    obj_data['Short'] = self.clean_val(val)
                elif key == 'long':
                    obj_data['Long'] = self.clean_val(val)
                elif key == 'wflags':
                    obj_data['WFlags'] = format_flag_string(val)
                elif key == 'flags':
                    obj_data['Flags'] = format_flag_string(val)
                elif key == 'values':
                    obj_data['Values'] = val.split()
                elif key == 'spells':
                    # 🛠️ PARSE SINGLE QUOTE SPELL STRINGS ACCURATELY:
                    # 'cure critical' 'armor' 'refresh' -> ["Cure Critical", "Armor", "Refresh"]
                    found_spells = re.findall(r"'(.*?)'", val)
                    obj_data['Spells'] = [s.strip().title() for s in found_spells if s.strip()]
                elif key == 'stats':
                    s_parts = val.split()
                    if len(s_parts) >= 1: obj_data['Weight'] = s_parts[0]
                    if len(s_parts) >= 2: obj_data['Cost'] = s_parts[1]
                    if len(s_parts) >= 4: obj_data['Level'] = s_parts[3]
                    if len(s_parts) >= 5: obj_data['Layers'] = s_parts[4]
                elif key == 'affect':
                    aff_parts = val.split()
                    if len(aff_parts) >= 4:
                        try:
                            modifier = int(aff_parts[1])
                            loc_id = int(aff_parts[2])
                            stat_name = AFFECT_LOCATIONS.get(loc_id)
                            if stat_name in stats:
                                stats[stat_name] += modifier
                        except (ValueError, IndexError):
                            pass

            if not obj_data['Vnum']: continue

            mapped_type = ITEM_TYPES.get(obj_data['Type'].lower(), obj_data['Type'])
            meanings = decode_specific_values(mapped_type, obj_data['Values'], obj_data['Spells'])

            record = {
                'Source_File': self.filename, 'VNUM': obj_data['Vnum'], 'Name': obj_data['Keywords'], 
                'Short_Desc': obj_data['Short'], 'Item_Type': mapped_type,
                'Wear_Flags': obj_data['WFlags'] if obj_data['WFlags'] else "None",
                'Extra_Flags': obj_data['Flags'] if obj_data['Flags'] else "None",
                'Weight': obj_data['Weight'], 'Gold_Cost': obj_data['Cost'], 
                'Level': obj_data['Level'], 'Layers': obj_data['Layers'],
                'Value_0': obj_data['Values'][0] if len(obj_data['Values']) > 0 else '0', 'V0_Meaning': meanings["V0_Meaning"],
                'Value_1': obj_data['Values'][1] if len(obj_data['Values']) > 1 else '0', 'V1_Meaning': meanings["V1_Meaning"],
                'Value_2': obj_data['Values'][2] if len(obj_data['Values']) > 2 else '0', 'V2_Meaning': meanings["V2_Meaning"],
                'Value_3': obj_data['Values'][3] if len(obj_data['Values']) > 3 else '0', 'V3_Meaning': meanings["V3_Meaning"],
                'Value_4': obj_data['Values'][4] if len(obj_data['Values']) > 4 else '0', 'V4_Meaning': meanings["V4_Meaning"],
                'Value_5': obj_data['Values'][5] if len(obj_data['Values']) > 5 else '0', 'V5_Meaning': meanings["V5_Meaning"]
            }
            record.update(stats)
            self.object_rows.append(record)

if __name__ == "__main__":
    all_objects = []
    area_files = glob.glob("*.are")
    
    if not area_files:
        print("Error: No .are files found in the current working directory.")
    else:
        print(f"Deep parsing keyed objects across {len(area_files)} area files...")
        for filepath in area_files:
            parser = KeyedSmaugParser(filepath)
            parser.parse()
            print(f" - Found {len(parser.object_rows)} objects inside '{parser.filename}'")
            all_objects.extend(parser.object_rows)
            
        csv_filename = "smaug_object_comprehensive_matrix.csv"
        headers = [
            'Source_File', 'VNUM', 'Name', 'Short_Desc', 'Item_Type', 'Wear_Flags', 'Extra_Flags',
            'Weight', 'Gold_Cost', 'Level', 'Layers',
            'Value_0', 'V0_Meaning', 'Value_1', 'V1_Meaning', 'Value_2', 'V2_Meaning', 
            'Value_3', 'V3_Meaning', 'Value_4', 'V4_Meaning', 'Value_5', 'V5_Meaning',
            'Strength', 'Dexterity', 'Intelligence', 'Wisdom', 'Constitution', 'Mana', 'HP', 'Move', 'AC', 'Hitroll', 'Damroll'
        ]
        
        with open(csv_filename, 'w', newline='', encoding='utf-8') as csvfile:
            writer = csv.DictWriter(csvfile, fieldnames=headers)
            writer.writeheader()
            writer.writerows(all_objects)
            
        print(f"\nExecution Complete! Successfully populated '{csv_filename}'.")


Good Luck!

Post is unread #2 Aug 6, 2026 6:33 am   
Go to the top of the page
Go to the bottom of the page

Angst
Fledgling
GroupMembers
Posts2
JoinedJul 31, 2026

 
After finding an issue, I have updated the code to resolved it.

import os
import csv
import glob
import re

# --- EXACT AFFECT FLAGS FROM YOUR BUILD.C ---
AFFECT_FLAGS = [
    "blind", "invisible", "detect_evil", "detect_invis", "detect_magic",
    "detect_hidden", "hold", "sanctuary", "faerie_fire", "infrared", "curse",
    "_flaming", "poison", "protect", "_paralysis", "sneak", "hide", "sleep",
    "charm", "flying", "pass_door", "floating", "truesight", "detect_traps",
    "scrying", "fireshield", "shockshield", "r1", "iceshield", "possess",
    "berserk", "aqua_breath", "recurringspell", "contagious", "acidmist",
    "venomshield", "grapple"
]

ITEM_TYPES = {
    "light": "Light", "scroll": "Scroll", "wand": "Wand", "staff": "Staff", 
    "weapon": "Weapon", "treasure": "Treasure", "armor": "Armor", "potion": "Potion", 
    "furniture": "Furniture", "trash": "Trash", "container": "Container", 
    "drinkcon": "DrinkCon", "key": "Key", "food": "Food", "money": "Money", 
    "boat": "Boat", "corpsenpc": "CorpseNpc", "corpsepc": "CorpsePc", 
    "fountain": "Fountain", "pill": "Pill", "armortinkered": "ArmorTinkered"
}

WEAPON_TYPES = {
    0: "Hit/Buff", 1: "Slice", 2: "Stab", 3: "Slash", 4: "Whip", 
    5: "Claw", 6: "Blast", 7: "Pound", 8: "Crush", 9: "Grapple", 
    10: "Bite", 11: "Sting", 12: "Gouge"
}

AFFECT_LOCATIONS = {
    1: "Strength", 2: "Dexterity", 3: "Intelligence", 4: "Wisdom", 5: "Constitution",
    12: "Mana", 13: "HP", 14: "Move", 17: "AC", 18: "Hitroll", 19: "Damroll",
    24: "Saving_Spell"
}

LIQUID_TYPES = {
    0: "Water", 1: "Beer", 2: "Wine", 3: "Ale", 4: "Dark_Ale", 5: "Whisky",
    6: "Lemonade", 7: "Firebreather", 8: "Local_Specialty", 9: "Slime",
    10: "Milk", 11: "Tea", 12: "Coffee", 13: "Blood", 14: "Salt_Water", 15: "Juice"
}

def decode_specific_values(item_type, values, explicit_spells):
    readable = {"V0_Meaning": "", "V1_Meaning": "", "V2_Meaning": "", "V3_Meaning": "", "V4_Meaning": "", "V5_Meaning": ""}
    while len(values) < 6:
        values.append("0")
    v0, v1, v2, v3, v4, v5 = values[0], values[1], values[2], values[3], values[4], values[5]
    
    try:
        clean_type = item_type.lower().replace('~', '').strip()
        
        if clean_type == "weapon":
            readable["V3_Meaning"] = WEAPON_TYPES.get(int(v3), f"Unknown({v3})")
            readable["V1_Meaning"] = f"{v1} (Min Damage)"
            readable["V2_Meaning"] = f"{v2} (Max Damage)"
            
        elif clean_type in ["scroll", "potion", "pill"]:
            readable["V0_Meaning"] = f"Cast Level: {v0}"
            s1 = explicit_spells[0] if len(explicit_spells) >= 1 else "None"
            s2 = explicit_spells[1] if len(explicit_spells) >= 2 else "None"
            s3 = explicit_spells[2] if len(explicit_spells) >= 3 else "None"
            readable["V1_Meaning"] = f"Spell 1: {s1}"
            readable["V2_Meaning"] = f"Spell 2: {s2}"
            readable["V3_Meaning"] = f"Spell 3: {s3}"
            
        elif clean_type in ["wand", "staff"]:
            readable["V0_Meaning"] = f"Cast Level: {v0}"
            readable["V1_Meaning"] = f"Max Charges: {v1}"
            readable["V2_Meaning"] = f"Current Charges: {v2}"
            s1 = explicit_spells[0] if explicit_spells else "None"
            readable["V3_Meaning"] = f"Spell: {s1}"
            
        elif clean_type == "container":
            readable["V0_Meaning"] = f"Max Weight Capacity: {v0}"
            flags = []
            val_v1 = int(v1)
            if val_v1 & 1: flags.append("Closeable")
            if val_v1 & 2: flags.append("Pickproof")
            if val_v1 & 4: flags.append("Closed")
            if val_v1 & 8: flags.append("Locked")
            readable["V1_Meaning"] = "|".join(flags) if flags else "None"
            readable["V2_Meaning"] = f"Key VNUM: {v2}" if int(v2) > 0 else "No Key"
            
        elif clean_type == "drinkcon":
            readable["V0_Meaning"] = f"Capacity: {v0}"
            readable["V1_Meaning"] = f"Current Quantity: {v1}"
            readable["V2_Meaning"] = LIQUID_TYPES.get(int(v2), f"Unknown Liquid({v2})")
            readable["V3_Meaning"] = "Poisoned!" if int(v3) != 0 else "Safe"
            
        elif clean_type == "light":
            readable["V2_Meaning"] = "Infinite Light" if int(v2) == -1 else f"Fuel: {v2} hours"
    except ValueError:
        pass
    return readable

def format_flag_string(raw_flags):
    if not raw_flags: return "None"
    clean = raw_flags.replace('~', '').strip()
    parts = [p.strip().capitalize() for p in clean.split() if p.strip()]
    return "; ".join(parts) if parts else "None"

class KeyedSmaugParser:
    def __init__(self, filepath):
        self.filepath = filepath
        self.filename = os.path.basename(filepath)
        self.object_rows = []

    def clean_val(self, val_str):
        return val_str.replace('~', '').strip()

    def parse(self):
        with open(self.filepath, 'r', encoding='latin-1', errors='ignore') as f:
            content = f.read()

        object_blocks = re.findall(r'#OBJECT\b(.*?)(?=#ENDOBJECT|#OBJECT|\Z)', content, re.DOTALL | re.IGNORECASE)

        for block in object_blocks:
            lines = [line.strip() for line in block.split('\n') if line.strip()]
            
            obj_data = {
                'Vnum': '', 'Keywords': '', 'Type': '', 'Short': '', 'Long': '',
                'WFlags': '', 'Flags': '', 'Values': ['0', '0', '0', '0', '0', '0'],
                'Weight': '0', 'Cost': '0', 'Level': '0', 'Layers': '0',
                'Spells': []
            }
            stats = {"Strength": 0, "Dexterity": 0, "Intelligence": 0, "Wisdom": 0, "Constitution": 0, "Mana": 0, "HP": 0, "Move": 0, "AC": 0, "Hitroll": 0, "Damroll": 0}

            for line in lines:
                parts = line.split(None, 1)
                if len(parts) < 2: continue
                
                key = parts[0].lower()
                val = parts[1]

                if key == 'vnum':
                    obj_data['Vnum'] = val
                elif key == 'keywords':
                    obj_data['Keywords'] = self.clean_val(val)
                elif key == 'type':
                    obj_data['Type'] = self.clean_val(val)
                elif key == 'short':
                    obj_data['Short'] = self.clean_val(val)
                elif key == 'long':
                    obj_data['Long'] = self.clean_val(val)
                elif key == 'wflags':
                    obj_data['WFlags'] = format_flag_string(val)
                elif key == 'flags':
                    obj_data['Flags'] = format_flag_string(val)
                elif key == 'values':
                    obj_data['Values'] = val.split()
                elif key == 'spells':
                    # 🛠️ PARSE SINGLE QUOTE SPELL STRINGS ACCURATELY:
                    # 'cure critical' 'armor' 'refresh' -> ["Cure Critical", "Armor", "Refresh"]
                    found_spells = re.findall(r"'(.*?)'", val)
                    obj_data['Spells'] = [s.strip().title() for s in found_spells if s.strip()]
                elif key == 'stats':
                    s_parts = val.split()
                    if len(s_parts) >= 1: obj_data['Weight'] = s_parts[0]
                    if len(s_parts) >= 2: obj_data['Cost'] = s_parts[1]
                    if len(s_parts) >= 4: obj_data['Level'] = s_parts[3]
                    if len(s_parts) >= 5: obj_data['Layers'] = s_parts[4]
                elif key == 'affect':
                    aff_parts = val.split()
                    # --- NEW AFFECT PARSING BASED ON THE EXAMPLE ---
                    # Expecting: Affect <num> <num> <modifier> <location_id> <other>
                    if len(aff_parts) >= 5:
                        try:
                            # Check if first token is 'Affect'
                            if aff_parts[0].lower() == 'affect':
                                modifier = int(aff_parts[2])
                                loc_id = int(aff_parts[3])
                            else:
                                # fallback
                                modifier = int(aff_parts[2])
                                loc_id = int(aff_parts[3])
                            stat_name = AFFECT_LOCATIONS.get(loc_id)
                            if stat_name and stat_name in stats:
                                stats[stat_name] += modifier
                        except (ValueError, IndexError):
                            pass

            if not obj_data['Vnum']: continue

            mapped_type = ITEM_TYPES.get(obj_data['Type'].lower(), obj_data['Type'])
            meanings = decode_specific_values(mapped_type, obj_data['Values'], obj_data['Spells'])

            record = {
                'Source_File': self.filename, 'VNUM': obj_data['Vnum'], 'Name': obj_data['Keywords'], 
                'Short_Desc': obj_data['Short'], 'Item_Type': mapped_type,
                'Wear_Flags': obj_data['WFlags'] if obj_data['WFlags'] else "None",
                'Extra_Flags': obj_data['Flags'] if obj_data['Flags'] else "None",
                'Weight': obj_data['Weight'], 'Gold_Cost': obj_data['Cost'], 
                'Level': obj_data['Level'], 'Layers': obj_data['Layers'],
                'Value_0': obj_data['Values'][0] if len(obj_data['Values']) > 0 else '0', 'V0_Meaning': meanings["V0_Meaning"],
                'Value_1': obj_data['Values'][1] if len(obj_data['Values']) > 1 else '0', 'V1_Meaning': meanings["V1_Meaning"],
                'Value_2': obj_data['Values'][2] if len(obj_data['Values']) > 2 else '0', 'V2_Meaning': meanings["V2_Meaning"],
                'Value_3': obj_data['Values'][3] if len(obj_data['Values']) > 3 else '0', 'V3_Meaning': meanings["V3_Meaning"],
                'Value_4': obj_data['Values'][4] if len(obj_data['Values']) > 4 else '0', 'V4_Meaning': meanings["V4_Meaning"],
                'Value_5': obj_data['Values'][5] if len(obj_data['Values']) > 5 else '0', 'V5_Meaning': meanings["V5_Meaning"]
            }
            record.update(stats)
            self.object_rows.append(record)

if __name__ == "__main__":
    all_objects = []
    area_files = glob.glob("*.are")
    
    if not area_files:
        print("Error: No .are files found in the current working directory.")
    else:
        print(f"Deep parsing keyed objects across {len(area_files)} area files...")
        for filepath in area_files:
            parser = KeyedSmaugParser(filepath)
            parser.parse()
            print(f" - Found {len(parser.object_rows)} objects inside '{parser.filename}'")
            all_objects.extend(parser.object_rows)
            
        csv_filename = "smaug_object_comprehensive_matrix2.csv"
        headers = [
            'Source_File', 'VNUM', 'Name', 'Short_Desc', 'Item_Type', 'Wear_Flags', 'Extra_Flags',
            'Weight', 'Gold_Cost', 'Level', 'Layers',
            'Value_0', 'V0_Meaning', 'Value_1', 'V1_Meaning', 'Value_2', 'V2_Meaning', 
            'Value_3', 'V3_Meaning', 'Value_4', 'V4_Meaning', 'Value_5', 'V5_Meaning',
            'Strength', 'Dexterity', 'Intelligence', 'Wisdom', 'Constitution', 'Mana', 'HP', 'Move', 'AC', 'Hitroll', 'Damroll'
        ]
        
        with open(csv_filename, 'w', newline='', encoding='utf-8') as csvfile:
            writer = csv.DictWriter(csvfile, fieldnames=headers)
            writer.writeheader()
            writer.writerows(all_objects)
        
        print(f"\nExecution Complete! Successfully populated '{csv_filename}'.")

Post is unread #3 Nov 9, 2026 2:31 am   
Go to the top of the page
Go to the bottom of the page

camdenriley
Fledgling
GroupMembers
Posts1
JoinedNov 9, 2026

 
I truly appreciate the effort put into developing the Object Reader for SmaugFUSS. It’s fascinating how it enhances gameplay by making object data more accessible. This tool can really help players dive deeper into their experience. Thank you for sharing this resource; it’s a valuable addition to our community! speed stars



Pages:<< prev 1 next >>