mirror of
https://github.com/bdnugget/rs-sdk.git
synced 2026-11-07 09:07:30 +00:00
pull insteadof push neerby locs and stuff
This commit is contained in:
1 parent
9c16e927ed
commit
347ea327aa
9 files changed
+159
-98
No files matched your search
+24
-13
@@ -176,7 +176,7 @@ export class BotActions {
|
||||
// ============ Porcelain: Smart Actions ============
|
||||
|
||||
async openDoor(target?: NearbyLoc | string | RegExp): Promise<OpenDoorResult> {
|
||||
const door = this.resolveLocation(target, /door|gate/i);
|
||||
const door = await this.resolveLocation(target, /door|gate/i);
|
||||
if (!door) {
|
||||
return { success: false, message: 'No door found nearby', reason: 'door_not_found' };
|
||||
}
|
||||
@@ -187,7 +187,8 @@ export class BotActions {
|
||||
if (closeOpt) {
|
||||
return { success: true, message: `${door.name} is already open`, reason: 'already_open', door };
|
||||
}
|
||||
return { success: false, message: `${door.name} has no Open option (options: ${door.options.join(', ')})`, reason: 'no_open_option', door };
|
||||
const optTexts = door.optionsWithIndex.map(o => o.text);
|
||||
return { success: false, message: `${door.name} has no Open option (options: ${optTexts.join(', ')})`, reason: 'no_open_option', door };
|
||||
}
|
||||
|
||||
if (door.distance > 2) {
|
||||
@@ -196,7 +197,9 @@ export class BotActions {
|
||||
return { success: false, message: `Could not walk to ${door.name}: ${walkResult.message}`, reason: 'walk_failed', door };
|
||||
}
|
||||
|
||||
const doorsNow = this.sdk.getNearbyLocs().filter(l =>
|
||||
// Re-scan after walking
|
||||
const locsNow = await this.sdk.scanNearbyLocs();
|
||||
const doorsNow = locsNow.filter(l =>
|
||||
l.x === door.x && l.z === door.z && /door|gate/i.test(l.name)
|
||||
);
|
||||
const refreshedDoor = doorsNow[0];
|
||||
@@ -278,7 +281,7 @@ export class BotActions {
|
||||
async chopTree(target?: NearbyLoc | string | RegExp): Promise<ChopTreeResult> {
|
||||
await this.dismissBlockingUI();
|
||||
|
||||
const tree = this.resolveLocation(target, /^tree$/i);
|
||||
const tree = await this.resolveLocation(target, /^tree$/i);
|
||||
if (!tree) {
|
||||
return { success: false, message: 'No tree found' };
|
||||
}
|
||||
@@ -368,7 +371,7 @@ export class BotActions {
|
||||
}
|
||||
|
||||
async pickupItem(target: GroundItem | string | RegExp): Promise<PickupResult> {
|
||||
const item = this.resolveGroundItem(target);
|
||||
const item = await this.resolveGroundItem(target);
|
||||
if (!item) {
|
||||
return { success: false, message: 'Item not found on ground', reason: 'item_not_found' };
|
||||
}
|
||||
@@ -801,7 +804,7 @@ export class BotActions {
|
||||
await this.dismissBlockingUI();
|
||||
|
||||
const banker = this.sdk.findNearbyNpc(/banker/i);
|
||||
const bankBooth = this.sdk.findNearbyLoc(/bank booth|bank chest/i);
|
||||
const bankBooth = await this.sdk.scanFindNearbyLoc(/bank booth|bank chest/i);
|
||||
|
||||
let interactSuccess = false;
|
||||
|
||||
@@ -1691,7 +1694,7 @@ export class BotActions {
|
||||
}
|
||||
|
||||
// Find anvil
|
||||
const anvil = this.sdk.findNearbyLoc(/anvil/i);
|
||||
const anvil = await this.sdk.scanFindNearbyLoc(/anvil/i);
|
||||
if (!anvil) {
|
||||
return { success: false, message: 'No anvil nearby', reason: 'no_anvil' };
|
||||
}
|
||||
@@ -1816,17 +1819,21 @@ export class BotActions {
|
||||
|
||||
// ============ Resolution Helpers ============
|
||||
|
||||
private resolveLocation(
|
||||
/**
|
||||
* Resolve a location target by scanning if needed.
|
||||
* Now async because location scanning is on-demand.
|
||||
*/
|
||||
private async resolveLocation(
|
||||
target: NearbyLoc | string | RegExp | undefined,
|
||||
defaultPattern: RegExp
|
||||
): NearbyLoc | null {
|
||||
): Promise<NearbyLoc | null> {
|
||||
if (!target) {
|
||||
return this.sdk.findNearbyLoc(defaultPattern);
|
||||
return this.sdk.scanFindNearbyLoc(defaultPattern);
|
||||
}
|
||||
if (typeof target === 'object' && 'x' in target) {
|
||||
return target;
|
||||
}
|
||||
return this.sdk.findNearbyLoc(target);
|
||||
return this.sdk.scanFindNearbyLoc(target);
|
||||
}
|
||||
|
||||
private resolveInventoryItem(
|
||||
@@ -1842,11 +1849,15 @@ export class BotActions {
|
||||
return this.sdk.findInventoryItem(target);
|
||||
}
|
||||
|
||||
private resolveGroundItem(target: GroundItem | string | RegExp): GroundItem | null {
|
||||
/**
|
||||
* Resolve a ground item target by scanning if needed.
|
||||
* Now async because ground item scanning is on-demand.
|
||||
*/
|
||||
private async resolveGroundItem(target: GroundItem | string | RegExp): Promise<GroundItem | null> {
|
||||
if (typeof target === 'object' && 'x' in target) {
|
||||
return target;
|
||||
}
|
||||
return this.sdk.findGroundItem(target);
|
||||
return this.sdk.scanFindGroundItem(target);
|
||||
}
|
||||
|
||||
private resolveNpc(target: NearbyNpc | string | RegExp): NearbyNpc | null {
|
||||
|
||||
@@ -360,6 +360,66 @@ export class BotSDK {
|
||||
return this.state?.dialog || null;
|
||||
}
|
||||
|
||||
// ============ On-Demand Scanning ============
|
||||
// These methods scan the environment on-demand rather than relying on pushed state
|
||||
// Use these for expensive scans of nearby locations and ground items
|
||||
|
||||
/**
|
||||
* Scan for nearby locations (trees, rocks, doors, etc.) on-demand.
|
||||
* This is more efficient than constantly pushing this data in state updates.
|
||||
* @param radius - Scan radius in tiles (default 15)
|
||||
* @returns Array of nearby locations sorted by distance
|
||||
*/
|
||||
async scanNearbyLocs(radius?: number): Promise<NearbyLoc[]> {
|
||||
const result = await this.sendAction({ type: 'scanNearbyLocs', radius, reason: 'SDK' });
|
||||
if (result.success && result.data) {
|
||||
return result.data as NearbyLoc[];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for ground items on-demand.
|
||||
* This is more efficient than constantly pushing this data in state updates.
|
||||
* @param radius - Scan radius in tiles (default 15)
|
||||
* @returns Array of ground items sorted by distance
|
||||
*/
|
||||
async scanGroundItems(radius?: number): Promise<GroundItem[]> {
|
||||
const result = await this.sendAction({ type: 'scanGroundItems', radius, reason: 'SDK' });
|
||||
if (result.success && result.data) {
|
||||
return result.data as GroundItem[];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a nearby location by name pattern (on-demand scan).
|
||||
* @param pattern - String or RegExp to match location name
|
||||
* @param radius - Scan radius in tiles (default 15)
|
||||
* @returns First matching location or null
|
||||
*/
|
||||
async scanFindNearbyLoc(pattern: string | RegExp, radius?: number): Promise<NearbyLoc | null> {
|
||||
const locs = await this.scanNearbyLocs(radius);
|
||||
const regex = typeof pattern === 'string'
|
||||
? new RegExp(pattern, 'i')
|
||||
: pattern;
|
||||
return locs.find(l => regex.test(l.name)) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a ground item by name pattern (on-demand scan).
|
||||
* @param pattern - String or RegExp to match item name
|
||||
* @param radius - Scan radius in tiles (default 15)
|
||||
* @returns First matching item or null
|
||||
*/
|
||||
async scanFindGroundItem(pattern: string | RegExp, radius?: number): Promise<GroundItem | null> {
|
||||
const items = await this.scanGroundItems(radius);
|
||||
const regex = typeof pattern === 'string'
|
||||
? new RegExp(pattern, 'i')
|
||||
: pattern;
|
||||
return items.find(i => regex.test(i.name)) || null;
|
||||
}
|
||||
|
||||
// ============ State Subscriptions ============
|
||||
|
||||
onStateUpdate(listener: (state: BotWorldState) => void): () => void {
|
||||
|
||||
+6
-4
@@ -49,7 +49,6 @@ export interface InventoryItem {
|
||||
id: number;
|
||||
name: string;
|
||||
count: number;
|
||||
options: string[];
|
||||
optionsWithIndex: InventoryItemOption[];
|
||||
}
|
||||
|
||||
@@ -73,7 +72,6 @@ export interface NearbyNpc {
|
||||
combatCycle: number;
|
||||
animId: number;
|
||||
spotanimId: number;
|
||||
options: string[];
|
||||
optionsWithIndex: NpcOption[];
|
||||
}
|
||||
|
||||
@@ -106,7 +104,6 @@ export interface NearbyLoc {
|
||||
x: number;
|
||||
z: number;
|
||||
distance: number;
|
||||
options: string[];
|
||||
optionsWithIndex: LocOption[];
|
||||
}
|
||||
|
||||
@@ -249,11 +246,16 @@ export type BotAction =
|
||||
| { type: 'spellOnItem'; slot: number; spellComponent: number; reason: string }
|
||||
| { type: 'setTab'; tabIndex: number; reason: string }
|
||||
| { type: 'bankDeposit'; slot: number; amount: number; reason: string }
|
||||
| { type: 'bankWithdraw'; slot: number; amount: number; reason: string };
|
||||
| { type: 'bankWithdraw'; slot: number; amount: number; reason: string }
|
||||
// On-demand scanning (returns data in action result)
|
||||
| { type: 'scanNearbyLocs'; radius?: number; reason: string }
|
||||
| { type: 'scanGroundItems'; radius?: number; reason: string };
|
||||
|
||||
export interface ActionResult {
|
||||
success: boolean;
|
||||
message: string;
|
||||
/** Optional data payload (used by scan actions to return results) */
|
||||
data?: any;
|
||||
}
|
||||
|
||||
// ============ SDK Config ============
|
||||
|
||||
@@ -2,22 +2,34 @@
|
||||
// Maps BotAction types to actual game client operations
|
||||
|
||||
import type { Client } from '#/client/Client.js';
|
||||
import type { BotAction } from './types.js';
|
||||
import type { BotAction, NearbyLoc, GroundItem } from './types.js';
|
||||
|
||||
export interface ActionResult {
|
||||
success: boolean;
|
||||
message: string;
|
||||
data?: any; // Optional data payload for scan results
|
||||
}
|
||||
|
||||
export type ActionResultOrPromise = ActionResult | Promise<ActionResult>;
|
||||
|
||||
// Interface for on-demand scanning (provided by StateCollector)
|
||||
export interface ScanProvider {
|
||||
scanNearbyLocs(radius?: number): NearbyLoc[];
|
||||
scanGroundItems(radius?: number): GroundItem[];
|
||||
}
|
||||
|
||||
export class ActionExecutor {
|
||||
private client: Client;
|
||||
private scanProvider: ScanProvider | null = null;
|
||||
|
||||
constructor(client: Client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
setScanProvider(provider: ScanProvider): void {
|
||||
this.scanProvider = provider;
|
||||
}
|
||||
|
||||
execute(action: BotAction): ActionResultOrPromise {
|
||||
try {
|
||||
switch (action.type) {
|
||||
@@ -214,6 +226,26 @@ export class ActionExecutor {
|
||||
'Failed to send message'
|
||||
);
|
||||
|
||||
case 'scanNearbyLocs':
|
||||
if (!this.scanProvider) {
|
||||
return { success: false, message: 'No scan provider available' };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
message: `Scanned nearby locations`,
|
||||
data: this.scanProvider.scanNearbyLocs(action.radius)
|
||||
};
|
||||
|
||||
case 'scanGroundItems':
|
||||
if (!this.scanProvider) {
|
||||
return { success: false, message: 'No scan provider available' };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
message: `Scanned ground items`,
|
||||
data: this.scanProvider.scanGroundItems(action.radius)
|
||||
};
|
||||
|
||||
default:
|
||||
return { success: false, message: `Unknown action type: ${(action as any).type}` };
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ export class BotOverlay implements GatewayMessageHandler {
|
||||
onPacketLogToggle: () => {}
|
||||
});
|
||||
|
||||
// Wire scan provider so ActionExecutor can trigger on-demand scans
|
||||
this.executor.setScanProvider(this.collector);
|
||||
|
||||
// Connect to gateway
|
||||
this.gateway.connect();
|
||||
|
||||
@@ -205,7 +208,7 @@ export class BotOverlay implements GatewayMessageHandler {
|
||||
this.gateway.sendState(state, formattedState);
|
||||
}
|
||||
|
||||
private sendActionResult(result: { success: boolean; message: string }): void {
|
||||
private sendActionResult(result: { success: boolean; message: string; data?: any }): void {
|
||||
if (this.currentActionId) {
|
||||
this.gateway.sendActionResult(this.currentActionId, result);
|
||||
this.ui.logAction(result.success ? 'success' : 'failed', result.message);
|
||||
|
||||
@@ -111,7 +111,7 @@ export class GatewayConnection {
|
||||
});
|
||||
}
|
||||
|
||||
sendActionResult(actionId: string, result: { success: boolean; message: string }): void {
|
||||
sendActionResult(actionId: string, result: { success: boolean; message: string; data?: any }): void {
|
||||
this.send({
|
||||
type: 'actionResult',
|
||||
actionId,
|
||||
|
||||
@@ -39,8 +39,9 @@ import {
|
||||
type DialogState,
|
||||
type InterfaceState
|
||||
} from './types.js';
|
||||
import type { ScanProvider } from './ActionExecutor.js';
|
||||
|
||||
export class BotStateCollector {
|
||||
export class BotStateCollector implements ScanProvider {
|
||||
private client: Client;
|
||||
// Combat event tracking
|
||||
private combatEvents: CombatEvent[] = [];
|
||||
@@ -69,8 +70,8 @@ export class BotStateCollector {
|
||||
combatStyle: this.collectCombatStyle(),
|
||||
nearbyNpcs: this.collectNearbyNpcs(),
|
||||
nearbyPlayers: this.collectNearbyPlayers(),
|
||||
nearbyLocs: this.collectNearbyLocs(),
|
||||
groundItems: this.collectGroundItems(),
|
||||
nearbyLocs: [], // On-demand via scanNearbyLocs()
|
||||
groundItems: [], // On-demand via scanGroundItems()
|
||||
gameMessages: this.collectGameMessages(),
|
||||
menuActions: this.collectMenuActions(),
|
||||
shop: this.collectShopState(),
|
||||
@@ -398,7 +399,6 @@ export class BotStateCollector {
|
||||
|
||||
if (objId > 0) {
|
||||
let name = 'Unknown';
|
||||
const options: string[] = [];
|
||||
const optionsWithIndex: InventoryItemOption[] = [];
|
||||
|
||||
try {
|
||||
@@ -410,7 +410,6 @@ export class BotStateCollector {
|
||||
for (let opIdx = 0; opIdx < obj.iop.length; opIdx++) {
|
||||
const op = obj.iop[opIdx];
|
||||
if (op) {
|
||||
options.push(op);
|
||||
optionsWithIndex.push({ text: op, opIndex: opIdx + 1 }); // opIndex is 1-based
|
||||
}
|
||||
}
|
||||
@@ -422,7 +421,6 @@ export class BotStateCollector {
|
||||
id: objId - 1,
|
||||
name,
|
||||
count,
|
||||
options,
|
||||
optionsWithIndex
|
||||
});
|
||||
}
|
||||
@@ -454,13 +452,11 @@ export class BotStateCollector {
|
||||
const dz = (npc.z || 0) - (player.z || 0);
|
||||
const distance = Math.max(Math.abs(dx), Math.abs(dz)) >> 7;
|
||||
|
||||
const options: string[] = [];
|
||||
const optionsWithIndex: NpcOption[] = [];
|
||||
if (npcType.op) {
|
||||
for (let opIdx = 0; opIdx < npcType.op.length; opIdx++) {
|
||||
const op = npcType.op[opIdx];
|
||||
if (op) {
|
||||
options.push(op);
|
||||
optionsWithIndex.push({ text: op, opIndex: opIdx + 1 }); // opIndex is 1-based
|
||||
}
|
||||
}
|
||||
@@ -492,7 +488,6 @@ export class BotStateCollector {
|
||||
combatCycle,
|
||||
animId: npc.primarySeqId ?? -1,
|
||||
spotanimId: npc.spotanimId ?? -1,
|
||||
options,
|
||||
optionsWithIndex
|
||||
});
|
||||
}
|
||||
@@ -538,7 +533,8 @@ export class BotStateCollector {
|
||||
return players;
|
||||
}
|
||||
|
||||
private collectNearbyLocs(): NearbyLoc[] {
|
||||
// On-demand scanning for nearby locations (implements ScanProvider)
|
||||
scanNearbyLocs(radius?: number): NearbyLoc[] {
|
||||
const c = this.client as any;
|
||||
const locs: NearbyLoc[] = [];
|
||||
const player = c.localPlayer;
|
||||
@@ -555,8 +551,8 @@ export class BotStateCollector {
|
||||
// Track seen locations to avoid duplicates (key = `${id}_${x}_${z}`)
|
||||
const seen = new Set<string>();
|
||||
|
||||
// Scan nearby tiles
|
||||
const scanRadius = 15;
|
||||
// Scan nearby tiles (default 15 tile radius)
|
||||
const scanRadius = radius ?? 15;
|
||||
for (let dx = -scanRadius; dx <= scanRadius; dx++) {
|
||||
for (let dz = -scanRadius; dz <= scanRadius; dz++) {
|
||||
const tileX = playerTileX + dx;
|
||||
@@ -577,13 +573,11 @@ export class BotStateCollector {
|
||||
const locType = LocType.get(locId);
|
||||
// Include locations that have a name (skip unnamed scenery)
|
||||
if (locType.name) {
|
||||
const options: string[] = [];
|
||||
const optionsWithIndex: LocOption[] = [];
|
||||
if (locType.op) {
|
||||
for (let i = 0; i < locType.op.length; i++) {
|
||||
const op = locType.op[i];
|
||||
if (op) {
|
||||
options.push(op);
|
||||
optionsWithIndex.push({ text: op, opIndex: i + 1 }); // opIndex is 1-based
|
||||
}
|
||||
}
|
||||
@@ -594,7 +588,6 @@ export class BotStateCollector {
|
||||
x: baseX + tileX,
|
||||
z: baseZ + tileZ,
|
||||
distance,
|
||||
options,
|
||||
optionsWithIndex
|
||||
});
|
||||
}
|
||||
@@ -612,13 +605,11 @@ export class BotStateCollector {
|
||||
try {
|
||||
const locType = LocType.get(wallId);
|
||||
if (locType.name) {
|
||||
const options: string[] = [];
|
||||
const optionsWithIndex: LocOption[] = [];
|
||||
if (locType.op) {
|
||||
for (let i = 0; i < locType.op.length; i++) {
|
||||
const op = locType.op[i];
|
||||
if (op) {
|
||||
options.push(op);
|
||||
optionsWithIndex.push({ text: op, opIndex: i + 1 });
|
||||
}
|
||||
}
|
||||
@@ -629,7 +620,6 @@ export class BotStateCollector {
|
||||
x: baseX + tileX,
|
||||
z: baseZ + tileZ,
|
||||
distance,
|
||||
options,
|
||||
optionsWithIndex
|
||||
});
|
||||
}
|
||||
@@ -647,13 +637,11 @@ export class BotStateCollector {
|
||||
try {
|
||||
const locType = LocType.get(decorId);
|
||||
if (locType.name) {
|
||||
const options: string[] = [];
|
||||
const optionsWithIndex: LocOption[] = [];
|
||||
if (locType.op) {
|
||||
for (let i = 0; i < locType.op.length; i++) {
|
||||
const op = locType.op[i];
|
||||
if (op) {
|
||||
options.push(op);
|
||||
optionsWithIndex.push({ text: op, opIndex: i + 1 });
|
||||
}
|
||||
}
|
||||
@@ -664,7 +652,6 @@ export class BotStateCollector {
|
||||
x: baseX + tileX,
|
||||
z: baseZ + tileZ,
|
||||
distance,
|
||||
options,
|
||||
optionsWithIndex
|
||||
});
|
||||
}
|
||||
@@ -682,13 +669,11 @@ export class BotStateCollector {
|
||||
try {
|
||||
const locType = LocType.get(groundDecorId);
|
||||
if (locType.name) {
|
||||
const options: string[] = [];
|
||||
const optionsWithIndex: LocOption[] = [];
|
||||
if (locType.op) {
|
||||
for (let i = 0; i < locType.op.length; i++) {
|
||||
const op = locType.op[i];
|
||||
if (op) {
|
||||
options.push(op);
|
||||
optionsWithIndex.push({ text: op, opIndex: i + 1 });
|
||||
}
|
||||
}
|
||||
@@ -699,7 +684,6 @@ export class BotStateCollector {
|
||||
x: baseX + tileX,
|
||||
z: baseZ + tileZ,
|
||||
distance,
|
||||
options,
|
||||
optionsWithIndex
|
||||
});
|
||||
}
|
||||
@@ -714,7 +698,8 @@ export class BotStateCollector {
|
||||
return locs;
|
||||
}
|
||||
|
||||
private collectGroundItems(): GroundItem[] {
|
||||
// On-demand scanning for ground items (implements ScanProvider)
|
||||
scanGroundItems(radius?: number): GroundItem[] {
|
||||
const c = this.client as any;
|
||||
const items: GroundItem[] = [];
|
||||
const player = c.localPlayer;
|
||||
@@ -730,8 +715,8 @@ export class BotStateCollector {
|
||||
const baseX = c.sceneBaseTileX || 0;
|
||||
const baseZ = c.sceneBaseTileZ || 0;
|
||||
|
||||
// Scan nearby tiles (within reasonable range)
|
||||
const scanRadius = 15;
|
||||
// Scan nearby tiles (default 15 tile radius)
|
||||
const scanRadius = radius ?? 15;
|
||||
for (let dx = -scanRadius; dx <= scanRadius; dx++) {
|
||||
for (let dz = -scanRadius; dz <= scanRadius; dz++) {
|
||||
const tileX = playerTileX + dx;
|
||||
|
||||
@@ -57,7 +57,8 @@ export function formatBotState(state: BotState): string {
|
||||
const npc = state.nearbyNpcs[i];
|
||||
const lvlStr = npc.combatLevel > 0 ? ` (Lvl ${npc.combatLevel})` : '';
|
||||
const hpStr = npc.maxHp > 0 ? ` HP: ${npc.hp}/${npc.maxHp}` : '';
|
||||
const opStr = npc.options.length > 0 ? ` [${npc.options.join(', ')}]` : '';
|
||||
const opts = npc.optionsWithIndex.map(o => o.text);
|
||||
const opStr = opts.length > 0 ? ` [${opts.join(', ')}]` : '';
|
||||
lines.push(`${npc.name}${lvlStr}${hpStr} - ${npc.distance} tiles${opStr}`);
|
||||
}
|
||||
if (state.nearbyNpcs.length > 5) {
|
||||
@@ -81,35 +82,14 @@ export function formatBotState(state: BotState): string {
|
||||
}
|
||||
lines.push('');
|
||||
|
||||
// Nearby Locations (interactable objects)
|
||||
// Nearby Locations (interactable objects) - now on-demand via SDK scan methods
|
||||
lines.push('--- NEARBY OBJECTS ---');
|
||||
if (state.nearbyLocs.length === 0) {
|
||||
lines.push('None');
|
||||
} else {
|
||||
for (let i = 0; i < Math.min(8, state.nearbyLocs.length); i++) {
|
||||
const loc = state.nearbyLocs[i];
|
||||
const opStr = loc.options.length > 0 ? ` [${loc.options.join(', ')}]` : '';
|
||||
lines.push(`${loc.name} at (${loc.x}, ${loc.z}) - ${loc.distance} tiles${opStr}`);
|
||||
}
|
||||
if (state.nearbyLocs.length > 8) {
|
||||
lines.push(`... and ${state.nearbyLocs.length - 8} more`);
|
||||
}
|
||||
}
|
||||
lines.push('(Use sdk.scanNearbyLocs() for on-demand scan)');
|
||||
lines.push('');
|
||||
|
||||
// Ground items
|
||||
// Ground items - now on-demand via SDK scan methods
|
||||
lines.push('--- GROUND ITEMS ---');
|
||||
if (state.groundItems.length === 0) {
|
||||
lines.push('None');
|
||||
} else {
|
||||
for (let i = 0; i < Math.min(5, state.groundItems.length); i++) {
|
||||
const item = state.groundItems[i];
|
||||
lines.push(`${item.name} x${item.count} - ${item.distance} tiles`);
|
||||
}
|
||||
if (state.groundItems.length > 5) {
|
||||
lines.push(`... and ${state.groundItems.length - 5} more`);
|
||||
}
|
||||
}
|
||||
lines.push('(Use sdk.scanGroundItems() for on-demand scan)');
|
||||
lines.push('');
|
||||
|
||||
// Recent game messages
|
||||
@@ -265,20 +245,14 @@ export function formatWorldStateForAgent(state: BotWorldState, goal: string): st
|
||||
for (const npc of state.nearbyNpcs.slice(0, 8)) {
|
||||
const lvl = npc.combatLevel > 0 ? ` (Lvl ${npc.combatLevel})` : '';
|
||||
const hp = npc.maxHp > 0 ? ` HP: ${npc.hp}/${npc.maxHp}` : '';
|
||||
const opts = npc.options.length > 0 ? ` [${npc.options.join(', ')}]` : '';
|
||||
const optTexts = npc.optionsWithIndex.map(o => o.text);
|
||||
const opts = optTexts.length > 0 ? ` [${optTexts.join(', ')}]` : '';
|
||||
lines.push(`- ${npc.name}${lvl}${hp} - ${npc.distance} tiles away, index: ${npc.index}${opts}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Nearby Objects (trees, rocks, doors, etc.)
|
||||
if (state.nearbyLocs && state.nearbyLocs.length > 0) {
|
||||
lines.push('');
|
||||
lines.push('### Nearby Objects');
|
||||
for (const loc of state.nearbyLocs.slice(0, 10)) {
|
||||
const opts = loc.options.length > 0 ? ` [${loc.options.join(', ')}]` : '';
|
||||
lines.push(`- ${loc.name} at (${loc.x}, ${loc.z}) - ${loc.distance} tiles, id: ${loc.id}${opts}`);
|
||||
}
|
||||
}
|
||||
// Nearby Objects note - scanning is now on-demand
|
||||
// (Removed auto-display since nearbyLocs is empty until scanned)
|
||||
|
||||
// Inventory summary
|
||||
if (state.inventory.length > 0) {
|
||||
@@ -293,14 +267,8 @@ export function formatWorldStateForAgent(state: BotWorldState, goal: string): st
|
||||
}
|
||||
}
|
||||
|
||||
// Ground items
|
||||
if (state.groundItems.length > 0) {
|
||||
lines.push('');
|
||||
lines.push('### Ground Items Nearby');
|
||||
for (const item of state.groundItems.slice(0, 5)) {
|
||||
lines.push(`- ${item.name} x${item.count} at (${item.x}, ${item.z}), ${item.distance} tiles`);
|
||||
}
|
||||
}
|
||||
// Ground items note - scanning is now on-demand
|
||||
// (Removed auto-display since groundItems is empty until scanned)
|
||||
|
||||
// Recent game messages
|
||||
if (state.gameMessages && state.gameMessages.length > 0) {
|
||||
|
||||
@@ -37,8 +37,7 @@ export interface InventoryItem {
|
||||
id: number;
|
||||
name: string;
|
||||
count: number;
|
||||
options: string[]; // Display-only list of option texts
|
||||
optionsWithIndex: InventoryItemOption[]; // Options with their actual op index
|
||||
optionsWithIndex: InventoryItemOption[]; // Options with op index (use .map(o => o.text) for display)
|
||||
}
|
||||
|
||||
export interface NpcOption {
|
||||
@@ -69,8 +68,7 @@ export interface NearbyNpc {
|
||||
animId: number;
|
||||
/** Current spot animation ID (-1 = none) */
|
||||
spotanimId: number;
|
||||
options: string[]; // Display-only list of option texts
|
||||
optionsWithIndex: NpcOption[]; // Options with their actual op index
|
||||
optionsWithIndex: NpcOption[]; // Options with op index (use .map(o => o.text) for display)
|
||||
}
|
||||
|
||||
export interface NearbyPlayer {
|
||||
@@ -102,8 +100,7 @@ export interface NearbyLoc {
|
||||
x: number;
|
||||
z: number;
|
||||
distance: number;
|
||||
options: string[]; // Display-only list of option texts
|
||||
optionsWithIndex: LocOption[]; // Options with their actual op index
|
||||
optionsWithIndex: LocOption[]; // Options with op index (use .map(o => o.text) for display)
|
||||
}
|
||||
|
||||
export interface MenuAction {
|
||||
@@ -295,4 +292,7 @@ export type BotAction =
|
||||
| { type: 'setTab'; tabIndex: number; reason: string }
|
||||
| { type: 'say'; message: string; reason: string }
|
||||
| { type: 'bankDeposit'; slot: number; amount: number; reason: string }
|
||||
| { type: 'bankWithdraw'; slot: number; amount: number; reason: string };
|
||||
| { type: 'bankWithdraw'; slot: number; amount: number; reason: string }
|
||||
// On-demand scanning (returns data in action result)
|
||||
| { type: 'scanNearbyLocs'; radius?: number; reason: string }
|
||||
| { type: 'scanGroundItems'; radius?: number; reason: string };
|
||||
Reference in new issue
Block a user