Aeternitas 18+ Edition - Complete Modding Guide

Learn how to create and modify content for Aeternitas 18+ Edition

Introduction

Aeternitas 18+ Edition features a powerful modding system that allows you to extend and modify the game in almost any way imaginable. Mods are JavaScript files that run in a sandboxed environment with full access to the game's modding API.

What Can Mods Do?

Mod Safety

Mods run in an isolated execution context using new Function(), providing a level of sandboxing. However, mods have full access to the game state through the modAPI object. Always load mods from trusted sources.


Getting Started

Loading a Mod

  1. In-Game Method:
    • Type loadmod in the game
    • Select a .js file from your computer
    • The mod will load automatically
  2. Mod Menu:
    • Type mods or mod to open the mod menu
    • View loaded mods and their status

Basic Mod Structure

A mod is a JavaScript file that receives a modAPI object:


modAPI.displayOutput({
    success: true,
    message: "Hello from my mod!"
});

Modded Saves

When mods are loaded, the game enters "MODDED MODE":


Modding API Reference

Core Objects

modAPI.game

Direct reference to the game instance. Use with caution - prefer API methods when available.


Content Creation

Items

modAPI.addItem(itemId, itemData)

Adds a new item to the game.

Parameters:

Item Properties:

{
    name: "Item Name",              
    description: "Item description", 
    takeable: true,                 
    consumable: false,              
    heals: 0,                      
    encumbrance: 1,                
    value: 10,                     
    weapon: false,                 
    damage: 0,                     
    armor: false,                  
    defense: 0,                    
    magical: false,                
    lightSource: false,            
    readable: {                    
        lore: "Text content"
    },
    openable: false,               
    container: false,              
    fragile: false,                
    hidden: false                  
}

Example:

modAPI.addItem("magic_sword", {
    name: "Magic Sword",
    description: "A glowing blade that pulses with energy.",
    takeable: true,
    weapon: true,
    damage: 15,
    encumbrance: 3,
    magical: true,
    value: 100
});

modAPI.modifyItem(itemId, itemData)

Modifies an existing item. Properties are merged with existing data.

Example:

modAPI.modifyItem("mailbox", {
    description: "A mailbox. [MODIFIED BY MY MOD]"
});

modAPI.removeItem(itemId)

Removes an item from the game.

Rooms

modAPI.addRoom(roomId, roomData)

Adds a new room to the game world.

Room Properties:

{
    name: "Room Name",              
    description: "Room description", 
    exits: {                        
        north: "room_id",
        south: "another_room",
        east: "yet_another_room"
    },
    items: ["item1", "item2"],     
    hiddenItems: ["secret_item"],   
    entity: "npc_id",               
    visited: false,                 
    locked: false,                  
    dark: false,                    
    gatheringResources: {           
        harvest: {
            materials: ["herb", "wood"],
            maxUses: 5,
            uses: 5,
            exhausted: false
        }
    }
}

Example:

modAPI.addRoom("my_custom_room", {
    name: "Custom Room",
    description: "A room created by my mod!",
    exits: {
        north: "west_of_house"
    },
    items: ["magic_sword"],
    visited: false,
    locked: false,
    dark: false
});

modAPI.modifyRoom(roomId, roomData)

Modifies an existing room.

modAPI.removeRoom(roomId)

Removes a room from the game.

NPCs/Entities

modAPI.addEntity(entityId, entityData)

Adds a new NPC/entity to the game.

Entity Properties:

{
    name: "Entity Name",            
    description: "Entity description",
    gender: "male",                 
    peaceful: true,                 
    health: 50,                     
    maxHealth: 50,                  
    damage: 5,                      
    defense: 2,                     
    drops: ["item1", "item2"],      
    fleeChance: 0.3,                
    tamable: false,                 
    merchant: false,                
    inventory: ["item1"],           
    prices: {                       
        "item1": 10
    },
    relationship: 0,                
    friendshipLevel: 0,            
    romanceLevel: 0,                
    relationshipStage: "stranger",  
    currentLocation: "room_id",     
    favoriteGifts: ["item1"],       
    dialogue: {                     
        greeting: "Hello!",
        topics: {
            "topic": "Response text"
        }
    },
    aiRoutine: {                    
        schedule: [
            {time: 6, location: "room_id", behaviors: ["behavior1"]}
        ]
    }
}

