File size: 16,264 Bytes
29b445b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
#!/usr/bin/env python3
"""

Modified scan handler for Tag Collector Game with Enkephalin rewards for rare tags

"""

import streamlit as st
import torch
import time
import math
from tag_categories import (
    get_unlocked_categories,
    get_collection_power_level
)
from game_constants import TAG_CURRENCY_NAME, ENKEPHALIN_CURRENCY_NAME, ENKEPHALIN_ICON, RARITY_LEVELS, TAG_POWER_BONUSES
from state_manager import update_game_state 

def enhanced_scan_button_handler(image_path):
    """

    Enhanced scan button handler with Enkephalin rewards for rare tag discoveries

    """
    try:
        # Run inference
        results = st.session_state.model.predict(
            image_path=image_path,
            threshold=st.session_state.threshold
        )
        
        # Get probabilities
        probs = results['refined_probabilities'][0]  # Remove batch dimension
        
        # All categories are now unlocked
        unlocked_categories = get_unlocked_categories(st.session_state)
        
        # No limit on tags
        max_tags = float('inf')  # Unlimited
        
        # Get collection power bonus
        power_info = get_collection_power_level(st.session_state)
        coin_multiplier = power_info['current_level']['coin_bonus']
        
        # Store all detected tags for display
        all_tags = {}  # Format: {category: [(tag, probability, rarity), ...]}
        found_tags = []  # Tags that pass the threshold
        total_currency_earned = 0
        total_enkephalin_earned = 0
        new_tag_count = 0
        
        # Minimum probability to display (can be lower than threshold)
        min_display_prob = 0.1
        
        # Track any newly completed combinations
        previously_unlocked = set(st.session_state.unlocked_combinations) if hasattr(st.session_state, 'unlocked_combinations') else set()
        
        # Collect all tags that are above threshold
        candidates = []
        for idx in range(len(probs)):
            prob_value = probs[idx].item()
            
            # Only process tags above threshold
            if prob_value >= st.session_state.threshold:
                tag, category = st.session_state.model.dataset.get_tag_info(idx)
                candidates.append({
                    "idx": idx,
                    "tag": tag,
                    "probability": prob_value,
                    "category": category
                })
        
        # Sort by probability (highest first)
        candidates.sort(key=lambda x: x["probability"], reverse=True)
        
        # Add all tags to appropriate categories (for display purposes)
        for idx in range(len(probs)):
            prob_value = probs[idx].item()
            
            # Skip if below display threshold
            if prob_value < min_display_prob:
                continue
            
            # Get tag information
            tag, category = st.session_state.model.dataset.get_tag_info(idx)
            
            # Determine rarity
            rarity = determine_tag_rarity(tag, prob_value, category)
            
            # Add to category in all_tags
            if category not in all_tags:
                all_tags[category] = []
            
            # Check if this tag is above threshold (collected)
            is_collected = prob_value >= st.session_state.threshold
            
            # Add to all_tags with appropriate status
            if is_collected:
                all_tags[category].append((tag, prob_value, rarity, "collected"))
            else:
                all_tags[category].append((tag, prob_value, rarity, "displayed"))
        
        # Process all candidates for collection and currency
        for candidate in candidates:
            tag = candidate["tag"]
            prob_value = candidate["probability"]
            category = candidate["category"]
            
            # Determine rarity
            rarity = determine_tag_rarity(tag, prob_value, category)
            
            # Add tag to collection and get currency
            currency_earned, enkephalin_earned, is_new_tag = add_tag_to_collection(tag, prob_value, category, coin_multiplier)
            
            # Count new tags
            if is_new_tag:
                new_tag_count += 1
            
            # Add to total currency earned
            if currency_earned > 0:
                total_currency_earned += currency_earned
                
            # Add to total enkephalin earned
            if enkephalin_earned > 0:
                total_enkephalin_earned += enkephalin_earned
            
            # Add to found tags list
            found_tags.append({
                "tag": tag,
                "probability": prob_value,
                "category": category,
                "currency": currency_earned,
                "enkephalin": enkephalin_earned,
                "rarity": rarity,
                "is_new": is_new_tag
            })
        
        # Sort each category by probability
        for category in all_tags:
            all_tags[category].sort(key=lambda x: x[1], reverse=True)
        
        # Update game stats - IMPORTANT: Direct modification to ensure updates 
        # are properly tracked by Streamlit's session state mechanism
        st.session_state.game_stats["images_processed"] += 1
        st.session_state.game_stats["total_tags_found"] += len(found_tags)
        
        # Update enkephalin stats if we earned any
        if total_enkephalin_earned > 0:
            if "enkephalin_generated" not in st.session_state.game_stats:
                st.session_state.game_stats["enkephalin_generated"] = 0
            st.session_state.game_stats["enkephalin_generated"] += total_enkephalin_earned
            
        # Update tag power ONCE
        threshold_bonus, coin_bonus = calculate_tag_power()
        st.session_state.tag_power_bonus = threshold_bonus
        st.session_state.coin_multiplier = coin_bonus

        # Force update of state_version to trigger UI refresh
        if 'state_version' not in st.session_state:
            st.session_state.state_version = 0
        st.session_state.state_version += 1
        
        # Store results in session state
        st.session_state.current_scan = {
            "all_tags": all_tags,
            "found_tags": found_tags,
            "threshold": st.session_state.threshold,
            "total_currency_earned": total_currency_earned,
            "total_enkephalin_earned": total_enkephalin_earned,
            "new_tag_count": new_tag_count,
        }
        
        # # Save game state explicitly
        # save_game_state()
        
        return True
            
    except Exception as e:
        st.error(f"Error scanning image: {str(e)}")
        import traceback
        st.code(traceback.format_exc())
        return False

