kill-switch-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Fight the nearest player (or a specific target) with tick-optimized auto-eat.
3
+ *
4
+ * Uses RS PvP combat fundamentals:
5
+ * - Attack FIRST, eat AFTER — eating delays your attack by 3 ticks,
6
+ * but if you eat right after your hit lands, the delay expires before
7
+ * your next attack is ready. Zero DPS loss.
8
+ * - Emergency eat at HP <= max hit (13) regardless of threshold
9
+ * - Won't eat above HP 28 (40 max - 12 lobster heal = wasted healing)
10
+ * - Targets lowest-HP visible player for fastest kills (unless overridden)
11
+ *
12
+ * @param opts.eatAt - HP threshold to eat at (default: 25)
13
+ * @param opts.duration - How long to fight in ms (default: 15000)
14
+ * @param opts.target - Specific player name or /pattern/ (default: weakest nearby)
15
+ * @param opts.fleeAt - Food count to flee at if outnumbered (default: 3)
16
+ * @returns { hp, maxHp, foodLeft, target, nearbyPlayers } — status at end of loop
17
+ *
18
+ * Usage:
19
+ * await actions.fightLoop()
20
+ * await actions.fightLoop({ eatAt: 20, duration: 20000 })
21
+ * await actions.fightLoop({ target: /vex/i })
22
+ */
23
+ export default async function fightLoop(bot: any, sdk: any, opts: any = {}) {
24
+ const eatAt = opts.eatAt ?? 25;
25
+ const emergencyHp = 13; // one-hit kill range — eat no matter what
26
+ const maxEatHp = 28; // don't eat above this (wastes food: 40 max - 12 heal)
27
+ const duration = opts.duration ?? 15000;
28
+ const targetPattern = opts.target ?? null;
29
+ const fleeAt = opts.fleeAt ?? 3;
30
+ const endTime = Date.now() + duration;
31
+
32
+ let lastTarget: string | null = null;
33
+
34
+ while (Date.now() < endTime) {
35
+ const state = sdk.getState();
36
+ if (!state) { await sdk.waitForTicks(1); continue; }
37
+
38
+ const hp = state.player.hitpoints;
39
+ const players = sdk.getNearbyPlayers();
40
+
41
+ // Bail signal: low food + outnumbered
42
+ const foodCount = countFood(sdk);
43
+ if (foodCount <= fleeAt && players.length > 1) {
44
+ return {
45
+ hp,
46
+ maxHp: state.player.hitpointsBase ?? 0,
47
+ foodLeft: foodCount,
48
+ target: lastTarget,
49
+ nearbyPlayers: players,
50
+ fled: true,
51
+ };
52
+ }
53
+
54
+ // Priority 1: Attack (deal damage BEFORE eating — tick-optimal)
55
+ let target;
56
+ if (targetPattern) {
57
+ target = players.find((p: any) =>
58
+ typeof targetPattern === 'string'
59
+ ? p.name.toLowerCase() === targetPattern.toLowerCase()
60
+ : targetPattern.test(p.name)
61
+ );
62
+ }
63
+
64
+ // Default: attack nearest player (simplest, most reliable)
65
+ if (!target && players.length > 0) {
66
+ target = players.sort((a: any, b: any) => a.distance - b.distance)[0];
67
+ }
68
+
69
+ if (target) {
70
+ lastTarget = target.name;
71
+ try {
72
+ await bot.attackPlayer(target);
73
+ } catch (e) {
74
+ // Target may have died or moved — continue loop
75
+ }
76
+ }
77
+
78
+ // Priority 2: Eat AFTER attacking (3-tick eat delay fits inside attack cooldown)
79
+ const shouldEat = hp <= emergencyHp || (hp < eatAt && hp <= maxEatHp);
80
+ if (shouldEat) {
81
+ const food = findBestFood(sdk);
82
+ if (food) {
83
+ await bot.eatFood(food);
84
+ await sdk.waitForTicks(1);
85
+ continue; // re-engage immediately
86
+ }
87
+ }
88
+
89
+ await sdk.waitForTicks(2);
90
+ }
91
+
92
+ // Return status
93
+ const finalState = sdk.getState();
94
+ return {
95
+ hp: finalState?.player?.hitpoints ?? 0,
96
+ maxHp: finalState?.player?.hitpointsBase ?? 0,
97
+ foodLeft: countFood(sdk),
98
+ target: lastTarget,
99
+ nearbyPlayers: sdk.getNearbyPlayers(),
100
+ };
101
+ }
102
+
103
+ function findBestFood(sdk: any): any {
104
+ return sdk.findInventoryItem(/swordfish/i)
105
+ || sdk.findInventoryItem(/lobster/i)
106
+ || sdk.findInventoryItem(/salmon/i)
107
+ || sdk.findInventoryItem(/trout/i)
108
+ || sdk.findInventoryItem(/bread/i)
109
+ || sdk.findInventoryItem(/meat/i);
110
+ }
111
+
112
+ function countFood(sdk: any): number {
113
+ const inv = sdk.getInventory();
114
+ return inv.filter((i: any) =>
115
+ /swordfish|lobster|salmon|trout|bread|meat/i.test(i.name)
116
+ ).length;
117
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Retreat from the nearest enemy while eating food to recover HP.
3
+ *
4
+ * Walks away from the closest player while prioritizing eating.
5
+ * Uses tick-optimal eating: won't eat above HP 28 (40 max - 12 heal = waste).
6
+ * Stops when HP is above the safe threshold or food/time runs out.
7
+ *
8
+ * @param opts.safeHp - HP to heal to before stopping (default: 40)
9
+ * @param opts.duration - Max time to kite in ms (default: 10000)
10
+ * @param opts.direction - "north"|"south"|"east"|"west"|"away" (default: "away" from nearest enemy)
11
+ * @returns { hp, foodLeft, escaped } — status after kiting
12
+ *
13
+ * Usage:
14
+ * await actions.kite()
15
+ * await actions.kite({ safeHp: 35, direction: "north" })
16
+ */
17
+ export default async function kite(bot: any, sdk: any, opts: any = {}) {
18
+ const safeHp = opts.safeHp ?? 40;
19
+ const duration = opts.duration ?? 10000;
20
+ const direction = opts.direction ?? 'away';
21
+ const maxEatHp = 28; // don't eat above this (wastes food)
22
+ const endTime = Date.now() + duration;
23
+
24
+ const STEP_SIZE = 5; // tiles per retreat step
25
+
26
+ while (Date.now() < endTime) {
27
+ const state = sdk.getState();
28
+ if (!state) { await sdk.waitForTicks(1); continue; }
29
+
30
+ const hp = state.player.hitpoints;
31
+
32
+ // Check if we've healed enough
33
+ if (hp >= safeHp) {
34
+ return { hp, foodLeft: countFood(sdk), escaped: true };
35
+ }
36
+
37
+ // Eat if below the waste ceiling (don't eat at 29+ HP — wastes healing)
38
+ if (hp <= maxEatHp) {
39
+ const food = findBestFood(sdk);
40
+ if (food) {
41
+ await bot.eatFood(food);
42
+ } else {
43
+ // No food left, no point kiting
44
+ return { hp, foodLeft: 0, escaped: false };
45
+ }
46
+ }
47
+
48
+ // Calculate retreat direction
49
+ const myX = state.player.worldX;
50
+ const myZ = state.player.worldZ;
51
+ let dx = 0, dz = 0;
52
+
53
+ if (direction === 'away') {
54
+ const players = sdk.getNearbyPlayers();
55
+ if (players.length > 0) {
56
+ const nearest = players.sort((a: any, b: any) => a.distance - b.distance)[0];
57
+ // Move opposite direction from nearest player
58
+ dx = myX - nearest.x;
59
+ dz = myZ - nearest.z;
60
+ // Normalize to step size
61
+ const dist = Math.sqrt(dx * dx + dz * dz) || 1;
62
+ dx = Math.round((dx / dist) * STEP_SIZE);
63
+ dz = Math.round((dz / dist) * STEP_SIZE);
64
+ }
65
+ } else {
66
+ switch (direction) {
67
+ case 'north': dz = STEP_SIZE; break;
68
+ case 'south': dz = -STEP_SIZE; break;
69
+ case 'east': dx = STEP_SIZE; break;
70
+ case 'west': dx = -STEP_SIZE; break;
71
+ }
72
+ }
73
+
74
+ if (dx !== 0 || dz !== 0) {
75
+ try {
76
+ await bot.walkTo(myX + dx, myZ + dz, 2);
77
+ } catch (e) {
78
+ // Hit a wall or boundary — try different direction
79
+ }
80
+ }
81
+
82
+ await sdk.waitForTicks(2);
83
+ }
84
+
85
+ const finalHp = sdk.getState()?.player?.hitpoints ?? 0;
86
+ return { hp: finalHp, foodLeft: countFood(sdk), escaped: finalHp >= safeHp };
87
+ }
88
+
89
+ function findBestFood(sdk: any): any {
90
+ return sdk.findInventoryItem(/swordfish/i)
91
+ || sdk.findInventoryItem(/lobster/i)
92
+ || sdk.findInventoryItem(/salmon/i)
93
+ || sdk.findInventoryItem(/trout/i)
94
+ || sdk.findInventoryItem(/bread/i)
95
+ || sdk.findInventoryItem(/meat/i);
96
+ }
97
+
98
+ function countFood(sdk: any): number {
99
+ const inv = sdk.getInventory();
100
+ return inv.filter((i: any) =>
101
+ /swordfish|lobster|salmon|trout|bread|meat/i.test(i.name)
102
+ ).length;
103
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Scan for nearby ground items, pick up the best available, and equip gear.
3
+ *
4
+ * Prioritizes weapons > armor > food. Picks up items closest to you first
5
+ * within each priority tier. Equips weapons and armor automatically.
6
+ *
7
+ * @param opts.maxItems - Max items to pick up before stopping (default: 5)
8
+ * @param opts.radius - Only grab items within this distance (default: 10)
9
+ * @param opts.foodOnly - Only pick up food, skip weapons/armor (default: false)
10
+ * @returns { picked, equipped, inventory } — what was grabbed and equipped
11
+ *
12
+ * Usage:
13
+ * await actions.lootAndEquip()
14
+ * await actions.lootAndEquip({ maxItems: 3, foodOnly: true })
15
+ */
16
+ export default async function lootAndEquip(bot: any, sdk: any, opts: any = {}) {
17
+ const maxItems = opts.maxItems ?? 5;
18
+ const maxRadius = opts.radius ?? 10;
19
+ const foodOnly = opts.foodOnly ?? false;
20
+
21
+ const picked: string[] = [];
22
+ const equipped: string[] = [];
23
+
24
+ // Item tier lists (best first)
25
+ const weapons = [
26
+ /rune scimitar/i, /rune long/i,
27
+ /adamant sword/i, /mithril scimitar/i,
28
+ /iron sword/i, /bronze dagger/i,
29
+ ];
30
+
31
+ const armor = [
32
+ /rune chain/i, /adamant plate/i,
33
+ /steel chain/i, /mithril.*helm/i,
34
+ /hardleather/i, /leather chaps/i, /leather body/i,
35
+ ];
36
+
37
+ const food = [
38
+ /swordfish/i, /lobster/i,
39
+ /salmon/i, /trout/i,
40
+ /bread/i, /meat/i,
41
+ ];
42
+
43
+ // Build a prioritized pickup list
44
+ const priorities = foodOnly
45
+ ? [...food]
46
+ : [...weapons, ...armor, ...food];
47
+
48
+ for (const pattern of priorities) {
49
+ if (picked.length >= maxItems) break;
50
+
51
+ const item = sdk.findGroundItem(pattern);
52
+ if (item && item.distance <= maxRadius) {
53
+ try {
54
+ const result = await bot.pickupItem(item);
55
+ if (result.success) {
56
+ picked.push(item.name);
57
+ }
58
+ } catch (e) {
59
+ // Item may have been grabbed by someone else
60
+ }
61
+ }
62
+ }
63
+
64
+ // Equip best weapon found (try best first)
65
+ if (!foodOnly) {
66
+ for (const pattern of weapons) {
67
+ const item = sdk.findInventoryItem(pattern);
68
+ if (item) {
69
+ try {
70
+ await bot.equipItem(item);
71
+ equipped.push(item.name);
72
+ } catch (e) { /* already equipped or can't */ }
73
+ break; // Only equip one weapon
74
+ }
75
+ }
76
+
77
+ // Equip best armor found
78
+ for (const pattern of armor) {
79
+ const item = sdk.findInventoryItem(pattern);
80
+ if (item) {
81
+ try {
82
+ await bot.equipItem(item);
83
+ equipped.push(item.name);
84
+ } catch (e) { /* already equipped or can't */ }
85
+ // Don't break — can equip body + legs + helm
86
+ }
87
+ }
88
+ }
89
+
90
+ return {
91
+ picked,
92
+ equipped,
93
+ inventory: sdk.getInventory(),
94
+ };
95
+ }