diff --git a/application.py b/application.py index f7e78f1..54f296a 100644 --- a/application.py +++ b/application.py @@ -66,7 +66,8 @@ def initialize_database(): killer_identifier TEXT, victim_identifier TEXT, victim_previous_target TEXT, - kill_timestamp TEXT + kill_timestamp TEXT, + report_status TEXT DEFAULT 'confirmed' ) """) try: @@ -85,6 +86,11 @@ def initialize_database(): connection.execute("ALTER TABLE player ADD COLUMN late_joiner INTEGER DEFAULT 0") except sqlite3.OperationalError: pass + try: + connection.execute("ALTER TABLE kill_log ADD COLUMN report_status TEXT DEFAULT 'confirmed'") + except sqlite3.OperationalError: + pass + cursor = connection.execute("SELECT configuration_value FROM game_configuration WHERE configuration_key = 'game_status'") if not cursor.fetchone(): connection.execute("INSERT INTO game_configuration (configuration_key, configuration_value) VALUES ('game_status', 'pending')") @@ -246,7 +252,7 @@ def process_administrator_action(action_type, form_data): connection.execute("UPDATE player SET target_identifier = ? WHERE player_identifier = ?", (new_target, attacker_identifier)) timestamp = datetime.now(european_timezone).isoformat() - connection.execute("INSERT INTO kill_log (killer_identifier, victim_identifier, victim_previous_target, kill_timestamp) VALUES (?, ?, ?, ?)", (attacker_identifier, target_identifier, new_target, timestamp)) + connection.execute("INSERT INTO kill_log (killer_identifier, victim_identifier, victim_previous_target, kill_timestamp, report_status) VALUES (?, ?, ?, ?, 'confirmed')", (attacker_identifier, target_identifier, new_target, timestamp)) alive_count_record = connection.execute("SELECT COUNT(*) as alive_count FROM player WHERE is_alive = 1 AND is_approved = 1").fetchone() if alive_count_record["alive_count"] <= 1: @@ -259,32 +265,52 @@ def process_administrator_action(action_type, form_data): connection.commit() has_game_state_changed = True - - elif action_type == "edit_kill": + + elif action_type == "delete_report": kill_identifier = form_data.get("kill_identifier") - new_killer_identifier = form_data.get("new_killer_identifier") - if new_killer_identifier == "": - new_killer_identifier = None - new_timestamp = form_data.get("kill_timestamp") + report = connection.execute("SELECT * FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)).fetchone() - old_kill = connection.execute("SELECT * FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)).fetchone() - if old_kill: - old_killer_identifier = old_kill["killer_identifier"] - if old_killer_identifier != new_killer_identifier: - if old_killer_identifier: - connection.execute("UPDATE player SET score = MAX(0, score - 1) WHERE player_identifier = ?", (old_killer_identifier,)) - if new_killer_identifier: - connection.execute("UPDATE player SET score = score + 1 WHERE player_identifier = ?", (new_killer_identifier,)) - - connection.execute("UPDATE kill_log SET killer_identifier = ?, kill_timestamp = ? WHERE kill_identifier = ?", (new_killer_identifier, new_timestamp, kill_identifier)) - connection.commit() - has_game_state_changed = True + if report and report["report_status"] == 'pending': + connection.execute("UPDATE player SET pending_attacker_identifier = NULL WHERE player_identifier = ?", (report["victim_identifier"],)) + + connection.execute("DELETE FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)) + connection.commit() + has_game_state_changed = True + + elif action_type == "force_confirm_report": + kill_identifier = form_data.get("kill_identifier") + report = connection.execute("SELECT * FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)).fetchone() + + if report and report["report_status"] == 'pending': + attacker_identifier = report["killer_identifier"] + victim_identifier = report["victim_identifier"] + victim = connection.execute("SELECT target_identifier, is_alive FROM player WHERE player_identifier = ?", (victim_identifier,)).fetchone() + if victim and victim["is_alive"] == 1: + new_target = victim["target_identifier"] + connection.execute("UPDATE player SET is_alive = 0, target_identifier = NULL, pending_attacker_identifier = NULL WHERE player_identifier = ?", (victim_identifier,)) + connection.execute("UPDATE player SET target_identifier = ?, score = score + 1 WHERE player_identifier = ?", (new_target, attacker_identifier)) + + timestamp = datetime.now(european_timezone).isoformat() + connection.execute("UPDATE kill_log SET report_status = 'confirmed', kill_timestamp = ? WHERE kill_identifier = ?", (timestamp, kill_identifier)) + + alive_count_record = connection.execute("SELECT COUNT(*) as alive_count FROM player WHERE is_alive = 1 AND is_approved = 1").fetchone() + if alive_count_record["alive_count"] <= 1: + status_record = connection.execute("SELECT configuration_value FROM game_configuration WHERE configuration_key = 'game_status'").fetchone() + current_status = status_record["configuration_value"] if status_record else "unknown" + connection.execute("UPDATE game_configuration SET configuration_value = 'finished' WHERE configuration_key = 'game_status'") + + if alive_count_record["alive_count"] == 1 and current_status != 'finished': + connection.execute("UPDATE player SET score = score + 3 WHERE is_alive = 1 AND is_approved = 1") + + connection.commit() + has_game_state_changed = True + elif action_type == "revoke_kill": kill_identifier = form_data.get("kill_identifier") kill_record = connection.execute("SELECT * FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)).fetchone() - if kill_record: + if kill_record and kill_record["report_status"] == 'confirmed': if kill_record["killer_identifier"]: connection.execute("UPDATE player SET score = MAX(0, score - 1) WHERE player_identifier = ?", (kill_record["killer_identifier"],)) @@ -297,7 +323,7 @@ def process_administrator_action(action_type, form_data): if player_pointing_to_target: connection.execute("UPDATE player SET target_identifier = ? WHERE player_identifier = ?", (victim_identifier, player_pointing_to_target["player_identifier"])) - connection.execute("DELETE FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)) + connection.execute("UPDATE kill_log SET report_status = 'revoked' WHERE kill_identifier = ?", (kill_identifier,)) alive_count = connection.execute("SELECT COUNT(*) as alive_count FROM player WHERE is_alive = 1 AND is_approved = 1").fetchone()["alive_count"] if alive_count > 1: @@ -581,9 +607,16 @@ def handle_elimination_request(): attacker = connection.execute("SELECT target_identifier FROM player WHERE player_identifier = ?", (attacker_identifier,)).fetchone() if attacker and attacker["target_identifier"]: victim_identifier = attacker["target_identifier"] + victim = connection.execute("SELECT target_identifier FROM player WHERE player_identifier = ?", (victim_identifier,)).fetchone() + connection.execute("UPDATE player SET pending_attacker_identifier = ? WHERE player_identifier = ?", (attacker_identifier, victim_identifier)) + + timestamp = datetime.now(european_timezone).isoformat() + connection.execute("INSERT INTO kill_log (killer_identifier, victim_identifier, victim_previous_target, kill_timestamp, report_status) VALUES (?, ?, ?, ?, 'pending')", (attacker_identifier, victim_identifier, victim["target_identifier"], timestamp)) + connection.commit() emit("elimination_verification_requested", to=victim_identifier) + websocket_manager.emit("admin_state_changed", to="administrator_room") connection.close() @websocket_manager.on("confirm_elimination") @@ -601,7 +634,7 @@ def handle_elimination_confirmation(): connection.execute("UPDATE player SET target_identifier = ?, score = score + 1 WHERE player_identifier = ?", (new_target, attacker_identifier)) timestamp = datetime.now(european_timezone).isoformat() - connection.execute("INSERT INTO kill_log (killer_identifier, victim_identifier, victim_previous_target, kill_timestamp) VALUES (?, ?, ?, ?)", (attacker_identifier, victim_identifier, new_target, timestamp)) + connection.execute("UPDATE kill_log SET report_status = 'confirmed', kill_timestamp = ? WHERE killer_identifier = ? AND victim_identifier = ? AND report_status = 'pending'", (timestamp, attacker_identifier, victim_identifier)) alive_count_record = connection.execute("SELECT COUNT(*) as alive_count FROM player WHERE is_alive = 1 AND is_approved = 1").fetchone() if alive_count_record["alive_count"] <= 1: @@ -614,6 +647,7 @@ def handle_elimination_confirmation(): connection.commit() websocket_manager.emit("game_state_changed") + websocket_manager.emit("admin_state_changed", to="administrator_room") connection.close() @websocket_manager.on("reject_elimination") @@ -626,8 +660,10 @@ def handle_elimination_rejection(): if victim and victim["pending_attacker_identifier"]: attacker_identifier = victim["pending_attacker_identifier"] connection.execute("UPDATE player SET pending_attacker_identifier = NULL WHERE player_identifier = ?", (victim_identifier,)) + connection.execute("UPDATE kill_log SET report_status = 'rejected' WHERE killer_identifier = ? AND victim_identifier = ? AND report_status = 'pending'", (attacker_identifier, victim_identifier)) connection.commit() emit("elimination_rejected", to=attacker_identifier) + websocket_manager.emit("admin_state_changed", to="administrator_room") connection.close() if __name__ == "__main__": diff --git a/execute_identifier_update.py b/execute_identifier_update.py new file mode 100644 index 0000000..5de20c9 --- /dev/null +++ b/execute_identifier_update.py @@ -0,0 +1,69 @@ +import sqlite3 +import pathlib + +database_file_path = "game_database.sqlite" + +def execute_identifier_update(): + if not pathlib.Path(database_file_path).exists(): + print(f"Fehler: Die Datenbankdatei '{database_file_path}' wurde nicht gefunden.") + raise SystemExit(1) + + old_player_identifier = input("Bitte gib die aktuelle ID ein: ").strip().upper() + new_player_identifier = input("Bitte gib die neue gewünschte ID ein: ").strip().upper() + + if not old_player_identifier or not new_player_identifier: + print("Fehler: Beide IDs müssen eingegeben werden.") + raise SystemExit(1) + + if old_player_identifier == new_player_identifier: + print("Die neue ID ist identisch mit der alten.") + raise SystemExit(0) + + database_connection = sqlite3.connect(database_file_path) + database_connection.isolation_level = None + database_cursor = database_connection.cursor() + + try: + database_cursor.execute("BEGIN TRANSACTION;") + + database_cursor.execute("SELECT display_name FROM player WHERE player_identifier = ?", (old_player_identifier,)) + player_record = database_cursor.fetchone() + + if not player_record: + print(f"Fehler: Es wurde kein Spieler mit der ID '{old_player_identifier}' gefunden.") + database_cursor.execute("ROLLBACK TRANSACTION;") + raise SystemExit(1) + + database_cursor.execute("SELECT display_name FROM player WHERE player_identifier = ?", (new_player_identifier,)) + existing_player_record = database_cursor.fetchone() + + if existing_player_record: + print(f"Fehler: Die ID '{new_player_identifier}' wird bereits von einem anderen Spieler verwendet.") + database_cursor.execute("ROLLBACK TRANSACTION;") + raise SystemExit(1) + + player_name = player_record[0] + print(f"\nÄndere ID für Spieler '{player_name}' von '{old_player_identifier}' zu '{new_player_identifier}'...") + + database_cursor.execute("UPDATE player SET player_identifier = ? WHERE player_identifier = ?", (new_player_identifier, old_player_identifier)) + + database_cursor.execute("UPDATE player SET target_identifier = ? WHERE target_identifier = ?", (new_player_identifier, old_player_identifier)) + database_cursor.execute("UPDATE player SET pending_attacker_identifier = ? WHERE pending_attacker_identifier = ?", (new_player_identifier, old_player_identifier)) + + database_cursor.execute("UPDATE kill_log SET killer_identifier = ? WHERE killer_identifier = ?", (new_player_identifier, old_player_identifier)) + database_cursor.execute("UPDATE kill_log SET victim_identifier = ? WHERE victim_identifier = ?", (new_player_identifier, old_player_identifier)) + database_cursor.execute("UPDATE kill_log SET victim_previous_target = ? WHERE victim_previous_target = ?", (new_player_identifier, old_player_identifier)) + + database_cursor.execute("COMMIT TRANSACTION;") + print("\nErfolg! Die ID wurde überall in der Datenbank geaendert.") + + except sqlite3.Error as database_error: + database_cursor.execute("ROLLBACK TRANSACTION;") + print(f"\nEin Datenbankfehler ist aufgetreten: {database_error}") + raise SystemExit(1) + + finally: + database_connection.close() + +if __name__ == "__main__": + execute_identifier_update() \ No newline at end of file diff --git a/game_database.sqlite b/game_database.sqlite new file mode 100644 index 0000000..baf8ef2 Binary files /dev/null and b/game_database.sqlite differ diff --git a/static/behavior.js b/static/behavior.js index 36ccec9..6c63521 100644 --- a/static/behavior.js +++ b/static/behavior.js @@ -304,20 +304,15 @@ document.addEventListener("DOMContentLoaded", function() { }); websocket_connection.on("elimination_verification_requested", function() { - const modal_element = document.getElementById("verification-modal"); - if (modal_element) { - modal_element.classList.add("active-modal"); - } else { - fetch(window.location.href) - .then(function(network_response) { return network_response.text(); }) - .then(function(markup_text) { - replace_main_content(markup_text); - const new_modal_element = document.getElementById("verification-modal"); - if (new_modal_element) { - new_modal_element.classList.add("active-modal"); - } - }); - } + fetch(window.location.href) + .then(function(network_response) { return network_response.text(); }) + .then(function(markup_text) { + replace_main_content(markup_text); + const new_modal_element = document.getElementById("verification-modal"); + if (new_modal_element) { + new_modal_element.classList.add("active-modal"); + } + }); }); websocket_connection.on("elimination_rejected", function() { diff --git a/static/stylesheet.css b/static/stylesheet.css index e66e0df..1003c6a 100644 --- a/static/stylesheet.css +++ b/static/stylesheet.css @@ -39,6 +39,9 @@ @media (prefers-color-scheme: dark) { :root { + --lightness-primary: 0.65; + --chroma-primary: 0.20; + --lightness-background: 0.2; --chroma-background: 0.02; @@ -47,9 +50,6 @@ --lightness-text: 0.90; --chroma-text: 0.02; - - --lightness-primary: 0.65; - --chroma-primary: 0.20; } } diff --git a/templates/administrator.html b/templates/administrator.html index a6a9006..88f9c3f 100644 --- a/templates/administrator.html +++ b/templates/administrator.html @@ -37,7 +37,7 @@