ATS
Andor's Trail Scripting Language
AT (Andor's Trail) Scripting Language is a simple, C-like language used to write scripts (.ats files) that define game logic, trigger events, and control interactive elements in Andor's Trail.
Script files are located in the res/raw/ folder of the project, as plain-text .ats files. The file extension used doesn't matter, but it helps for identification. ATS stands for Andor's Trail Script. There is a detailed breakdown by Zukero on the forums.
Overview
AT scripts are stored in res/raw/ as .ats files and are executed by the game engine in response to triggers like:
Map entry/exit
Player actions
NPC interactions
Combat events
Item usage
Scripts define behavior through associations - connections between game objects and script methods.
Basic Script Structure
textassociation MyAssociation {
onCondition() {
// Triggered when condition is met
}
onExecute() {
// Main execution logic
}
onDeactivate() {
// Cleanup when association ends
}
}Script Lifecycle
onLoad - Script file is loaded into memory.
onInstantiate - Association object is created.
onActivate - Condition is met, association becomes active.
onExecute - Main logic runs each game tick.
onDeactivate - Association becomes inactive or is destroyed.
Variables and Types
Variable Declaration
text// Numerals (integers)
numeral myCounter = 0;
numeral damage = 10;
// Booleans
boolean isActive = true;
boolean hasItem = false;
// Strings
string dialogueText = "Hello, adventurer!";
string npcName = "Merchant";Value Types
numeral: Integer values (-∞ to +∞)
boolean: true or false.
string: Text values enclosed in quotes.
association: Reference to another association.
actor: Reference to an NPC or monster.
Trigger Conditions
Conditions determine when an association activates:
Map Triggers
textassociation OnMapEntry {
onCondition() {
// Triggered when player enters the map
return map.onEnter();
}
onExecute() {
// Show welcome dialogue
npc.say("Welcome!");
}
}Player Triggers
textassociation OnPlayerDeath {
onCondition() {
return player.onKilled();
}
onExecute() {
// Handle death
}
}
association OnPlayerLevelUp {
onCondition() {
return player.onGainLevel();
}
}NPC Triggers
textassociation OnNPCKilled {
onCondition() {
return npc.onKilled();
}
}
association OnNPCSpoken {
onCondition() {
return npc.onSpoken();
}
}Item Triggers
textassociation OnItemPickup {
onCondition() {
return player.onPickupItem("item_id");
}
}
association OnItemUse {
onCondition() {
return player.onUseItem("item_id");
}
}Control Flow
If-Else Statements
textassociation CheckPlayerHealth {
onExecute() {
if (player.getHP() < 10) {
player.say("I'm badly wounded!");
} else if (player.getHP() < 50) {
player.say("I'm injured.");
} else {
player.say("I'm healthy.");
}
}
}While Loops
textassociation CounterLoop {
numeral count = 0;
onExecute() {
while (count < 10) {
// Perform action
count = count + 1;
}
}
}Logical Operators
textif (condition1 AND condition2) {
// Both must be true
}
if (condition1 OR condition2) {
// Either can be true
}
if (NOT condition) {
// Condition must be false
}Method Calls
Player Methods
textplayer.getHP() // Get current HP
player.getMaxHP() // Get maximum HP
player.getAP() // Get action points
player.getLevel() // Get current level
player.hasItem("item_id") // Check if player has item
player.addItem("item_id") // Add item to inventory
player.removeItem("item_id") // Remove item from inventory
player.say("text") // Display dialogue
player.moveNorth() // Move player north
player.moveSouth() // Move player south
player.moveEast() // Move player east
player.moveWest() // Move player westNPC Methods
textnpc.say("text") // NPC says text
npc.getHP() // Get NPC health
npc.getLevel() // Get NPC level
npc.moveToPlayer() // NPC moves toward player
npc.moveAway() // NPC moves away from player
npc.attack(player) // NPC attacks player
npc.die() // NPC diesMap Methods
textmap.changeMap("map_id") // Change to another map
map.spawnMonster("id") // Spawn a monster
map.despawnMonster("id") // Remove a monster
map.displayMessage("text") // Show message to playerItem Methods
textitem.getID() // Get item ID
item.getName() // Get item name
item.getDescription() // Get item description
item.getQuantity() // Get quantity in inventoryAssociations
Associations link script logic to game objects and events:
Association Types
text// NPC Association
association NPCGreeting {
npc merchantName;
onCondition() {
return merchantName.onSpoken();
}
onExecute() {
merchantName.say("Welcome to my shop!");
}
}
// Map Association
association TrapTile {
numeral damageAmount = 10;
onCondition() {
return player.onEnterTile(15, 20);
}
onExecute() {
player.takeDamage(damageAmount);
map.displayMessage("You stepped on a trap!");
}
}
// Item Association
association PotionEffect {
onCondition() {
return player.onUseItem("health_potion");
}
onExecute() {
player.heal(50);
map.displayMessage("You drank the potion!");
}
}State Management
Track state using association variables:
textassociation QuestProgress {
numeral stage = 0;
boolean hasReward = false;
onExecute() {
if (stage == 0 AND player.hasItem("quest_item")) {
stage = 1;
npc.say("You found the item!");
}
if (stage == 1 AND NOT hasReward) {
player.addItem("reward");
hasReward = true;
stage = 2;
}
}
}Common Patterns
Quest Trigger
textassociation QuestStart {
onCondition() {
return npc.onSpoken();
}
onExecute() {
if (player.getLevel() >= 5) {
npc.say("Will you help me?");
// Add quest to player
} else {
npc.say("Come back when you're stronger.");
}
}
}Dialogue Progression
textassociation Dialogue {
numeral stage = 0;
onCondition() {
return npc.onSpoken();
}
onExecute() {
if (stage == 0) {
npc.say("Hello, traveler!");
stage = 1;
} else if (stage == 1) {
npc.say("Have you considered my offer?");
stage = 2;
} else {
npc.say("Farewell!");
}
}
}Conditional Reward
textassociation RewardNPC {
onCondition() {
return npc.onSpoken();
}
onExecute() {
if (player.hasItem("required_item")) {
player.removeItem("required_item");
player.addItem("reward_item");
npc.say("Thank you! Here is your reward.");
} else {
npc.say("Do you have what I asked for?");
}
}
}Best Practices
Use descriptive names - Name associations and variables clearly
Keep scripts focused - One association should handle one logical unit
Check conditions - Always verify conditions before executing actions
State tracking - Use variables to track quest/dialogue progress
Error handling - Assume items or NPCs might not exist
Comments - Document complex logic
Testing - Test edge cases (missing items, NPCs, etc.)
Integration with Game Files
Scripts are referenced in JSON files:
json{
"id": "example_npc",
"name": "Merchant",
"scripts": ["npc_greeting", "npc_trade"],
"private_scripts": ["npc_internal_logic"]
}Limitations
Scripts run synchronously - they cannot create delays or wait
Script execution is limited to prevent infinite loops
Access to game objects is restricted for security
Cannot directly modify save game data
Debugging Tips
Add dialogue messages to track execution
Check console output for script errors
Use map.displayMessage() to show variable values
Test each association independently
Verify JSON references are correct
Resources
Forum Discussion: AT Scripting Language documentation
Example Scripts: Check res/raw/*.ats in game repository
Game Engine: See source code in src/com/.../ for method definitions
Last updated