Example:

modAPI.addEntity("my_npc", {
    name: "Mod NPC",
    description: "A friendly NPC created by my mod.",
    peaceful: true,
    health: 50,
    maxHealth: 50,
    currentLocation: "my_custom_room",
    relationship: 0,
    relationshipStage: "stranger",
    dialogue: {
        greeting: "Hello! I'm from a mod!",
        topics: {
            "mod": "This mod adds cool features!",
            "help": "I can help you with modding!"
        }
    }
});

modAPI.modifyEntity(entityId, entityData)

Modifies an existing entity.

modAPI.removeEntity(entityId)

Removes an entity from the game.

Crafting Recipes

modAPI.addRecipe(recipeId, recipeData)

Adds a new crafting recipe.

Recipe Properties:

{
    name: "Recipe Name",            
    description: "Recipe description",
    materials: ["item1", "item2"],  
    result: "result_item",          
    skill: "alchemy",               
    skillLevel: 5,                  
    discovered: false               
}

Example:

modAPI.addRecipe("magic_potion", {
    name: "Magic Potion",
    description: "A potion that restores health.",
    materials: ["herb", "water"],
    result: "healing_potion",
    skill: "alchemy",
    skillLevel: 3
});

Command System

Custom Commands

modAPI.addCommand(commandName, handler)

Adds a new custom command.

Handler Function:

function handler(target) {

    return {
        success: true,              
        message: "Command output"   
    };
}

Example:

modAPI.addCommand("hello", (target) => {
    return {
        success: true,
        message: "Hello from my mod!"
    };
});

Command Overrides

modAPI.overrideCommand(commandName, handler)

Overrides a base game command. Return null to use default behavior.

Example:

modAPI.overrideCommand("look", (target) => {
    const game = modAPI.game;
    if (game.currentRoom === "my_custom_room") {
        return {
            success: true,
            message: "You see a custom room with special mod content!"
        };
    }

    return null;
});

Event Hooks

Command Hooks

modAPI.onCommand(callback)

Hooks into all commands before they execute.

Callback Function:

function callback(command) {

    return null;
}

Example:

modAPI.onCommand((command) => {
    if (command.toLowerCase().includes("test")) {
        return {
            handled: true,
            message: "Command intercepted by mod!"
        };
    }
    return null;
});

Turn Hooks

modAPI.onTurn(callback)

Called every turn.

Callback Function:

function callback(turn, game) {

}

Example:

let turnCount = 0;
modAPI.onTurn((turn, game) => {
    turnCount++;
    if (turnCount % 10 === 0) {
        modAPI.displayOutput({
            success: true,
            message: `You've taken ${turnCount} turns!`
        });
    }
});

Room Entry Hooks

modAPI.onRoomEnter(callback)

Called when entering a room.

Callback Function:

function callback(roomId, game) {

}

Example:

modAPI.onRoomEnter((roomId, game) => {
    if (roomId === "my_custom_room") {
        modAPI.displayOutput({
            success: true,
            message: "You enter a special mod room!"
        });
    }
});

Item Take Hooks

modAPI.onItemTake(callback)

Called when an item is taken.

Callback Function:

function callback(itemId, game) {

}

Example:

modAPI.onItemTake((itemId, game) => {
    if (itemId === "magic_sword") {
        modAPI.displayOutput({
            success: true,
            message: "The sword pulses with energy!"
        });
        game.score += 10;
    }
});

Advanced Features

Starting Room Override

modAPI.setStartingRoom(roomId)

Changes the starting room for new games.

Example:

modAPI.setStartingRoom("my_custom_room");

Character Creation Override

modAPI.overrideCharacterCreation(handler)

Overrides the character creation process.

Handler Function:

function handler(game) {

    game.playerName = "Mod Character";

    return true;
}

Full Conversion Mods

modAPI.setFullConversion(enabled)

Marks the mod as a full conversion mod.

Example:

modAPI.setFullConversion(true);

Save/Load Overrides

modAPI.overrideSave(handler)

Overrides the save system.

Handler Function:

function handler(game) {

    return {
        customData: "value"
    };
}

modAPI.overrideLoad(handler)

Overrides the load system.

Handler Function:

function handler(saveData, game) {

}

Grammar Templates

modAPI.registerGrammar(grammarName, grammarRules)

Registers a custom grammar template for the parser.