def determine_tag_rarity(tag, probability, category):
    """

    Determine the rarity of a tag based on the metadata if available,

    otherwise use a simplified probability-based approach.

    Always returns a valid rarity level.

    """
    # Set a default rarity (safeguard against returning None)
    default_rarity = "Canard"
    
    try:
        # If we have the rarity metadata loaded, use it
        if hasattr(st.session_state, 'tag_rarity_metadata') and st.session_state.tag_rarity_metadata:
            # Check if this tag exists in our metadata
            if tag in st.session_state.tag_rarity_metadata:
                tag_info = st.session_state.tag_rarity_metadata[tag]
                
                # Handle both new and old format
                if isinstance(tag_info, dict) and "rarity" in tag_info:
                    # New format with rarity and sample_count
                    rarity = tag_info["rarity"]
                else:
                    # Old format where tag_info is the rarity string directly
                    rarity = tag_info
                    
                # Verify the rarity is valid
                if rarity in RARITY_LEVELS:
                    return rarity
            
            # Special handling for rating_* and year_* tags
            if tag.startswith("rating_") or tag.startswith("year_"):
                for metadata_tag in st.session_state.tag_rarity_metadata:
                    if metadata_tag == tag:
                        tag_info = st.session_state.tag_rarity_metadata[metadata_tag]
                        if isinstance(tag_info, dict) and "rarity" in tag_info:
                            rarity = tag_info["rarity"]
                        else:
                            rarity = tag_info
                            
                        if rarity in RARITY_LEVELS:
                            return rarity
    
    except Exception as e:
        # Log the error but don't crash
        print(f"Error determining rarity for tag {tag}: {str(e)}")
    
    # Return the default rarity as a fallback
    return default_rarity

def get_enkephalin_reward(rarity):
    """

    Determine the Enkephalin reward based on tag rarity

    

    Args:

        rarity (str): The tag rarity level

        

    Returns:

        int: Amount of Enkephalin to award

    """
    # Get enkephalin reward from TAG_POWER_BONUSES
    if rarity in TAG_POWER_BONUSES:
        return TAG_POWER_BONUSES[rarity]["enkephalin_reward"]
    return 0

