Login
User Name:

Password:



Register

Forgot your password?
Object Reader for SmaugFUSS Created for 1.9.9
Jul 31, 2026 6:40 pm
By Angst
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
Force Skills
Jan 1, 2026 3:58 pm
By Elwood
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, Bing, Amazonbot, Baiduspider

Members: 0
Guests: 23
Stats
Files
Topics
Posts
Members
Newest Member
518
3,814
19,727
591
MeriMutch5

» 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
Posts1
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!

Pages:<< prev 1 next >>