Justxd22 commited on
Commit
de805e3
Β·
1 Parent(s): 4b16b59

Added unlocked evidence tracking, updated tool costs, and improving UI interactions for evidence display and tool usage

Browse files
app.py CHANGED
@@ -41,12 +41,23 @@ class GameSession:
41
  def _get_init_data(self):
42
  if not self.game:
43
  return None
 
 
 
 
 
 
 
 
44
  return {
45
  "action": "init_game",
46
  "data": {
47
  "scenario": self.game.scenario,
48
  "round": self.game.round,
49
- "points": self.game.points
 
 
 
50
  }
51
  }
52
 
@@ -171,8 +182,12 @@ class GameSession:
171
  # Format the result nicely
172
  evidence_data = format_tool_response(tool_name, arg, result, self.game.scenario)
173
 
174
- # Include updated points in response
175
  evidence_data["updated_points"] = self.game.points
 
 
 
 
176
 
177
  return {
178
  "action": "add_evidence",
 
41
  def _get_init_data(self):
42
  if not self.game:
43
  return None
44
+
45
+ # Prepare static data for tools
46
+ cameras = list(self.game.scenario["evidence"]["footage_data"].keys())
47
+
48
+ dna_map = {}
49
+ for k, v in self.game.scenario["evidence"]["dna_evidence"].items():
50
+ dna_map[k] = v.get("label", k) # Fallback to ID if no label
51
+
52
  return {
53
  "action": "init_game",
54
  "data": {
55
  "scenario": self.game.scenario,
56
  "round": self.game.round,
57
+ "points": self.game.points,
58
+ "available_cameras": cameras,
59
+ "dna_map": dna_map,
60
+ "unlocked_evidence": self.game.unlocked_evidence
61
  }
62
  }
63
 
 
182
  # Format the result nicely
183
  evidence_data = format_tool_response(tool_name, arg, result, self.game.scenario)
184
 
185
+ # Include updated points and unlocks in response
186
  evidence_data["updated_points"] = self.game.points
187
+ evidence_data["unlocked_evidence"] = self.game.unlocked_evidence
188
+
189
+ if "newly_unlocked" in result and result["newly_unlocked"]:
190
+ evidence_data["newly_unlocked"] = result["newly_unlocked"]
191
 
192
  return {
193
  "action": "add_evidence",
game/game_engine.py CHANGED
@@ -17,6 +17,7 @@ class GameInstance:
17
  self.verdict_correct = False
18
  self.eliminated_suspects = []
19
  self.max_rounds = 3 # 3 Chances
 
20
 
21
  # Initialize Agents
22
  self._init_agents()
@@ -88,10 +89,20 @@ class GameInstance:
88
  cost = 2
89
  result = tools.get_location(self.scenario, kwargs.get("phone_number"), kwargs.get("timestamp"))
90
  elif tool_name == "get_footage":
91
- cost = 2
92
  result = tools.get_footage(self.scenario, kwargs.get("location"), kwargs.get("time_range"))
 
 
 
 
 
 
 
 
 
 
93
  elif tool_name == "get_dna_test":
94
- cost = 3
95
  result = tools.get_dna_test(self.scenario, kwargs.get("evidence_id"))
96
  elif tool_name == "call_alibi":
97
  cost = 1
 
17
  self.verdict_correct = False
18
  self.eliminated_suspects = []
19
  self.max_rounds = 3 # 3 Chances
20
+ self.unlocked_evidence = [] # Track unlocked DNA items
21
 
22
  # Initialize Agents
23
  self._init_agents()
 
89
  cost = 2
90
  result = tools.get_location(self.scenario, kwargs.get("phone_number"), kwargs.get("timestamp"))
91
  elif tool_name == "get_footage":
92
+ cost = 3
93
  result = tools.get_footage(self.scenario, kwargs.get("location"), kwargs.get("time_range"))
94
+
95
+ # Handle unlocks
96
+ if "unlocks" in result:
97
+ new_items = []
98
+ for item_id in result["unlocks"]:
99
+ if item_id not in self.unlocked_evidence:
100
+ self.unlocked_evidence.append(item_id)
101
+ new_items.append(item_id)
102
+ result["newly_unlocked"] = new_items
103
+
104
  elif tool_name == "get_dna_test":
105
+ cost = 4
106
  result = tools.get_dna_test(self.scenario, kwargs.get("evidence_id"))
107
  elif tool_name == "call_alibi":
108
  cost = 1
mcp/tools.py CHANGED
@@ -96,16 +96,26 @@ def get_footage(case_data, location: str, time_range: str = None) -> dict:
96
  return {"error": f"No footage for time {time_range}. Available: {list(loc_footage.keys())}"}
97
  else:
98
  # Return the first available clip info
99
- first_key = list(loc_footage.keys())[0]
 
 
 
 
 
 
 
 
 
100
  footage = loc_footage[first_key]
101
  time_range = first_key # Update for return
102
 
103
  return {
104
  "location": target_loc_key,
105
  "time_range": time_range,
106
- "visible_people": footage["visible_people"],
107
- "quality": footage["quality"],
108
- "key_details": footage.get("key_frame", "No significant events")
 
109
  }
110
 
111
  def get_dna_test(case_data, evidence_id: str) -> dict:
 
96
  return {"error": f"No footage for time {time_range}. Available: {list(loc_footage.keys())}"}
97
  else:
98
  # Return the first available clip info
99
+ # keys() might include "unlocks", so filter for time-like keys?
100
+ # Actually, logic assumes keys are time ranges.
101
+ # "unlocks" is a key but not a time range.
102
+ # We should find a key that contains ":" or is not "unlocks"
103
+
104
+ valid_keys = [k for k in loc_footage.keys() if k != "unlocks"]
105
+ if not valid_keys:
106
+ return {"error": "No footage clips available."}
107
+
108
+ first_key = valid_keys[0]
109
  footage = loc_footage[first_key]
110
  time_range = first_key # Update for return
111
 
112
  return {
113
  "location": target_loc_key,
114
  "time_range": time_range,
115
+ "visible_people": footage.get("visible_people", []),
116
+ "quality": footage.get("quality", "Unknown"),
117
+ "key_details": footage.get("key_frame", "No significant events"),
118
+ "unlocks": loc_footage.get("unlocks", []) # Fix: Get form camera level
119
  }
120
 
121
  def get_dna_test(case_data, evidence_id: str) -> dict:
scenarios/silicon_valley.json CHANGED
@@ -80,22 +80,35 @@
80
  "visible_people": ["Person in black hoodie entering"],
81
  "quality": "Grainy",
82
  "key_frame": "8:47 PM - figure strikes victim with trophy"
83
- }
 
84
  },
