cogames 0.3.49__py3-none-any.whl → 0.3.64__py3-none-any.whl
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.
- cogames/cli/client.py +60 -6
- cogames/cli/docsync/__init__.py +0 -0
- cogames/cli/docsync/_nb_md_directive_processing.py +180 -0
- cogames/cli/docsync/_nb_md_sync.py +103 -0
- cogames/cli/docsync/_nb_py_sync.py +122 -0
- cogames/cli/docsync/_three_way_sync.py +115 -0
- cogames/cli/docsync/_utils.py +76 -0
- cogames/cli/docsync/docsync.py +156 -0
- cogames/cli/leaderboard.py +112 -28
- cogames/cli/mission.py +64 -53
- cogames/cli/policy.py +46 -10
- cogames/cli/submit.py +268 -67
- cogames/cogs_vs_clips/cog.py +79 -0
- cogames/cogs_vs_clips/cogs_vs_clips_mapgen.md +19 -16
- cogames/cogs_vs_clips/cogsguard_reward_variants.py +153 -0
- cogames/cogs_vs_clips/cogsguard_tutorial.py +56 -0
- cogames/cogs_vs_clips/evals/README.md +10 -16
- cogames/cogs_vs_clips/evals/cogsguard_evals.py +81 -0
- cogames/cogs_vs_clips/evals/diagnostic_evals.py +49 -444
- cogames/cogs_vs_clips/evals/difficulty_variants.py +13 -326
- cogames/cogs_vs_clips/evals/integrated_evals.py +5 -45
- cogames/cogs_vs_clips/evals/spanning_evals.py +9 -180
- cogames/cogs_vs_clips/mission.py +187 -146
- cogames/cogs_vs_clips/missions.py +46 -137
- cogames/cogs_vs_clips/procedural.py +8 -8
- cogames/cogs_vs_clips/sites.py +107 -3
- cogames/cogs_vs_clips/stations.py +198 -186
- cogames/cogs_vs_clips/tutorial_missions.py +1 -1
- cogames/cogs_vs_clips/variants.py +25 -476
- cogames/device.py +13 -1
- cogames/{policy/scripted_agent/README.md → docs/SCRIPTED_AGENT.md} +82 -58
- cogames/evaluate.py +18 -30
- cogames/main.py +1434 -243
- cogames/maps/canidate1_1000.map +1 -1
- cogames/maps/canidate1_1000_stations.map +2 -2
- cogames/maps/canidate1_500.map +1 -1
- cogames/maps/canidate1_500_stations.map +2 -2
- cogames/maps/canidate2_1000.map +1 -1
- cogames/maps/canidate2_1000_stations.map +2 -2
- cogames/maps/canidate2_500.map +1 -1
- cogames/maps/canidate2_500_stations.map +2 -2
- cogames/maps/canidate3_1000.map +1 -1
- cogames/maps/canidate3_1000_stations.map +2 -2
- cogames/maps/canidate3_500.map +1 -1
- cogames/maps/canidate3_500_stations.map +2 -2
- cogames/maps/canidate4_500.map +1 -1
- cogames/maps/canidate4_500_stations.map +2 -2
- cogames/maps/cave_base_50.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_agile.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_agile_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_charge_up.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_charge_up_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation1.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation1_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation2.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation2_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation3.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation3_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_near.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_search.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_search_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_extract_lab.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_extract_lab_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_memory.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_memory_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_radial.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_radial_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_resource_lab.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_unclip.map +2 -2
- cogames/maps/evals/eval_balanced_spread.map +9 -5
- cogames/maps/evals/eval_clip_oxygen.map +9 -5
- cogames/maps/evals/eval_collect_resources.map +9 -5
- cogames/maps/evals/eval_collect_resources_hard.map +9 -5
- cogames/maps/evals/eval_collect_resources_medium.map +9 -5
- cogames/maps/evals/eval_divide_and_conquer.map +9 -5
- cogames/maps/evals/eval_energy_starved.map +9 -5
- cogames/maps/evals/eval_multi_coordinated_collect_hard.map +9 -5
- cogames/maps/evals/eval_oxygen_bottleneck.map +9 -5
- cogames/maps/evals/eval_single_use_world.map +9 -5
- cogames/maps/evals/extractor_hub_100x100.map +9 -5
- cogames/maps/evals/extractor_hub_30x30.map +9 -5
- cogames/maps/evals/extractor_hub_50x50.map +9 -5
- cogames/maps/evals/extractor_hub_70x70.map +9 -5
- cogames/maps/evals/extractor_hub_80x80.map +9 -5
- cogames/maps/machina_100_stations.map +2 -2
- cogames/maps/machina_200_stations.map +2 -2
- cogames/maps/machina_200_stations_small.map +2 -2
- cogames/maps/machina_eval_exp01.map +2 -2
- cogames/maps/machina_eval_template_large.map +2 -2
- cogames/maps/machinatrainer4agents.map +2 -2
- cogames/maps/machinatrainer4agentsbase.map +2 -2
- cogames/maps/machinatrainerbig.map +2 -2
- cogames/maps/machinatrainersmall.map +2 -2
- cogames/maps/planky_evals/aligner_avoid_aoe.map +28 -0
- cogames/maps/planky_evals/aligner_full_cycle.map +28 -0
- cogames/maps/planky_evals/aligner_gear.map +24 -0
- cogames/maps/planky_evals/aligner_hearts.map +24 -0
- cogames/maps/planky_evals/aligner_junction.map +26 -0
- cogames/maps/planky_evals/exploration_distant.map +28 -0
- cogames/maps/planky_evals/maze.map +32 -0
- cogames/maps/planky_evals/miner_best_resource.map +26 -0
- cogames/maps/planky_evals/miner_deposit.map +24 -0
- cogames/maps/planky_evals/miner_extract.map +26 -0
- cogames/maps/planky_evals/miner_full_cycle.map +28 -0
- cogames/maps/planky_evals/miner_gear.map +24 -0
- cogames/maps/planky_evals/multi_role.map +28 -0
- cogames/maps/planky_evals/resource_chain.map +30 -0
- cogames/maps/planky_evals/scout_explore.map +32 -0
- cogames/maps/planky_evals/scout_gear.map +24 -0
- cogames/maps/planky_evals/scrambler_full_cycle.map +28 -0
- cogames/maps/planky_evals/scrambler_gear.map +24 -0
- cogames/maps/planky_evals/scrambler_target.map +26 -0
- cogames/maps/planky_evals/stuck_corridor.map +32 -0
- cogames/maps/planky_evals/survive_retreat.map +26 -0
- cogames/maps/training_facility_clipped.map +2 -2
- cogames/maps/training_facility_open_1.map +2 -2
- cogames/maps/training_facility_open_2.map +2 -2
- cogames/maps/training_facility_open_3.map +2 -2
- cogames/maps/training_facility_tight_4.map +2 -2
- cogames/maps/training_facility_tight_5.map +2 -2
- cogames/maps/vanilla_large.map +2 -2
- cogames/maps/vanilla_small.map +2 -2
- cogames/pickup.py +183 -0
- cogames/play.py +166 -33
- cogames/policy/chaos_monkey.py +54 -0
- cogames/policy/nim_agents/__init__.py +27 -10
- cogames/policy/nim_agents/agents.py +121 -60
- cogames/policy/nim_agents/thinky_eval.py +35 -222
- cogames/policy/pufferlib_policy.py +67 -32
- cogames/policy/starter_agent.py +184 -0
- cogames/policy/trainable_policy_template.py +4 -1
- cogames/train.py +51 -13
- cogames/verbose.py +2 -2
- cogames-0.3.64.dist-info/METADATA +1842 -0
- cogames-0.3.64.dist-info/RECORD +159 -0
- cogames-0.3.64.dist-info/licenses/LICENSE +21 -0
- cogames-0.3.64.dist-info/top_level.txt +2 -0
- metta_alo/__init__.py +0 -0
- metta_alo/job_specs.py +17 -0
- metta_alo/policy.py +16 -0
- metta_alo/pure_single_episode_runner.py +75 -0
- metta_alo/py.typed +0 -0
- metta_alo/rollout.py +322 -0
- metta_alo/scoring.py +168 -0
- cogames/maps/diagnostic_evals/diagnostic_assembler_near.map +0 -49
- cogames/maps/diagnostic_evals/diagnostic_assembler_search.map +0 -49
- cogames/maps/diagnostic_evals/diagnostic_assembler_search_hard.map +0 -89
- cogames/policy/nim_agents/common.nim +0 -887
- cogames/policy/nim_agents/install.sh +0 -1
- cogames/policy/nim_agents/ladybug_agent.nim +0 -984
- cogames/policy/nim_agents/nim_agents.nim +0 -55
- cogames/policy/nim_agents/nim_agents.nims +0 -14
- cogames/policy/nim_agents/nimby.lock +0 -3
- cogames/policy/nim_agents/racecar_agents.nim +0 -884
- cogames/policy/nim_agents/random_agents.nim +0 -68
- cogames/policy/nim_agents/test_agents.py +0 -53
- cogames/policy/nim_agents/thinky_agents.nim +0 -717
- cogames/policy/scripted_agent/baseline_agent.py +0 -1049
- cogames/policy/scripted_agent/demo_policy.py +0 -244
- cogames/policy/scripted_agent/pathfinding.py +0 -126
- cogames/policy/scripted_agent/starter_agent.py +0 -136
- cogames/policy/scripted_agent/types.py +0 -235
- cogames/policy/scripted_agent/unclipping_agent.py +0 -476
- cogames/policy/scripted_agent/utils.py +0 -385
- cogames-0.3.49.dist-info/METADATA +0 -406
- cogames-0.3.49.dist-info/RECORD +0 -136
- cogames-0.3.49.dist-info/top_level.txt +0 -1
- {cogames-0.3.49.dist-info → cogames-0.3.64.dist-info}/WHEEL +0 -0
- {cogames-0.3.49.dist-info → cogames-0.3.64.dist-info}/entry_points.txt +0 -0
|
@@ -52,7 +52,7 @@ class MachinaArenaConfig(SceneConfig):
|
|
|
52
52
|
#### Building placement ####
|
|
53
53
|
|
|
54
54
|
# How much of the map is covered by buildings
|
|
55
|
-
building_coverage: float = 0.
|
|
55
|
+
building_coverage: float = 0.05
|
|
56
56
|
# Resource placement (building-based API)
|
|
57
57
|
# Defines the set of buildings that can be placed on the map
|
|
58
58
|
building_names: list[str] | None = None
|
|
@@ -113,8 +113,8 @@ class MachinaArena(Scene[MachinaArenaConfig]):
|
|
|
113
113
|
# Building weights
|
|
114
114
|
default_building_weights = {
|
|
115
115
|
"chest": 0.0,
|
|
116
|
-
"
|
|
117
|
-
"germanium_extractor": 0.
|
|
116
|
+
"junction": 0.7,
|
|
117
|
+
"germanium_extractor": 0.3,
|
|
118
118
|
"silicon_extractor": 0.3,
|
|
119
119
|
"oxygen_extractor": 0.3,
|
|
120
120
|
"carbon_extractor": 0.3,
|
|
@@ -372,11 +372,11 @@ class SequentialMachinaArena(Scene[SequentialMachinaArenaConfig]):
|
|
|
372
372
|
base_cfg: SceneConfig = BaseCfgModel.model_validate(cfg.base_biome_config or {})
|
|
373
373
|
default_building_weights = {
|
|
374
374
|
"chest": 0.0,
|
|
375
|
-
"
|
|
376
|
-
"germanium_extractor": 0.
|
|
377
|
-
"silicon_extractor": 0.
|
|
378
|
-
"oxygen_extractor": 0.
|
|
379
|
-
"carbon_extractor": 0.
|
|
375
|
+
"junction": 0.6,
|
|
376
|
+
"germanium_extractor": 0.2,
|
|
377
|
+
"silicon_extractor": 0.2,
|
|
378
|
+
"oxygen_extractor": 0.2,
|
|
379
|
+
"carbon_extractor": 0.2,
|
|
380
380
|
}
|
|
381
381
|
weights_dict: dict[str, float] = {str(k): v for k, v in (cfg.building_weights or {}).items()}
|
|
382
382
|
if not weights_dict:
|
cogames/cogs_vs_clips/sites.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"""Central site definitions shared across mission modules."""
|
|
2
2
|
|
|
3
|
+
from typing import cast
|
|
4
|
+
|
|
3
5
|
from cogames.cogs_vs_clips.mission import Site
|
|
4
6
|
from cogames.cogs_vs_clips.mission_utils import get_map
|
|
5
7
|
from cogames.cogs_vs_clips.procedural import MachinaArena, RandomTransform, SequentialMachinaArena
|
|
6
|
-
from mettagrid.mapgen.mapgen import MapGen
|
|
7
|
-
from mettagrid.mapgen.scenes.base_hub import BaseHub
|
|
8
|
+
from mettagrid.mapgen.mapgen import MapGen, MapGenConfig
|
|
9
|
+
from mettagrid.mapgen.scenes.base_hub import BaseHub, BaseHubConfig
|
|
8
10
|
|
|
9
11
|
TRAINING_FACILITY = Site(
|
|
10
12
|
name="training_facility",
|
|
@@ -46,6 +48,22 @@ MACHINA_1 = Site(
|
|
|
46
48
|
max_cogs=20,
|
|
47
49
|
)
|
|
48
50
|
|
|
51
|
+
|
|
52
|
+
def _cogsguard_hub_config() -> BaseHubConfig:
|
|
53
|
+
return BaseHubConfig(
|
|
54
|
+
corner_bundle="extractors",
|
|
55
|
+
cross_bundle="none",
|
|
56
|
+
cross_distance=7,
|
|
57
|
+
stations=[
|
|
58
|
+
"aligner_station",
|
|
59
|
+
"scrambler_station",
|
|
60
|
+
"miner_station",
|
|
61
|
+
"scout_station",
|
|
62
|
+
"chest",
|
|
63
|
+
],
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
49
67
|
# Evals site used by diagnostic evaluation missions
|
|
50
68
|
# Note: Individual diagnostic missions override this with their own specific maps
|
|
51
69
|
EVALS = Site(
|
|
@@ -56,9 +74,95 @@ EVALS = Site(
|
|
|
56
74
|
max_cogs=8,
|
|
57
75
|
)
|
|
58
76
|
|
|
59
|
-
|
|
77
|
+
|
|
78
|
+
def make_cogsguard_arena_site(num_agents: int = 10) -> Site:
|
|
79
|
+
"""Create a CogsGuard arena site with configurable agent count."""
|
|
80
|
+
map_builder = MapGen.Config(
|
|
81
|
+
width=50,
|
|
82
|
+
height=50,
|
|
83
|
+
instance=MachinaArena.Config(
|
|
84
|
+
spawn_count=num_agents,
|
|
85
|
+
building_coverage=0.1,
|
|
86
|
+
hub=_cogsguard_hub_config(),
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
return Site(
|
|
90
|
+
name="cogsguard_arena",
|
|
91
|
+
description="CogsGuard arena map",
|
|
92
|
+
map_builder=map_builder,
|
|
93
|
+
min_cogs=num_agents,
|
|
94
|
+
max_cogs=num_agents,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _build_cogsguard_machina1_map_builder(spawn_count: int) -> MapGenConfig:
|
|
99
|
+
map_builder = cast(MapGenConfig, MACHINA_1.map_builder).model_copy(deep=True)
|
|
100
|
+
instance = map_builder.instance
|
|
101
|
+
assert instance is not None
|
|
102
|
+
return map_builder.model_copy(
|
|
103
|
+
update={
|
|
104
|
+
"instance": instance.model_copy(
|
|
105
|
+
update={
|
|
106
|
+
"spawn_count": spawn_count,
|
|
107
|
+
"hub": _cogsguard_hub_config(),
|
|
108
|
+
}
|
|
109
|
+
),
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def make_cogsguard_machina1_site(num_agents: int = 10) -> Site:
|
|
115
|
+
"""Create a CogsGuard Machina1 site with configurable agent count."""
|
|
116
|
+
return Site(
|
|
117
|
+
name="cogsguard_machina_1",
|
|
118
|
+
description="CogsGuard Machina1 layout with gear stations.",
|
|
119
|
+
map_builder=_build_cogsguard_machina1_map_builder(num_agents),
|
|
120
|
+
min_cogs=num_agents,
|
|
121
|
+
max_cogs=num_agents,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Default CogsGuard Machina1 site with flexible agent count
|
|
126
|
+
COGSGUARD_MACHINA_1 = Site(
|
|
127
|
+
name="cogsguard_machina_1",
|
|
128
|
+
description="CogsGuard Machina1 layout with gear stations.",
|
|
129
|
+
map_builder=_build_cogsguard_machina1_map_builder(20),
|
|
130
|
+
min_cogs=1,
|
|
131
|
+
max_cogs=20,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Default CogsGuard arena site with flexible agent count
|
|
135
|
+
COGSGUARD_ARENA = Site(
|
|
136
|
+
name="cogsguard_arena",
|
|
137
|
+
description="CogsGuard arena - compact training map with gear stations.",
|
|
138
|
+
map_builder=MapGen.Config(
|
|
139
|
+
width=50,
|
|
140
|
+
height=50,
|
|
141
|
+
instance=MachinaArena.Config(
|
|
142
|
+
spawn_count=20,
|
|
143
|
+
building_coverage=0.1,
|
|
144
|
+
hub=_cogsguard_hub_config(),
|
|
145
|
+
),
|
|
146
|
+
),
|
|
147
|
+
min_cogs=1,
|
|
148
|
+
max_cogs=20,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# Feature flag: Set to True to include legacy (pre-CogsGuard) sites in the CLI.
|
|
153
|
+
# To enable, add TRAINING_FACILITY, HELLO_WORLD, MACHINA_1 to SITES below.
|
|
154
|
+
# Also set _INCLUDE_LEGACY_MISSIONS = True in missions.py.
|
|
155
|
+
_INCLUDE_LEGACY_SITES = False
|
|
156
|
+
|
|
157
|
+
_LEGACY_SITES = [
|
|
60
158
|
TRAINING_FACILITY,
|
|
61
159
|
HELLO_WORLD,
|
|
62
160
|
MACHINA_1,
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
SITES = [
|
|
164
|
+
COGSGUARD_MACHINA_1,
|
|
165
|
+
COGSGUARD_ARENA,
|
|
63
166
|
EVALS,
|
|
167
|
+
*(_LEGACY_SITES if _INCLUDE_LEGACY_SITES else []),
|
|
64
168
|
]
|
|
@@ -1,13 +1,33 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
1
3
|
from pydantic import Field
|
|
2
4
|
|
|
3
5
|
from mettagrid.base_config import Config
|
|
4
6
|
from mettagrid.config import vibes
|
|
7
|
+
from mettagrid.config.handler_config import (
|
|
8
|
+
AOEConfig,
|
|
9
|
+
ClearInventoryMutation,
|
|
10
|
+
EntityTarget,
|
|
11
|
+
Handler,
|
|
12
|
+
actorCollectiveHas,
|
|
13
|
+
actorHas,
|
|
14
|
+
alignToActor,
|
|
15
|
+
collectiveDeposit,
|
|
16
|
+
collectiveWithdraw,
|
|
17
|
+
isAlignedToActor,
|
|
18
|
+
isEnemy,
|
|
19
|
+
isNeutral,
|
|
20
|
+
removeAlignment,
|
|
21
|
+
targetCollectiveHas,
|
|
22
|
+
updateActor,
|
|
23
|
+
updateTarget,
|
|
24
|
+
updateTargetCollective,
|
|
25
|
+
withdraw,
|
|
26
|
+
)
|
|
5
27
|
from mettagrid.config.mettagrid_config import (
|
|
6
|
-
AssemblerConfig,
|
|
7
28
|
ChestConfig,
|
|
8
29
|
GridObjectConfig,
|
|
9
30
|
InventoryConfig,
|
|
10
|
-
ProtocolConfig,
|
|
11
31
|
WallConfig,
|
|
12
32
|
)
|
|
13
33
|
|
|
@@ -24,11 +44,35 @@ resources = [
|
|
|
24
44
|
"scrambler",
|
|
25
45
|
]
|
|
26
46
|
|
|
47
|
+
# CogsGuard constants
|
|
48
|
+
GEAR = ["aligner", "scrambler", "miner", "scout"]
|
|
49
|
+
ELEMENTS = ["oxygen", "carbon", "germanium", "silicon"]
|
|
27
50
|
|
|
28
|
-
class CvCStationConfig(Config):
|
|
29
|
-
start_clipped: bool = Field(default=False)
|
|
30
|
-
clip_immune: bool = Field(default=False)
|
|
31
51
|
|
|
52
|
+
HEART_COST = {e: 10 for e in ELEMENTS}
|
|
53
|
+
COGSGUARD_ALIGN_COST = {"heart": 1}
|
|
54
|
+
COGSGUARD_SCRAMBLE_COST = {"heart": 1}
|
|
55
|
+
|
|
56
|
+
GEAR_COSTS = {
|
|
57
|
+
"aligner": {"carbon": 3, "oxygen": 1, "germanium": 1, "silicon": 1},
|
|
58
|
+
"scrambler": {"carbon": 1, "oxygen": 3, "germanium": 1, "silicon": 1},
|
|
59
|
+
"miner": {"carbon": 1, "oxygen": 1, "germanium": 3, "silicon": 1},
|
|
60
|
+
"scout": {"carbon": 1, "oxygen": 1, "germanium": 1, "silicon": 3},
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
GEAR_SYMBOLS = {
|
|
64
|
+
"aligner": "🔗",
|
|
65
|
+
"scrambler": "🌀",
|
|
66
|
+
"miner": "⛏️",
|
|
67
|
+
"scout": "🔭",
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _neg(recipe: dict[str, int]) -> dict[str, int]:
|
|
72
|
+
return {k: -v for k, v in recipe.items()}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class CvCStationConfig(Config):
|
|
32
76
|
def station_cfg(self) -> GridObjectConfig:
|
|
33
77
|
raise NotImplementedError("Subclasses must implement this method")
|
|
34
78
|
|
|
@@ -38,203 +82,171 @@ class CvCWallConfig(CvCStationConfig):
|
|
|
38
82
|
return WallConfig(name="wall", render_symbol=vibes.VIBE_BY_NAME["wall"].symbol)
|
|
39
83
|
|
|
40
84
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# How much this extractor produces relative to its default.
|
|
45
|
-
# Efficiency outside of this range won't technically break things, but they'll be far enough from the
|
|
46
|
-
# expectations that we don't want to go beyond them without some thought.
|
|
47
|
-
efficiency: int = Field(ge=20, le=500, default=100)
|
|
48
|
-
# How much additional agents increase production.
|
|
49
|
-
# Scaled so 0 means none and 100 means some version of "twice as much".
|
|
50
|
-
synergy: int = Field(default=0)
|
|
51
|
-
max_uses: int = Field()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class ChargerConfig(ExtractorConfig):
|
|
55
|
-
max_uses: int = 0 # unlimited uses
|
|
56
|
-
|
|
57
|
-
def station_cfg(self) -> AssemblerConfig:
|
|
58
|
-
output = 50 * self.efficiency // 100
|
|
59
|
-
return AssemblerConfig(
|
|
60
|
-
name="charger",
|
|
61
|
-
render_symbol=vibes.VIBE_BY_NAME["charger"].symbol,
|
|
62
|
-
# Protocols
|
|
63
|
-
allow_partial_usage=True, # can use it while its on cooldown
|
|
64
|
-
max_uses=self.max_uses,
|
|
65
|
-
protocols=[
|
|
66
|
-
ProtocolConfig(
|
|
67
|
-
min_agents=(additional_agents + 1) if additional_agents >= 1 else 0,
|
|
68
|
-
output_resources={"energy": output * (100 + additional_agents * self.synergy) // 100},
|
|
69
|
-
cooldown=10,
|
|
70
|
-
)
|
|
71
|
-
for additional_agents in range(4)
|
|
72
|
-
],
|
|
73
|
-
# Clipping
|
|
74
|
-
start_clipped=self.start_clipped,
|
|
75
|
-
clip_immune=self.clip_immune,
|
|
76
|
-
)
|
|
85
|
+
# ==============================================================================
|
|
86
|
+
# CogsGuard Station Configs
|
|
87
|
+
# ==============================================================================
|
|
77
88
|
|
|
78
89
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
max_uses: int = Field(default=25)
|
|
82
|
-
|
|
83
|
-
def station_cfg(self) -> AssemblerConfig:
|
|
84
|
-
output = 2 * self.efficiency // 100
|
|
85
|
-
return AssemblerConfig(
|
|
86
|
-
name="carbon_extractor",
|
|
87
|
-
render_symbol=vibes.VIBE_BY_NAME["carbon_a"].symbol,
|
|
88
|
-
max_uses=self.max_uses,
|
|
89
|
-
protocols=[
|
|
90
|
-
ProtocolConfig(
|
|
91
|
-
min_agents=(additional_agents + 1) if additional_agents >= 1 else 0,
|
|
92
|
-
output_resources={"carbon": output * (100 + additional_agents * self.synergy) // 100},
|
|
93
|
-
cooldown=0,
|
|
94
|
-
)
|
|
95
|
-
for additional_agents in range(4)
|
|
96
|
-
],
|
|
97
|
-
# Clipping
|
|
98
|
-
start_clipped=self.start_clipped,
|
|
99
|
-
clip_immune=self.clip_immune,
|
|
100
|
-
)
|
|
90
|
+
class SimpleExtractorConfig(CvCStationConfig):
|
|
91
|
+
"""Simple resource extractor with inventory that transfers resources to actors."""
|
|
101
92
|
|
|
93
|
+
resource: str = Field(description="The resource to extract")
|
|
94
|
+
initial_amount: int = Field(default=100, description="Initial amount of resource in extractor")
|
|
95
|
+
small_amount: int = Field(default=1, description="Amount extracted without mining equipment")
|
|
96
|
+
large_amount: int = Field(default=10, description="Amount extracted with mining equipment")
|
|
102
97
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
)
|
|
121
|
-
for additional_agents in range(4)
|
|
122
|
-
],
|
|
123
|
-
# Clipping
|
|
124
|
-
start_clipped=self.start_clipped,
|
|
125
|
-
clip_immune=self.clip_immune,
|
|
98
|
+
def station_cfg(self) -> ChestConfig:
|
|
99
|
+
return ChestConfig(
|
|
100
|
+
name=f"{self.resource}_extractor",
|
|
101
|
+
map_name=f"{self.resource}_extractor",
|
|
102
|
+
render_symbol="📦",
|
|
103
|
+
on_use_handlers={
|
|
104
|
+
# Order matters: miner first so agents with miner gear get the bonus
|
|
105
|
+
"miner": Handler(
|
|
106
|
+
filters=[actorHas({"miner": 1})],
|
|
107
|
+
mutations=[withdraw({self.resource: self.large_amount}, remove_when_empty=True)],
|
|
108
|
+
),
|
|
109
|
+
"extract": Handler(
|
|
110
|
+
filters=[],
|
|
111
|
+
mutations=[withdraw({self.resource: self.small_amount}, remove_when_empty=True)],
|
|
112
|
+
),
|
|
113
|
+
},
|
|
114
|
+
inventory=InventoryConfig(initial={self.resource: self.initial_amount}),
|
|
126
115
|
)
|
|
127
116
|
|
|
128
117
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
118
|
+
class JunctionConfig(CvCStationConfig):
|
|
119
|
+
"""Supply depot that receives element resources via default vibe into collective."""
|
|
120
|
+
|
|
121
|
+
map_name: str = Field(description="Map name for this junction")
|
|
122
|
+
team: Optional[str] = Field(default=None, description="Team/collective this junction belongs to")
|
|
123
|
+
aoe_range: int = Field(default=10, description="Range for AOE effects")
|
|
124
|
+
influence_deltas: dict[str, int] = Field(default_factory=lambda: {"influence": 10, "energy": 100, "hp": 100})
|
|
125
|
+
attack_deltas: dict[str, int] = Field(default_factory=lambda: {"hp": -1, "influence": -100})
|
|
126
|
+
elements: list[str] = Field(default_factory=lambda: ELEMENTS)
|
|
127
|
+
align_cost: dict[str, int] = Field(default_factory=lambda: COGSGUARD_ALIGN_COST)
|
|
128
|
+
scramble_cost: dict[str, int] = Field(default_factory=lambda: COGSGUARD_SCRAMBLE_COST)
|
|
129
|
+
|
|
130
|
+
def station_cfg(self) -> GridObjectConfig:
|
|
131
|
+
return GridObjectConfig(
|
|
132
|
+
name="junction",
|
|
133
|
+
map_name=self.map_name,
|
|
134
|
+
render_symbol="📦",
|
|
135
|
+
collective=self.team,
|
|
136
|
+
aoes={
|
|
137
|
+
"influence": AOEConfig(
|
|
138
|
+
radius=self.aoe_range,
|
|
139
|
+
filters=[isAlignedToActor()],
|
|
140
|
+
mutations=[updateTarget(self.influence_deltas)],
|
|
141
|
+
),
|
|
142
|
+
"attack": AOEConfig(
|
|
143
|
+
radius=self.aoe_range,
|
|
144
|
+
filters=[isEnemy()],
|
|
145
|
+
mutations=[updateTarget(self.attack_deltas)],
|
|
146
|
+
),
|
|
147
|
+
},
|
|
148
|
+
on_use_handlers={
|
|
149
|
+
"deposit": Handler(
|
|
150
|
+
filters=[isAlignedToActor()],
|
|
151
|
+
mutations=[collectiveDeposit({resource: 100 for resource in self.elements})],
|
|
152
|
+
),
|
|
153
|
+
"align": Handler(
|
|
154
|
+
filters=[isNeutral(), actorHas({"aligner": 1, "influence": 1, **self.align_cost})],
|
|
155
|
+
mutations=[updateActor(_neg(self.align_cost)), alignToActor()],
|
|
156
|
+
),
|
|
157
|
+
"scramble": Handler(
|
|
158
|
+
filters=[isEnemy(), actorHas({"scrambler": 1, **self.scramble_cost})],
|
|
159
|
+
mutations=[removeAlignment(), updateActor(_neg(self.scramble_cost))],
|
|
160
|
+
),
|
|
161
|
+
},
|
|
152
162
|
)
|
|
153
163
|
|
|
154
164
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
render_symbol=
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
165
|
+
class HubConfig(JunctionConfig):
|
|
166
|
+
"""Main hub with influence AOE effect. A junction without align/scramble handlers."""
|
|
167
|
+
|
|
168
|
+
def station_cfg(self) -> GridObjectConfig:
|
|
169
|
+
return GridObjectConfig(
|
|
170
|
+
name="hub",
|
|
171
|
+
map_name=self.map_name,
|
|
172
|
+
render_name="hub",
|
|
173
|
+
render_symbol="📦",
|
|
174
|
+
collective=self.team,
|
|
175
|
+
aoes={
|
|
176
|
+
"influence": AOEConfig(
|
|
177
|
+
radius=self.aoe_range,
|
|
178
|
+
filters=[isAlignedToActor()],
|
|
179
|
+
mutations=[updateTarget(self.influence_deltas)],
|
|
180
|
+
),
|
|
181
|
+
"attack": AOEConfig(
|
|
182
|
+
radius=self.aoe_range,
|
|
183
|
+
filters=[isEnemy()],
|
|
184
|
+
mutations=[updateTarget(self.attack_deltas)],
|
|
185
|
+
),
|
|
186
|
+
},
|
|
187
|
+
on_use_handlers={
|
|
188
|
+
"deposit": Handler(
|
|
189
|
+
filters=[isAlignedToActor()],
|
|
190
|
+
mutations=[collectiveDeposit({resource: 100 for resource in self.elements})],
|
|
191
|
+
),
|
|
192
|
+
},
|
|
176
193
|
)
|
|
177
194
|
|
|
178
195
|
|
|
179
|
-
class
|
|
180
|
-
|
|
196
|
+
class CogsGuardChestConfig(CvCStationConfig):
|
|
197
|
+
"""Chest for heart management in CogsGuard."""
|
|
181
198
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
"
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
"
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
collective: str = Field(default="cogs", description="Collective this chest belongs to")
|
|
200
|
+
heart_cost: dict[str, int] = Field(default_factory=lambda: HEART_COST)
|
|
201
|
+
|
|
202
|
+
def station_cfg(self) -> GridObjectConfig:
|
|
203
|
+
return GridObjectConfig(
|
|
204
|
+
name="chest",
|
|
205
|
+
map_name="chest",
|
|
206
|
+
render_symbol="📦",
|
|
207
|
+
collective=self.collective,
|
|
208
|
+
on_use_handlers={
|
|
209
|
+
"get_heart": Handler(
|
|
210
|
+
filters=[isAlignedToActor(), targetCollectiveHas({"heart": 1})],
|
|
211
|
+
mutations=[collectiveWithdraw({"heart": 1})],
|
|
212
|
+
),
|
|
213
|
+
"make_heart": Handler(
|
|
214
|
+
filters=[isAlignedToActor(), targetCollectiveHas(self.heart_cost)],
|
|
215
|
+
mutations=[
|
|
216
|
+
updateTargetCollective(_neg(self.heart_cost)),
|
|
217
|
+
updateActor({"heart": 1}),
|
|
218
|
+
],
|
|
219
|
+
),
|
|
199
220
|
},
|
|
200
|
-
inventory=InventoryConfig(initial=self.initial_inventory),
|
|
201
221
|
)
|
|
202
222
|
|
|
203
223
|
|
|
204
|
-
class
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
vibes=["gear", f"{gear[i][0]}_a"],
|
|
233
|
-
input_resources={gear[i][0]: 1},
|
|
234
|
-
output_resources={gear[i][1]: 1},
|
|
235
|
-
)
|
|
236
|
-
for i in range(len(gear))
|
|
237
|
-
],
|
|
238
|
-
# Note: Generic ['gear'] protocol is added dynamically by clipping variants
|
|
239
|
-
# C++ only allows ONE protocol per unique vibe list, so we can't pre-add all 4 here
|
|
224
|
+
class GearStationConfig(CvCStationConfig):
|
|
225
|
+
"""Gear station that clears all gear and adds the specified gear type."""
|
|
226
|
+
|
|
227
|
+
gear_type: str = Field(description="Type of gear this station provides")
|
|
228
|
+
collective: str = Field(default="cogs", description="Collective this station belongs to")
|
|
229
|
+
gear_costs: dict[str, dict[str, int]] = Field(default_factory=lambda: GEAR_COSTS)
|
|
230
|
+
|
|
231
|
+
def station_cfg(self) -> GridObjectConfig:
|
|
232
|
+
cost = self.gear_costs.get(self.gear_type, {})
|
|
233
|
+
return GridObjectConfig(
|
|
234
|
+
name=f"{self.gear_type}_station",
|
|
235
|
+
map_name=f"{self.gear_type}_station",
|
|
236
|
+
render_symbol=GEAR_SYMBOLS.get(self.gear_type, "⚙️"),
|
|
237
|
+
collective=self.collective,
|
|
238
|
+
on_use_handlers={
|
|
239
|
+
"keep_gear": Handler(
|
|
240
|
+
filters=[isAlignedToActor(), actorHas({self.gear_type: 1})],
|
|
241
|
+
mutations=[],
|
|
242
|
+
),
|
|
243
|
+
"change_gear": Handler(
|
|
244
|
+
filters=[isAlignedToActor(), actorCollectiveHas(cost)],
|
|
245
|
+
mutations=[
|
|
246
|
+
ClearInventoryMutation(target=EntityTarget.ACTOR, limit_name="gear"),
|
|
247
|
+
updateTargetCollective(_neg(cost)),
|
|
248
|
+
updateActor({self.gear_type: 1}),
|
|
249
|
+
],
|
|
250
|
+
),
|
|
251
|
+
},
|
|
240
252
|
)
|