@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.
Files changed (178) hide show
  1. package/README.md +20 -51
  2. package/dist/cli-tool-generator.d.ts +2 -1
  3. package/dist/cli-tool-generator.d.ts.map +1 -1
  4. package/dist/cli.js +61 -32
  5. package/dist/cli.js.map +1 -1
  6. package/dist/contracts/space-info.d.ts.map +1 -1
  7. package/dist/contracts/space-info.js +22 -1
  8. package/dist/contracts/space-info.js.map +1 -1
  9. package/dist/fleet/resolve.d.ts +1 -1
  10. package/dist/fleet/resolve.d.ts.map +1 -1
  11. package/dist/fleet/resolve.js +5 -4
  12. package/dist/fleet/resolve.js.map +1 -1
  13. package/dist/fleet/send.d.ts.map +1 -1
  14. package/dist/fleet/send.js +8 -8
  15. package/dist/fleet/send.js.map +1 -1
  16. package/dist/index.d.ts +6 -32
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +21 -128
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp.d.ts +14 -0
  21. package/dist/mcp.d.ts.map +1 -0
  22. package/dist/mcp.js +29 -0
  23. package/dist/mcp.js.map +1 -0
  24. package/dist/planet/acquire.d.ts +3 -2
  25. package/dist/planet/acquire.d.ts.map +1 -1
  26. package/dist/planet/acquire.js +6 -4
  27. package/dist/planet/acquire.js.map +1 -1
  28. package/dist/planet/exit.d.ts.map +1 -1
  29. package/dist/planet/exit.js +1 -0
  30. package/dist/planet/exit.js.map +1 -1
  31. package/dist/planet/manager.d.ts +63 -0
  32. package/dist/planet/manager.d.ts.map +1 -1
  33. package/dist/planet/manager.js +125 -2
  34. package/dist/planet/manager.js.map +1 -1
  35. package/dist/planet/withdraw.d.ts +17 -0
  36. package/dist/planet/withdraw.d.ts.map +1 -0
  37. package/dist/planet/withdraw.js +25 -0
  38. package/dist/planet/withdraw.js.map +1 -0
  39. package/dist/storage/interface.d.ts +6 -0
  40. package/dist/storage/interface.d.ts.map +1 -1
  41. package/dist/storage/json-storage.d.ts +1 -0
  42. package/dist/storage/json-storage.d.ts.map +1 -1
  43. package/dist/storage/json-storage.js +10 -1
  44. package/dist/storage/json-storage.js.map +1 -1
  45. package/dist/tool-handling/cli-tool-generator.d.ts +22 -0
  46. package/dist/tool-handling/cli-tool-generator.d.ts.map +1 -0
  47. package/dist/tool-handling/cli-tool-generator.js +345 -0
  48. package/dist/tool-handling/cli-tool-generator.js.map +1 -0
  49. package/dist/tool-handling/cli.d.ts +19 -0
  50. package/dist/tool-handling/cli.d.ts.map +1 -0
  51. package/dist/tool-handling/cli.js +472 -0
  52. package/dist/tool-handling/cli.js.map +1 -0
  53. package/dist/tool-handling/index.d.ts +15 -0
  54. package/dist/tool-handling/index.d.ts.map +1 -0
  55. package/dist/tool-handling/index.js +32 -0
  56. package/dist/tool-handling/index.js.map +1 -0
  57. package/dist/tool-handling/mcp.d.ts +22 -0
  58. package/dist/tool-handling/mcp.d.ts.map +1 -0
  59. package/dist/tool-handling/mcp.js +88 -0
  60. package/dist/tool-handling/mcp.js.map +1 -0
  61. package/dist/tool-handling/types.d.ts +72 -0
  62. package/dist/tool-handling/types.d.ts.map +1 -0
  63. package/dist/tool-handling/types.js +10 -0
  64. package/dist/tool-handling/types.js.map +1 -0
  65. package/dist/tools/acquire_planets.d.ts +7 -5
  66. package/dist/tools/acquire_planets.d.ts.map +1 -1
  67. package/dist/tools/acquire_planets.js +28 -42
  68. package/dist/tools/acquire_planets.js.map +1 -1
  69. package/dist/tools/exit_planets.d.ts +7 -3
  70. package/dist/tools/exit_planets.d.ts.map +1 -1
  71. package/dist/tools/exit_planets.js +20 -9
  72. package/dist/tools/exit_planets.js.map +1 -1
  73. package/dist/tools/get_my_planets.d.ts +3 -2
  74. package/dist/tools/get_my_planets.d.ts.map +1 -1
  75. package/dist/tools/get_my_planets.js +5 -4
  76. package/dist/tools/get_my_planets.js.map +1 -1
  77. package/dist/tools/get_native_token_balance.d.ts +6 -0
  78. package/dist/tools/get_native_token_balance.d.ts.map +1 -0
  79. package/dist/tools/get_native_token_balance.js +64 -0
  80. package/dist/tools/get_native_token_balance.js.map +1 -0
  81. package/dist/tools/get_pending_exits.d.ts +2 -1
  82. package/dist/tools/get_pending_exits.d.ts.map +1 -1
  83. package/dist/tools/get_pending_exits.js +5 -4
  84. package/dist/tools/get_pending_exits.js.map +1 -1
  85. package/dist/tools/get_pending_fleets.d.ts +2 -1
  86. package/dist/tools/get_pending_fleets.d.ts.map +1 -1
  87. package/dist/tools/get_pending_fleets.js +5 -4
  88. package/dist/tools/get_pending_fleets.js.map +1 -1
  89. package/dist/tools/get_planets_around.d.ts +8 -4
  90. package/dist/tools/get_planets_around.d.ts.map +1 -1
  91. package/dist/tools/get_planets_around.js +40 -15
  92. package/dist/tools/get_planets_around.js.map +1 -1
  93. package/dist/tools/get_play_token_balance.d.ts +6 -0
  94. package/dist/tools/get_play_token_balance.d.ts.map +1 -0
  95. package/dist/tools/get_play_token_balance.js +80 -0
  96. package/dist/tools/get_play_token_balance.js.map +1 -0
  97. package/dist/tools/index.d.ts +7 -1
  98. package/dist/tools/index.d.ts.map +1 -1
  99. package/dist/tools/index.js +7 -1
  100. package/dist/tools/index.js.map +1 -1
  101. package/dist/tools/missiv_get_user.d.ts +6 -0
  102. package/dist/tools/missiv_get_user.d.ts.map +1 -0
  103. package/dist/tools/missiv_get_user.js +50 -0
  104. package/dist/tools/missiv_get_user.js.map +1 -0
  105. package/dist/tools/missiv_register.d.ts +6 -0
  106. package/dist/tools/missiv_register.d.ts.map +1 -0
  107. package/dist/tools/missiv_register.js +103 -0
  108. package/dist/tools/missiv_register.js.map +1 -0
  109. package/dist/tools/resolve_fleet.d.ts +3 -2
  110. package/dist/tools/resolve_fleet.d.ts.map +1 -1
  111. package/dist/tools/resolve_fleet.js +5 -4
  112. package/dist/tools/resolve_fleet.js.map +1 -1
  113. package/dist/tools/send_fleet.d.ts +3 -2
  114. package/dist/tools/send_fleet.d.ts.map +1 -1
  115. package/dist/tools/send_fleet.js +16 -15
  116. package/dist/tools/send_fleet.js.map +1 -1
  117. package/dist/tools/simulate.d.ts +14 -0
  118. package/dist/tools/simulate.d.ts.map +1 -0
  119. package/dist/tools/simulate.js +123 -0
  120. package/dist/tools/simulate.js.map +1 -0
  121. package/dist/tools/simulate_multiple.d.ts +17 -0
  122. package/dist/tools/simulate_multiple.d.ts.map +1 -0
  123. package/dist/tools/simulate_multiple.js +166 -0
  124. package/dist/tools/simulate_multiple.js.map +1 -0
  125. package/dist/tools/verify_exit_status.d.ts +5 -3
  126. package/dist/tools/verify_exit_status.d.ts.map +1 -1
  127. package/dist/tools/verify_exit_status.js +12 -8
  128. package/dist/tools/verify_exit_status.js.map +1 -1
  129. package/dist/tools/withdraw.d.ts +9 -0
  130. package/dist/tools/withdraw.d.ts.map +1 -0
  131. package/dist/tools/withdraw.js +86 -0
  132. package/dist/tools/withdraw.js.map +1 -0
  133. package/dist/types.d.ts +31 -28
  134. package/dist/types.d.ts.map +1 -1
  135. package/dist/types.js +1 -33
  136. package/dist/types.js.map +1 -1
  137. package/dist/util/time.d.ts +0 -30
  138. package/dist/util/time.d.ts.map +1 -1
  139. package/dist/util/time.js +0 -36
  140. package/dist/util/time.js.map +1 -1
  141. package/package.json +80 -77
  142. package/src/cli.ts +88 -59
  143. package/src/contracts/space-info.ts +24 -1
  144. package/src/fleet/resolve.ts +5 -4
  145. package/src/fleet/send.ts +9 -8
  146. package/src/index.ts +28 -162
  147. package/src/mcp.ts +46 -0
  148. package/src/planet/acquire.ts +6 -6
  149. package/src/planet/exit.ts +1 -0
  150. package/src/planet/manager.ts +163 -0
  151. package/src/planet/withdraw.ts +33 -0
  152. package/src/storage/interface.ts +7 -0
  153. package/src/storage/json-storage.ts +11 -1
  154. package/src/tool-handling/cli.ts +559 -0
  155. package/src/tool-handling/index.ts +45 -0
  156. package/src/tool-handling/mcp.ts +127 -0
  157. package/src/tool-handling/types.ts +86 -0
  158. package/src/tools/acquire_planets.ts +34 -60
  159. package/src/tools/exit_planets.ts +25 -12
  160. package/src/tools/get_native_token_balance.ts +72 -0
  161. package/src/tools/get_pending_exits.ts +8 -5
  162. package/src/tools/get_pending_fleets.ts +8 -5
  163. package/src/tools/get_planets_around.ts +45 -16
  164. package/src/tools/get_play_token_balance.ts +90 -0
  165. package/src/tools/index.ts +7 -1
  166. package/src/tools/missiv_get_user.ts +68 -0
  167. package/src/tools/missiv_register.ts +122 -0
  168. package/src/tools/resolve_fleet.ts +8 -5
  169. package/src/tools/send_fleet.ts +21 -18
  170. package/src/tools/simulate.ts +141 -0
  171. package/src/tools/simulate_multiple.ts +197 -0
  172. package/src/tools/verify_exit_status.ts +15 -11
  173. package/src/tools/withdraw.ts +100 -0
  174. package/src/types.ts +33 -71
  175. package/src/util/time.ts +0 -46
  176. package/src/cli-tool-generator.ts +0 -287
  177. package/src/helpers/index.ts +0 -59
  178. 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
- export const resolve_fleet = createTool({
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: z.object({
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);
@@ -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
- export const send_fleet = createTool({
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: z.object({
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
- export const verify_exit_status = createTool({
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: z.object({
8
- planetId: z
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 result = await env.planetManager.verifyExitStatus(
15
- typeof planetId === 'string' ? BigInt(planetId) : BigInt(planetId),
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);