Guides

TinTin++ with TinTin++

TinTin++ operates as a terminal-first MUD client where configuration errors crash sessions silently. This guide establishes a production-ready architecture using modular script loading, strict variable scoping, and terminal multiplexer integration to prevent data loss during network instability.

45 minutes8 steps
TinTin++ with TinTin++ illustration
Placeholder illustration shown while custom artwork is being produced.
1

Establish Modular Directory Structure

Create a directory hierarchy that separates logic from data. Place configuration files in ~/.config/tintin/ with subdirectories for modules, logs, and character profiles. Use #path to set the load path before any #read commands to avoid relative path failures when launching from different working directories.

main.tin
# ~/.config/tintin/main.tin
#path {/home/user/.config/tintin/modules}
#path {/home/user/.config/tintin/characters}
#read {core/variables.tin}
#read {core/aliases.tin}
#read {core/triggers.tin}

⚠ Common Pitfalls

  • Loading files before #path is set causes 'file not found' errors when launching outside the config directory
  • Circular #read dependencies create infinite loops on startup
2

Configure Terminal Multiplexer Integration

TinTin++ must declare terminal capabilities to prevent display corruption in tmux. Set TERM to screen-256color or tmux-256color before launching. Configure #config to handle resize events gracefully, ensuring the #split command recalculates row counts when detaching and reattaching sessions.

launch.sh
# Launch script: ~/bin/mud
export TERM=tmux-256color
tmux new-session -d -s mud 'tt++ ~/.config/tintin/main.tin'
tmux attach -t mud

⚠ Common Pitfalls

  • 256-color support requires TERM variable set before tt++ starts, not after
  • Detaching tmux while #split is active collapses the status line until next #split reset
3

Implement Session-Local Variable Scoping

Store character credentials and state variables in separate session files loaded per-character. Use #var for global defaults and #local for combat-specific counters that must reset on disconnect. Never hardcode passwords in shared module files; instead, load them from restricted character files (chmod 600).

warrior.tin
# ~/.config/tintin/characters/warrior.tin
#session {main} {mud.example.com} {4000}
#var {char_name} {Grond}
#var {char_pass} {secretpassword}
#local {combat_round} {0}

⚠ Common Pitfalls

  • Global variables persist across sessions, causing cross-contamination when multiplaying
  • Plaintext password storage requires strict file permissions (600) to prevent reading by other users
4

Build Robust Trigger Regex with Priority Levels

Construct #action triggers using anchored regex to avoid matching player chat. Assign explicit priorities (1-9) to prevent heal triggers firing after death triggers. Use %1, %2 capture groups instead of greedy wildcards to parse prompt lines accurately. Test regex offline using #showme before connecting.

combat.tin
#action {^%*HP:%d/%d MV:%d/%d%*$} {
  #var {current_hp} {%2};
  #var {max_hp} {%3};
  #if {%2 < %3 * 0.3} {cast cure}
} {5}

⚠ Common Pitfalls

  • Unanchored patterns (%*) match system messages and player chat, causing accidental firing
  • Missing priority levels cause high-priority combat triggers to override low-priority chat triggers unexpectedly
5

Create Anti-Spam Aliases with Command Separation

Aliases must use semicolon command separation and include #delay to respect server-side rate limits. Build compound actions that check state variables before executing to prevent command flooding. Never create aliases that call themselves directly or through intermediaries.

aliases.tin
#alias {healup} {
  #if {$combat_round == 0} {
    quaff healing;#delay 1 {quaff healing};#delay 2 {quaff mana}
  } {
    #showme Cannot healup in combat!
  }
}

⚠ Common Pitfalls

  • Aliases calling themselves create infinite loops that disconnect the session
  • Missing #delay between commands triggers server-side rate limiting and temporary bans
6

Configure Persistent Split Screen Layouts

Use #split to reserve top rows for status and bottom rows for chat history. Calculate exact row counts based on terminal size ($rows variable) minus reserved space. Store the split configuration in a file loaded after terminal detection to ensure proper initialization sequence.

ui.tin
#math {split_point} {$rows - 3}
#split {$split_point}
#action {^%*HP:%*%*$} {#showme @ {$split_point+1} {HP: $current_hp/$max_hp}}

⚠ Common Pitfalls

  • Incorrect row calculations hide the prompt or truncate combat messages
  • Resizing the terminal without recalculating $split_point corrupts the display until #split is reissued
7

Implement Rotated Logging with Timestamp Filenames

Automate session logging using #log with date-stamped filenames to prevent unbounded file growth. Create logs/ subdirectories per character. Use #format to generate ISO 8601 timestamps and open logs on session start, closing them cleanly on #zap or disconnect to prevent corruption.

logging.tin
#format {logfile} {%t_%c.tinlog} {%Y-%m-%d} {$char_name}
#log {append} {/home/user/.config/tintin/logs/$logfile}
#action {^Disconnected from server.$} {#log off}

⚠ Common Pitfalls

  • Appending to a single log file creates multi-gigabyte files that crash text editors
  • Missing #log off on disconnect leaves file handles open, corrupting logs on unclean exit
8

Establish Offline Debugging Protocol

Test trigger regex and variable assignments using #showme and #debug before connecting to production servers. Create a test file that simulates server output to verify capture groups. Use #debug {action} {5} to see trigger matches without executing commands, preventing accidental automation in test environments.

debug.tin
#debug {action} {5}
#showme {HP:450/500 MV:100/100} 
#var {test_mode} {1}
#if {$test_mode} {#showme Trigger matched: $current_hp}

⚠ Common Pitfalls

  • Debugging in production reveals passwords in plaintext when #debug captures variable contents
  • Case sensitivity mismatches between #showme test data and actual server output cause silent trigger failures

What you built

Store all .tin files under version control and test configuration changes in an isolated tmux session before attaching to production. Monitor log rotation to prevent disk space exhaustion, and review trigger priorities quarterly when MUD output formats change. This architecture supports migration between servers by swapping character session files while preserving core automation logic.