def add_tag_to_collection(tag, probability, category, coin_multiplier=1.0):
    """

    Add a tag to the user's collection and award currency and enkephalin for new discoveries.

    """
    try:
        # Get the tag's rarity
        rarity = determine_tag_rarity(tag, probability, category)
        
        # Check if this is a new tag discovery
        is_new_tag = tag not in st.session_state.collected_tags
        
        # Check if tag was previously sacrificed
        was_sacrificed = hasattr(st.session_state, 'sacrificed_tags') and tag in st.session_state.sacrificed_tags
        
        # Get base currency value for this rarity
        base_currency_value = RARITY_LEVELS[rarity]["value"]
        
        # Basic debug info - always print this
        print(f"Processing tag: {tag}, rarity: {rarity}, is_new: {is_new_tag}, base_value: {base_currency_value}")
        
        # Initialize currency earned
        currency_earned = 0
        enkephalin_earned = 0
        
        # Record the tag acquisition
        timestamp = time.strftime("%H:%M:%S")
        
        # Update tag collection
        if tag in st.session_state.collected_tags:
            # If already collected, just increment the count, no new currency
            st.session_state.collected_tags[tag]["count"] += 1
        else:
            # New tag discovery - create entry in collection
            st.session_state.collected_tags[tag] = {
                "count": 1,
                "rarity": rarity,
                "category": category,
                "discovery_time": timestamp
            }
            
            # Award currency and enkephalin only if not previously sacrificed and is a new tag
            if not was_sacrificed and is_new_tag:
                # Calculate tag power bonuses
                tag_power_bonus, base_coin_multiplier = calculate_tag_power()
                
                # Now print the debug info AFTER calculating base_coin_multiplier
                print(f"  Base multiplier: {base_coin_multiplier}, Collection multiplier: {coin_multiplier}")
                
                # Apply collection power multiplier
                total_multiplier = base_coin_multiplier * coin_multiplier
                
                # Check if category is mastered for additional bonus
                if hasattr(st.session_state, 'mastered_categories') and category in st.session_state.mastered_categories:
                    from tag_categories import CATEGORY_MASTERY_BONUS
                    total_multiplier += CATEGORY_MASTERY_BONUS.get('coin_multiplier', 0)
                
                # Award currency with multiplier for new discoveries
                currency_earned = int(base_currency_value * total_multiplier)
                
                # Award enkephalin for new tag discoveries based on rarity
                enkephalin_earned = get_enkephalin_reward(rarity)
                
                # Apply any enkephalin bonus from achievements if it exists
                if hasattr(st.session_state, 'enkephalin_bonus') and st.session_state.enkephalin_bonus > 0:
                    enkephalin_earned = int(enkephalin_earned * (1 + st.session_state.enkephalin_bonus))
                
                print(f"  Final multiplier: {total_multiplier}, Final award: {currency_earned} {TAG_CURRENCY_NAME}, {enkephalin_earned} {ENKEPHALIN_CURRENCY_NAME}")
                
                # Add to player's currency
                st.session_state.tag_currency += currency_earned
                
                # Add to player's enkephalin if earned
                if enkephalin_earned > 0:
                    st.session_state.enkephalin += enkephalin_earned
                
                # Track in stats
                st.session_state.game_stats["total_currency_earned"] += currency_earned
                
                # Add to history for new discoveries
                if not hasattr(st.session_state, 'tag_history'):
                    st.session_state.tag_history = []
                    
                st.session_state.tag_history.append({
                    "tag": tag,
                    "rarity": rarity,
                    "value": currency_earned,
                    "enkephalin": enkephalin_earned,
                    "time": timestamp,
                    "is_new": True
                })
        
        # Always increment total tags found count
        st.session_state.game_stats["total_tags_found"] += 1
        
        # Update tag power calculations with the new tag
        threshold_bonus, coin_bonus = calculate_tag_power()
        st.session_state.tag_power_bonus = threshold_bonus
        st.session_state.coin_multiplier = coin_bonus

        update_game_state(tag_currency=st.session_state.tag_currency, enkephalin=st.session_state.enkephalin)

        # Return the earned currency, enkephalin, and new tag status
        return currency_earned, enkephalin_earned, is_new_tag
    
    except Exception as e:
        # Log the error
        print(f"Error adding tag '{tag}' to collection: {str(e)}")
        import traceback
        traceback.print_exc()
        
        # Return safe defaults to prevent crashing
        return 0, 0, False

def calculate_tag_power():
    """

    Calculate tag power bonuses based on collected tags (not sacrificed ones).

    Tags that are sacrificed no longer contribute to tag power until recollected.

    

    Returns:

        (threshold_reduction, coin_multiplier)

    """
    if not hasattr(st.session_state, 'collected_tags'):
        return 0, 1.0
    
    total_threshold_reduction = 0
    total_coin_multiplier = 1.0
    
    # Calculate bonuses from individual tags
    for tag, info in st.session_state.collected_tags.items():
        rarity = info["rarity"]
        if rarity in TAG_POWER_BONUSES:
            # Add threshold reduction (scales with tag count, but with diminishing returns)
            count = info["count"]
            # Use logarithmic scaling to prevent excessive bonuses from farming
            scaling_factor = 1 + (math.log(count) / 2) if count > 1 else 1
            
            # Apply the bonus
            total_coin_multiplier += TAG_POWER_BONUSES[rarity]["coin_multiplier"] * scaling_factor
    
    # Apply collection power coin bonus
    if hasattr(st.session_state, 'collection_power_coin_bonus'):
        total_coin_multiplier *= st.session_state.collection_power_coin_bonus
    
    return total_threshold_reduction, total_coin_multiplier