Updated game

This commit is contained in:
MeBeBruno committed 2026-08-10 15:57:08 +02:00
1 parent 6a56e5a921
commit f924016478
7 files changed
+167 -52

No files matched your search

+55 -19
View File
@@ -66,7 +66,8 @@ def initialize_database():
killer_identifier TEXT, killer_identifier TEXT,
victim_identifier TEXT, victim_identifier TEXT,
victim_previous_target TEXT, victim_previous_target TEXT,
kill_timestamp TEXT kill_timestamp TEXT,
report_status TEXT DEFAULT 'confirmed'
) )
""") """)
try: try:
@@ -85,6 +86,11 @@ def initialize_database():
connection.execute("ALTER TABLE player ADD COLUMN late_joiner INTEGER DEFAULT 0") connection.execute("ALTER TABLE player ADD COLUMN late_joiner INTEGER DEFAULT 0")
except sqlite3.OperationalError: except sqlite3.OperationalError:
pass 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'") cursor = connection.execute("SELECT configuration_value FROM game_configuration WHERE configuration_key = 'game_status'")
if not cursor.fetchone(): if not cursor.fetchone():
connection.execute("INSERT INTO game_configuration (configuration_key, configuration_value) VALUES ('game_status', 'pending')") 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)) connection.execute("UPDATE player SET target_identifier = ? WHERE player_identifier = ?", (new_target, attacker_identifier))
timestamp = datetime.now(european_timezone).isoformat() 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() 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: if alive_count_record["alive_count"] <= 1:
@@ -260,23 +266,43 @@ def process_administrator_action(action_type, form_data):
connection.commit() connection.commit()
has_game_state_changed = True has_game_state_changed = True
elif action_type == "edit_kill": elif action_type == "delete_report":
kill_identifier = form_data.get("kill_identifier") kill_identifier = form_data.get("kill_identifier")
new_killer_identifier = form_data.get("new_killer_identifier") report = connection.execute("SELECT * FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)).fetchone()
if new_killer_identifier == "":
new_killer_identifier = None
new_timestamp = form_data.get("kill_timestamp")
old_kill = connection.execute("SELECT * FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)).fetchone() if report and report["report_status"] == 'pending':
if old_kill: connection.execute("UPDATE player SET pending_attacker_identifier = NULL WHERE player_identifier = ?", (report["victim_identifier"],))
old_killer_identifier = old_kill["killer_identifier"]
if old_killer_identifier != new_killer_identifier: connection.execute("DELETE FROM kill_log WHERE kill_identifier = ?", (kill_identifier,))
if old_killer_identifier: connection.commit()
connection.execute("UPDATE player SET score = MAX(0, score - 1) WHERE player_identifier = ?", (old_killer_identifier,)) has_game_state_changed = True
if new_killer_identifier:
connection.execute("UPDATE player SET score = score + 1 WHERE player_identifier = ?", (new_killer_identifier,)) 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.execute("UPDATE kill_log SET killer_identifier = ?, kill_timestamp = ? WHERE kill_identifier = ?", (new_killer_identifier, new_timestamp, kill_identifier))
connection.commit() connection.commit()
has_game_state_changed = True has_game_state_changed = True
@@ -284,7 +310,7 @@ def process_administrator_action(action_type, form_data):
kill_identifier = form_data.get("kill_identifier") kill_identifier = form_data.get("kill_identifier")
kill_record = connection.execute("SELECT * FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)).fetchone() 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"]: if kill_record["killer_identifier"]:
connection.execute("UPDATE player SET score = MAX(0, score - 1) WHERE player_identifier = ?", (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: 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("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"] 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: 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() attacker = connection.execute("SELECT target_identifier FROM player WHERE player_identifier = ?", (attacker_identifier,)).fetchone()
if attacker and attacker["target_identifier"]: if attacker and attacker["target_identifier"]:
victim_identifier = 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)) 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() connection.commit()
emit("elimination_verification_requested", to=victim_identifier) emit("elimination_verification_requested", to=victim_identifier)
websocket_manager.emit("admin_state_changed", to="administrator_room")
connection.close() connection.close()
@websocket_manager.on("confirm_elimination") @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)) connection.execute("UPDATE player SET target_identifier = ?, score = score + 1 WHERE player_identifier = ?", (new_target, attacker_identifier))
timestamp = datetime.now(european_timezone).isoformat() 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() 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: if alive_count_record["alive_count"] <= 1:
@@ -614,6 +647,7 @@ def handle_elimination_confirmation():
connection.commit() connection.commit()
websocket_manager.emit("game_state_changed") websocket_manager.emit("game_state_changed")
websocket_manager.emit("admin_state_changed", to="administrator_room")
connection.close() connection.close()
@websocket_manager.on("reject_elimination") @websocket_manager.on("reject_elimination")
@@ -626,8 +660,10 @@ def handle_elimination_rejection():
if victim and victim["pending_attacker_identifier"]: if victim and victim["pending_attacker_identifier"]:
attacker_identifier = 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 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() connection.commit()
emit("elimination_rejected", to=attacker_identifier) emit("elimination_rejected", to=attacker_identifier)
websocket_manager.emit("admin_state_changed", to="administrator_room")
connection.close() connection.close()
if __name__ == "__main__": if __name__ == "__main__":
+69
View File
@@ -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()
Binary file not shown.
-5
View File
@@ -304,10 +304,6 @@ document.addEventListener("DOMContentLoaded", function() {
}); });
websocket_connection.on("elimination_verification_requested", 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) fetch(window.location.href)
.then(function(network_response) { return network_response.text(); }) .then(function(network_response) { return network_response.text(); })
.then(function(markup_text) { .then(function(markup_text) {
@@ -317,7 +313,6 @@ document.addEventListener("DOMContentLoaded", function() {
new_modal_element.classList.add("active-modal"); new_modal_element.classList.add("active-modal");
} }
}); });
}
}); });
websocket_connection.on("elimination_rejected", function() { websocket_connection.on("elimination_rejected", function() {
+3 -3
View File
@@ -39,6 +39,9 @@
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
--lightness-primary: 0.65;
--chroma-primary: 0.20;
--lightness-background: 0.2; --lightness-background: 0.2;
--chroma-background: 0.02; --chroma-background: 0.02;
@@ -47,9 +50,6 @@
--lightness-text: 0.90; --lightness-text: 0.90;
--chroma-text: 0.02; --chroma-text: 0.02;
--lightness-primary: 0.65;
--chroma-primary: 0.20;
} }
} }
+39 -24
View File
@@ -37,7 +37,7 @@
<div class="tab-container"> <div class="tab-container">
<button class="tab-button active-tab" data-target="control-panel"><i data-lucide="sliders"></i> Steuerung</button> <button class="tab-button active-tab" data-target="control-panel"><i data-lucide="sliders"></i> Steuerung</button>
<button class="tab-button" data-target="player-panel"><i data-lucide="users"></i> Spieler</button> <button class="tab-button" data-target="player-panel"><i data-lucide="users"></i> Spieler</button>
<button class="tab-button" data-target="kill-panel"><i data-lucide="skull"></i> Kills</button> <button class="tab-button" data-target="kill-panel"><i data-lucide="message-square"></i> Meldungen</button>
</div> </div>
<div id="control-panel" class="tab-content active-content"> <div id="control-panel" class="tab-content active-content">
@@ -270,43 +270,58 @@
<th>Zeitpunkt</th> <th>Zeitpunkt</th>
<th>Killer</th> <th>Killer</th>
<th>Opfer</th> <th>Opfer</th>
<th>Status</th>
<th>Aktionen</th> <th>Aktionen</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for kill in kill_logs %} {% for report in kill_logs %}
<tr> <tr>
<td>{{ report.kill_timestamp[:16].replace('T', ' ') if report.kill_timestamp else '-' }}</td>
<td>{{ report.killer_name or 'Unbekannt' }} ({{ report.killer_identifier }})</td>
<td>{{ report.victim_name or 'Unbekannt' }} ({{ report.victim_identifier }})</td>
<td> <td>
{% if report.report_status == 'confirmed' %}
<span class="status-pill success-pill" style="margin-left: 0;">Bestätigt</span>
{% elif report.report_status == 'pending' %}
<span class="status-pill warning-pill" style="margin-left: 0;">Ausstehend</span>
{% elif report.report_status == 'rejected' %}
<span class="status-pill danger-pill" style="margin-left: 0;">Abgelehnt</span>
{% elif report.report_status == 'revoked' %}
<span class="status-pill danger-pill" style="margin-left: 0;">Widerrufen</span>
{% else %}
{{ report.report_status }}
{% endif %}
</td>
<td>
{% if report.report_status == 'confirmed' %}
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form"> <form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form">
<input type="hidden" name="action_type" value="edit_kill">
<input type="hidden" name="kill_id" value="{{ kill.kill_id }}">
<input type="datetime-local" name="kill_timestamp" value="{{ kill.kill_timestamp[:16] if kill.kill_timestamp else '' }}" class="text-input small-input" required>
</td>
<td>
<select name="new_killer_identifier" class="text-input small-input">
<option value="">Keiner (Admin)</option>
{% for p in all_players %}
<option value="{{ p.player_identifier }}" {% if p.player_identifier == kill.killer_identifier %}selected{% endif %}>{{ p.display_name }} ({{ p.player_identifier }})</option>
{% endfor %}
</select>
</td>
<td>
{{ kill.victim_name or 'Unbekannt' }} ({{ kill.victim_identifier }})
</td>
<td>
<button type="submit" class="action-button primary-button small-button" title="Speichern"><i data-lucide="save"></i></button>
</form>
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form" style="margin-top: var(--spacing-small);">
<input type="hidden" name="action_type" value="revoke_kill"> <input type="hidden" name="action_type" value="revoke_kill">
<input type="hidden" name="kill_id" value="{{ kill.kill_id }}"> <input type="hidden" name="kill_identifier" value="{{ report.kill_identifier }}">
<button type="submit" class="action-button danger-button small-button"><i data-lucide="rotate-ccw"></i> Rückgängig</button> <button type="submit" class="action-button danger-button small-button"><i data-lucide="rotate-ccw"></i> Rückgängig</button>
</form> </form>
{% endif %}
{% if report.report_status == 'pending' %}
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form">
<input type="hidden" name="action_type" value="force_confirm_report">
<input type="hidden" name="kill_identifier" value="{{ report.kill_identifier }}">
<button type="submit" class="action-button success-button small-button"><i data-lucide="check"></i> Bestätigen</button>
</form>
{% endif %}
{% if report.report_status in ['pending', 'rejected', 'revoked'] %}
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form" style="margin-top: var(--spacing-small);">
<input type="hidden" name="action_type" value="delete_report">
<input type="hidden" name="kill_identifier" value="{{ report.kill_identifier }}">
<button type="submit" class="action-button secondary-button small-button"><i data-lucide="trash-2"></i> Löschen</button>
</form>
{% endif %}
</td> </td>
</tr> </tr>
{% else %} {% else %}
<tr> <tr>
<td colspan="4" style="text-align: center; opacity: 0.6;">Bisher keine Kills im System.</td> <td colspan="5" style="text-align: center; opacity: 0.6;">Bisher keine Meldungen im System.</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
+1 -1
View File
@@ -55,7 +55,7 @@
<form action="{{ url_for('handle_login') }}" method="POST" class="input-form"> <form action="{{ url_for('handle_login') }}" method="POST" class="input-form">
<div class="form-group"> <div class="form-group">
<label for="player_identifier" class="input-label">ID</label> <label for="player_identifier" class="input-label">ID</label>
<input type="text" id="player_identifier" name="player_identifier" class="text-input" pattern="[A-Za-z]{{ '{' }}{{ identifier_length }}{{ '}' }}" required> <input type="text" id="player_identifier" name="player_identifier" class="text-input" style="text-transform: uppercase;" maxlength="{{ identifier_length }}" oninput="this.value = this.value.replace(/[^a-zA-Z]/g, '').toUpperCase().slice(0, {{ identifier_length }});" pattern="[A-Za-z]{{ '{' }}{{ identifier_length }}{{ '}' }}" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="password_string" class="input-label">Passwort</label> <label for="password_string" class="input-label">Passwort</label>