JavaScript client for Stealth with async/await API. Minimal implementation matching py_stealth functionality.
# No dependencies - pure Bun.jsimport './js_stealth';
config.HOST = '192.168.88.13';
const selfId = await Self();
const [x, y, z] = await parallel([
[GetX, selfId],
[GetY, selfId],
[GetZ, selfId],
]);
console.log(`Position: ${x}, ${y}, ${z}`);Connect to Stealth client. Port is auto-discovered if not provided.
await connect('192.168.88.13', 50026);
// or
config.HOST = '192.168.88.13';
// await connect(); Close connection to
await disconnect();Subscribe to Stealth events.
on('evspeech', (data) => {
console.log('Speech:', data);
});All event names are available as constants. Common events:
Item Events:
'eviteminfo'- Item information received'evitemdeleted'- Item deleted'evadditemtocontainer'- Item added to container'evaddmultipleitemsincont'- Multiple items added'evrejectmoveitem'- Item move rejected
Speech/Communication:
'evspeech'- Speech event (most common)'evclilocspeech'- Cliloc speech'evclilocspeechaffix'- Cliloc speech with affix'evunicodespeech'- Unicode speech'evglobalchat'- Global chat message
Character/Movement:
'evdrawgameplayer'- Player drawn'evmoverejection'- Movement rejected'evupdatechar'- Character updated'evcharanimation'- Character animation
UI/Interaction:
'evmenu'- Menu event'evmapmessage'- Map message'evincominggump'- Gump received'evgumptextentry'- Gump text entry'evcontextmenu'- Context menu
Combat:
'evallowrefuseattack'- Attack allowed/refused'evwardamage'- War damage'evdeath'- Death event
System:
'evtimer1','evtimer2'- Timer events'evbuffdebuffsystem'- Buff/debuff system'evupdateobjstats'- Object stats updated'evsetglobalvar'- Global variable set'evgraphicaleffect'- Graphical effect'evsound'- Sound event
Complete list: See EVENTS constant - all event names are exported and available globally after import.
Execute multiple commands in parallel for maximum performance.
const [x, y, z, type, name] = await parallel([
[GetX, selfId],
[GetY, selfId],
[GetZ, selfId],
[GetType, selfId],
[GetName, selfId],
]);Execute operations on multiple items in parallel.
const items = await FindType(0xFFFF, Ground());
const results = await parallel_items(items, [
GetX,
GetY,
GetZ,
GetType,
GetName,
]);
// Returns array of {id, data: [x, y, z, type, name]}
// Note: Use Find() or FindProps() for a more convenient API with automatic key mappingSelf()- Get player's object IDCharName()- Get character nameProfileName()- Get profile nameShardName()- Get shard nameWorldNum()- Get current world number
const selfId = await Self();
const charName = await CharName();
const profileName = await ProfileName();
const shardName = await ShardName();
const worldNum = await WorldNum();
console.log(`${charName} on ${shardName} (profile: ${profileName}, world: ${worldNum})`);GetX(objId)- Get X coordinateGetY(objId)- Get Y coordinateGetZ(objId)- Get Z coordinatePredictedX()- Get predicted X (for movement)PredictedY()- Get predicted Y (for movement)PredictedZ()- Get predicted Z (for movement)PredictedDirection()- Get predicted facing direction
const selfId = await Self();
const x = await GetX(selfId);
const y = await GetY(selfId);
const z = await GetZ(selfId);
console.log(`Position: [${x}, ${y}, ${z}]`);
// Predicted position (for movement calculations)
const predX = await PredictedX();
const predY = await PredictedY();
const predZ = await PredictedZ();
const predDir = await PredictedDirection();Str()- Get strengthInt()- Get intelligenceDex()- Get dexterityHP()- Get current hit pointsMana()- Get current manaStam()- Get current staminaMaxHP()- Get maximum hit pointsMaxMana()- Get maximum manaMaxStam()- Get maximum staminaWeight()- Get current weightMaxWeight()- Get maximum weightGold()- Get gold amountArmor()- Get armor ratingLuck()- Get luck valueRace()- Get raceSex()- Get genderBackpack()- Get backpack ID
// Get all stats in parallel
const [str, int, dex, hp, maxhp, mana, maxmana, stam, maxstam] = await parallel([
[Str],
[Int],
[Dex],
[HP],
[MaxHP],
[Mana],
[MaxMana],
[Stam],
[MaxStam],
]);
console.log(`Stats: STR ${str}, INT ${int}, DEX ${dex}`);
console.log(`HP: ${hp}/${maxhp}, Mana: ${mana}/${maxmana}, Stam: ${stam}/${maxstam}`);
const weight = await Weight();
const maxWeight = await MaxWeight();
const gold = await Gold();
const armor = await Armor();
const luck = await Luck();
const race = await Race();
const sex = await Sex();
const backpackId = await Backpack();
console.log(`Weight: ${weight}/${maxWeight}, Gold: ${gold}, Armor: ${armor}, Luck: ${luck}`);
console.log(`Race: ${race}, Gender: ${sex}, Backpack ID: ${backpackId}`);GetStr(objId)- Get strengthGetInt(objId)- Get intelligenceGetDex(objId)- Get dexterityGetHP(objId)- Get hit pointsGetMana(objId)- Get manaGetStam(objId)- Get staminaGetMaxHP(objId)- Get max hit pointsGetMaxMana(objId)- Get max manaGetMaxStam(objId)- Get max stamina
const targetId = await WarTargetID();
if (targetId) {
const [hp, maxhp, str, int, dex] = await parallel([
[GetHP, targetId],
[GetMaxHP, targetId],
[GetStr, targetId],
[GetInt, targetId],
[GetDex, targetId],
]);
console.log(`Target HP: ${hp}/${maxhp}, Stats: ${str}/${int}/${dex}`);
}Connected()- Check if connected to serverDead()- Check if deadHidden()- Check if hiddenPoisoned()- Check if poisonedParalyzed()- Check if paralyzedWarMode()- Check if in war modeIsDead(objId)- Check if object is deadIsRunning(objId)- Check if object is runningIsNPC(objId)- Check if object is NPCIsContainer(objId)- Check if object is containerIsMovable(objId)- Check if object is movable
// Check connection and self status
if (!(await Connected())) {
console.log('Not connected!');
}
const isDead = await Dead();
const isHidden = await Hidden();
const isPoisoned = await Poisoned();
const isParalyzed = await Paralyzed();
const inWarMode = await WarMode();
// Check object status
const targetId = await WarTargetID();
if (targetId) {
const isTargetDead = await IsDead(targetId);
const isTargetRunning = await IsRunning(targetId);
const isTargetNPC = await IsNPC(targetId);
const isTargetContainer = await IsContainer(targetId);
const isTargetMovable = await IsMovable(targetId);
console.log(`Target: Dead=${isTargetDead}, Running=${isTargetRunning}, NPC=${isTargetNPC}`);
}GetType(objId)- Get object type (graphic ID)GetName(objId)- Get object nameGetAltName(objId)- Get alternate nameGetTitle(objId)- Get titleGetColor(objId)- Get colorGetDirection(objId)- Get facing directionGetLayer(objId)- Get equipped layerGetDistance(objId)- Get distance to objectGetQuantity(objId)- Get quantityGetPrice(objId)- Get priceGetTooltip(objId)- Get tooltip textGetParent(objId)- Get parent container IDGetNotoriety(objId)- Get notorietyIsObjectExists(objId)- Check if object exists
const itemId = 12345;
// Get basic properties in parallel
const [type, name, color, quantity, distance, parent] = await parallel([
[GetType, itemId],
[GetName, itemId],
[GetColor, itemId],
[GetQuantity, itemId],
[GetDistance, itemId],
[GetParent, itemId],
]);
console.log(`${name} (type: 0x${type.toString(16)}, color: 0x${color.toString(16)})`);
console.log(`Quantity: ${quantity}, Distance: ${distance}, Parent: ${parent}`);
// Check if object exists before using
if (await IsObjectExists(itemId)) {
const tooltip = await GetTooltip(itemId);
const notoriety = await GetNotoriety(itemId);
console.log(`Tooltip: ${tooltip}, Notoriety: ${notoriety}`);
}IsYellowHits(objId)- Check if yellow hitsIsFemale(objId)- Check if femaleIsHouse(objId)- Check if house
const targetId = await WarTargetID();
if (targetId) {
const hasYellowHits = await IsYellowHits(targetId);
const isFemale = await IsFemale(targetId);
const isHouse = await IsHouse(targetId);
console.log(`Yellow hits: ${hasYellowHits}, Female: ${isFemale}, House: ${isHouse}`);
}SetFindDistance(value)- Set find distanceGetFindDistance()- Get find distanceSetFindVertical(value)- Set vertical find rangeGetFindVertical()- Get vertical find rangeGround()- Ground container constant (0)
// Set find distance to 35 tiles
await SetFindDistance(35);
const currentDistance = await GetFindDistance();
console.log(`Find distance: ${currentDistance}`);
// Set vertical range to 100
await SetFindVertical(100);
const currentVertical = await GetFindVertical();
console.log(`Find vertical: ${currentVertical}`);
// Use Ground() constant (equals 0)
const groundItems = await FindType(0xFFFF, Ground());Finds items and optionally gets their properties in one call. Supports filtering and getting additional properties after filtering.
Basic usage:
// Find items with basic properties
const creatures = await Find({
objTypes: [0xFFFF], // Find items of ANY of these types
colors: [0xFFFF], // With ANY of these colors
containers: [Ground()], // In ANY of these containers
operations: [GetHP, GetDistance] // Get properties: hp, distance
});
// Returns: [{ id: 123, hp: 100, distance: 50 }, { id: 456, hp: 75, distance: 120 }, ...]With filters:
const healthyCreatures = await Find({
objTypes: [0xFFFF],
operations: [GetHP],
filters: [(item) => item.hp > 0 && item.hp < 100] // Only creatures with HP between 0 and 100
});With properties (runs FindProps after filters):
// First get HP, filter by HP > 0, then get additional properties on filtered results
const creaturesDetails = await Find({
objTypes: [0xFFFF],
operations: [GetHP], // Get HP first
filters: [(item) => item.hp > 0], // Filter by HP > 0
properties: [GetName, GetNotoriety, GetX, GetY] // Then get these properties on filtered results
});
// Returns: [{ id: 123, hp: 100, name: 'a drake', notoriety: 4, x: 100, y: 200 }, ...]Parameters:
objTypesorobjType: Array or single number/hex (e.g.,[0x190, 0x191]or0x190)colorsorcolor: Array or single number/hex (default:[0xFFFF]- any color)containersorcontainer: Array or single container (numbers, hex, orGround(),Backpack()- promises auto-awaited)operations: Optional array of functions to execute on found items (e.g.,[GetX, GetY, GetHP])- If omitted or empty, returns objects with just
{ id }properties - Keys are auto-derived from function names (e.g.,
GetX→x,GetName→name)
- If omitted or empty, returns objects with just
keys: Optional custom keys array (auto-derived if omitted)filters: Optional function or array of functions to filter results (applied after operations)- All filters must return
truefor an item to be included (AND logic)
- All filters must return
properties: Optional array of functions to get additional properties after filtering (runsFindPropson filtered results)- Executed after filters, so you can filter first, then get expensive properties on fewer items
numConnections: Number of parallel connections (default: 16)
Examples:
// Find all items (just IDs)
const allItems = await Find({ objTypes: [0xFFFF], colors: [0xFFFF] });
// Returns: [{ id: 123 }, { id: 456 }, ...]
// Find with properties
const items = await Find({
objTypes: [0x0191, 0x0190],
operations: [GetName, GetQuantity],
filters: [(item) => item.quantity > 2]
});
// Returns: [{ id: 123, name: 'Apple', quantity: 5 }, ...]
// Find, filter, then get additional properties
const nearbyCreatures = await Find({
objTypes: [0xFFFF],
operations: [GetDistance, GetHP],
filters: [
(item) => item.distance < 10, // Filter by distance first
(item) => item.hp > 0 // Then by HP
],
properties: [GetName, GetNotoriety, GetType] // Get these only on filtered results
});FindType(objType, container)- Find objects by type- Returns array of object IDs (automatically calls GetFindedList)
containerdefaults to backpack if null, useGround()for ground- Automatically awaits promises (e.g.,
Backpack()) - noawaitneeded
const items = await FindType(0x0EED, Ground());
const backpackItems = await FindType(0x0EED); // null = backpack
const backpackItems2 = await FindType(0x0EED, Backpack()); // âś… No await needed - works directly!FindTypeEx(objType, color, container, inSub)- Find objects by type and color- Returns array of object IDs (automatically calls GetFindedList)
- Automatically awaits promises (e.g.,
Backpack()) - noawaitneeded
const redApples = await FindTypeEx(0x09D0, 0x0021, Ground(), false);
const backpackApples = await FindTypeEx(0x09D0, 0x0021, Backpack(), false); // âś… No await needed!GetFindedList()- Get list of found objects (usually auto-called)FindCount()- Get count of found objectsFindItem()- Get first found itemFindAtCoord(x, y)- Find items at coordinatesFindNotoriety(objType, notoriety)- Find by notoriety
// FindCount and FindItem (manual usage - usually auto-called)
const count = await FindCount();
const firstItem = await FindItem();
console.log(`Found ${count} items, first: ${firstItem}`);
// Find items at specific coordinates
const selfId = await Self();
const x = await GetX(selfId);
const y = await GetY(selfId);
const itemsAtCoord = await FindAtCoord(x, y);
console.log(`Items at [${x}, ${y}]:`, itemsAtCoord);
// Find by notoriety
const innocents = await FindNotoriety(0x0190, NOTORIETY.Innocent);
const enemies = await FindNotoriety(0x0191, NOTORIETY.Enemy);
console.log(`Innocents: ${innocents.length}, Enemies: ${enemies.length}`);Available notoriety values for FindNotoriety:
NOTORIETY.Innocent // 1 - Blue
NOTORIETY.Ally // 2 - Green
NOTORIETY.Attackable // 3 - Grey
NOTORIETY.Criminal // 4 - Grey
NOTORIETY.Enemy // 5 - Orange/Red
NOTORIETY.Murderer // 6 - Red
NOTORIETY.Invulnerable // 7 - Yellow
// Usage
const innocents = await FindNotoriety(0x0190, NOTORIETY.Innocent);
const enemies = await FindNotoriety(0x0191, NOTORIETY.Enemy);FindFullQuantity(objId)- Get full quantity of found itemFindTypesArrayEx(objTypes, colors, containers, inSub)- Find multiple types with multiple colors/containers- Automatically awaits promises in
containersarray (e.g.,Backpack()) - noawaitneeded
- Automatically awaits promises in
// Find full quantity of an item
const itemId = 12345;
const fullQuantity = await FindFullQuantity(itemId);
console.log(`Full quantity: ${fullQuantity}`);
// Find multiple types with multiple colors/containers
const items = await FindTypesArrayEx(
[0x0191, 0x0190], // Human and creature types
[0xFFFF, 0x0000], // Any color or black
[Backpack(), Ground()], // âś… No await needed - promises auto-awaited!
false // Don't search in subcontainers
);
console.log(`Found ${items.length} items matching criteria`);Find(options)- Find items and get their properties in one call (custom convenience method)- Finds items matching criteria and automatically fetches properties
- Returns objects with properties as keys (auto-derived from function names)
- Automatically awaits promises in
containers- noawaitneeded forBackpack()etc.
// Basic usage - single type, auto-derived keys
const creatures = await Find({
objTypes: [0xFFFF],
containers: [Ground()],
operations: [GetHP, GetX, GetY, GetName, GetDistance]
});
// Returns: [{ id: 123, hp: 25, x: 100, y: 200, name: 'a drake', distance: 10 }, ...]
// Multiple types, colors, containers - promises auto-awaited!
const items = await Find({
objTypes: [0x0191, 0x0190],
colors: [0xFFFF, 0x0000],
containers: [Backpack(), Ground()], // âś… No await needed - works directly!
operations: [GetName, GetQuantity]
});
// With filters
const alive = await Find({
objTypes: [0xFFFF],
operations: [GetHP, GetDistance],
filters: [(item) => item.hp > 0 && item.distance < 100]
});
// Custom keys
const data = await Find({
objTypes: [0x0EED],
operations: [GetX, GetY, GetName],
keys: ['posX', 'posY', 'itemName']
});FindProps(items, operations, keys?)- Get properties for existing objects (custom convenience method)- Adds properties to existing objects or creates new ones from IDs
- Automatically preserves existing properties when objects are passed
// Get properties for IDs
const objects = await FindProps([obj1, obj2], [GetX, GetY, GetName]);
// Returns: [{ id: obj1, x: 100, y: 200, name: 'item' }, ...]
// Get properties for existing objects (preserves existing properties)
const creatures = await Find({ objTypes: [0xFFFF], operations: [GetHP] });
const withNames = await FindProps(creatures, [GetName, GetDistance]);
// Returns: [{ id: 123, hp: 25, name: 'a drake', distance: 10 }, ...]
// Note: hp property is preserved from the original objects!Ignore(objId)- Add object to ignore listIgnoreOff(objId)- Remove object from ignore listIgnoreReset()- Clear ignore listGetIgnoreList()- Get ignore list
// Ignore self so we don't find ourselves
const selfId = await Self();
await Ignore(selfId);
// Ignore specific items/creatures
const itemId = 12345;
await Ignore(itemId);
// Check ignore list
const ignoreList = await GetIgnoreList();
console.log(`Ignoring ${ignoreList.length} objects`);
// Remove from ignore list
await IgnoreOff(itemId);
// Clear all ignores
await IgnoreReset();ClickOnObject(objId)- Click objectUseObject(objId)- Use objectUseType(objType, color)- Use object by type/colorUseFromGround(objType, color)- Use object from groundAttack(objId)- Attack objectDragItem(objId, count)- Drag itemDropItem(objId, x, y, z)- Drop item at coordinatesOpenDoor(objId)- Open doorBow()- Bow gestureSalute()- Salute gesture
// Click on an object
const itemId = 12345;
await ClickOnObject(itemId);
// Use an object
await UseObject(itemId);
// Use object by type (tinker tools)
await UseType(0x1EB8);
// Use from ground
await UseFromGround(0x0EED, 0xFFFF); // Use gold from ground
// Attack target
const targetId = await WarTargetID();
if (targetId) {
await Attack(targetId);
}
// Drag and drop item
const itemToMove = 12345;
const success = await DragItem(itemToMove, 10); // Drag 10 items
if (success) {
const selfId = await Self();
const x = await GetX(selfId);
const y = await GetY(selfId);
const z = await GetZ(selfId);
await DropItem(itemToMove, x + 1, y + 1, z); // Drop 1 tile away
}
// Open a door
const doorId = 67890;
await OpenDoor(doorId);
// Gestures
await Bow();
await Salute();WearItem(layer, objId)- Equip item to layerObjAtLayerEx(layer, objId)- Get object at layer
// Equip a weapon
const weaponId = 12345;
await WearItem(LAYERS.Rhand, weaponId);
// Check what's equipped
const equippedWeapon = await ObjAtLayerEx(LAYERS.Rhand);
const equippedShield = await ObjAtLayerEx(LAYERS.Lhand);
const equippedArmor = await ObjAtLayerEx(LAYERS.Torso);
console.log(`Weapon: ${equippedWeapon}, Shield: ${equippedShield}, Armor: ${equippedArmor}`);
// Equip full set
const [weapon, shield, armor, legs] = await parallel([
[FindType, 0x0F47, Backpack()], // Sword
[FindType, 0x1BC4, Backpack()], // Shield
[FindType, 0x144E, Backpack()], // Armor
[FindType, 0x144E, Backpack()], // Legs
]);
if (weapon.length > 0) await WearItem(LAYERS.Rhand, weapon[0]);
if (shield.length > 0) await WearItem(LAYERS.Lhand, shield[0]);
if (armor.length > 0) await WearItem(LAYERS.Torso, armor[0]);
if (legs.length > 0) await WearItem(LAYERS.Legs, legs[0]);Available layer constants (use with WearItem and ObjAtLayerEx):
// Core equipment
LAYERS.Rhand // 0x01 - Right hand
LAYERS.Lhand // 0x02 - Left hand
LAYERS.Shoes // 0x03
LAYERS.Pants // 0x04
LAYERS.Shirt // 0x05
LAYERS.Hat // 0x06
LAYERS.Gloves // 0x07
LAYERS.Ring // 0x08
LAYERS.Neck // 0x0A
LAYERS.Hair // 0x0B
LAYERS.Waist // 0x0C
LAYERS.Torso // 0x0D
LAYERS.Arms // 0x13
LAYERS.Cloak // 0x14
LAYERS.Bpack // 0x15 - Backpack
LAYERS.Robe // 0x16
LAYERS.Legs // 0x18
// Special
LAYERS.Talisman // 0x09
LAYERS.Brace // 0x0E
LAYERS.Beard // 0x10
LAYERS.TorsoH // 0x11
LAYERS.Ear // 0x12
LAYERS.Eggs // 0x17
LAYERS.Horse // 0x19
// Usage
await WearItem(LAYERS.Rhand, weaponId);
const equippedWeapon = await ObjAtLayerEx(LAYERS.Rhand);SetWarMode(value)- Set war mode on/offWarTargetID()- Get war target IDAttack(objId)- Attack target
// Check war mode status
const inWarMode = await WarMode();
// Toggle war mode
if (!inWarMode) {
await SetWarMode(true);
console.log('War mode enabled');
}
// Get current war target
const targetId = await WarTargetID();
if (targetId) {
console.log(`War target: ${targetId}`);
await Attack(targetId);
} else {
console.log('No war target');
}
// Disable war mode
await SetWarMode(false);TargetID()- Get current target IDLastTarget()- Get last target IDCancelTarget()- Cancel current targetTargetToObject(objId)- Target objectTargetToXYZ(x, y, z)- Target coordinatesTargetToTile(tileType, x, y)- Target tile
// Get current target
const currentTarget = await TargetID();
console.log(`Current target: ${currentTarget}`);
// Get last target
const lastTarget = await LastTarget();
console.log(`Last target: ${lastTarget}`);
// Target an object
const enemyId = 12345;
await TargetToObject(enemyId);
// Target coordinates
const selfId = await Self();
const x = await GetX(selfId);
const y = await GetY(selfId);
const z = await GetZ(selfId);
await TargetToXYZ(x + 5, y + 5, z);
// Target a tile (floor tile type)
await TargetToTile(0x400, x + 5, y + 5);
// Cancel target
await CancelTarget();WaitTargetObject(objId)- Wait for target on objectWaitTargetSelf()- Wait for target on selfWaitTargetLast()- Wait for target on last targetWaitTargetType(objType, color)- Wait for target on typeWaitTargetGround()- Wait for target on groundCancelWaitTarget()- Cancel wait target
// Cast heal and wait for target on self
await Cast('heal');
await WaitTargetSelf();
await Wait(500);
// Cast heal and wait for target on specific object
const friendId = 12345;
await Cast('greater heal');
await WaitTargetObject(friendId);
await Wait(500);
// Cast teleport and wait for target on last target
await Cast('teleport');
await WaitTargetLast();
await Wait(500);
// Cast dispel and wait for target on specific type
await Cast('dispel');
await WaitTargetType(0x0190, 0xFFFF); // Target humans
await Wait(500);
// Cast wall of stone and wait for target on ground
await Cast('wall of stone');
await WaitTargetGround();
await Wait(500);
// Cancel wait target
await CancelWaitTarget();Step(direction, run)- Step in direction (0-7, 0=North, 2=East, 4=South, 6=West)StepQ(direction, run)- Quick step with queue
// Step north (not running)
await Step(DIRECTIONS.North, false);
// Step east (running)
await Step(DIRECTIONS.East, true);
// Step in all directions
await Step(DIRECTIONS.North, false);
await Wait(500);
await Step(DIRECTIONS.East, false);
await Wait(500);
await Step(DIRECTIONS.South, false);
await Wait(500);
await Step(DIRECTIONS.West, false);
// Quick step (queued)
await StepQ(DIRECTIONS.Northeast, true);Available direction constants:
DIRECTIONS.North // 0
DIRECTIONS.Northeast // 1
DIRECTIONS.East // 2
DIRECTIONS.Southeast // 3
DIRECTIONS.South // 4
DIRECTIONS.Southwest // 5
DIRECTIONS.West // 6
DIRECTIONS.Northwest // 7
// Usage
await Step(DIRECTIONS.North, false);
await Step(DIRECTIONS.East, true); // runMoveXY(x, y, accuracyXY, running, exact)- Move to X, Y coordinatesMoveXYZ(x, y, z, accuracyXY, accuracyZ, running)- Move to X, Y, Z coordinatesnewMoveXY(x, y, optimized, accuracy, running)- Wrapper for MoveXYZ with Z=0newMoveXYZ(x, y, z, accuracyXY, accuracyZ, running, callback)- Pathfinding movement
// Simple movement
await MoveXY(2800, 480, 0, false, false);
// Pathfinding movement (may take longer)
await newMoveXYZ(2800, 480, 15, 0, 0, false);SetBadLocation(x, y)- Mark location as bad (avoid)SetGoodLocation(x, y)- Mark location as goodClearBadLocationList()- Clear bad location listSetBadObject(objType, color, radius)- Mark object type as badClearBadObjectList()- Clear bad object list
// Mark a location as bad (to avoid it)
await SetBadLocation(2800, 480);
await SetBadLocation(2801, 481);
// Mark a location as good
await SetGoodLocation(2900, 500);
// Clear all bad locations
await ClearBadLocationList();
// Mark object type as bad (avoid creatures)
await SetBadObject(0x0190, 0xFFFF, 5); // Avoid humans within 5 tiles
// Clear bad object list
await ClearBadObjectList();GetPathArray(x, y, running, accuracyXY)- Get 2D path arrayGetPathArray3D(x1, y1, z1, x2, y2, z2, worldNum, accuracyXY, accuracyZ, running)- Get 3D path arrayGetNextStepZ(x1, y1, z1, x2, y2, worldNum, stepZ)- Get next step Z coordinateCheckLOS(x1, y1, z1, x2, y2, z2, worldNum, flags, objId)- Check line of sight
const selfId = await Self();
const x1 = await GetX(selfId);
const y1 = await GetY(selfId);
const z1 = await GetZ(selfId);
const worldNum = await WorldNum();
// Get 2D path to destination
const path = await GetPathArray(3000, 500, false, 0);
console.log(`Path has ${path.length} steps`);
// Get 3D path
const path3D = await GetPathArray3D(x1, y1, z1, 3000, 500, 0, worldNum, 0, 0, false);
console.log(`3D path:`, path3D);
// Get next step Z coordinate
const nextZ = await GetNextStepZ(x1, y1, z1, 3000, 500, worldNum, 1);
console.log(`Next step Z: ${nextZ}`);
// Check line of sight
const targetId = await WarTargetID();
if (targetId) {
const [x2, y2, z2] = await parallel([
[GetX, targetId],
[GetY, targetId],
[GetZ, targetId],
]);
const hasLOS = await CheckLOS(x1, y1, z1, x2, y2, z2, worldNum, 0, 0);
console.log(`Line of sight: ${hasLOS}`);
}UseSkill(skillNameOrId)- Use skill by name (recommended) or IDUseSkillID(skillId)- Use skill by IDGetSkillValue(skillNameOrId)- Get skill value by name or IDGetSkillCap(skillNameOrId)- Get skill cap by name or IDGetSkillID(skillName)- Get skill ID from nameGetSkillCurrentValue(skillName)- Get skill value by name
// Use skill by name (recommended)
await UseSkill('hiding');
await UseSkill('stealth');
await UseSkill('detect hidden');
// Get skill values by name
const hidingValue = await GetSkillValue('hiding');
const hidingCap = await GetSkillCap('hiding');
// Or use by ID
await UseSkillID(14); // hiding
await UseSkill(14); // also works with ID
const value = await GetSkillValue(14); // also works with IDCombat: 'alchemy', 'anatomy', 'archery', 'arms lore', 'fencing', 'healing', 'mace fighting', 'parrying', 'swordsmanship', 'tactics', 'wrestling'
Magic: 'magery', 'necromancy', 'chivalry', 'bushido', 'ninjitsu', 'spellweaving', 'mysticism', 'evaluating intelligence', 'meditation', 'resisting spells', 'spirit speak'
Bard: 'discordance', 'musicianship', 'peacemaking', 'provocation'
Crafting: 'alchemy', 'blacksmithy', 'bowcraft', 'fletching', 'carpentry', 'cooking', 'inscription', 'tailoring', 'tinkering', 'imbuing', 'glassblowing', 'masonry'
Wilderness: 'animal lore', 'animal taming', 'camping', 'fishing', 'herding', 'lumberjacking', 'mining', 'tracking', 'veterinary'
Thief: 'detect hidden', 'hiding', 'lockpicking', 'poisoning', 'remove trap', 'snooping', 'stealing', 'stealth'
Miscellaneous: 'begging', 'cartography', 'focus', 'forensic evaluation', 'item identification', 'taste identification', 'throwing'
Note: Skill names are case-insensitive and should match UO skill names exactly. Use GetSkillID('skill name') to verify a skill name is valid.
Cast(spellName)- Cast spell by nameCastToObj(spellName, objId)- Cast spell and target objectCastToObject(spellName, objId)- Alias for CastToObjCastToSelf(spellName)- Cast spell and target selfCastSelf(spellName)- Alias for CastToSelfCastSpell(spellId)- Cast spell by IDIsActiveSpellAbility(spellNameOrId)- Check if spell ability is active
// Cast without target (waits for manual targeting)
await Cast('heal');
await WaitForTarget(3000);
if (await TargetPresent()) {
await TargetToSelf();
}
// Cast with target object (waits for target cursor, then casts)
const targetId = await WarTargetID();
if (targetId) {
await CastToObj('heal', targetId);
await CastToObject('greater heal', targetId); // Alias
}
// Cast to self
await CastToSelf('heal');
await CastSelf('greater heal'); // Alias
// Or cast by ID
await CastSpell(4); // heal
// Check if spell ability is active (see list below)
const enemyOfOneActive = await IsActiveSpellAbility('enemy of one');
const confidenceActive = await IsActiveSpellAbility('confidence');
if (!enemyOfOneActive) {
await Cast('enemy of one');
await WaitForTarget(3000);
if (await TargetPresent()) {
const enemyId = await WarTargetID();
if (enemyId) {
await TargetToObject(enemyId);
}
}
}
// Also works with spell IDs (using getSpellId helper)
const enemyOfOneId = getSpellId('enemy of one');
const isActive = await IsActiveSpellAbility(enemyOfOneId);These are spells/abilities that have an active state and can be checked with IsActiveSpellAbility:
Chivalry (Paladin):
'divine fury'- Increases damage and attack speed'enemy of one'- Massive damage bonus against one target
Bushido:
'confidence'- Increases damage and reduces damage taken'counter attack'- Automatic counter-attack'evasion'- Dodges next attack
Ninjitsu:
'animal form'- Transforms into an animal'mirror image'- Creates a decoy
Necromancy:
'vampiric embrace'- Vampire form (life leech)'lich form'- Lich form (mana leech)'wraith form'- Wraith form (physical damage immunity)
Other:
- Some transformation spells may also have active states
// Example: Check and activate Chivalry abilities
const divineFuryActive = await IsActiveSpellAbility('divine fury');
const enemyOfOneActive = await IsActiveSpellAbility('enemy of one');
if (!divineFuryActive) {
await Cast('divine fury');
await Wait(500);
}
// Example: Check Bushido abilities before combat
const confidenceActive = await IsActiveSpellAbility('confidence');
if (!confidenceActive) {
await Cast('confidence');
await Wait(500);
}
// Example: Check Necromancy forms
const vampiricEmbraceActive = await IsActiveSpellAbility('vampiric embrace');
const lichFormActive = await IsActiveSpellAbility('lich form');
const wraithFormActive = await IsActiveSpellAbility('wraith form');
// Only one form can be active at a time
if (!vampiricEmbraceActive && !lichFormActive && !wraithFormActive) {
await Cast('vampiric embrace');
await Wait(500);
}1st Circle: 'clumsy', 'create food', 'feeblemind', 'heal', 'magic arrow', 'night sight', 'reactive armor', 'weaken'
2nd Circle: 'agility', 'cunning', 'cure', 'harm', 'magic trap', 'magic untrap', 'protection', 'strength'
3rd Circle: 'bless', 'fireball', 'magic lock', 'poison', 'telekinesis', 'teleport', 'unlock', 'wall of stone'
4th Circle: 'arch cure', 'arch protection', 'curse', 'fire field', 'greater heal', 'lightning', 'mana drain', 'recall'
5th Circle: 'blade spirit', 'dispel field', 'incognito', 'magic reflection', 'spell reflection', 'mind blast', 'paralyze', 'poison field', 'summon creature'
6th Circle: 'dispel', 'energy bolt', 'explosion', 'invisibility', 'mark', 'mass curse', 'paralyze field', 'reveal'
7th Circle: 'chain lightning', 'energy field', 'flame strike', 'gate travel', 'mana vampire', 'mass dispel', 'meteor swarm', 'polymorph'
8th Circle: 'earthquake', 'energy vortex', 'resurrection', 'summon air elemental', 'summon daemon', 'summon earth elemental', 'summon fire elemental', 'summon water elemental'
Necromancy: 'animate dead', 'blood oath', 'corpse skin', 'curse weapon', 'evil omen', 'horrific beast', 'lich form', 'mind rot', 'pain spike', 'poison strike', 'strangle', 'summon familiar', 'vampiric embrace', 'vengeful spirit', 'wither', 'wraith form', 'exorcism'
Paladin: 'cleanse by fire', 'close wounds', 'consecrate weapon', 'dispel evil', 'divine fury', 'enemy of one', 'holy light', 'noble sacrifice', 'remove curse', 'sacred journey'
Bushido: 'confidence', 'counter attack', 'evasion', 'honorable execution', 'lightning strike', 'momentum strike'
Ninjitsu: 'animal form', 'backstab', 'death strike', 'focus attack', 'ki attack', 'mirror image', 'shadow jump', 'surprise attack'
Spellweaving: 'arcane circle', 'arcane empowerment', 'attune weapon', 'dryad allure', 'essence of wind', 'ethereal voyage', 'gift of life', 'gift of renewal', 'immolating weapon', 'mana phantasm', 'nature's fury', 'reaper form', 'rising colossus', 'soul seeker', 'summon fey', 'summon fiend', 'thunderstorm', 'wildfire', 'word of death'
Mysticism: 'animated weapon', 'bombard', 'cleansing winds', 'eagle strike', 'enchant', 'healing stone', 'hail storm', 'mass sleep', 'nether bolt', 'purge magic', 'rising colossus', 'sleep', 'spell plague', 'stone form', 'spell trigger', 'spellweaving'
InJournal(text)- Search for text in journalLastJournalMessage()- Get last journal messageJournal(index)- Get journal entry by indexLowJournal()- Get lowest journal indexHighJournal()- Get highest journal indexClearJournal()- Clear journalAddToSystemJournal(text)- Add message to system journal
// Get journal range
const low = await LowJournal();
const high = await HighJournal();
console.log(`Journal entries: ${low} to ${high}`);
// Get last journal message
const lastMessage = await LastJournalMessage();
console.log(`Last message: ${lastMessage}`);
// Search for text in journal
const hasText = await InJournal('You see');
if (hasText > 0) {
console.log(`Found 'You see' at index ${hasText}`);
}
// Read all journal entries
for (let i = low; i <= high; i++) {
const message = await Journal(i);
if (message) {
console.log(`[${i}] ${message}`);
}
}
// Add to system journal
await AddToSystemJournal('Script started');
// Clear journal
await ClearJournal();LastTarget()- Get last target IDLastAttack()- Get last attack IDLastContainer()- Get last container IDLastObject()- Get last object ID
// Get last actions
const lastTarget = await LastTarget();
const lastAttack = await LastAttack();
const lastContainer = await LastContainer();
const lastObject = await LastObject();
console.log(`Last target: ${lastTarget}`);
console.log(`Last attack: ${lastAttack}`);
console.log(`Last container: ${lastContainer}`);
console.log(`Last object: ${lastObject}`);
// Use last target for spell casting
await Cast('heal');
await WaitTargetLast();Wait(ms)- Wait specified milliseconds
await Wait(1000); // Wait 1 secondon(event, callback)- Subscribe to events
on('evspeech', (data) => {
console.log('Speech event:', data);
});All constants are exported and available globally after importing js_stealth:
EVENTS- Array of all available event names foron()functionLAYERS- Equipment layer constants (e.g.,LAYERS.Rhand,LAYERS.Cloak)DIRECTIONS- Movement direction constants (e.g.,DIRECTIONS.North,DIRECTIONS.East)NOTORIETY- Notoriety constants (e.g.,NOTORIETY.Innocent,NOTORIETY.Enemy)SPELLS- Spell name to ID mapping (used internally, but available for reference)SKILL_NAMES- Array of all valid skill namesBUFFS- Buff/debuff icon ID mapping (e.g.,BUFFS.curse,BUFFS.bless)getBuffName(iconId)- Helper function to get buff name from icon ID (forevbuffdebuffsystemevents)
import './js_stealth';
// Use constants directly
await WearItem(LAYERS.Rhand, weaponId);
await Step(DIRECTIONS.North, false);
const innocents = await FindNotoriety(0x0190, NOTORIETY.Innocent);
on("evspeech", (data) => { // 'evspeech'
console.log('Speech event:', data);
});
// Buff/debuff events - translate icon IDs to names
await on('evbuffdebuffsystem', (characterId, iconId, isAdded) => {
const buffName = getBuffName(iconId) || `unknown (${iconId})`;
console.log(`${buffName} ${isAdded ? 'added to' : 'removed from'} character ${characterId}`);
// Or use BUFFS directly:
if (iconId === BUFFS.curse) {
console.log('Curse detected!');
}
});config.HOST = '192.168.88.13';
config.PORT = 50026; // Optional, auto-discovered if not setconst apples = await FindType(0x09D0, Ground());
for (const appleId of apples) {
await UseObject(appleId);
await Wait(1000);
}const target = await WarTargetID();
if (target) {
await Attack(target);
const hp = await GetHP(target);
if (hp < 50) {
await Cast('heal'); // Heal
}
}const selfId = await Self();
const [x, y] = await parallel([
[GetX, selfId],
[GetY, selfId],
]);
// Move to coordinates
await MoveXY(x + 4, y + 4, 0, false, false);// Using Find() - recommended for finding and getting properties in one call
const creatures = await Find({
objTypes: [0xFFFF],
containers: [Ground()],
operations: [GetX, GetY, GetZ, GetType, GetName, GetHP],
filters: [(item) => item.hp > 0 && item.distance < 100]
});
// Returns: [{ id: 123, x: 100, y: 200, z: 0, type: 60, name: 'a drake', hp: 25 }, ...]
// Using parallel_items (lower-level API)
const items = await FindType(0xFFFF, Ground());
const data = await parallel_items(items, [
GetX,
GetY,
GetZ,
GetType,
GetName,
GetHP,
]);
// Returns: [{id: 123, data: [x, y, z, type, name, hp]}, ...]
// Using FindProps to add properties to existing objects
const filtered = creatures.filter(c => c.hp > 0);
const withDetails = await FindProps(filtered, [GetDistance, GetColor]);
// Returns: [{ id: 123, hp: 25, x: 100, y: 200, ..., distance: 10, color: 0 }, ...]
// Note: All properties from 'filtered' are preserved!- All methods are async and must be awaited
- Use
parallel()for multiple operations to maximize performance FindTypeandFindTypeExautomatically return the found list- Use
Find()for finding items and getting their properties in one call (recommended) - Use
FindProps()to add properties to existing objects or convert IDs to objects parallel_items()is a lower-level API - preferFind()orFindProps()for convenience- Method signatures match py_stealth for easy porting
- Functions are available globally after
import './js_stealth'- no namespace needed