85
  "lobby_camera": {
86
  "8:40-8:55 PM": {
87
  "visible_people": ["Suspect 1 entering at 8:43", "Suspect 1 leaving at 8:52"],
 
88
  "notes": "Suspect changed clothes, looks flustered"
89
- }
 
 
 
 
 
 
 
 
 
90
  }
91
  },
92
  "dna_evidence": {
93
  "trophy_weapon": {
 
94
  "primary_match": "suspect_1",
95
  "confidence": "95%",
96
  "notes": "Clear fingerprints found on the base"
97
  },
98
  "door_handle": {
 
99
  "matches": ["suspect_1", "suspect_2", "victim"],
100
  "notes": "Multiple people touched door recently"
101
  }
@@ -133,4 +146,4 @@
133
  "8:47 PM": "Murder occurs",
134
  "8:52 PM": "Suspect 1 leaves building"
135
  }
136
- }
 
80
  "visible_people": ["Person in black hoodie entering"],
81
  "quality": "Grainy",
82
  "key_frame": "8:47 PM - figure strikes victim with trophy"
83
+ },
84
+ "unlocks": ["trophy_weapon", "door_handle"]
85
  },
86
  "lobby_camera": {
87
  "8:40-8:55 PM": {
88
  "visible_people": ["Suspect 1 entering at 8:43", "Suspect 1 leaving at 8:52"],
89
+ "quality": "Grainy",
90
  "notes": "Suspect changed clothes, looks flustered"
91
+ },
92
+ "unlocks": []
93
+ },
94
+ "kitchen_camera": {
95
+ "8:40-8:55 PM": {
96
+ "visible_people": ["Empty"],
97
+ "quality": "Low",
98
+ "notes": "Nothing happening."
99
+ },
100
+ "unlocks": []
101
  }
