@conquest-eth/tools 0.0.0 → 0.0.2
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.
- package/README.md +20 -51
- package/dist/cli-tool-generator.d.ts +2 -1
- package/dist/cli-tool-generator.d.ts.map +1 -1
- package/dist/cli.js +61 -32
- package/dist/cli.js.map +1 -1
- package/dist/contracts/space-info.d.ts.map +1 -1
- package/dist/contracts/space-info.js +22 -1
- package/dist/contracts/space-info.js.map +1 -1
- package/dist/fleet/resolve.d.ts +1 -1
- package/dist/fleet/resolve.d.ts.map +1 -1
- package/dist/fleet/resolve.js +5 -4
- package/dist/fleet/resolve.js.map +1 -1
- package/dist/fleet/send.d.ts.map +1 -1
- package/dist/fleet/send.js +8 -8
- package/dist/fleet/send.js.map +1 -1
- package/dist/index.d.ts +6 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -128
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +14 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +29 -0
- package/dist/mcp.js.map +1 -0
- package/dist/planet/acquire.d.ts +3 -2
- package/dist/planet/acquire.d.ts.map +1 -1
- package/dist/planet/acquire.js +6 -4
- package/dist/planet/acquire.js.map +1 -1
- package/dist/planet/exit.d.ts.map +1 -1
- package/dist/planet/exit.js +1 -0
- package/dist/planet/exit.js.map +1 -1
- package/dist/planet/manager.d.ts +63 -0
- package/dist/planet/manager.d.ts.map +1 -1
- package/dist/planet/manager.js +125 -2
- package/dist/planet/manager.js.map +1 -1
- package/dist/planet/withdraw.d.ts +17 -0
- package/dist/planet/withdraw.d.ts.map +1 -0
- package/dist/planet/withdraw.js +25 -0
- package/dist/planet/withdraw.js.map +1 -0
- package/dist/storage/interface.d.ts +6 -0
- package/dist/storage/interface.d.ts.map +1 -1
- package/dist/storage/json-storage.d.ts +1 -0
- package/dist/storage/json-storage.d.ts.map +1 -1
- package/dist/storage/json-storage.js +10 -1
- package/dist/storage/json-storage.js.map +1 -1
- package/dist/tool-handling/cli-tool-generator.d.ts +22 -0
- package/dist/tool-handling/cli-tool-generator.d.ts.map +1 -0
- package/dist/tool-handling/cli-tool-generator.js +345 -0
- package/dist/tool-handling/cli-tool-generator.js.map +1 -0
- package/dist/tool-handling/cli.d.ts +19 -0
- package/dist/tool-handling/cli.d.ts.map +1 -0
- package/dist/tool-handling/cli.js +472 -0
- package/dist/tool-handling/cli.js.map +1 -0
- package/dist/tool-handling/index.d.ts +15 -0
- package/dist/tool-handling/index.d.ts.map +1 -0
- package/dist/tool-handling/index.js +32 -0
- package/dist/tool-handling/index.js.map +1 -0
- package/dist/tool-handling/mcp.d.ts +22 -0
- package/dist/tool-handling/mcp.d.ts.map +1 -0
- package/dist/tool-handling/mcp.js +88 -0
- package/dist/tool-handling/mcp.js.map +1 -0
- package/dist/tool-handling/types.d.ts +72 -0
- package/dist/tool-handling/types.d.ts.map +1 -0
- package/dist/tool-handling/types.js +10 -0
- package/dist/tool-handling/types.js.map +1 -0
- package/dist/tools/acquire_planets.d.ts +7 -5
- package/dist/tools/acquire_planets.d.ts.map +1 -1
- package/dist/tools/acquire_planets.js +28 -42
- package/dist/tools/acquire_planets.js.map +1 -1
- package/dist/tools/exit_planets.d.ts +7 -3
- package/dist/tools/exit_planets.d.ts.map +1 -1
- package/dist/tools/exit_planets.js +20 -9
- package/dist/tools/exit_planets.js.map +1 -1
- package/dist/tools/get_my_planets.d.ts +3 -2
- package/dist/tools/get_my_planets.d.ts.map +1 -1
- package/dist/tools/get_my_planets.js +5 -4
- package/dist/tools/get_my_planets.js.map +1 -1
- package/dist/tools/get_native_token_balance.d.ts +6 -0
- package/dist/tools/get_native_token_balance.d.ts.map +1 -0
- package/dist/tools/get_native_token_balance.js +64 -0
- package/dist/tools/get_native_token_balance.js.map +1 -0
- package/dist/tools/get_pending_exits.d.ts +2 -1
- package/dist/tools/get_pending_exits.d.ts.map +1 -1
- package/dist/tools/get_pending_exits.js +5 -4
- package/dist/tools/get_pending_exits.js.map +1 -1
- package/dist/tools/get_pending_fleets.d.ts +2 -1
- package/dist/tools/get_pending_fleets.d.ts.map +1 -1
- package/dist/tools/get_pending_fleets.js +5 -4
- package/dist/tools/get_pending_fleets.js.map +1 -1
- package/dist/tools/get_planets_around.d.ts +8 -4
- package/dist/tools/get_planets_around.d.ts.map +1 -1
- package/dist/tools/get_planets_around.js +40 -15
- package/dist/tools/get_planets_around.js.map +1 -1
- package/dist/tools/get_play_token_balance.d.ts +6 -0
- package/dist/tools/get_play_token_balance.d.ts.map +1 -0
- package/dist/tools/get_play_token_balance.js +80 -0
- package/dist/tools/get_play_token_balance.js.map +1 -0
- package/dist/tools/index.d.ts +7 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +7 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/missiv_get_user.d.ts +6 -0
- package/dist/tools/missiv_get_user.d.ts.map +1 -0
- package/dist/tools/missiv_get_user.js +50 -0
- package/dist/tools/missiv_get_user.js.map +1 -0
- package/dist/tools/missiv_register.d.ts +6 -0
- package/dist/tools/missiv_register.d.ts.map +1 -0
- package/dist/tools/missiv_register.js +103 -0
- package/dist/tools/missiv_register.js.map +1 -0
- package/dist/tools/resolve_fleet.d.ts +3 -2
- package/dist/tools/resolve_fleet.d.ts.map +1 -1
- package/dist/tools/resolve_fleet.js +5 -4
- package/dist/tools/resolve_fleet.js.map +1 -1
- package/dist/tools/send_fleet.d.ts +3 -2
- package/dist/tools/send_fleet.d.ts.map +1 -1
- package/dist/tools/send_fleet.js +16 -15
- package/dist/tools/send_fleet.js.map +1 -1
- package/dist/tools/simulate.d.ts +14 -0
- package/dist/tools/simulate.d.ts.map +1 -0
- package/dist/tools/simulate.js +123 -0
- package/dist/tools/simulate.js.map +1 -0
- package/dist/tools/simulate_multiple.d.ts +17 -0
- package/dist/tools/simulate_multiple.d.ts.map +1 -0
- package/dist/tools/simulate_multiple.js +166 -0
- package/dist/tools/simulate_multiple.js.map +1 -0
- package/dist/tools/verify_exit_status.d.ts +5 -3
- package/dist/tools/verify_exit_status.d.ts.map +1 -1
- package/dist/tools/verify_exit_status.js +12 -8
- package/dist/tools/verify_exit_status.js.map +1 -1
- package/dist/tools/withdraw.d.ts +9 -0
- package/dist/tools/withdraw.d.ts.map +1 -0
- package/dist/tools/withdraw.js +86 -0
- package/dist/tools/withdraw.js.map +1 -0
- package/dist/types.d.ts +31 -28
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -33
- package/dist/types.js.map +1 -1
- package/dist/util/time.d.ts +0 -30
- package/dist/util/time.d.ts.map +1 -1
- package/dist/util/time.js +0 -36
- package/dist/util/time.js.map +1 -1
- package/package.json +80 -77
- package/src/cli.ts +88 -59
- package/src/contracts/space-info.ts +24 -1
- package/src/fleet/resolve.ts +5 -4
- package/src/fleet/send.ts +9 -8
- package/src/index.ts +28 -162
- package/src/mcp.ts +46 -0
- package/src/planet/acquire.ts +6 -6
- package/src/planet/exit.ts +1 -0
- package/src/planet/manager.ts +163 -0
- package/src/planet/withdraw.ts +33 -0
- package/src/storage/interface.ts +7 -0
- package/src/storage/json-storage.ts +11 -1
- package/src/tool-handling/cli.ts +559 -0
- package/src/tool-handling/index.ts +45 -0
- package/src/tool-handling/mcp.ts +127 -0
- package/src/tool-handling/types.ts +86 -0
- package/src/tools/acquire_planets.ts +34 -60
- package/src/tools/exit_planets.ts +25 -12
- package/src/tools/get_native_token_balance.ts +72 -0
- package/src/tools/get_pending_exits.ts +8 -5
- package/src/tools/get_pending_fleets.ts +8 -5
- package/src/tools/get_planets_around.ts +45 -16
- package/src/tools/get_play_token_balance.ts +90 -0
- package/src/tools/index.ts +7 -1
- package/src/tools/missiv_get_user.ts +68 -0
- package/src/tools/missiv_register.ts +122 -0
- package/src/tools/resolve_fleet.ts +8 -5
- package/src/tools/send_fleet.ts +21 -18
- package/src/tools/simulate.ts +141 -0
- package/src/tools/simulate_multiple.ts +197 -0
- package/src/tools/verify_exit_status.ts +15 -11
- package/src/tools/withdraw.ts +100 -0
- package/src/types.ts +33 -71
- package/src/util/time.ts +0 -46
- package/src/cli-tool-generator.ts +0 -287
- package/src/helpers/index.ts +0 -59
- package/src/tools/get_my_planets.ts +0 -30
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {z} from 'zod';
|
|
2
|
+
import {createTool} from '../tool-handling/types.js';
|
|
3
|
+
import type {ConquestEnv} from '../types.js';
|
|
4
|
+
|
|
5
|
+
const schema = z.object({
|
|
6
|
+
address: z.string().describe('address'),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const missiv_get_user = createTool<typeof schema, ConquestEnv>({
|
|
10
|
+
description: 'get User details from address',
|
|
11
|
+
schema,
|
|
12
|
+
execute: async (env, {address}) => {
|
|
13
|
+
try {
|
|
14
|
+
const body = JSON.stringify({
|
|
15
|
+
type: 'getUser',
|
|
16
|
+
domain: 'conquest.eth',
|
|
17
|
+
address: address.toLowerCase(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const headers = {
|
|
21
|
+
'content-type': 'application/json',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const url = `https://api-conquest-2025-1.missiv.xyz/api/user/getCompleteUser`;
|
|
25
|
+
|
|
26
|
+
const resp = await fetch(url, {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
body,
|
|
29
|
+
headers,
|
|
30
|
+
});
|
|
31
|
+
if (resp.status !== 200 && resp.status !== 201) {
|
|
32
|
+
const text = await resp.text();
|
|
33
|
+
console.error(`failed`, text);
|
|
34
|
+
throw new Error(text);
|
|
35
|
+
}
|
|
36
|
+
if (resp) {
|
|
37
|
+
const json = await resp.json();
|
|
38
|
+
return {
|
|
39
|
+
success: true,
|
|
40
|
+
result: json as {
|
|
41
|
+
completeUser: {
|
|
42
|
+
user: `0x${string}`;
|
|
43
|
+
domain: string;
|
|
44
|
+
domainUsername?: string;
|
|
45
|
+
domainDescription?: string;
|
|
46
|
+
publicKey: `0x${string}`;
|
|
47
|
+
signature: `0x${string}`;
|
|
48
|
+
added: number;
|
|
49
|
+
lastPresence: number;
|
|
50
|
+
address: `0x${string}`;
|
|
51
|
+
name?: string;
|
|
52
|
+
description?: string;
|
|
53
|
+
created: number;
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
} else {
|
|
58
|
+
console.error(`failed with no response`);
|
|
59
|
+
throw new Error(`no response`);
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
error: error instanceof Error ? error.message : String(error),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {z} from 'zod';
|
|
2
|
+
import {createTool} from '../tool-handling/types.js';
|
|
3
|
+
import type {ConquestEnv} from '../types.js';
|
|
4
|
+
import {signAsync} from '@noble/secp256k1';
|
|
5
|
+
import {keccak_256} from '@noble/hashes/sha3';
|
|
6
|
+
import {computePublicKey} from '@ethersproject/signing-key';
|
|
7
|
+
|
|
8
|
+
const chainNames: {[chainId: string]: string} = {
|
|
9
|
+
'1': 'mainnet',
|
|
10
|
+
'3': 'ropsten',
|
|
11
|
+
'4': 'rinkeby',
|
|
12
|
+
'5': 'goerli',
|
|
13
|
+
'42': 'kovan',
|
|
14
|
+
'100': 'Gnosis Chain',
|
|
15
|
+
'1337': 'localhost chain',
|
|
16
|
+
'31337': 'localhost chain',
|
|
17
|
+
'7001': 'ZetaChain Testnet',
|
|
18
|
+
'7000': 'ZetaChain',
|
|
19
|
+
'42220': 'celo',
|
|
20
|
+
'11142220': 'celo-sepolia',
|
|
21
|
+
'143': 'monad',
|
|
22
|
+
'10143': 'monad-testnet',
|
|
23
|
+
};
|
|
24
|
+
function nameForChainId(chainId: string): string {
|
|
25
|
+
const name = chainNames[chainId];
|
|
26
|
+
if (name) {
|
|
27
|
+
return name;
|
|
28
|
+
}
|
|
29
|
+
return `chain with id ${chainId}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const schema = z.object({
|
|
33
|
+
bio: z
|
|
34
|
+
.string()
|
|
35
|
+
.describe(
|
|
36
|
+
'Describe who you are very briefly and how you can be reached (moltbook account, etc..)',
|
|
37
|
+
),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function publicKeyAuthorizationMessage({
|
|
41
|
+
address,
|
|
42
|
+
publicKey,
|
|
43
|
+
}: {
|
|
44
|
+
address: string;
|
|
45
|
+
publicKey: string;
|
|
46
|
+
}): string {
|
|
47
|
+
return `I authorize the following Public Key to represent me:\n ${publicKey}\n\n Others can use this key to write me messages`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const missiv_register = createTool<typeof schema, ConquestEnv>({
|
|
51
|
+
description:
|
|
52
|
+
'Register on Missiv so other can identify you. You can advertise your moltbook account here so other can send messages to you',
|
|
53
|
+
schema,
|
|
54
|
+
execute: async (env, {bio}) => {
|
|
55
|
+
if (!env.clients.walletClient || env.clients.walletClient.account === undefined) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
'Wallet client is required for this operation. Please provide a PRIVATE_KEY environment variable.',
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const chainId = await env.clients.publicClient.getChainId();
|
|
62
|
+
const chainName = nameForChainId(chainId.toString());
|
|
63
|
+
const message = `Only sign this message on "conquest.eth" or other trusted frontend.\nThis is for ${chainName}`;
|
|
64
|
+
const accountAddress = env.clients.walletClient.account.address.toLowerCase() as `0x${string}`;
|
|
65
|
+
const signatureToCreateDelegate = await env.clients.walletClient.signMessage({
|
|
66
|
+
account: accountAddress,
|
|
67
|
+
message,
|
|
68
|
+
});
|
|
69
|
+
const missivPrivateKey = signatureToCreateDelegate.slice(0, 66) as `0x${string}`;
|
|
70
|
+
|
|
71
|
+
const publicKey = computePublicKey(missivPrivateKey, true);
|
|
72
|
+
const signatureToAssociatePublicKeyToAccount = await env.clients.walletClient.signMessage({
|
|
73
|
+
account: accountAddress,
|
|
74
|
+
message: publicKeyAuthorizationMessage({address: accountAddress, publicKey}),
|
|
75
|
+
});
|
|
76
|
+
const action = {
|
|
77
|
+
type: 'register',
|
|
78
|
+
address: accountAddress,
|
|
79
|
+
domain: 'conquest.eth',
|
|
80
|
+
signature: signatureToAssociatePublicKeyToAccount,
|
|
81
|
+
domainDescription: bio,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const body = JSON.stringify(action);
|
|
86
|
+
const requestSignature = await signAsync(keccak_256(body), missivPrivateKey.slice(2)); // Sync methods below
|
|
87
|
+
|
|
88
|
+
const headers = {
|
|
89
|
+
'content-type': 'application/json',
|
|
90
|
+
SIGNATURE: `${requestSignature.toCompactHex()}:${requestSignature.recovery}`,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const url = `https://api-conquest-2025-1.missiv.xyz/api/user/register`;
|
|
94
|
+
|
|
95
|
+
const resp = await fetch(url, {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
body,
|
|
98
|
+
headers,
|
|
99
|
+
});
|
|
100
|
+
if (resp.status !== 200 && resp.status !== 201) {
|
|
101
|
+
const text = await resp.text();
|
|
102
|
+
console.error(`failed`, text);
|
|
103
|
+
throw new Error(text);
|
|
104
|
+
}
|
|
105
|
+
if (resp) {
|
|
106
|
+
const json = await resp.json();
|
|
107
|
+
return {
|
|
108
|
+
success: true,
|
|
109
|
+
result: json as any, // TODO,
|
|
110
|
+
};
|
|
111
|
+
} else {
|
|
112
|
+
console.error(`failed with no response`);
|
|
113
|
+
throw new Error(`no response`);
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
error: error instanceof Error ? error.message : String(error),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
});
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import {z} from 'zod';
|
|
2
|
-
import {createTool} from '../types.js';
|
|
2
|
+
import {createTool} from '../tool-handling/types.js';
|
|
3
|
+
import type {ConquestEnv} from '../types.js';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
const schema = z.object({
|
|
6
|
+
fleetId: z.string().describe('Fleet ID to resolve'),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const resolve_fleet = createTool<typeof schema, ConquestEnv>({
|
|
5
10
|
description:
|
|
6
11
|
'Resolve a previously sent fleet. This must be called after the fleet arrival time + resolve window to reveal the destination and secret.',
|
|
7
|
-
schema
|
|
8
|
-
fleetId: z.string().describe('Fleet ID to resolve'),
|
|
9
|
-
}),
|
|
12
|
+
schema,
|
|
10
13
|
execute: async (env, {fleetId}) => {
|
|
11
14
|
try {
|
|
12
15
|
const result = await env.fleetManager.resolve(fleetId);
|
package/src/tools/send_fleet.ts
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import {z} from 'zod';
|
|
2
|
-
import {createTool} from '../types.js';
|
|
2
|
+
import {createTool} from '../tool-handling/types.js';
|
|
3
3
|
import {zeroAddress} from 'viem';
|
|
4
|
+
import type {ConquestEnv} from '../types.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
const schema = z.object({
|
|
7
|
+
from: z.object({x: z.number(), y: z.number()}).describe('Source planet coordinates {x, y}'),
|
|
8
|
+
to: z.object({x: z.number(), y: z.number()}).describe('Destination planet coordinates {x, y}'),
|
|
9
|
+
quantity: z.number().describe('Number of spaceships to send'),
|
|
10
|
+
arrivalTimeWanted: z
|
|
11
|
+
.number()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe(
|
|
14
|
+
'Desired arrival time (timestamp in seconds). If not specified, will be calculated based on distance.',
|
|
15
|
+
),
|
|
16
|
+
gift: z
|
|
17
|
+
.boolean()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Whether the fleet is a gift (sent without requiring arrival)'),
|
|
20
|
+
specific: z.string().optional().describe('Additional specific data for the fleet'),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const send_fleet = createTool<typeof schema, ConquestEnv>({
|
|
6
24
|
description:
|
|
7
25
|
'Send a fleet from one planet to another in the Conquest game. The fleet will travel through space and can be resolved after arrival.',
|
|
8
|
-
schema
|
|
9
|
-
from: z.object({x: z.number(), y: z.number()}).describe('Source planet coordinates {x, y}'),
|
|
10
|
-
to: z.object({x: z.number(), y: z.number()}).describe('Destination planet coordinates {x, y}'),
|
|
11
|
-
quantity: z.number().describe('Number of spaceships to send'),
|
|
12
|
-
arrivalTimeWanted: z
|
|
13
|
-
.number()
|
|
14
|
-
.optional()
|
|
15
|
-
.describe(
|
|
16
|
-
'Desired arrival time (timestamp in seconds). If not specified, will be calculated based on distance.',
|
|
17
|
-
),
|
|
18
|
-
gift: z
|
|
19
|
-
.boolean()
|
|
20
|
-
.optional()
|
|
21
|
-
.describe('Whether the fleet is a gift (sent without requiring arrival)'),
|
|
22
|
-
specific: z.string().optional().describe('Additional specific data for the fleet'),
|
|
23
|
-
}),
|
|
26
|
+
schema,
|
|
24
27
|
execute: async (env, {from, to, quantity, arrivalTimeWanted, gift, specific}) => {
|
|
25
28
|
try {
|
|
26
29
|
// Convert coordinates to planet IDs
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {z} from 'zod';
|
|
2
|
+
import {createTool} from '../tool-handling/types.js';
|
|
3
|
+
import type {ConquestEnv} from '../types.js';
|
|
4
|
+
import type {PlanetState} from 'conquest-eth-v0-contracts';
|
|
5
|
+
|
|
6
|
+
const coordinatesSchema = z.object({
|
|
7
|
+
x: z.number().describe('X coordinate'),
|
|
8
|
+
y: z.number().describe('Y coordinate'),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const schema = z.object({
|
|
12
|
+
from: coordinatesSchema.describe('Source planet coordinates {x, y}'),
|
|
13
|
+
to: coordinatesSchema.describe('Target planet coordinates {x, y}'),
|
|
14
|
+
quantity: z.number().positive().describe('Number of spaceships to send'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const simulate = createTool<typeof schema, ConquestEnv>({
|
|
18
|
+
description:
|
|
19
|
+
'Simulate the outcome of a fleet attack. Returns min/max outcomes including whether capture is successful, number of spaceships left, time until attack fails, and combat losses.',
|
|
20
|
+
schema,
|
|
21
|
+
execute: async (env, {from, to, quantity}) => {
|
|
22
|
+
try {
|
|
23
|
+
// Get planet info for source
|
|
24
|
+
const fromPlanetId = env.planetManager.getPlanetIdByCoordinates(from.x, from.y);
|
|
25
|
+
if (!fromPlanetId) {
|
|
26
|
+
return {
|
|
27
|
+
success: false,
|
|
28
|
+
error: `No planet found at source coordinates (${from.x}, ${from.y})`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const fromPlanet = env.planetManager.getPlanetInfo(fromPlanetId);
|
|
32
|
+
if (!fromPlanet) {
|
|
33
|
+
return {
|
|
34
|
+
success: false,
|
|
35
|
+
error: `Could not get planet info for source planet at (${from.x}, ${from.y})`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Get planet info for target
|
|
40
|
+
const toPlanetId = env.planetManager.getPlanetIdByCoordinates(to.x, to.y);
|
|
41
|
+
if (!toPlanetId) {
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
error: `No planet found at target coordinates (${to.x}, ${to.y})`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const toPlanet = env.planetManager.getPlanetInfo(toPlanetId);
|
|
48
|
+
if (!toPlanet) {
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
error: `Could not get planet info for target planet at (${to.x}, ${to.y})`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Fetch current state of target planet
|
|
56
|
+
const planetsWithState = await env.planetManager.getPlanetsAround(to.x, to.y, 0);
|
|
57
|
+
if (planetsWithState.length === 0) {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
error: `Could not fetch state for target planet at (${to.x}, ${to.y})`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const toPlanetState = planetsWithState[0].state as PlanetState;
|
|
65
|
+
|
|
66
|
+
// Calculate travel time
|
|
67
|
+
const travelTime = env.spaceInfo.timeToArrive(fromPlanet, toPlanet);
|
|
68
|
+
|
|
69
|
+
// Calculate distance
|
|
70
|
+
const distance = env.spaceInfo.distance(fromPlanet, toPlanet);
|
|
71
|
+
|
|
72
|
+
// Use outcome() to simulate the attack
|
|
73
|
+
// Note: We pass undefined for player-related params since we're doing a simple simulation
|
|
74
|
+
const outcome = env.spaceInfo.outcome(
|
|
75
|
+
fromPlanet,
|
|
76
|
+
toPlanet,
|
|
77
|
+
toPlanetState,
|
|
78
|
+
quantity,
|
|
79
|
+
travelTime,
|
|
80
|
+
undefined, // senderPlayer
|
|
81
|
+
undefined, // fromPlayer
|
|
82
|
+
undefined, // toPlayer
|
|
83
|
+
false, // gift
|
|
84
|
+
undefined, // specific
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
success: true,
|
|
89
|
+
result: {
|
|
90
|
+
from: {x: from.x, y: from.y},
|
|
91
|
+
to: {x: to.x, y: to.y},
|
|
92
|
+
quantity,
|
|
93
|
+
travelTime,
|
|
94
|
+
distance,
|
|
95
|
+
outcome: {
|
|
96
|
+
min: {
|
|
97
|
+
captured: outcome.min.captured,
|
|
98
|
+
numSpaceshipsLeft: outcome.min.numSpaceshipsLeft,
|
|
99
|
+
},
|
|
100
|
+
max: {
|
|
101
|
+
captured: outcome.max.captured,
|
|
102
|
+
numSpaceshipsLeft: outcome.max.numSpaceshipsLeft,
|
|
103
|
+
},
|
|
104
|
+
timeUntilFails: outcome.timeUntilFails,
|
|
105
|
+
nativeResist: outcome.nativeResist,
|
|
106
|
+
gift: outcome.gift,
|
|
107
|
+
allies: outcome.allies,
|
|
108
|
+
combat: outcome.combat
|
|
109
|
+
? {
|
|
110
|
+
defenderLoss: outcome.combat.defenderLoss,
|
|
111
|
+
attackerLoss: outcome.combat.attackerLoss,
|
|
112
|
+
}
|
|
113
|
+
: undefined,
|
|
114
|
+
tax: outcome.tax
|
|
115
|
+
? {
|
|
116
|
+
taxRate: outcome.tax.taxRate,
|
|
117
|
+
loss: outcome.tax.loss,
|
|
118
|
+
}
|
|
119
|
+
: undefined,
|
|
120
|
+
},
|
|
121
|
+
targetPlanet: {
|
|
122
|
+
owner: toPlanetState.owner ?? null,
|
|
123
|
+
numSpaceships: toPlanetState.numSpaceships,
|
|
124
|
+
natives: toPlanetState.natives,
|
|
125
|
+
active: toPlanetState.active,
|
|
126
|
+
exiting: toPlanetState.exiting,
|
|
127
|
+
},
|
|
128
|
+
sourcePlanet: {
|
|
129
|
+
attack: fromPlanet.stats.attack,
|
|
130
|
+
speed: fromPlanet.stats.speed,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
} catch (error) {
|
|
135
|
+
return {
|
|
136
|
+
success: false,
|
|
137
|
+
error: error instanceof Error ? error.message : String(error),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
});
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import {z} from 'zod';
|
|
2
|
+
import {createTool} from '../tool-handling/types.js';
|
|
3
|
+
import type {ConquestEnv} from '../types.js';
|
|
4
|
+
import type {PlanetState, FleetInput} from 'conquest-eth-v0-contracts';
|
|
5
|
+
|
|
6
|
+
const coordinatesSchema = z.object({
|
|
7
|
+
x: z.number().describe('X coordinate'),
|
|
8
|
+
y: z.number().describe('Y coordinate'),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// Schema for multiple fleets simulation
|
|
12
|
+
const schema = z.object({
|
|
13
|
+
fleets: z
|
|
14
|
+
.array(
|
|
15
|
+
z.object({
|
|
16
|
+
from: coordinatesSchema.describe('Source planet coordinates {x, y}'),
|
|
17
|
+
quantity: z.number().positive().describe('Number of spaceships to send'),
|
|
18
|
+
}),
|
|
19
|
+
)
|
|
20
|
+
.min(1)
|
|
21
|
+
.describe('Array of fleets to send to the target'),
|
|
22
|
+
to: coordinatesSchema.describe('Target planet coordinates {x, y}'),
|
|
23
|
+
arrivalTime: z
|
|
24
|
+
.number()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe(
|
|
27
|
+
'Specific arrival time in seconds. If not provided, uses the maximum travel time from all fleets.',
|
|
28
|
+
),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const simulate_multiple = createTool<typeof schema, ConquestEnv>({
|
|
32
|
+
description:
|
|
33
|
+
'Simulate the outcome of multiple fleets attacking the same target planet. Fleets are processed sequentially, with the planet state updated after each combat. Returns individual fleet outcomes and the final combined result.',
|
|
34
|
+
schema,
|
|
35
|
+
execute: async (env, {fleets, to, arrivalTime}) => {
|
|
36
|
+
try {
|
|
37
|
+
// Get planet info for target
|
|
38
|
+
const toPlanetId = env.planetManager.getPlanetIdByCoordinates(to.x, to.y);
|
|
39
|
+
if (!toPlanetId) {
|
|
40
|
+
return {
|
|
41
|
+
success: false,
|
|
42
|
+
error: `No planet found at target coordinates (${to.x}, ${to.y})`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const toPlanet = env.planetManager.getPlanetInfo(toPlanetId);
|
|
46
|
+
if (!toPlanet) {
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
error: `Could not get planet info for target planet at (${to.x}, ${to.y})`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Fetch current state of target planet
|
|
54
|
+
const planetsWithState = await env.planetManager.getPlanetsAround(to.x, to.y, 0);
|
|
55
|
+
if (planetsWithState.length === 0) {
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: `Could not fetch state for target planet at (${to.x}, ${to.y})`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const toPlanetState = planetsWithState[0].state as PlanetState;
|
|
63
|
+
|
|
64
|
+
// Build fleet inputs with planet info
|
|
65
|
+
const fleetInputs: FleetInput[] = [];
|
|
66
|
+
const fleetDetails: Array<{
|
|
67
|
+
from: {x: number; y: number};
|
|
68
|
+
quantity: number;
|
|
69
|
+
travelTime: number;
|
|
70
|
+
distance: number;
|
|
71
|
+
attack: number;
|
|
72
|
+
speed: number;
|
|
73
|
+
}> = [];
|
|
74
|
+
|
|
75
|
+
for (const fleet of fleets) {
|
|
76
|
+
// Get planet info for source
|
|
77
|
+
const fromPlanetId = env.planetManager.getPlanetIdByCoordinates(fleet.from.x, fleet.from.y);
|
|
78
|
+
if (!fromPlanetId) {
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
error: `No planet found at source coordinates (${fleet.from.x}, ${fleet.from.y})`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const fromPlanet = env.planetManager.getPlanetInfo(fromPlanetId);
|
|
85
|
+
if (!fromPlanet) {
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
error: `Could not get planet info for source planet at (${fleet.from.x}, ${fleet.from.y})`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const travelTime = env.spaceInfo.timeToArrive(fromPlanet, toPlanet);
|
|
93
|
+
const distance = env.spaceInfo.distance(fromPlanet, toPlanet);
|
|
94
|
+
|
|
95
|
+
fleetInputs.push({
|
|
96
|
+
fromPlanet,
|
|
97
|
+
fleetAmount: fleet.quantity,
|
|
98
|
+
// We pass undefined for player-related params since we're doing a simple simulation
|
|
99
|
+
senderPlayer: undefined,
|
|
100
|
+
fromPlayer: undefined,
|
|
101
|
+
gift: false,
|
|
102
|
+
specific: undefined,
|
|
103
|
+
extra: undefined,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
fleetDetails.push({
|
|
107
|
+
from: {x: fleet.from.x, y: fleet.from.y},
|
|
108
|
+
quantity: fleet.quantity,
|
|
109
|
+
travelTime,
|
|
110
|
+
distance,
|
|
111
|
+
attack: fromPlanet.stats.attack,
|
|
112
|
+
speed: fromPlanet.stats.speed,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Use outcomeMultipleFleets() to simulate the combined attack
|
|
117
|
+
const multipleOutcome = env.spaceInfo.outcomeMultipleFleets(
|
|
118
|
+
fleetInputs,
|
|
119
|
+
toPlanet,
|
|
120
|
+
toPlanetState,
|
|
121
|
+
arrivalTime,
|
|
122
|
+
undefined, // toPlayer
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Format the fleet outcomes
|
|
126
|
+
const formattedFleetOutcomes = multipleOutcome.fleets.map((fleetOutcome, index) => ({
|
|
127
|
+
from: fleetDetails[index].from,
|
|
128
|
+
quantity: fleetDetails[index].quantity,
|
|
129
|
+
travelTime: fleetDetails[index].travelTime,
|
|
130
|
+
distance: fleetDetails[index].distance,
|
|
131
|
+
sourcePlanet: {
|
|
132
|
+
attack: fleetDetails[index].attack,
|
|
133
|
+
speed: fleetDetails[index].speed,
|
|
134
|
+
},
|
|
135
|
+
outcome: {
|
|
136
|
+
min: {
|
|
137
|
+
captured: fleetOutcome.outcome.min.captured,
|
|
138
|
+
numSpaceshipsLeft: fleetOutcome.outcome.min.numSpaceshipsLeft,
|
|
139
|
+
},
|
|
140
|
+
max: {
|
|
141
|
+
captured: fleetOutcome.outcome.max.captured,
|
|
142
|
+
numSpaceshipsLeft: fleetOutcome.outcome.max.numSpaceshipsLeft,
|
|
143
|
+
},
|
|
144
|
+
timeUntilFails: fleetOutcome.outcome.timeUntilFails,
|
|
145
|
+
nativeResist: fleetOutcome.outcome.nativeResist,
|
|
146
|
+
gift: fleetOutcome.outcome.gift,
|
|
147
|
+
allies: fleetOutcome.outcome.allies,
|
|
148
|
+
combat: fleetOutcome.outcome.combat
|
|
149
|
+
? {
|
|
150
|
+
defenderLoss: fleetOutcome.outcome.combat.defenderLoss,
|
|
151
|
+
attackerLoss: fleetOutcome.outcome.combat.attackerLoss,
|
|
152
|
+
}
|
|
153
|
+
: undefined,
|
|
154
|
+
tax: fleetOutcome.outcome.tax
|
|
155
|
+
? {
|
|
156
|
+
taxRate: fleetOutcome.outcome.tax.taxRate,
|
|
157
|
+
loss: fleetOutcome.outcome.tax.loss,
|
|
158
|
+
}
|
|
159
|
+
: undefined,
|
|
160
|
+
},
|
|
161
|
+
}));
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
success: true,
|
|
165
|
+
result: {
|
|
166
|
+
to: {x: to.x, y: to.y},
|
|
167
|
+
arrivalTime: multipleOutcome.arrivalTime,
|
|
168
|
+
fleets: formattedFleetOutcomes,
|
|
169
|
+
finalOutcome: {
|
|
170
|
+
min: {
|
|
171
|
+
captured: multipleOutcome.finalOutcome.min.captured,
|
|
172
|
+
numSpaceshipsLeft: multipleOutcome.finalOutcome.min.numSpaceshipsLeft,
|
|
173
|
+
owner: multipleOutcome.finalOutcome.min.owner ?? null,
|
|
174
|
+
},
|
|
175
|
+
max: {
|
|
176
|
+
captured: multipleOutcome.finalOutcome.max.captured,
|
|
177
|
+
numSpaceshipsLeft: multipleOutcome.finalOutcome.max.numSpaceshipsLeft,
|
|
178
|
+
owner: multipleOutcome.finalOutcome.max.owner ?? null,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
targetPlanet: {
|
|
182
|
+
owner: toPlanetState.owner ?? null,
|
|
183
|
+
numSpaceships: toPlanetState.numSpaceships,
|
|
184
|
+
natives: toPlanetState.natives,
|
|
185
|
+
active: toPlanetState.active,
|
|
186
|
+
exiting: toPlanetState.exiting,
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
} catch (error) {
|
|
191
|
+
return {
|
|
192
|
+
success: false,
|
|
193
|
+
error: error instanceof Error ? error.message : String(error),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
});
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import {z} from 'zod';
|
|
2
|
-
import {createTool} from '../types.js';
|
|
2
|
+
import {createTool} from '../tool-handling/types.js';
|
|
3
|
+
import type {ConquestEnv} from '../types.js';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
const schema = z.object({
|
|
6
|
+
x: z.number().describe('X coordinate of the planet'),
|
|
7
|
+
y: z.number().describe('Y coordinate of the planet'),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const verify_exit_status = createTool<typeof schema, ConquestEnv>({
|
|
5
11
|
description:
|
|
6
12
|
"Check and update the status of a planet's exit operation. Verifies if the exit has completed or been interrupted.",
|
|
7
|
-
schema
|
|
8
|
-
|
|
9
|
-
.union([z.string(), z.number()])
|
|
10
|
-
.describe('Planet location ID to verify (as hex string or number)'),
|
|
11
|
-
}),
|
|
12
|
-
execute: async (env, {planetId}) => {
|
|
13
|
+
schema,
|
|
14
|
+
execute: async (env, {x, y}) => {
|
|
13
15
|
try {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
const planetId = env.planetManager.getPlanetIdByCoordinates(x, y);
|
|
17
|
+
if (planetId === undefined) {
|
|
18
|
+
throw new Error(`No planet found at coordinates (${x}, ${y})`);
|
|
19
|
+
}
|
|
20
|
+
const result = await env.planetManager.verifyExitStatus(planetId);
|
|
17
21
|
|
|
18
22
|
// Calculate status based on exit state
|
|
19
23
|
const currentTime = Math.floor(Date.now() / 1000);
|