Example:

modAPI.registerGrammar("pirate", {
    greetings: ["ahoy", "arr", "yo ho"],
    affirmations: ["aye", "arr", "aye aye"]
});

modAPI.getGrammar(grammarName)

Retrieves a registered grammar template.

Parser Information

modAPI.getCommandSlots()

Returns the extracted command slots including manner, tone, purpose, condition, and deep semantic intent (Schank's Theory).

Returns:

{
    manner: "gently" | null,        
    tone: "lovingly" | null,         
    purpose: "to comfort her" | null, 
    condition: "if she agrees" | null, 

    closeness: "intimate" | "friendly" | "neutral" | "hostile" | "distant",
    mood: "happy" | "sad" | "angry" | "playful" | "serious" | "romantic" | "fearful" | "calm" | "excited" | "bored" | "confident" | "shy" | "grateful" | "jealous" | "guilty" | "proud" | "neutral",
    roleIntention: "protector" | "attacker" | "helper" | "companion" | "healer" | "teacher" | "romantic" | "provider" | "leader" | "follower" | "negotiator" | "explorer" | null,
    targetIntimacy: "intimate" | "personal" | "social" | "public" | null,
    socialRuleViolation: "none" | "minor" | "major"
}

Example:


const slots = modAPI.getCommandSlots();

            

modAPI.getChainOfIntent()

Returns the chain-of-intent analysis for complex commands with multiple purposes.

Returns:

{
    primaryIntent: {
        type: "primary",
        action: "CONTACT",  
        original: "grab"
    } | null,
    secondaryIntents: [
        {
            type: "secondary",
            intent: "PROTECTIVE",
            description: "pull her away from danger",
            strength: "high"
        }
    ],
    combinedIntent: "CONTACT_PROTECTIVE" | null,
    intentChain: ["CONTACT", "PROTECTIVE"],
    emotionalContext: "concerned" | "caring" | "protective" | "romantic" | "friendly" | "hostile" | null,
    socialContext: "public" | "private" | "group" | "one-on-one"
}

Example:


const chain = modAPI.getChainOfIntent();

            

modAPI.normalizeActionToPrimitive(action)

Maps action synonyms to universal primitives (ATTACK, CONTACT, AFFECTION, MOVEMENT, EXAMINE, TAKE, GIVE, COMMUNICATE, USE, CRAFT, DROP, OPEN, CLOSE, EAT, READ, WEAR, REMOVE).

Parameters:

  • action (string) - The action word to normalize

Returns: The normalized primitive (e.g., "ATTACK", "CONTACT") or the original action if no match is found.

Example:

modAPI.normalizeActionToPrimitive("smack");  
modAPI.normalizeActionToPrimitive("pat");   
modAPI.normalizeActionToPrimitive("peck");  
modAPI.normalizeActionToPrimitive("unknown"); 
            

modAPI.getCommandTense()

Returns the detected command tense ("past", "present", "future", "ongoing").

Using Semantic Intent in Commands

You can use semantic intent analysis to create more nuanced command responses based on the player's emotional state, relationship level, and intent.

Example:

modAPI.addCommand("comfort", (target) => {
    const slots = modAPI.getCommandSlots();
    const chain = modAPI.getChainOfIntent();
    const player = modAPI.getPlayer();

    if (chain.secondaryIntents.some(i => i.intent === "COMFORTING")) {

        if (slots.closeness === "intimate") {
            return {
                success: true,
                message: "You hold them close, offering warmth and reassurance."
            };
        } else if (slots.closeness === "friendly") {
            return {
                success: true,
                message: "You offer a friendly pat on the shoulder and words of encouragement."
            };
        }
    }

    if (slots.mood === "caring") {
        return {
            success: true,
            message: "You express genuine concern and care."
        };
    }
    return {
        success: true,
        message: "You try to comfort them."
    };
});

modAPI.onCommand((command, target) => {
    const normalized = modAPI.normalizeActionToPrimitive(command.split(" ")[0]);
    if (normalized === "ATTACK") {
        const slots = modAPI.getCommandSlots();

        if (slots.mood === "playful") {
            modAPI.displayOutput({
                success: true,
                message: "You playfully strike at them!"
            });
        } else if (slots.socialRuleViolation === "major") {
            modAPI.displayOutput({
                success: false,
                message: "That would be a serious violation of social norms!"
            });
        }
    }
});

Utility Functions

Display Output

modAPI.displayOutput(message)

Displays a message to the player.

Example:

modAPI.displayOutput({
    success: true,
    message: "Hello from mod!"
});

Execute Command

modAPI.executeCommand(command)

Executes a game command programmatically.

Example:

modAPI.executeCommand("go north");

Random Number

modAPI.getRandom(min, max)

Returns a random integer between min and max (inclusive).

Example:

const roll = modAPI.getRandom(1, 20);

Player Data

modAPI.getPlayer()

Returns player data object.

Returns:

{
    name: "Player Name",
    inventory: ["item1", "item2"],
    equipment: {weapon: "sword", armor: "leather"},
    stats: {str: 10, int: 8, ...},
    skills: {alchemy: 5, ...},
    currentRoom: "room_id",
    money: 100,
    health: 50,
    mana: 30
}

modAPI.setPlayer(playerData)

Sets player data. Only provided properties are updated.

Example:

modAPI.setPlayer({
    money: 1000,
    health: 100
});

Game State Access

modAPI.getItems()

Returns all items object.

modAPI.getWorld()

Returns all rooms object.

modAPI.getEntities()

Returns all entities object.

modAPI.getRecipes()

Returns all crafting recipes object.


Best Practices

1. Unique Identifiers

Always use unique, descriptive IDs for your content:


modAPI.addItem("my_mod_sword_v2", {...});

modAPI.addItem("sword", {...}); 
            

2. Error Handling

Check if content exists before modifying:

if (modAPI.getItems()["mailbox"]) {
    modAPI.modifyItem("mailbox", {...});
}

3. Mod Compatibility

Prefix your mod's content with a unique identifier:

const MOD_PREFIX = "my_mod_";
modAPI.addItem(MOD_PREFIX + "sword", {...});
modAPI.addRoom(MOD_PREFIX + "room", {...});

4. Clean Up

Provide unload functionality if needed:


const addedItems = ["my_mod_sword", "my_mod_potion"];

            

5. Documentation

Document your mod's features and requirements:

modAPI.displayOutput({
    success: true,
    message: `
=== My Mod v1.0 ===
Features:
- New items: Magic Sword, Health Potion
- New room: Custom Chamber
- New command: 'mymod'
- Requires: No dependencies
    `
});

6. Testing

Test your mod thoroughly:

  • Test with and without other mods
  • Test save/load functionality
  • Test command conflicts
  • Test edge cases

Examples

Example 1: Simple Item Mod


modAPI.addItem("modded_apple", {
    name: "Modded Apple",
    description: "A shiny red apple created by a mod.",
    takeable: true,
    consumable: true,
    heals: 20,
    encumbrance: 1
});
modAPI.displayOutput({
    success: true,
    message: "Modded Apple mod loaded!"
});

Example 2: Custom Room and NPC


modAPI.addRoom("mod_tavern", {
    name: "Mod Tavern",
    description: "A cozy tavern added by a mod.",
    exits: {
        north: "west_of_house"
    },
    items: ["modded_apple"],
    entity: "mod_bartender",
    visited: false
});

modAPI.addEntity("mod_bartender", {
    name: "Mod Bartender",
    description: "A friendly bartender from a mod.",
    peaceful: true,
    currentLocation: "mod_tavern",
    relationship: 0,
    dialogue: {
        greeting: "Welcome to the mod tavern!",
        topics: {
            "drink": "I serve the finest modded beverages!",
            "mod": "This tavern was created by a mod!"
        }
    }
});
modAPI.displayOutput({
    success: true,
    message: "Mod Tavern mod loaded! Type 'go mod tavern' to visit!"
});

Example 3: Custom Command with Hook


modAPI.addCommand("modtest", (target) => {
    return {
        success: true,
        message: "Mod test command works! Target: " + (target || "none")
    };
});

modAPI.onCommand((command) => {
    if (command.toLowerCase().startsWith("modtest")) {
        modAPI.displayOutput({
            success: true,
            message: "[HOOK] Command intercepted!"
        });
    }
    return null; 
});
modAPI.displayOutput({
    success: true,
    message: "Command mod loaded! Try 'modtest'!"
});

Example 4: Turn-Based Event

let modTurnCount = 0;
modAPI.onTurn((turn, game) => {
    modTurnCount++;

    if (modTurnCount % 5 === 0 && game.health < game.maxHealth) {
        game.health = Math.min(game.maxHealth, game.health + 1);
        modAPI.displayOutput({
            success: true,
            message: "[MOD] You feel slightly refreshed! (+1 HP)"
        });
    }
});
modAPI.displayOutput({
    success: true,
    message: "Regeneration mod loaded! You'll heal 1 HP every 5 turns."
});

Example 5: Full Conversion Mod


modAPI.setFullConversion(true);

modAPI.setStartingRoom("mod_start_room");

modAPI.addRoom("mod_start_room", {
    name: "Modded Starting Area",
    description: "You begin your adventure in a modded world!",
    exits: {
        east: "mod_town"
    },
    items: ["mod_starter_sword"],
    visited: false
});

modAPI.overrideCharacterCreation((game) => {
    game.playerName = "Mod Character";

    return true; 
});
modAPI.displayOutput({
    success: true,
    message: "Full conversion mod loaded! Starting in modded world..."
});

Troubleshooting

Mod Won't Load

Problem: Mod file doesn't load or shows error.

Solutions:

  • Check JavaScript syntax errors
  • Ensure file is .js format
  • Check browser console for errors
  • Verify modAPI is used correctly

Mod Conflicts

Problem: Mod conflicts with base game or other mods.

Solutions:

  • Use unique IDs with prefixes
  • Check for ID conflicts before adding content
  • Test mod compatibility
  • Load mods in different orders

Save/Load Issues

Problem: Modded saves don't work.

Solutions:

  • Ensure same mods are loaded when loading save
  • Check if mod uses save/load overrides
  • Verify mod state is saved correctly
  • Use save modded and load modded commands

Commands Not Working

Problem: Custom commands don't execute.

Solutions:

  • Check command name conflicts
  • Verify handler returns correct format
  • Check if command is overridden
  • Test command hook interception

Content Not Appearing

Problem: Added items/rooms/NPCs don't appear.

Solutions:

  • Verify IDs are correct
  • Check if content is added to correct locations
  • Ensure rooms have proper exits
  • Verify entities have currentLocation set

API Quick Reference

Content Management

  • addItem(itemId, itemData) - Add item
  • modifyItem(itemId, itemData) - Modify item
  • removeItem(itemId) - Remove item
  • addRoom(roomId, roomData) - Add room
  • modifyRoom(roomId, roomData) - Modify room
  • removeRoom(roomId) - Remove room
  • addEntity(entityId, entityData) - Add entity
  • modifyEntity(entityId, entityData) - Modify entity
  • removeEntity(entityId) - Remove entity
  • addRecipe(recipeId, recipeData) - Add recipe

Commands

  • addCommand(commandName, handler) - Add command
  • overrideCommand(commandName, handler) - Override command

Hooks

  • onCommand(callback) - Command hook
  • onTurn(callback) - Turn hook
  • onRoomEnter(callback) - Room entry hook
  • onItemTake(callback) - Item take hook

Advanced

  • setStartingRoom(roomId) - Set starting room
  • setCurrentRoom(roomId) - Teleport player
  • overrideCharacterCreation(handler) - Override character creation
  • setFullConversion(enabled) - Mark as full conversion
  • overrideSave(handler) - Override save
  • overrideLoad(handler) - Override load
  • registerGrammar(grammarName, grammarRules) - Register grammar
  • getGrammar(grammarName) - Get grammar
  • getCommandSlots() - Get command slots (including semantic intent)
  • getChainOfIntent() - Get chain-of-intent analysis
  • normalizeActionToPrimitive(action) - Normalize action to primitive
  • getCommandTense() - Get command tense

Utilities

  • displayOutput(message) - Display message
  • executeCommand(command) - Execute command
  • getRandom(min, max) - Random number
  • getPlayer() - Get player data
  • setPlayer(playerData) - Set player data
  • getItems() - Get all items
  • getWorld() - Get all rooms
  • getEntities() - Get all entities
  • getRecipes() - Get all recipes

Support

For modding support:

  • Check the test mod (test_mod.js) for examples
  • Review the game's source code for implementation details
  • Test your mods in a safe environment before sharing

Happy Modding!

Aeternitas Mod Validator

Validate your mod files before loading them into the game

Drop your mod file here or click to browse

Supports .js files