aedmark commited on
Commit
bac61bd
·
verified ·
1 Parent(s): 04c3f6c

Delete bone_inventory.py

Browse files
Files changed (1) hide show
  1. bone_inventory.py +0 -391
bone_inventory.py DELETED
@@ -1,391 +0,0 @@
1
- import random, re
2
- from dataclasses import dataclass, field
3
- from typing import List, Dict, Tuple, Optional
4
- from bone_core import LoreManifest
5
- from bone_types import Prisma
6
- from bone_config import BoneConfig
7
-
8
-
9
- @dataclass
10
- class Item:
11
- name: str
12
- description: str
13
- function: str
14
- passive_traits: List[str] = field(default_factory=list)
15
- spawn_context: str = "COMMON"
16
- value: float = 1.0
17
- usage_msg: str = "Used."
18
- consume_on_use: bool = False
19
- reflex_trigger: Optional[str] = None
20
-
21
- @classmethod
22
- def from_dict(cls, name: str, data: Dict):
23
- return cls(
24
- name=name,
25
- description=data.get("description", "Unknown Artifact"),
26
- function=data.get("function", "MISC"),
27
- passive_traits=data.get("passive_traits", []),
28
- spawn_context=data.get("spawn_context", "COMMON"),
29
- value=data.get("value", 1.0),
30
- usage_msg=data.get("usage_msg", f"You use the {name}."),
31
- consume_on_use=data.get("consume_on_use", False),
32
- reflex_trigger=data.get("reflex_trigger", None),
33
- )
34
-
35
-
36
- class GordonKnot:
37
- def __init__(self, events=None, mode="ADVENTURE"):
38
- self.mode = mode.upper()
39
- self.blueprints = None
40
- self.events = events
41
- self.inventory: List[str] = []
42
- self.registry: Dict[str, Item] = {}
43
- self.ITEM_REGISTRY: Dict[str, Dict] = {}
44
- self.recipes: List[Dict] = []
45
- self.action_coupling: Dict[str, List[str]] = {}
46
- self.location_coupling: Dict[str, str] = {}
47
- self.max_slots = 10
48
- self.last_flinch_turn = -100
49
- self.scar_tissue = {}
50
- self.refusal_markers = {
51
- "cannot", "can't", "unable", "fail", "too heavy",
52
- "stuck", "don't", "do not", "locked", "refuse", "impossible",
53
- }
54
- self.loot_triggers = [
55
- "found a", "picked up", "pick up", "acquired",
56
- "took the", "take the", "grab the", "takes the",
57
- ]
58
- self.load_config()
59
-
60
- def enforce_object_action_coupling(
61
- self, user_input: str, current_zone: str
62
- ) -> Optional[str]:
63
- if self.mode in ["CREATIVE", "CONVERSATION", "TECHNICAL"]:
64
- return None
65
- text = user_input.lower()
66
- for action_obj_pair, required_loc in self.location_coupling.items():
67
- words = action_obj_pair.split()
68
- if all(re.search(rf'\b{w}\b', text) for w in words):
69
- if required_loc not in current_zone.lower():
70
- return (
71
- f"{Prisma.SLATE}🏢 GORDON [PREMISE VIOLATION]: The action requires the object "
72
- f"to be at the location '{required_loc}'. You are currently at '{current_zone}'. "
73
- f"You must bring the object to the location. Action denied.{Prisma.RST}"
74
- )
75
-
76
- inventory_items = " ".join([i.get("name", "").lower() for i in self.get_inventory_data()])
77
- for action, required_objects in self.action_coupling.items():
78
-
79
- verb_pattern = rf"\b(?:i\s+(?:will\s+)?{action}|to\s+{action}|{action}\s+(?:the|a|an|my|some|it|this|that)|{action}ing)\b|^{action}\b"
80
-
81
- if re.search(verb_pattern, text):
82
- has_item = any(obj in inventory_items for obj in required_objects)
83
- mentions_item = any(obj in text for obj in required_objects)
84
- if not has_item and not mentions_item:
85
- req_str = ", ".join(required_objects)
86
- return (
87
- f"{Prisma.SLATE}🏢 GORDON [PREMISE VIOLATION]: The action '{action}' requires an object "
88
- f"of type [{req_str}]. The object is neither in your inventory nor the immediate environment. "
89
- f"Coupling failed. Action denied.{Prisma.RST}"
90
- )
91
-
92
- interaction_verbs = ["use", "drop", "throw", "consume", "eat", "drink", "read", "activate", "give", "equip"]
93
- has_interaction = any(re.search(rf'\b{v}\b', text) for v in interaction_verbs)
94
-
95
- if has_interaction:
96
- all_known = set(self.registry.keys()) | set(self.ITEM_REGISTRY.keys())
97
- for item_name in all_known:
98
- item_lower = item_name.lower().replace("_", " ")
99
- if item_lower in text and item_name.upper() not in self.inventory:
100
- return (
101
- f"{Prisma.SLATE}🏢 GORDON [PREMISE VIOLATION]: You are attempting to interact with "
102
- f"[{item_lower}], but it is not in your inventory. Action denied.{Prisma.RST}"
103
- )
104
-
105
- return None
106
-
107
- def load_config(self):
108
- data = LoreManifest.get_instance().get("GORDON") or {}
109
- if not data and hasattr(LoreManifest, "get_raw"):
110
- data = LoreManifest.get_raw("gordon.json") or {}
111
- self.action_coupling = data.get("ACTION_COUPLING", {})
112
- self.location_coupling = data.get("LOCATION_COUPLING", {})
113
- if "REFUSAL_MARKERS" in data:
114
- self.refusal_markers = set(data["REFUSAL_MARKERS"])
115
- if self.mode in ["CREATIVE", "CONVERSATION"]:
116
- self.loot_triggers = [
117
- "grasped the concept of",
118
- "held onto",
119
- "felt a",
120
- "internalized the",
121
- "embraced the",
122
- "clung to the",
123
- "remembered the",
124
- ]
125
- elif "LOOT_TRIGGERS" in data:
126
- self.loot_triggers = data["LOOT_TRIGGERS"]
127
- self.blueprints = LoreManifest.get_instance().get("ITEM_GENERATION") or {}
128
- self.ITEM_REGISTRY = data.get("ITEM_REGISTRY", {})
129
- for name, props in self.ITEM_REGISTRY.items():
130
- self.registry[name] = Item.from_dict(name, props)
131
- self.recipes = data.get("RECIPES", [])
132
- self.scar_tissue = data.get("SCAR_TISSUE", {})
133
- starters = data.get("STARTING_INVENTORY", [])
134
- if not self.inventory and starters:
135
- self.inventory = [s for s in starters if isinstance(s, str)]
136
- if hasattr(BoneConfig, "INVENTORY"):
137
- self.max_slots = getattr(BoneConfig.INVENTORY, "MAX_SLOTS", 10)
138
-
139
- def process_loot_tags(self, text: str, user_input: str) -> Tuple[str, List[str]]:
140
- loot_pattern = r"\[\[LOOT:\s*(.*?)\]\]"
141
- lost_pattern = r"\[\[LOST:\s*(.*?)\]\]"
142
- raw_loot = re.findall(loot_pattern, text, re.IGNORECASE)
143
- raw_lost = re.findall(lost_pattern, text, re.IGNORECASE)
144
-
145
- def normalize(items):
146
- return list({re.sub(r"[^A-Z0-9_]", "", i.strip().upper().replace(" ", "_")) for i in items if i})
147
- new_loot = normalize(raw_loot)
148
- lost_loot = normalize(raw_lost)
149
- logs = []
150
- if new_loot:
151
- acquisition_verbs = [
152
- "take",
153
- "grab",
154
- "pick",
155
- "get",
156
- "steal",
157
- "seize",
158
- "collect",
159
- "snatch",
160
- "acquire",
161
- "pocket",
162
- "loot",
163
- "harvest",
164
- ]
165
- clean_input = user_input.lower()
166
- has_intent = any(verb in clean_input for verb in acquisition_verbs)
167
- if has_intent:
168
- for item in new_loot:
169
- logs.append(self.acquire(item))
170
- if self.events:
171
- self.events.publish("ITEM_ACQUIRED", {"item": item})
172
- else:
173
- if self.events:
174
- for item in new_loot:
175
- self.events.log(
176
- f"CONSENT: Intercepted auto-loot for '{item}'. User did not ask.",
177
- "GORDON",
178
- )
179
- for item in lost_loot:
180
- if self.safe_remove_item(item):
181
- logs.append(f"{Prisma.GRY}ENTROPY: {item} consumed/lost.{Prisma.RST}")
182
- else:
183
- logs.append(
184
- f"{Prisma.OCHRE}GLITCH: Tried to lose {item}, but you didn't have it.{Prisma.RST}"
185
- )
186
- clean_text = re.sub(loot_pattern, "", text, flags=re.IGNORECASE)
187
- clean_text = re.sub(lost_pattern, "", clean_text, flags=re.IGNORECASE)
188
- return clean_text.strip(), logs
189
-
190
- def get_item_data(self, item_name: str) -> Optional[Item]:
191
- if item_name in self.registry:
192
- return self.registry[item_name]
193
- if item_name in self.ITEM_REGISTRY:
194
- raw_data = self.ITEM_REGISTRY[item_name]
195
- item_obj = Item.from_dict(item_name, raw_data)
196
- self.registry[item_name] = item_obj
197
- return item_obj
198
- return None
199
-
200
- def get_inventory_data(self) -> List[Dict]:
201
- return [item.__dict__ for name in self.inventory if (item := self.get_item_data(name))]
202
-
203
- def acquire(self, tool_name: str) -> str:
204
- tool_name = tool_name.upper() if tool_name else "UNKNOWN"
205
- if tool_name in self.inventory:
206
- return f"{Prisma.OCHRE}Inventory duplicate: You already have the {tool_name}.{Prisma.RST}"
207
- item_obj = self.get_item_data(tool_name)
208
- if not item_obj:
209
- item_obj = self.get_item_data(tool_name.lower())
210
- if not item_obj:
211
- new_item = Item(name=tool_name, description="???", function="MISC")
212
- self.registry[tool_name] = new_item
213
- self.ITEM_REGISTRY[tool_name] = new_item.__dict__
214
- if len(self.inventory) >= self.max_slots:
215
- dropped = self.inventory.pop(0)
216
- if self.events:
217
- self.events.log(f"Inventory full. Dropped {dropped}.", "INV")
218
- self.inventory.append(tool_name)
219
- if self.events:
220
- self.events.publish("ITEM_ACQUIRED", {"item": tool_name})
221
- return f"{Prisma.GRN}📦 ACQUIRED: {tool_name}{Prisma.RST}"
222
-
223
- def safe_remove_item(self, item_name: str) -> bool:
224
- item_name = item_name.upper()
225
- if item_name in self.inventory:
226
- self.inventory.remove(item_name)
227
- return True
228
- return False
229
-
230
- def rummage(
231
- self, physics_ref: Dict, stamina_pool: float
232
- ) -> Tuple[bool, str, float]:
233
- cost = 15.0
234
- if hasattr(BoneConfig, "INVENTORY"):
235
- cost = getattr(BoneConfig.INVENTORY, "RUMMAGE_COST", 15.0)
236
- if stamina_pool < cost:
237
- return (
238
- False,
239
- f"{Prisma.OCHRE}Gordon sighs. 'Too tired. Eat first.'{Prisma.RST}",
240
- 0.0,
241
- )
242
- loot_table = self._get_loot_candidates(physics_ref)
243
- if not loot_table:
244
- return False, "Gordon dug deep but found only lint.", cost
245
- found_item = random.choice(loot_table)
246
- msg = self.acquire(found_item)
247
- return True, msg, cost
248
-
249
- def _get_loot_candidates(self, physics: Dict) -> List[str]:
250
- candidates = []
251
- voltage = physics.get("voltage", 0.0)
252
- drag = physics.get("narrative_drag", 0.0)
253
- psi = physics.get("psi", 0.0)
254
- for name in set(self.registry) | set(self.ITEM_REGISTRY):
255
- if not (item := self.get_item_data(name)):
256
- continue
257
- ctx = item.spawn_context
258
- if ctx in ("COMMON", "STANDARD") or \
259
- (ctx == "VOLTAGE_HIGH" and voltage > 12.0) or \
260
- (ctx == "VOLTAGE_CRITICAL" and voltage > 18.0) or \
261
- (ctx == "DRAG_HEAVY" and drag > 4.0) or \
262
- (ctx == "PSI_HIGH" and psi > 0.6):
263
- candidates.append(name)
264
- return candidates
265
-
266
- def register_dynamic_item(self, name: str, data: Dict):
267
- name = name.upper()
268
- if name not in self.registry:
269
- new_item = Item.from_dict(name, data)
270
- self.registry[name] = new_item
271
- if self.events:
272
- self.events.log(
273
- f"{Prisma.CYN}🎒 GORDON: 'I'll make space for {name}.'{Prisma.RST}",
274
- "INV",
275
- )
276
-
277
- def synthesize_item(self, physics_vector: Dict[str, float]) -> str:
278
- if not hasattr(self, "blueprints") or not self.blueprints:
279
- self.blueprints = LoreManifest.get_instance().get("ITEM_GENERATION") or {}
280
-
281
- dim_map = {
282
- "STR": "heavy", "VEL": "kinetic", "PHI": "thermal",
283
- "PSI": "abstract", "ENT": "void", "BET": "constructive"
284
- }
285
- dom_dim = max(physics_vector, key=physics_vector.get) if physics_vector else "ENT"
286
- archetype = dim_map.get(dom_dim, "void")
287
- prefixes = self.blueprints.get("PREFIXES", {}).get(archetype, ["Strange"])
288
- suffixes = self.blueprints.get("SUFFIXES", {}).get(archetype, ["of Mystery"])
289
- if self.mode in ["CREATIVE", "CONVERSATION"]:
290
- base_cat = "ABSTRACT"
291
- bases = self.blueprints.get("BASES", {}).get(
292
- base_cat, ["Feeling", "Sense", "Memory", "Idea", "Echo"]
293
- )
294
- prefixes = ["A Lingering", "A Sudden", "A Distant", "A Sharp", "A Quiet"]
295
- suffixes = ["of Dread", "of Hope", "of Clarity", "of Chaos", "of Stillness"]
296
- else:
297
- base_cat = random.choice(["TOOL", "JUNK", "ARTIFACT"])
298
- bases = self.blueprints.get("BASES", {}).get(base_cat, ["Object"])
299
- prefix = random.choice(prefixes)
300
- base = random.choice(bases)
301
- suffix = random.choice(suffixes)
302
- full_name = (
303
- f"{prefix} {base} {suffix}"
304
- if self.mode == "ADVENTURE"
305
- else f"{prefix} {base} {suffix}"
306
- )
307
- clean_id = full_name.upper().replace(" ", "_")
308
- item_data = {
309
- "description": f"A {base.lower()} manifesting {archetype} properties.",
310
- "function": "ARTIFACT",
311
- "passive_traits": ["DYNAMIC"],
312
- "value": round(physics_vector.get(dom_dim, 0.0) * 10, 1),
313
- "spawn_context": "FORGED"
314
- }
315
- self.register_dynamic_item(clean_id, item_data)
316
- return clean_id
317
-
318
- def parse_loot(self, user_text: str, sys_text: str) -> Optional[str]:
319
- text = (user_text + " " + sys_text).lower()
320
- sys_lower = sys_text.lower()
321
-
322
- for refusal in self.refusal_markers:
323
- if refusal in sys_lower:
324
- return None
325
-
326
- all_known_items = set(self.registry.keys()) | set(self.ITEM_REGISTRY.keys())
327
- for name in all_known_items:
328
- if name.lower() in text and name.upper() not in self.inventory:
329
- for t in self.loot_triggers:
330
- if t in text:
331
- return name
332
-
333
- sorted_triggers = sorted(self.loot_triggers, key=len, reverse=True)
334
- for t in sorted_triggers:
335
- if t in text:
336
- pattern = f"{re.escape(t)}\\s+(?:the\\s+|a\\s+|an\\s+)?(?P<item>[\\w\\s]{{1,30}}?)(?:\\s+(?:from|on|in|under|with|by|near|at|to|you|it|he|she|we|they)|[\\.,!?]|$)"
337
- match = re.search(pattern, text, re.IGNORECASE)
338
-
339
- if match:
340
- candidate = match.group("item").strip()
341
- if (
342
- 2 < len(candidate) < 40
343
- and candidate not in self.refusal_markers
344
- ):
345
- return candidate
346
-
347
- return None
348
-
349
- def consume(self, item_name: str) -> Tuple[bool, str]:
350
- item_name = item_name.upper()
351
- if item_name not in self.inventory:
352
- return False, "You don't have that."
353
- item = self.get_item_data(item_name)
354
- if not item or not item.consume_on_use:
355
- return False, f"The {item_name} cannot be consumed."
356
- self.inventory.remove(item_name)
357
- if item.function == "STABILITY":
358
- return True, f"🍕 {item_name}: Entropy paused. Satisfaction nominal."
359
- return True, f"Consumed {item_name}. {item.usage_msg}"
360
-
361
- def emergency_reflex(self, physics_ref: Dict) -> Tuple[bool, Optional[str]]:
362
- voltage = physics_ref.get("voltage", 0.0)
363
- drag = physics_ref.get("narrative_drag", 0.0)
364
- for name in self.inventory:
365
- item = self.get_item_data(name)
366
- if not item:
367
- continue
368
- trigger = item.reflex_trigger
369
- if trigger == "VOLTAGE_CRITICAL" and voltage > 18.0:
370
- self.safe_remove_item(name)
371
- physics_ref["voltage"] = 12.0
372
- return (
373
- True,
374
- f"{Prisma.CYN}🛡️ REFLEX: {name} sacrificed to absorb voltage spike! (Voltage -> 12.0v){Prisma.RST}",
375
- )
376
- if trigger == "DRIFT_CRITICAL" and drag > 6.0:
377
- self.safe_remove_item(name)
378
- physics_ref["narrative_drag"] = 0.0
379
- return (
380
- True,
381
- f"{Prisma.OCHRE}⚓ REFLEX: {name} deployed. Drag zeroed out.{Prisma.RST}"
382
- )
383
- kappa = physics_ref.get("kappa", 0.5)
384
- if trigger == "KAPPA_CRITICAL" and kappa < 0.2:
385
- self.safe_remove_item(name)
386
- physics_ref["kappa"] = 0.8
387
- return (
388
- True,
389
- f"{Prisma.GRN}🍕 REFLEX: {name} consumed. Structure restored.{Prisma.RST}"
390
- )
391
- return False, None