update
This commit is contained in:
173
scripts/kampagne.gd
Normal file
173
scripts/kampagne.gd
Normal file
@@ -0,0 +1,173 @@
|
||||
extends Node
|
||||
## Kampagne: eine Seekarte mit Kapitänen. Wen du schlägst, der verschwindet
|
||||
## auf See und kommt nach zwei Partien stärker zurück - höhere Wertung, bessere
|
||||
## Bots, mehr Mannschaft. Du hast eine Wertung (Elo) und daraus einen Rang.
|
||||
## Der Stand liegt in user://kampagne.json.
|
||||
|
||||
const DATEI := "user://kampagne.json"
|
||||
const K := 32.0 ## Elo-Schrittweite
|
||||
const AUF_SEE := 2 ## Partien, bis ein Geschlagener zurück ist
|
||||
const RAENGE := [
|
||||
[0, "Schiffsjunge"], [950, "Matrose"], [1050, "Maat"],
|
||||
[1150, "Steuermann"], [1280, "Kapitän"], [1420, "Admiral"],
|
||||
]
|
||||
## Kapitäne mit Wertung, Bot-Stufe, Mannschaft (weitere Bots eine Stufe
|
||||
## darunter) und Platz auf der Karte (0..1 in Breite und Höhe).
|
||||
const START_KAPITAENE := [
|
||||
{"name": "Roter Jack", "elo": 900, "stufe": 0, "mannschaft": 0, "pos": Vector2(0.14, 0.32)},
|
||||
{"name": "Salz-Marie", "elo": 960, "stufe": 0, "mannschaft": 1, "pos": Vector2(0.33, 0.68)},
|
||||
{"name": "Einauge Bill", "elo": 1030, "stufe": 1, "mannschaft": 1, "pos": Vector2(0.52, 0.24)},
|
||||
{"name": "Käpt'n Grau", "elo": 1110, "stufe": 1, "mannschaft": 2, "pos": Vector2(0.70, 0.62)},
|
||||
{"name": "Die Witwe", "elo": 1210, "stufe": 2, "mannschaft": 2, "pos": Vector2(0.87, 0.30)},
|
||||
{"name": "Admiral Krähe", "elo": 1360, "stufe": 2, "mannschaft": 3, "pos": Vector2(0.50, 0.86)},
|
||||
]
|
||||
|
||||
var datei := DATEI ## Tests schreiben woandershin
|
||||
var elo := 1000.0
|
||||
var partien := 0
|
||||
var siege := 0
|
||||
var kapitaene: Array = [] ## {name, elo, stufe, mannschaft, pos, weg, geschlagen}
|
||||
var aktiv := "" ## Kapitän der laufenden Partie, "" = keine Kampagnenpartie
|
||||
var letztes := "" ## Text zum letzten Ergebnis, fürs Endfeld
|
||||
var zur_karte := false ## nach dem Ende zurück auf die Karte statt ins Hauptmenü
|
||||
var kampagnenpartie := false ## die laufende (oder gerade beendete) Partie gehört zur Kampagne
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
laden()
|
||||
|
||||
|
||||
static func rang(wert: float) -> String:
|
||||
var r := ""
|
||||
for stufe in RAENGE:
|
||||
if wert >= float(stufe[0]):
|
||||
r = String(stufe[1])
|
||||
return r
|
||||
|
||||
|
||||
func mein_rang() -> String:
|
||||
return rang(elo)
|
||||
|
||||
|
||||
func zuruecksetzen() -> void:
|
||||
elo = 1000.0
|
||||
partien = 0
|
||||
siege = 0
|
||||
aktiv = ""
|
||||
letztes = ""
|
||||
kapitaene = []
|
||||
for k in START_KAPITAENE:
|
||||
var e: Dictionary = k.duplicate()
|
||||
e.weg = 0
|
||||
e.geschlagen = 0
|
||||
kapitaene.append(e)
|
||||
|
||||
|
||||
func kapitaen(name: String) -> Dictionary:
|
||||
for k in kapitaene:
|
||||
if k.name == name:
|
||||
return k
|
||||
return {}
|
||||
|
||||
|
||||
## Partie gegen einen Kapitän: er selbst auf seiner Stufe, seine Mannschaft
|
||||
## eine Stufe darunter. Der Spieler sitzt auf Platz 0.
|
||||
func starten(name: String) -> void:
|
||||
var k := kapitaen(name)
|
||||
if k.is_empty() or int(k.weg) > 0:
|
||||
return
|
||||
aktiv = name
|
||||
kampagnenpartie = true
|
||||
var bots: Array = [{"name": name, "stufe": int(k.stufe)}]
|
||||
for i in int(k.mannschaft):
|
||||
bots.append({"name": "Maat %d" % (i + 1), "stufe": maxi(0, int(k.stufe) - 1)})
|
||||
Net.start_singleplayer(Net.player_name, bots.size(), int(k.stufe), 5, bots)
|
||||
|
||||
|
||||
## Wird vom Spiel am Ende gerufen. `ausgeschieden` ist die Reihenfolge der
|
||||
## Plätze, die rausgeflogen sind. Geschlagen ist der Kapitän, wenn er vor dem
|
||||
## Spieler ging - oder der Spieler gewonnen hat.
|
||||
func ergebnis(seats: Array, ausgeschieden: Array) -> void:
|
||||
if aktiv == "":
|
||||
return
|
||||
var k := kapitaen(aktiv)
|
||||
aktiv = ""
|
||||
if k.is_empty():
|
||||
return
|
||||
var spieler := 0
|
||||
var kap := -1
|
||||
for i in seats.size():
|
||||
if String(seats[i].name) == String(k.name):
|
||||
kap = i
|
||||
var sieg: bool
|
||||
if seats[spieler].alive:
|
||||
sieg = true
|
||||
elif kap >= 0 and ausgeschieden.has(kap) and ausgeschieden.has(spieler):
|
||||
sieg = ausgeschieden.find(kap) < ausgeschieden.find(spieler)
|
||||
else:
|
||||
sieg = false
|
||||
|
||||
var erwartet := 1.0 / (1.0 + pow(10.0, (float(k.elo) - elo) / 400.0))
|
||||
var punkte := 1.0 if sieg else 0.0
|
||||
var vorher := elo
|
||||
var delta := K * (punkte - erwartet)
|
||||
elo = maxf(0.0, elo + delta)
|
||||
k.elo = maxf(0.0, float(k.elo) - delta)
|
||||
partien += 1
|
||||
|
||||
# Die anderen auf See rücken einen Schritt näher an die Rückkehr.
|
||||
for o in kapitaene:
|
||||
if o != k and int(o.weg) > 0:
|
||||
o.weg = int(o.weg) - 1
|
||||
if int(o.weg) == 0:
|
||||
_zurueck(o)
|
||||
if sieg:
|
||||
siege += 1
|
||||
k.weg = AUF_SEE
|
||||
k.geschlagen = int(k.geschlagen) + 1
|
||||
letztes = "Sieg gegen %s! %d → %d (%s)" % [k.name, int(round(vorher)), int(round(elo)), mein_rang()]
|
||||
else:
|
||||
letztes = "%s behält die Oberhand. %d → %d (%s)" % [k.name, int(round(vorher)), int(round(elo)), mein_rang()]
|
||||
speichern()
|
||||
|
||||
|
||||
## Zurück von See: besser als vorher. Stufe bis 2, dann wächst die Mannschaft.
|
||||
func _zurueck(k: Dictionary) -> void:
|
||||
k.elo = float(k.elo) + 60.0
|
||||
if int(k.stufe) < 2:
|
||||
k.stufe = int(k.stufe) + 1
|
||||
else:
|
||||
k.mannschaft = mini(4, int(k.mannschaft) + 1)
|
||||
|
||||
|
||||
func speichern() -> void:
|
||||
var daten := {"elo": elo, "partien": partien, "siege": siege, "kapitaene": []}
|
||||
for k in kapitaene:
|
||||
daten.kapitaene.append({"name": k.name, "elo": k.elo, "stufe": k.stufe,
|
||||
"mannschaft": k.mannschaft, "weg": k.weg, "geschlagen": k.geschlagen})
|
||||
var f := FileAccess.open(datei, FileAccess.WRITE)
|
||||
if f != null:
|
||||
f.store_string(JSON.stringify(daten))
|
||||
f.close()
|
||||
|
||||
|
||||
func laden() -> void:
|
||||
zuruecksetzen()
|
||||
if not FileAccess.file_exists(datei):
|
||||
return
|
||||
var text := FileAccess.get_file_as_string(datei)
|
||||
var daten = JSON.parse_string(text)
|
||||
if not (daten is Dictionary):
|
||||
return
|
||||
elo = float(daten.get("elo", 1000.0))
|
||||
partien = int(daten.get("partien", 0))
|
||||
siege = int(daten.get("siege", 0))
|
||||
for d in daten.get("kapitaene", []):
|
||||
var k := kapitaen(String(d.get("name", "")))
|
||||
if k.is_empty():
|
||||
continue
|
||||
k.elo = float(d.get("elo", k.elo))
|
||||
k.stufe = int(d.get("stufe", k.stufe))
|
||||
k.mannschaft = int(d.get("mannschaft", k.mannschaft))
|
||||
k.weg = int(d.get("weg", 0))
|
||||
k.geschlagen = int(d.get("geschlagen", 0))
|
||||
Reference in New Issue
Block a user