Attorney Online is an open-source courtroom drama simulator client. Players connect to servers, choose characters, and act out cases in real time using animated sprites, chat messages, sound effects, and music. The client communicates with servers via the AO2 network protocol over WebSockets.
- Version: 2.11.0.0
- License: GPLv3
- Original client by FanatSors; this remake by OmniTroid and contributors
| Component | Detail |
|---|---|
| Language | C++20 |
| UI Framework | Qt 6 (recommended: 6.5.3) |
| Qt Modules | Core, Gui, Network, Widgets, Concurrent, WebSockets, UiTools |
| Build System | CMake (minimum 3.7.0) + Ninja |
| Compiler (Win) | MinGW 64-bit (bundled with Qt) |
| Compiler (Unix) | GCC / G++ (system) |
| Audio | BASS 2.4 + BASSOPUS 2.4 (un4seen.com) |
| Image Plugin | QtApng (APNG support, built from source) |
| Discord RPC | discord-rpc v3.4.0 (optional, enabled by default) |
| Code Formatter | clang-format (LLVM-based, see .clang-format) |
| Test Framework | Qt Test (QtTest module) |
AO2-Client/
├── bin/ # Build output directory (executables, DLLs, plugins)
│ ├── base/ # Game content (themes, characters, sounds) — not in repo
│ │ └── themes/ # Cloned from AO2-Themes repo by configure.sh
│ └── imageformats/ # QtApng plugin output (qapng.dll / libqapng.so)
├── data/ # Qt resource data (data.qrc, logo-client.rc for Windows)
├── lib/ # Third-party library headers and import libs
│ │ # (bass.h, bassopus.h, discord_rpc.h, *.lib / *.so)
│ │ # Populated by configure.sh — not committed to repo
├── scripts/ # Helper and release scripts
│ ├── APPIMAGE_INSTALL.sh
│ ├── Attorney_Online.desktop
│ ├── DYNAMIC_INSTALL.sh
│ ├── macos_release.sh
│ ├── wasabi.sh
│ └── wasabi_program.sh
├── src/ # All application source code
│ ├── network/ # Network layer
│ │ ├── serverinfo.h / serverinfo.cpp
│ │ └── websocketconnection.h / websocketconnection.cpp
│ ├── widgets/ # Standalone dialog/widget classes
│ │ ├── aooptionsdialog.h / aooptionsdialog.cpp
│ │ ├── direct_connect_dialog.h / direct_connect_dialog.cpp
│ │ ├── moderator_dialog.h / moderator_dialog.cpp
│ │ ├── playerlistwidget.h / playerlistwidget.cpp
│ │ └── server_editor_dialog.h / server_editor_dialog.cpp
│ ├── main.cpp
│ ├── aoapplication.h / aoapplication.cpp # Central application class
│ ├── lobby.h / lobby.cpp # Server browser / lobby window
│ ├── courtroom.h / courtroom.cpp # Main gameplay window
│ ├── networkmanager.h / networkmanager.cpp # Manages server connections
│ ├── aopacket.h / aopacket.cpp # AO2 network packet encode/decode
│ ├── packet_distribution.cpp # Routes incoming packets
│ ├── datatypes.h # Shared enums and structs
│ ├── options.h / options.cpp # User settings (QSettings-backed)
│ ├── animationlayer.h / animationlayer.cpp # Sprite animation rendering layer
│ ├── animationloader.h / animationloader.cpp
│ ├── aoblipplayer.h / aoblipplayer.cpp # Blip (typewriter) audio
│ ├── aomusicplayer.h / aomusicplayer.cpp # Music playback (BASS)
│ ├── aosfxplayer.h / aosfxplayer.cpp # SFX playback (BASS)
│ ├── aobutton / aocharbutton / aoemotebutton / aoevidencebutton # custom Qt buttons
│ ├── aoimage.h / aoimage.cpp # Image display widget
│ ├── aoevidencedisplay / aotextarea / aotextboxwidgets / aoclocklabel / aoemotepreview
│ ├── chatlogpiece.h / chatlogpiece.cpp # Chat log entry model
│ ├── serverdata.h / serverdata.cpp # Server metadata
│ ├── demoserver.h / demoserver.cpp # Demo/replay server
│ ├── discord_rich_presence.h / discord_rich_presence.cpp
│ ├── debug_functions.h / debug_functions.cpp
│ ├── file_functions.h / file_functions.cpp
│ ├── hardware_functions.h / hardware_functions.cpp
│ ├── charselect.cpp # Character selection logic
│ ├── emotes.cpp # Emote handling logic
│ └── evidence.cpp # Evidence handling logic
├── test/ # Unit tests
│ ├── CMakeLists.txt
│ ├── test_aopacket.cpp # AOPacket encode/decode tests (Qt Test)
│ ├── missle.png # Test asset
│ └── snackoo.png # Test asset
├── CMakeLists.txt
├── configure.sh # Cross-platform setup + build script
└── .clang-format # Code formatting rules
| Option | Default | Description |
|---|---|---|
AO_BUILD_TESTS |
ON | Build unit test programs |
AO_ENABLE_DISCORD_RPC |
ON | Enable Discord Rich Presence support |
The executable is output to ./bin/ via RUNTIME_OUTPUT_DIRECTORY.
configure.sh is the one-stop entry point for setting up and building the project.
./configure.sh # Auto-detect Qt, build Debug
./configure.sh QT_ROOT=/c/Qt # Specify Qt root explicitly
./configure.sh clean # Remove lib/, bin/, tmp/, qtapng/
./configure.sh -h # Print helpWhat configure.sh does:
- Detects platform (
windows/linux/macos) viauname -s - Locates Qt installation root and resolves versioned Qt 6.5.3 paths
- Finds CMake, MinGW (Windows), and Ninja bundled with Qt
- Downloads and installs dependencies into
./lib/and./bin/:- BASS from
https://www.un4seen.com/files/bass24.zip - BASSOPUS from
https://www.un4seen.com/files/bassopus24.zip - discord-rpc v3.4.0 from GitHub releases
- QtApng (cloned from GitHub, built with CMake+Ninja)
- Themes (cloned into
./bin/base/themes)
- BASS from
- Runs CMake and Ninja to build the project
- On Windows Release: runs
windeployqtto copy Qt DLLs - Saves the full CMake command to
cmake_cmd.txtfor IDE reference
mkdir cbuild && cd cbuild
cmake .. -G Ninja -DCMAKE_PREFIX_PATH=/path/to/Qt/6.5.3/gcc_64
ninjaThe vanilla base content (characters, sounds, backgrounds) is not in the repository. Download and extract into ./bin/base/:
https://ao-dl.b-cdn.net/vanilla_full_2024_8_2.zip
| Script | Purpose |
|---|---|
APPIMAGE_INSTALL.sh |
Linux AppImage installation |
DYNAMIC_INSTALL.sh |
Linux dynamic library installation |
Attorney_Online.desktop |
Linux desktop entry file |
macos_release.sh |
macOS release packaging |
wasabi.sh / wasabi_program.sh |
Wasabi (S3-compatible) asset upload/sync |
All code must be formatted with clang-format before committing. The CI pipeline enforces this.
clang-format -i src/**/*.cpp src/**/*.h- Base style: LLVM
- Indent width: 2 spaces
- Column limit: 486 (effectively no hard wrap)
- Brace style: Allman — every opening brace on its own line
- Short blocks: Only empty blocks on a single line
- Pointer alignment: Right (
int *ptr) - Qualifier alignment: Left (
const int) - Constructor initializers: Each on its own line (BeforeComma)
| Element | Convention | Example |
|---|---|---|
| Classes | PascalCase | AOApplication, Courtroom, AOPacket |
| AO-prefixed classes | AO + PascalCase |
AOButton, AOImage, AOBlipPlayer |
| Member variables | m_ prefix + snake_case |
m_header, m_content |
| Public member vars | snake_case (no prefix) | net_manager, w_lobby |
| Functions / methods | snake_case | construct_lobby(), send_server_packet() |
| Parameters | p_ prefix + snake_case (some older code) |
p_packet |
| Enums | SCREAMING_SNAKE_CASE | CHAT_MESSAGE, EMOTE_MOD_TYPE |
| File names | lowercase snake_case | file_functions.cpp, debug_functions.h |
| Header guards | #pragma once |
- Corresponding
.hfor a.cppfile - Project headers (
"filename.h") - Third-party library headers (
<bass.h>) - Qt headers (
<QObject>,<QString>, etc.) - Standard library headers
Tests use the Qt Test framework and are built when AO_BUILD_TESTS=ON (default).
# Build and run tests
cd cbuild && make test
# Run test binary directly
./test/test| Test | Source | What it tests |
|---|---|---|
test_aopacket |
test_aopacket.cpp |
AOPacket construction, encode(), decode(), special character substitutions |
AOPacket wire format: HEADER#arg1#arg2#%. Special character substitutions: #→<num>, %→<percent>, $→<dollar>, &→<and>.
Tests tagged [noci] are excluded from GitHub Actions CI (e.g. tests requiring audio hardware).
GitHub Actions runs .github/workflows/build.yml which checks:
- Clean compilation
- clang-format compliance (formatting check fails CI on unformatted code)
- Tests (excluding
[noci]tagged tests)