feat(globals): add personal global detection with PLAYER_NAME setting

- Add PLAYER_NAME setting to .env.example for avatar name configuration
- Add personal_global patterns for Swedish and English:
  - EN: '[Globals] Player killed a creature (Creature) for X PED'
  - SV: '[Globala] Player dödade ett kreatur (Creature) med X PED'
- Distinguish personal globals from other players' globals
- Show 🎉🎉🎉 YOUR GLOBAL notification with creature name
- Track personal_globals separately in session summary

Fixes #42 - Users can now see when THEY global vs others.
This commit is contained in:
LemonNexus 2026-02-08 18:23:35 +00:00
parent 06a95f56f4
commit 77d8e808fb
3 changed files with 149 additions and 96 deletions

View File

@ -69,6 +69,10 @@ DB_MAX_BACKUPS=10
# Linux/Wine: ~/.wine/drive_c/users/<Username>/Documents/Entropia Universe/chat.log
EU_CHAT_LOG_PATH=./test-data/chat.log
# Your Entropia Universe avatar name (for detecting personal globals/HoFs)
# Example: PLAYER_NAME=John Doe
PLAYER_NAME=
# Log polling interval (milliseconds)
LOG_POLL_INTERVAL=1000

View File

@ -73,6 +73,23 @@ class LogWatcher:
re.IGNORECASE
)
# PERSONAL GLOBAL (when YOU get a global - different from seeing others)
# English: "[Globals] [Player] killed a creature (Creature) with a value of X PED"
# Swedish: "[Globala] [Player] dödade ett kreatur (Creature) med ett värde av X PED"
PATTERN_PERSONAL_GLOBAL_EN = re.compile(
r'^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\[Globals\]\s+\[?\]?\s*'
r'([\w\s]+?)\s+killed\s+a\s+creature\s+\(([^)]+)\)\s+'
r'(?:with\s+a\s+value\s+of|for)\s+(\d+(?:\.\d+)?)\s+PED',
re.IGNORECASE
)
PATTERN_PERSONAL_GLOBAL_SV = re.compile(
r'^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\[Globala\]\s+\[?\]?\s*'
r'([\w\s]+?)\s+dödade\s+ett\s+kreatur\s+\(([^)]+)\)\s+'
r'med\s+ett\s+värde\s+av\s+(\d+(?:\.\d+)?)\s+PED',
re.IGNORECASE
)
# HALL OF FAME PATTERNS
# Swedish: "...En post har lagts till i Hall of Fame!"
PATTERN_HOF_MARKER = re.compile(
@ -234,6 +251,8 @@ class LogWatcher:
'loot_sv': PATTERN_LOOT_SV,
'global_en': PATTERN_GLOBAL_EN,
'global_sv': PATTERN_GLOBAL_SV,
'personal_global_en': PATTERN_PERSONAL_GLOBAL_EN,
'personal_global_sv': PATTERN_PERSONAL_GLOBAL_SV,
'hof': PATTERN_HOF_MARKER,
'skill_en': PATTERN_SKILL_EN,
'skill_sv': PATTERN_SKILL_SV,
@ -371,6 +390,16 @@ class LogWatcher:
if match:
return self._create_global_event_en(match, line)
# PERSONAL GLOBAL - Swedish (when YOU get a global)
match = self.PATTERN_PERSONAL_GLOBAL_SV.match(line)
if match:
return self._create_personal_global_event(match, line, 'swedish')
# PERSONAL GLOBAL - English (when YOU get a global)
match = self.PATTERN_PERSONAL_GLOBAL_EN.match(line)
if match:
return self._create_personal_global_event(match, line, 'english')
# HOF
match = self.PATTERN_HOF_MARKER.match(line)
if match:
@ -651,6 +680,20 @@ class LogWatcher:
}
)
def _create_personal_global_event(self, match: re.Match, line: str, language: str) -> LogEvent:
"""Create personal global event (when YOU get a global)."""
return LogEvent(
timestamp=self._parse_timestamp(match.group(1)),
event_type='personal_global',
raw_line=line,
data={
'player_name': match.group(2).strip(),
'creature': match.group(3).strip(),
'value_ped': Decimal(match.group(4)),
'language': language
}
)
# ========================================================================
# ASYNC POLLING LOOP
# ========================================================================

10
main.py
View File

@ -207,7 +207,7 @@ class LemontropiaApp:
logger.info(f"Using REAL log: {log_path}")
# Stats tracking
stats = {'loot': 0, 'globals': 0, 'hofs': 0, 'skills': 0, 'level_ups': 0, 'weapon_tiers': 0, 'enhancers_broken': 0, 'damage_dealt': 0, 'damage_taken': 0, 'evades': 0, 'total_ped': Decimal('0.0')}
stats = {'loot': 0, 'globals': 0, 'personal_globals': 0, 'hofs': 0, 'skills': 0, 'level_ups': 0, 'weapon_tiers': 0, 'enhancers_broken': 0, 'damage_dealt': 0, 'damage_taken': 0, 'evades': 0, 'total_ped': Decimal('0.0')}
def on_event(event):
"""Handle log events."""
@ -232,6 +232,10 @@ class LemontropiaApp:
stats['globals'] += 1
print(f" 🌍 GLOBAL: {event.data.get('player_name')} found {event.data.get('value_ped')} PED!")
elif event.event_type == 'personal_global':
stats['personal_globals'] += 1
print(f" 🎉🎉🎉 YOUR GLOBAL: {event.data.get('player_name')} killed {event.data.get('creature')} for {event.data.get('value_ped')} PED!!! 🎉🎉🎉")
elif event.event_type == 'hof':
stats['hofs'] += 1
print(f" 🏆 HALL OF FAME: {event.data.get('value_ped')} PED!")
@ -271,6 +275,7 @@ class LemontropiaApp:
# Subscribe to events
self.watcher.subscribe('loot', on_event)
self.watcher.subscribe('global', on_event)
self.watcher.subscribe('personal_global', on_event)
self.watcher.subscribe('hof', on_event)
self.watcher.subscribe('skill', on_event)
self.watcher.subscribe('level_up', on_event)
@ -307,7 +312,8 @@ class LemontropiaApp:
print("="*50)
print(f"\n📊 SESSION SUMMARY:")
print(f" Loot events: {stats['loot']}")
print(f" Globals: {stats['globals']}")
print(f" Your Globals: {stats['personal_globals']}")
print(f" Other Globals: {stats['globals']}")
print(f" HoFs: {stats['hofs']}")
print(f" Skills: {stats['skills']}")
print(f" Level Ups: {stats['level_ups']}")