102
  },
103
  "dna_evidence": {
104
  "trophy_weapon": {
105
+ "label": "Trophy (Found in Office)",
106
  "primary_match": "suspect_1",
107
  "confidence": "95%",
108
  "notes": "Clear fingerprints found on the base"
109
  },
110
  "door_handle": {
111
+ "label": "Door Handle (10th Floor)",
112
  "matches": ["suspect_1", "suspect_2", "victim"],
113
  "notes": "Multiple people touched door recently"
114
  }
 
146
  "8:47 PM": "Murder occurs",
147
  "8:52 PM": "Suspect 1 leaves building"
148
  }
149
+ }
ui/static/css/noir.css CHANGED
@@ -434,6 +434,28 @@ button.send-btn:hover {
434
  to { transform: rotate(360deg); }
435
  }
436
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
  /* --- Tool Modal --- */
438
  .modal-overlay {
439
  position: fixed;
@@ -484,6 +506,42 @@ button.send-btn:hover {
484
  box-sizing: border-box;
485
  }
486
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  .modal-actions {
488
  display: flex;
489
  justify-content: flex-end;
 
434
  to { transform: rotate(360deg); }
435
  }
436
 
437
+ @keyframes wiggle {
438
+ 0% { transform: rotate(0deg); }
439
+ 25% { transform: rotate(-10deg); }
440
+ 50% { transform: rotate(10deg); }
441
+ 75% { transform: rotate(-5deg); }
442
+ 100% { transform: rotate(0deg); }
443
+ }
444
+
445
+ .wiggle {
446
+ animation: wiggle 0.5s ease-in-out infinite;
447
+ border-color: var(--accent-red) !important;
448
+ color: var(--accent-red) !important;
449
+ }
450
+
451
+ .unlocked-list {
452
+ margin-top: 10px;
453
+ background: rgba(0,0,0,0.1);
454
+ padding: 5px;
455
+ border: 1px dashed #555;
456
+ font-size: 0.8rem;
457
+ }
458
+
459
  /* --- Tool Modal --- */
460
  .modal-overlay {
461
  position: fixed;
 
506
  box-sizing: border-box;
507
  }
508
 
509
+ /* Option List (Radio/Checkbox alternative) */
510
+ .modal-option-list {
511
+ display: flex;
512
+ flex-direction: column;
513
+ gap: 10px;
514
+ margin-bottom: 20px;
515
+ max-height: 200px;
516
+ overflow-y: auto;
517
+ }
518
+
519
+ .modal-option-item {
520
+ display: flex;
521
+ align-items: center;
522
+ padding: 10px;
523
+ background: rgba(0,0,0,0.1);
524
+ border: 1px dashed #555;
525
+ cursor: pointer;
526
+ transition: background 0.2s;
527
+ }
528
+
529
+ .modal-option-item:hover {
530
+ background: rgba(0,0,0,0.2);
531
+ }
532
+
533
+ .modal-option-item input {
534
+ margin-right: 10px;
535
+ transform: scale(1.2);
536
+ accent-color: var(--accent-red);
537
+ }
538
+
539
+ .modal-option-item label {
540
+ cursor: pointer;
541
+ flex-grow: 1;
542
+ font-family: 'Courier New', monospace;
543
+ }
544
+
545
  .modal-actions {
546
  display: flex;
547
  justify-content: flex-end;
ui/static/js/game_logic.js CHANGED
@@ -8,7 +8,10 @@ let gameState = {
8
  evidence: [],
9
  chatLog: [],
10
  currentSuspect: null,
11
- nextEvidenceSlot: 0 // Track grid position for new cards
 
 
 
12
  };
13
 
14
  // --- Bridge: Communication with Parent (Python/Gradio) ---
@@ -63,6 +66,25 @@ function handleServerMessage(message) {
63
  if (data.updated_points !== undefined) {
64
  document.getElementById('points-display').innerText = data.updated_points;
65
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  addEvidenceToBoard(data);
67
  break;
68
  case 'tool_error':
@@ -105,6 +127,11 @@ function initializeGame(data) {
105
  document.getElementById('round-display').innerText = `${data.round}/3`;
106
  document.getElementById('points-display').innerText = data.points;
107
 
 
 
 
 
 
108
  renderCaseFile(data.scenario);
109
  }
110
 
@@ -448,6 +475,7 @@ function useTool(toolName) {
448
  pendingTool = toolName;
449
  const modal = document.getElementById('tool-modal');
450
  const input = document.getElementById('modal-input');
 
451
  const promptText = document.getElementById('modal-prompt-text');
452
 
453
  const section2 = document.getElementById('modal-section-2');
@@ -456,6 +484,8 @@ function useTool(toolName) {
456
 
457
  // Reset
458
  section2.style.display = 'none';
 
 
459
  input.value = '';
460
  input2.value = '';
461
 
@@ -467,10 +497,23 @@ function useTool(toolName) {
467
  section2.style.display = 'block';
468
  promptText2.innerText = "Question for Alibi:";
469
  } else if (toolName === 'get_dna_test') {
470
- promptText.innerText = "Enter Evidence ID:";
 
 
 
 
 
 
 
 
 
 
471
  } else if (toolName === 'get_footage') {
472
- promptText.innerText = "Enter Camera Location:";
 
 
473
  } else if (toolName === 'accuse') {
 
474
  if (!gameState.currentSuspect) {
475
  showNotification("⚠️ Select a suspect to accuse!");
476
  closeModal();
@@ -482,17 +525,67 @@ function useTool(toolName) {
482
  }
483
 
484
  modal.classList.add('active');
485
- input.focus();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
  }
487
 
488
  function submitTool() {
489
  const input = document.getElementById('modal-input');
490
- const value = input.value.trim();
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  const confirmBtn = document.getElementById('modal-confirm');
492
 
493
  if (!pendingTool) return;
494
 
495
  let payload = null;
 
496
 
497
  if (pendingTool === 'call_alibi') {
498
  const input2 = document.getElementById('modal-input-2');
@@ -509,7 +602,7 @@ function submitTool() {
509
  return;
510
  }
511
  } else if (pendingTool === 'accuse') {
512
- if (value.toUpperCase() === 'GUILTY') {
513
  payload = {
514
  tool: 'accuse',
515
  suspect_id: gameState.currentSuspect
@@ -535,6 +628,11 @@ function submitTool() {
535
 
536
  if (result && result.action === 'tool_error') {
537
  showModalError(result.data.message);
 
 
 
 
 
538
  } else {
539
  closeModal();
540
  }
@@ -542,6 +640,51 @@ function submitTool() {
542
  }
543
  }
544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  function showModalError(msg) {
546
  let errDiv = document.getElementById('modal-error');
547
  if (!errDiv) {
@@ -561,6 +704,18 @@ function closeModal() {
561
  pendingTool = null;
562
  const errDiv = document.getElementById('modal-error');
563
  if (errDiv) errDiv.innerText = '';
 
 
 
 
 
 
 
 
 
 
 
 
564
  }
565
 
566
  // --- Listeners ---
 
8
  evidence: [],
9
  chatLog: [],
10
  currentSuspect: null,
11
+ nextEvidenceSlot: 0, // Track grid position for new cards
12
+ availableCameras: [],
13
+ dnaMap: {},
14
+ unlockedEvidence: []
15
  };
16
 
17
  // --- Bridge: Communication with Parent (Python/Gradio) ---
 
66
  if (data.updated_points !== undefined) {
67
  document.getElementById('points-display').innerText = data.updated_points;
68
  }
69
+ // console.log("Evidence Data:", data);
70
+ if (data.newly_unlocked && data.newly_unlocked.length > 0) {
71
+ console.log("πŸ”“ Unlocking items:", data.newly_unlocked);
72
+ data.newly_unlocked.forEach(id => {
73
+ if (!gameState.unlockedEvidence.includes(id)) {
74
+ gameState.unlockedEvidence.push(id);
75
+ }
76
+ });
77
+ showNotification("πŸ” NEW EVIDENCE UNLOCKED");
78
+
79
+ // Wiggle DNA button
80
+ const dnaBtn = document.getElementById('tool-dna');
81
+ dnaBtn.classList.add('wiggle');
82
+
83
+ // Append to html_content for board display
84
+ let unlockHtml = `<div style="margin-top:5px; border-top:1px solid #ccc; padding-top:2px; font-size:0.8em; color:var(--accent-red);">πŸ”“ NEW ITEMS UNLOCKED</div>`;
85
+ if (data.html_content) data.html_content += unlockHtml;
86
+ else data.description += unlockHtml; // Fallback
87
+ }
88
  addEvidenceToBoard(data);
89
  break;
90
  case 'tool_error':
 
127
  document.getElementById('round-display').innerText = `${data.round}/3`;
128
  document.getElementById('points-display').innerText = data.points;
129
 
130
+ // Store Tool Data
131
+ gameState.availableCameras = data.available_cameras || [];
132
+ gameState.dnaMap = data.dna_map || {};
133
+ gameState.unlockedEvidence = data.unlocked_evidence || [];
134
+
135
  renderCaseFile(data.scenario);
136
  }
137
 
 
475
  pendingTool = toolName;
476
  const modal = document.getElementById('tool-modal');
477
  const input = document.getElementById('modal-input');
478
+ const optionsContainer = document.getElementById('modal-options');
479
  const promptText = document.getElementById('modal-prompt-text');
480
 
481
  const section2 = document.getElementById('modal-section-2');
 
484
 
485
  // Reset
486
  section2.style.display = 'none';
487
+ input.style.display = 'block';
488
+ optionsContainer.style.display = 'none';
489
  input.value = '';
490
  input2.value = '';
491
 
 
497
  section2.style.display = 'block';
498
  promptText2.innerText = "Question for Alibi:";
499
  } else if (toolName === 'get_dna_test') {
500
+ promptText.innerText = "Select Evidence to Test:";
501
+
502
+ // Stop wiggling if clicked
503
+ document.getElementById('tool-dna').classList.remove('wiggle');
504
+
505
+ if (gameState.unlockedEvidence.length === 0) {
506
+ showNotification("⚠️ No physical evidence found yet. Check camera footage!");
507
+ return;
508
+ }
509
+ input.style.display = 'none';
510
+ populateOptionList(gameState.unlockedEvidence, gameState.dnaMap);
511
  } else if (toolName === 'get_footage') {
512
+ promptText.innerText = "Select Camera Feed:";
513
+ input.style.display = 'none';
514
+ populateOptionList(gameState.availableCameras);
515
  } else if (toolName === 'accuse') {
516
+ // ... existing accuse logic ...
517
  if (!gameState.currentSuspect) {
518
  showNotification("⚠️ Select a suspect to accuse!");
519
  closeModal();
 
525
  }
526
 
527
  modal.classList.add('active');
528
+ if (input.style.display !== 'none') input.focus();
529
+ }
530
+
531
+ function populateOptionList(items, labelMap = null) {
532
+ const container = document.getElementById('modal-options');
533
+ container.innerHTML = '';
534
+ container.style.display = 'flex';
535
+
536
+ items.forEach((item, index) => {
537
+ const wrapper = document.createElement('div');
538
+ wrapper.className = 'modal-option-item';
539
+ wrapper.onclick = () => {
540
+ wrapper.querySelector('input').checked = true;
541
+ };
542
+
543
+ const radio = document.createElement('input');
544
+ radio.type = 'radio';
545
+ radio.name = 'tool-option';
546
+ radio.value = item;
547
+ radio.id = `opt-${index}`;
548
+ if (index === 0) radio.checked = true;
549
+
550
+ const label = document.createElement('label');
551
+ label.htmlFor = `opt-${index}`;
552
+
553
+ let text = item;
554
+ if (labelMap && labelMap[item]) {
555
+ text = labelMap[item];
556
+ } else {
557
+ text = item.replace(/_/g, ' ').toUpperCase();
558
+ }
559
+ label.innerText = text;
560
+
561
+ wrapper.appendChild(radio);
562
+ wrapper.appendChild(label);
563
+ container.appendChild(wrapper);
564
+ });
565
  }
566
 
567
  function submitTool() {
568
  const input = document.getElementById('modal-input');
569
+ const optionsContainer = document.getElementById('modal-options');
570
+
571
+ let value = input.value.trim();
572
+
573
+ // Use radio value if visible
574
+ if (optionsContainer.style.display !== 'none') {
575
+ const selected = optionsContainer.querySelector('input[name="tool-option"]:checked');
576
+ if (selected) {
577
+ value = selected.value;
578
+ } else {
579
+ value = '';
580
+ }
581
+ }
582
+
583
  const confirmBtn = document.getElementById('modal-confirm');
584
 
585
  if (!pendingTool) return;
586
 
587
  let payload = null;
588
+ // ... rest of submitTool ... (Logic remains same as it uses 'value')
589
 
590
  if (pendingTool === 'call_alibi') {
591
  const input2 = document.getElementById('modal-input-2');
 
602
  return;
603
  }
604
  } else if (pendingTool === 'accuse') {
605
+ if (value.toUpperCase() === 'GUILTY') {
606
  payload = {
607
  tool: 'accuse',
608
  suspect_id: gameState.currentSuspect
 
628
 
629
  if (result && result.action === 'tool_error') {
630
  showModalError(result.data.message);
631
+ } else if (result && result.action === 'add_evidence') {
632
+ // Success: Show result in modal
633
+ showModalResult(result.data);
634
+ // Auto-close after 5s
635
+ setTimeout(closeModal, 5000);
636
  } else {
637
  closeModal();
638
  }
 
640
  }
641
  }
642
 
643
+ function showModalResult(data) {
644
+ // Hide inputs
645
+ document.getElementById('modal-input').style.display = 'none';
646
+ document.getElementById('modal-options').style.display = 'none';
647
+ document.getElementById('modal-section-2').style.display = 'none';
648
+ document.getElementById('modal-prompt-text').style.display = 'none';
649
+
650
+ // Show result
651
+ let resultDiv = document.getElementById('modal-result');
652
+ if (!resultDiv) {
653
+ resultDiv = document.createElement('div');
654
+ resultDiv.id = 'modal-result';
655
+ resultDiv.style.marginTop = '20px';
656
+ resultDiv.style.borderTop = '2px dashed var(--ink-color)';
657
+ resultDiv.style.paddingTop = '10px';
658
+ document.querySelector('.modal-content').insertBefore(resultDiv, document.querySelector('.modal-actions'));
659
+ }
660
+
661
+ resultDiv.style.display = 'block';
662
+
663
+ let html = `
664
+ <div style="font-weight:bold; margin-bottom:5px;">RESULT:</div>
665
+ ${data.html_content || data.description}
666
+ `;
667
+
668
+ if (data.newly_unlocked && data.newly_unlocked.length > 0) {
669
+ html += `<div class="unlocked-list"><strong>πŸ”“ UNLOCKED FOR DNA TEST:</strong><ul>`;
670
+ data.newly_unlocked.forEach(id => {
671
+ let label = id;
672
+ if (gameState.dnaMap && gameState.dnaMap[id]) {
673
+ label = gameState.dnaMap[id];
674
+ }
675
+ html += `<li>${label}</li>`;
676
+ });
677
+ html += `</ul></div>`;
678
+ }
679
+
680
+ resultDiv.innerHTML = html;
681
+
682
+ // Change button
683
+ const btn = document.getElementById('modal-confirm');
684
+ btn.innerText = "CLOSE";
685
+ btn.onclick = closeModal;
686
+ }
687
+
688
  function showModalError(msg) {
689
  let errDiv = document.getElementById('modal-error');
690
  if (!errDiv) {
 
704
  pendingTool = null;
705
  const errDiv = document.getElementById('modal-error');
706
  if (errDiv) errDiv.innerText = '';
707
+
708
+ const resultDiv = document.getElementById('modal-result');
709
+ if (resultDiv) resultDiv.style.display = 'none';
710
+
711
+ const btn = document.getElementById('modal-confirm');
712
+ btn.innerText = "SUBMIT";
713
+ btn.onclick = submitTool;
714
+ btn.disabled = false;
715
+
716
+ // Reset inputs visibility for next time (useTool will override, but safe default)
717
+ document.getElementById('modal-input').style.display = 'block';
718
+ document.getElementById('modal-prompt-text').style.display = 'block';
719
  }
720
 
721
  // --- Listeners ---
ui/templates/game_interface.html CHANGED
@@ -47,7 +47,7 @@
47
  <div class="tool-btn" id="tool-camera">
48
  <span class="tool-icon">πŸ“Ή</span>
49
  <span>Footage</span>
50
- <span class="tool-cost">2 pts</span>
51
  </div>
52
  <div class="tool-btn" id="tool-phone">
53
  <span class="tool-icon">πŸ“ž</span>
@@ -57,7 +57,7 @@
57
  <div class="tool-btn" id="tool-dna">
58
  <span class="tool-icon">πŸ”¬</span>
59
  <span>DNA Test</span>
60
- <span class="tool-cost">3 pts</span>
61
  </div>
62
  <div class="tool-btn" id="tool-accuse" style="margin-top: auto; border-color: red; color: red;">
63
  <span class="tool-icon">βš–οΈ</span>
@@ -85,6 +85,9 @@
85
  <div id="modal-prompt-text">Enter details:</div>
86
  <input type="text" id="modal-input" class="modal-input" placeholder="...">
87
 
 
 
 
88
  <div id="modal-section-2" style="display:none">
89
  <div id="modal-prompt-text-2">Question:</div>
90
  <input type="text" id="modal-input-2" class="modal-input" placeholder="What do you want to ask?">
 
47
  <div class="tool-btn" id="tool-camera">
48
  <span class="tool-icon">πŸ“Ή</span>
49
  <span>Footage</span>
50
+ <span class="tool-cost">3 pts</span>
51
  </div>
52
  <div class="tool-btn" id="tool-phone">
53
  <span class="tool-icon">πŸ“ž</span>
 
57
  <div class="tool-btn" id="tool-dna">
58
  <span class="tool-icon">πŸ”¬</span>
59
  <span>DNA Test</span>
60
+ <span class="tool-cost">4 pts</span>
61
  </div>
62
  <div class="tool-btn" id="tool-accuse" style="margin-top: auto; border-color: red; color: red;">
63
  <span class="tool-icon">βš–οΈ</span>
 
85
  <div id="modal-prompt-text">Enter details:</div>
86
  <input type="text" id="modal-input" class="modal-input" placeholder="...">
87
 
88
+ <div id="modal-options" class="modal-option-list" style="display:none"></div>
89
+ <select id="modal-select" class="modal-input" style="display:none"></select>
90
+
91
  <div id="modal-section-2" style="display:none">
92
  <div id="modal-prompt-text-2">Question:</div>
93
  <input type="text" id="modal-input-2" class="modal-input" placeholder="What do you want to ask?">