diff --git a/DBEditor/DBEditor.py b/DBEditor/DBEditor.py index 23dd903..34365e2 100644 --- a/DBEditor/DBEditor.py +++ b/DBEditor/DBEditor.py @@ -95,6 +95,7 @@ class DBEditor(QMainWindow): event_system.add_listener('gather_evolution_info', self.gather_evolution_info) event_system.add_listener('gather_encounter_info', self.gather_encounter_info) event_system.add_listener('reinitialize_database', self.reinitialize_database) + event_system.add_listener('gather_marks_info', self.gather_marks_info) self.conn = sqlite3.connect(':memory:', check_same_thread=False) # Use in-memory database for runtime self.cursor = self.conn.cursor() @@ -436,6 +437,32 @@ class DBEditor(QMainWindow): self.logger.info("Database reinitialized successfully.") QMessageBox.information(self, 'Database Reinitialized', 'The database has been cleared and reinitialized.') + def gather_marks_info(self, data): + event_system.emit_sync('clear_log_display') + self.logger.info("Starting to gather marks information...") + + pokemon_list = event_system.call_sync('get_pokemon_list') + + for pfic, name, form_name, national_dex in pokemon_list: + pokemon_data = event_system.call_sync('get_pokemon_data', pfic) + #Rule 1 + # 1. If a pokemon form has a previous evolution from within the same generation, + # use the mark of the previous evolution. This should be recursive within the same generation. + chain = event_system.call_sync('get_evolution_chain', pfic) + if chain: + find_me = lambda x: x[0] == pfic + target_index = next((i for i, item in enumerate(chain) if find_me(item)), -1) + base_form_in_generation = None + for i in range(target_index, -1, -1): + chain_pfic, chain_name, chain_form_name, method = chain[i] + chain_pokemon_data = event_system.call_sync('get_pokemon_data', chain_pfic) + if chain_pokemon_data[3] == pokemon_data[3]: + base_form_in_generation = chain_pfic + else: + break + + + def qt_message_handler(mode, context, message): diff --git a/DBEditor/db_controller.py b/DBEditor/db_controller.py index d0b3ec2..2baa8cc 100644 --- a/DBEditor/db_controller.py +++ b/DBEditor/db_controller.py @@ -34,6 +34,7 @@ class DBController: event_system.add_listener('add_new_exclusive_set', self.add_new_exclusive_set) event_system.add_listener('save_changes', self.save_changes) event_system.add_listener('export_database', self.export_database) + event_system.add_listener('assign_mark_to_form', self.assign_mark_to_form) def init_database(self): disk_conn = sqlite3.connect('pokemon_forms.db') @@ -48,6 +49,7 @@ class DBController: self.create_encounter_exclusive_group_table(disk_cursor) self.create_encounters_table(disk_cursor) self.create_mark_table(disk_cursor) + self.create_form_marks_table(disk_cursor) # Commit changes to the file-based database disk_conn.commit() @@ -159,30 +161,38 @@ class DBController: ("Kalos", "images/marks/Blue_pentagon_HOME.png", ["X", "Y", "Omega Ruby", "Alpha Sapphire"]), ("Alola", "images/marks/Black_clover_HOME.png", ["Sun", "Moon", "Ultra Sun", "Ultra Moon"]), ("Let's Go", "images/marks/Let's_Go_icon_HOME.png", ["Let's Go Pikachu", "Let's Go Eevee"]), - ("Galar", "images/marks/Galar_symbol_HOME.png", ["Sword", "Shield"]), + ("Galar", "images/marks/Galar_symbol_HOME.png", ["Sword", "Shield", "Expansion Pass"]), ("Sinnoh", "images/marks/BDSP_icon_HOME.png", ["Brilliant Diamond", "Shining Pearl"]), ("Hisui", "images/marks/Arceus_mark_HOME.png", ["Legends Arceus"]), - ("Paldea", "images/marks/Paldea_icon_HOME.png", ["Scarlet", "Violet"]), + ("Paldea", "images/marks/Paldea_icon_HOME.png", ["Scarlet", "Violet", "The Teal Mask", "The Hidden Treasure of Area Zero"]), ] # Check if marks already exist cursor.execute('SELECT COUNT(*) FROM marks') marks_count = cursor.fetchone()[0] - if marks_count == 0: - for mark in marks: + + for mark in marks: + mark_id = None + if marks_count == 0: cursor.execute(''' INSERT OR IGNORE INTO marks (name, icon_path) VALUES (?, ?) ''', (mark[0], mark[1])) mark_id = cursor.lastrowid - - for game_name in mark[2]: - cursor.execute(''' - INSERT OR IGNORE INTO mark_game_associations (mark_id, game_id) - SELECT ?, id FROM games WHERE name = ? - ''', (mark_id, game_name)) + + if mark_id == None: + cursor.execute(''' + SELECT id FROM marks WHERE name = ? + ''', (mark[0],)) + mark_id = cursor.fetchone()[0] + + for game_name in mark[2]: + cursor.execute(''' + INSERT OR IGNORE INTO mark_game_associations (mark_id, game_id) + SELECT ?, id FROM games WHERE name = ? + ''', (mark_id, game_name)) def create_games_table(self, cursor): @@ -249,14 +259,26 @@ class DBController: ("Pokémon Home", 98, ["Pokémon HOME"]), ("Pokémon Go", 99, ["Pokémon GO"]), ] - + + # Check if marks already exist + cursor.execute('SELECT COUNT(*) FROM games') + games_count = cursor.fetchone()[0] + for game in games: - cursor.execute(''' - INSERT OR IGNORE INTO games (name, generation) - VALUES (?, ?) - ''', (game[0], game[1])) + game_id = None + if games_count == 0: + cursor.execute(''' + INSERT OR IGNORE INTO games (name, generation) + VALUES (?, ?) + ''', (game[0], game[1])) + + game_id = cursor.lastrowid - game_id = cursor.lastrowid + if game_id == None: + cursor.execute(''' + SELECT id FROM games WHERE name = ? + ''', (game[0],)) + game_id = cursor.fetchone()[0] # Insert alternate names for alt_name in game[2]: @@ -265,6 +287,17 @@ class DBController: VALUES (?, ?) ''', (game_id, alt_name)) + def create_form_marks_table(self, cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS form_marks ( + pfic TEXT, + mark_id INTEGER, + FOREIGN KEY (pfic) REFERENCES pokemon_forms (PFIC), + FOREIGN KEY (mark_id) REFERENCES marks (id), + PRIMARY KEY (pfic, mark_id) + ) + ''') + def load_pokemon_details(self, pfic): self.cursor.execute(''' SELECT pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home, pf.is_baby_form @@ -402,7 +435,7 @@ class DBController: def get_exclusive_set_details(self, set_id): self.cursor.execute('SELECT group_name, description, game_id FROM exclusive_encounter_groups WHERE id = ?', (set_id,)) - return self.cursor.fetchone() + return self.cursor.fetchone() def get_set_encounters(self, set_id): self.cursor.execute(''' @@ -448,3 +481,9 @@ class DBController: export_conn = sqlite3.connect('pokemon_forms_production.db') self.conn.backup(export_conn) export_conn.close() + + def assign_mark_to_form(self, data): + pfic, mark_id = data + self.cursor.execute('INSERT INTO form_marks (pfic, mark_id) VALUES (?, ?)', (pfic, mark_id)) + self.conn.commit() + diff --git a/DBEditor/pokemon_db_ui.py b/DBEditor/pokemon_db_ui.py index 5247ede..5a93562 100644 --- a/DBEditor/pokemon_db_ui.py +++ b/DBEditor/pokemon_db_ui.py @@ -307,6 +307,10 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget gather_encounters_btn.clicked.connect(self.gather_encounter_info) db_tab_layout.addWidget(gather_encounters_btn) + gather_marks_btn = QPushButton("Gather Marks Information") + gather_marks_btn.clicked.connect(self.gather_marks_info) + db_tab_layout.addWidget(gather_marks_btn) + # Add QTextEdit for progress reporting self.progress_text = QTextEdit() self.progress_text.setReadOnly(True) @@ -848,26 +852,6 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget if hasattr(self, 'current_pfic'): storable_in_home = self.home_checkbox.isChecked() is_baby_form = self.is_baby_form_checkbox.isChecked() - - # Update the in-memory database - #self.cursor.execute(''' - # UPDATE pokemon_storage - # SET storable_in_home = ? - # WHERE PFIC = ? - #''', (storable_in_home, self.current_pfic)) - - #self.cursor.execute(''' - # UPDATE pokemon_forms - # SET is_baby_form = ? - # WHERE PFIC = ? - #''', (is_baby_form, self.current_pfic)) - - #self.conn.commit() - - # Write the in-memory database to disk - #disk_conn = sqlite3.connect('pokemon_forms.db') - #self.conn.backup(disk_conn) - #disk_conn.close() event_system.emit_sync('save_changes') @@ -940,4 +924,5 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget def gather_encounter_info(self): event_system.emit_sync('gather_encounter_info') - + def gather_marks_info(self): + event_system.emit_sync('gather_marks_info') diff --git a/Determining an origin mark.txt b/Determining an origin mark.txt index 4d77257..6b46416 100644 --- a/Determining an origin mark.txt +++ b/Determining an origin mark.txt @@ -3,8 +3,12 @@ To determine an origin mark: 1. If a pokemon form has a previous evolution from within the same generation, use the mark of the previous evolution. This should be recursive within the same generation. 2. If a pokemon form has no previous evolution from within the same generation, - look at the encounters of the pokemon form and use the mark of the earliest game you can encounter that form in. -3. If there are no encounters for the pokemon form, + look at the encounters of the pokemon form from this generation and use the mark of the earliest + game you can encounter that form in from that generation. +3. If there are no encounters for the pokemon form from this generation, + look to see if a previous evolution has an encounter from this generation, and use the mark of the earliest + game from this generation that the previous evolution is encounterable in. +4. If there are no encounters for the pokemon form or its evolution line from this generation, use the mark of the earliest game of the generation is marked as being introducted in. -4. If there is no mark for the earliest game of the generation, +5. If there is no mark for the earliest game of the generation, then it has no origin mark. diff --git a/Site/OriginDex.py b/Site/OriginDex.py index d1fc6bb..a1f415e 100644 --- a/Site/OriginDex.py +++ b/Site/OriginDex.py @@ -13,46 +13,101 @@ def load_pokemon_data(): # First query: Get all Pokémon data cursor.execute(''' - WITH EarliestGamePerPokemon AS ( - SELECT e.pfic, MIN(g.generation) as min_generation, MIN(g.id) as earliest_game_id - FROM encounters e - JOIN games g ON e.game_id = g.id - GROUP BY e.pfic - ) SELECT pf.national_dex, pf.name, pf.form_name, pf.PFIC, pf.generation, - ps.storable_in_home, g.name as earliest_game, - m.icon_path as mark_icon, m.id as mark_id, pf.is_baby_form + ps.storable_in_home FROM pokemon_forms pf JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC - LEFT JOIN EarliestGamePerPokemon eg ON pf.PFIC = eg.pfic - LEFT JOIN games g ON eg.earliest_game_id = g.id - LEFT JOIN mark_game_associations mga ON g.id = mga.game_id - LEFT JOIN marks m ON mga.mark_id = m.id WHERE ps.storable_in_home = 1 ORDER BY pf.PFIC ''') pokemon_data = cursor.fetchall() - # Second query: Get evolution chain with generation info - cursor.execute(''' - WITH RECURSIVE EvolutionChain AS ( - SELECT to_pfic AS PFIC, from_pfic, pf.generation - FROM evolution_chains ec - JOIN pokemon_forms pf ON ec.to_pfic = pf.PFIC - UNION ALL - SELECT ec.to_pfic, e.from_pfic, pf.generation - FROM evolution_chains ec - JOIN EvolutionChain e ON ec.from_pfic = e.PFIC - JOIN pokemon_forms pf ON ec.to_pfic = pf.PFIC - ) - SELECT PFIC, MIN(from_pfic) AS base_pfic, MIN(generation) AS base_generation - FROM EvolutionChain - GROUP BY PFIC - ''') - - evolution_data = {row[0]: (row[1], row[2]) for row in cursor.fetchall()} + # Function to get the origin mark for a Pokémon + def get_origin_mark(pfic, generation): + # Step 1: Check for previous evolution in the same generation + cursor.execute(''' + WITH RECURSIVE EvolutionChain AS ( + SELECT ec.to_pfic, ec.from_pfic, pf_to.generation as to_gen, pf_from.generation as from_gen + FROM evolution_chains ec + JOIN pokemon_forms pf_to ON ec.to_pfic = pf_to.PFIC + JOIN pokemon_forms pf_from ON ec.from_pfic = pf_from.PFIC + WHERE ec.to_pfic = ? AND pf_to.generation = ? + UNION ALL + SELECT ec.to_pfic, ec.from_pfic, pf_to.generation, pf_from.generation + FROM evolution_chains ec + JOIN EvolutionChain e ON ec.to_pfic = e.from_pfic + JOIN pokemon_forms pf_to ON ec.to_pfic = pf_to.PFIC + JOIN pokemon_forms pf_from ON ec.from_pfic = pf_from.PFIC + WHERE pf_to.generation = ? AND pf_from.generation = ? + ) + SELECT from_pfic + FROM EvolutionChain + WHERE from_pfic IS NOT NULL AND from_gen = ? + ORDER BY from_pfic + LIMIT 1 + ''', (pfic, generation, generation, generation, generation)) + base_pfic = cursor.fetchone() + + if base_pfic: + pfic = base_pfic[0] + + # Step 2: Look for the earliest encounter for this form in the current generation + cursor.execute(''' + SELECT g.name, m.icon_path, m.id + FROM encounters e + JOIN games g ON e.game_id = g.id + LEFT JOIN mark_game_associations mga ON g.id = mga.game_id + LEFT JOIN marks m ON mga.mark_id = m.id + WHERE e.pfic = ? AND g.generation = ? + ORDER BY g.id + LIMIT 1 + ''', (pfic, generation)) + encounter_data = cursor.fetchone() + + if encounter_data: + return encounter_data + + # Step 3: Look for encounters of previous evolutions in the current generation + cursor.execute(''' + WITH RECURSIVE EvolutionChain AS ( + SELECT ec.to_pfic, ec.from_pfic + FROM evolution_chains ec + WHERE ec.to_pfic = ? + UNION ALL + SELECT ec.to_pfic, ec.from_pfic + FROM evolution_chains ec + JOIN EvolutionChain e ON ec.to_pfic = e.from_pfic + ) + SELECT g.name, m.icon_path, m.id + FROM EvolutionChain ec + JOIN encounters e ON ec.from_pfic = e.pfic + JOIN games g ON e.game_id = g.id + LEFT JOIN mark_game_associations mga ON g.id = mga.game_id + LEFT JOIN marks m ON mga.mark_id = m.id + WHERE g.generation = ? + ORDER BY g.id + LIMIT 1 + ''', (pfic, generation)) + evolution_encounter_data = cursor.fetchone() + + if evolution_encounter_data: + return evolution_encounter_data + + # Step 4: Use the mark of the earliest game of the generation + cursor.execute(''' + SELECT g.name, m.icon_path, m.id + FROM games g + LEFT JOIN mark_game_associations mga ON g.id = mga.game_id + LEFT JOIN marks m ON mga.mark_id = m.id + WHERE g.generation = ? + ORDER BY g.id + LIMIT 1 + ''', (generation,)) + generation_data = cursor.fetchone() + + return generation_data if generation_data else (None, None, None) # Process the data current_group = [] @@ -61,33 +116,9 @@ def load_pokemon_data(): pokemon_forms = [] for row in pokemon_data: - national_dex, name, form_name, pfic, generation, storable_in_home, earliest_game, mark_icon, mark_id, is_baby_form = row + national_dex, name, form_name, pfic, generation, storable_in_home = row - # Find the base form for the mark, considering generation - base_pfic = pfic - base_generation = generation - while base_pfic in evolution_data: - prev_pfic, prev_generation = evolution_data[base_pfic] - if prev_pfic is not None and prev_generation == base_generation: - base_pfic = prev_pfic - else: - break - - # If the base form is different, we need to fetch its earliest game and mark - if base_pfic != pfic: - cursor.execute(''' - SELECT g.name, m.icon_path, m.id - FROM encounters e - JOIN games g ON e.game_id = g.id - LEFT JOIN mark_game_associations mga ON g.id = mga.game_id - LEFT JOIN marks m ON mga.mark_id = m.id - WHERE e.pfic = ? AND g.generation = ? - ORDER BY g.id - LIMIT 1 - ''', (base_pfic, base_generation)) - base_data = cursor.fetchone() - if base_data: - earliest_game, mark_icon, mark_id = base_data + earliest_game, mark_icon, mark_id = get_origin_mark(pfic, generation) pokemon = { 'pfic': pfic, @@ -102,9 +133,8 @@ def load_pokemon_data(): 'MarkIcon': mark_icon, 'MarkID': mark_id } - - + # Add the Pokémon to the current group if national_dex != current_dex_number: if pokemon_forms: for form in pokemon_forms: diff --git a/pokemon_forms.db b/pokemon_forms.db index fb25e57..cc7f947 100644 Binary files a/pokemon_forms.db and b/pokemon_forms.db differ