M3: Balance, Kartenprops, sieben Volksrepräsentanten und Abnahme

Bots planen Items/Champions vor der Armee und helfen deterministisch,
damit Spiegelmatches fair bleiben. Boss und Profile neu abgestimmt;
Balance-, Stress- und Volks-Werkzeuge sowie Kartenprops ergänzt.
This commit is contained in:
Martin Stickelbroeck 2026-09-28 00:41:05 +02:00
parent d7c3a03e23
commit faf0fbdef0
120 changed files with 16699 additions and 106 deletions

View file

@ -0,0 +1,248 @@
"""Map dressing for Champions of Luneraria: river bridge, curb stone, trees, rocks, banner
and edge cliffs, exported as separate named meshes in one GLB. Godot instances them with
MultiMeshes. Stone, bark and leaves use ENV_* names so the Kluft shaders (with wind on
foliage) apply at runtime.
Run: ALSOFT_DRIVERS=null blender -b --python-exit-code 1 --python assets-source/luneraria/build_map_props.py
Godot frame per prop: y up, prop origin at ground level; the bridge spans local +x.
"""
from pathlib import Path
import bpy, bmesh, json, hashlib, struct
from math import sin, cos, pi
from mathutils import Vector, noise
P = Path(__file__).resolve().parents[2]
SRC = Path(__file__).resolve().parent
OUT = P / 'assets/luneraria'
bpy.ops.wm.read_factory_settings(use_empty=True)
bpy.context.preferences.filepaths.save_version = 0
def G(x, y, z):
return Vector((x, -z, y))
def material(name, color, rough=.9, metal=0.0, emission=0.0):
m = bpy.data.materials.new(name)
m.diffuse_color = (*color, 1)
m.use_nodes = True
bs = m.node_tree.nodes.get('Principled BSDF')
bs.inputs['Base Color'].default_value = (*color, 1)
bs.inputs['Roughness'].default_value = rough
bs.inputs['Metallic'].default_value = metal
if emission:
bs.inputs['Emission Color'].default_value = (*color, 1)
bs.inputs['Emission Strength'].default_value = emission
return m
M = {
'limestone': material('ENV_limestone', (.283, .246, .178)),
'paving': material('ENV_paving', (.19, .185, .15), .92),
'cliff': material('ENV_cliff', (.133, .153, .138)),
'bark': material('ENV_bark', (.087, .056, .032), .93),
'leaf_dark': material('ENV_leaf_dark', (.031, .07, .04), .89),
'leaf_mid': material('ENV_leaf_mid', (.084, .144, .054), .85),
'leaf_light': material('ENV_leaf_light', (.258, .305, .091), .79),
'soil': material('ENV_soil', (.10, .15, .065), .97),
'brass': material('ENV_brass', (.515, .366, .153), .45, .7),
'cloth': material('PR_Banner', (.9, .9, .9), .8),
}
groups = {}
def add(group, name, vs, fs, kind, smooth=False):
me = bpy.data.meshes.new(name)
me.from_pydata([tuple(v) for v in vs], [], fs)
me.update()
me.materials.append(M[kind])
for p in me.polygons:
p.use_smooth = smooth
ob = bpy.data.objects.new(name, me)
bpy.context.collection.objects.link(ob)
groups.setdefault(group, []).append(ob)
return ob
def box(group, name, c, size, kind, yaw=0.0):
cx, cy, cz = c
hx, hy, hz = size[0] / 2, size[1] / 2, size[2] / 2
vs = []
for dy in (-1, 1):
for dz in (-1, 1):
for dx in (-1, 1):
x, z = dx * hx, dz * hz
vs.append(G(cx + x * cos(yaw) - z * sin(yaw), cy + dy * hy, cz + x * sin(yaw) + z * cos(yaw)))
return add(group, name, vs, [(0, 1, 3, 2), (4, 6, 7, 5), (0, 4, 5, 1), (2, 3, 7, 6), (0, 2, 6, 4), (1, 5, 7, 3)], kind)
def lathe(group, name, profile, sides, kind, c=(0, 0, 0), jitter=0.0, seed=0.0, smooth=False):
cx, cy, cz = c
vs, fs = [], []
for r, y in profile:
for k in range(sides):
a = 2 * pi * k / sides
rr = r * (1 + jitter * noise.noise(Vector((cos(a) * 2, y * 1.3, sin(a) * 2 + seed))))
vs.append(G(cx + cos(a) * rr, cy + y, cz + sin(a) * rr))
n = len(profile)
for j in range(n - 1):
for k in range(sides):
a, b = j * sides + k, j * sides + (k + 1) % sides
fs.append((a, b, b + sides, a + sides))
fs += [tuple(reversed(range(sides))), tuple(range((n - 1) * sides, n * sides))]
return add(group, name, vs, fs, kind, smooth)
def blob(group, name, c, size, kind, seed, subdiv=2, amp=.3, floor=None, smooth=False):
bm = bmesh.new()
bmesh.ops.create_icosphere(bm, subdivisions=subdiv, radius=1.0)
cc = G(*c)
for v in bm.verts:
d = v.co.normalized()
r = 1 + amp * noise.noise(d * 1.7 + Vector((seed, seed * .7, seed * .3)))
gx, gy, gz = d.x * r * size[0], d.z * r * size[1], -d.y * r * size[2]
if floor is not None and gy < floor * size[1]:
gy = floor * size[1]
v.co = cc + Vector((gx, -gz, gy))
me = bpy.data.meshes.new(name)
bm.to_mesh(me)
bm.free()
me.materials.append(M[kind])
for p in me.polygons:
p.use_smooth = smooth
ob = bpy.data.objects.new(name, me)
bpy.context.collection.objects.link(ob)
groups.setdefault(group, []).append(ob)
return ob
def tube(group, name, points, radii, kind, sides=8, steps=10, seed=0.0, gnarl=0.0):
pts = [G(*p) for p in points]
vs, fs = [], []
for j in range(steps + 1):
t = j / steps
seg = min(len(pts) - 2, int(t * (len(pts) - 1)))
u = t * (len(pts) - 1) - seg
p = pts[seg].lerp(pts[seg + 1], u)
tangent = (pts[seg + 1] - pts[seg]).normalized()
ref = Vector((0, 0, 1)) if abs(tangent.z) < .9 else Vector((1, 0, 0))
a1 = tangent.cross(ref).normalized()
a2 = tangent.cross(a1)
rs = min(len(radii) - 2, int(t * (len(radii) - 1)))
ru = t * (len(radii) - 1) - rs
radius = radii[rs] * (1 - ru) + radii[rs + 1] * ru
for k in range(sides):
ang = 2 * pi * k / sides
w = 1 + gnarl * noise.noise(Vector((cos(ang), t * 5, sin(ang) + seed)))
vs.append(p + (a1 * cos(ang) + a2 * sin(ang)) * radius * w)
for j in range(steps):
for k in range(sides):
a, b = j * sides + k, j * sides + (k + 1) % sides
fs.append((a, b, b + sides, a + sides))
fs += [tuple(reversed(range(sides))), tuple(range(steps * sides, (steps + 1) * sides))]
return add(group, name, vs, fs, kind, True)
# ---------------------------------------------------------------- bridge (spans local x, 11 m long, 7 m wide)
# The simulation is flat: the deck sits at ground level so units walk on it, not inside it.
L, Wd = 11.0, 7.0
for i in range(12):
x = -L / 2 + (i + .5) * L / 12
box('Bridge', 'Deck_%d' % i, (x, .05, 0), (L / 12 + .02, .1, Wd), 'paving')
for s_ in (-1, 1):
box('Bridge', 'Parapet_%d_%d' % (i, s_), (x, .42, s_ * (Wd / 2 - .22)), (L / 12 + .03, .62, .38), 'limestone')
for x in (-L / 2 + .4, -1.8, 1.8, L / 2 - .4):
for s_ in (-1, 1):
lathe('Bridge', 'Post_%d_%d' % (int(x * 10), s_), [(.32, 0), (.32, 1.05), (.26, 1.15), (.2, 1.3)], 6, 'limestone', (x, 0, s_ * (Wd / 2 - .22)))
lathe('Bridge', 'Cap_%d_%d' % (int(x * 10), s_), [(.22, 0), (.22, .1), (.14, .16)], 6, 'brass', (x, 1.3, s_ * (Wd / 2 - .22)))
for x in (-2.6, 2.6):
for s_ in (-1, 1):
box('Bridge', 'Pier_%d_%d' % (int(x), s_), (x, -.6, s_ * (Wd / 2 + .15)), (1.1, 1.4, .5), 'limestone')
# ---------------------------------------------------------------- curb stone (placed along lane edges)
box('Curb', 'Curb', (0, .12, 0), (1.3, .26, .42), 'limestone')
# ---------------------------------------------------------------- trees
for v, (h, seed) in enumerate([(3.8, 1.0), (4.6, 2.0), (3.2, 3.0)]):
group = 'Pine_%d' % v
tube(group, 'Trunk', [(0, 0, 0), (0, h * .55, 0), (0, h, 0)], [.24, .17, .08], 'bark', 8, 6, seed, .1)
for k in range(5):
y = h * (.28 + k * .15)
r = (1.35 - k * .22) * (1 + .08 * v)
lathe(group, 'Cone_%d' % k, [(r, y), (r * .75, y + .35), (.05, y + h * .26)], 9, ('leaf_dark', 'leaf_mid')[k % 2], (0, 0, 0), .12, seed + k)
for v, (h, seed) in enumerate([(3.4, 4.0), (4.0, 5.0), (2.8, 6.0)]):
group = 'Oak_%d' % v
tube(group, 'Trunk', [(0, 0, 0), (.15, h * .5, .05), (-.1, h * .85, 0)], [.34, .24, .15], 'bark', 9, 8, seed, .15)
for k in range(3):
ang = k * 2.1 + seed
tube(group, 'Branch_%d' % k, [(0, h * .55, 0), (cos(ang) * .9, h * .78, sin(ang) * .9)], [.13, .06], 'bark', 6, 4, seed + k, .1)
for k in range(9):
ang = k * 2.4 + seed
rr = .55 + .5 * ((k * .618) % 1.0)
s = .95 - .2 * ((k * .37) % 1.0)
blob(group, 'Leaves_%d' % k, (cos(ang) * rr, h * .88 + .5 * ((k * .53) % 1.0), sin(ang) * rr), (s, s * .78, s),
('leaf_mid', 'leaf_light', 'leaf_dark')[k % 3], seed * 10 + k, 2, .28)
for k in range(4):
ang = k * 1.57 + seed
tube(group, 'Root_%d' % k, [(0, .25, 0), (cos(ang) * .7, .05, sin(ang) * .7)], [.14, .05], 'bark', 6, 4, seed + k)
# ---------------------------------------------------------------- rocks and shrubs
for v, (size, seed) in enumerate([((1.2, .8, 1.0), 7.0), ((1.8, 1.1, 1.3), 8.0), ((.8, .5, .7), 9.0)]):
group = 'Rock_%d' % v
blob(group, 'Rock', (0, size[1] * .3, 0), size, 'cliff', seed, 2, .34, -.35)
blob(group, 'Moss', (size[0] * .15, size[1] * .82, 0), (size[0] * .55, size[1] * .25, size[2] * .5), 'leaf_dark', seed + 1, 1, .3, -.2)
for k in range(2):
blob(group, 'Pebble_%d' % k, (size[0] * (.9 + .3 * k), .1, size[2] * (.5 - k)), (.28, .18, .24), 'limestone', seed + 3 + k, 1, .3, -.3)
for v in range(2):
blob('Shrub_%d' % v, 'Shrub', (0, .3, 0), (.8 + .3 * v, .55, .7 + .2 * v), ('leaf_mid', 'leaf_dark')[v], 11 + v, 2, .35, -.3)
# ---------------------------------------------------------------- banner (team colour at runtime via PR_Banner)
lathe('Banner', 'Pole', [(.07, 0), (.07, 4.2), (.1, 4.3), (.02, 4.5)], 6, 'brass')
vs, fs = [], []
for j in range(6):
for i in range(4):
x = .08 + i * .35
y = 4.1 - j * .45
z = .08 * sin(i * 1.3 + j * .6)
vs.append(G(x, y - (.25 * (i / 3) if j == 5 else 0), z))
for j in range(5):
for i in range(3):
a = j * 4 + i
fs.append((a, a + 1, a + 5, a + 4))
add('Banner', 'Cloth', vs, fs, 'cloth', True)
# ---------------------------------------------------------------- edge cliffs (a 12 m wall segment, local x)
for i in range(7):
x = -6 + i * 2
h = 3.4 + 1.6 * noise.noise(Vector((i * .7, 3.1, 0)))
blob('EdgeCliff', 'Block_%d' % i, (x, h * .45, 0), (1.6, h * .6, 1.8), 'cliff', 20 + i, 2, .3, -.5)
blob('EdgeCliff', 'Grass_%d' % i, (x, h * .85, -.3), (1.2, .35, 1.3), 'leaf_mid', 30 + i, 1, .3, -.2)
# Join each group into one mesh object per prop and triangulate.
exported = []
for group, objects in groups.items():
bpy.ops.object.select_all(action='DESELECT')
for ob in objects:
ob.select_set(True)
bpy.context.view_layer.objects.active = objects[0]
bpy.ops.object.join()
joined = bpy.context.object
joined.name = group
bm = bmesh.new()
bm.from_mesh(joined.data)
bmesh.ops.triangulate(bm, faces=list(bm.faces))
bm.to_mesh(joined.data)
bm.free()
exported.append(joined)
bpy.ops.object.select_all(action='DESELECT')
for ob in exported:
ob.select_set(True)
bpy.ops.wm.save_as_mainfile(filepath=str(SRC / 'map_props.blend'))
bpy.ops.export_scene.gltf(filepath=str(OUT / 'map_props.glb'), export_format='GLB', use_selection=True,
export_materials='EXPORT', export_yup=True, export_animations=False)
raw = (OUT / 'map_props.glb').read_bytes()
doc = json.loads(raw[20:20 + struct.unpack_from('<I', raw, 12)[0]])
counts = {m['name']: sum(doc['accessors'][q['indices']]['count'] // 3 for q in m['primitives']) for m in doc['meshes']}
(OUT / 'map_props_manifest.json').write_text(json.dumps({'assets': [{'id': 'map_props', 'resource_path': 'res://assets/luneraria/map_props.glb',
'source': 'assets-source/luneraria/map_props.blend', 'props': counts, 'sha256': hashlib.sha256(raw).hexdigest()}]}, indent=2) + '\n')
print('MAP_PROPS_BUILD', counts, flush=True)

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -0,0 +1,245 @@
{
"figures": [
{
"id": "p_mensch",
"source_parts": 84,
"exported_clips": [
"ability",
"attack_a",
"attack_b",
"death",
"hit",
"idle",
"start",
"stop",
"walk"
],
"skins": 1,
"materials": [
"LP_Mensch_Cloth",
"LP_Mensch_Skin",
"LP_Mensch_Metal",
"LP_Mensch_TrimMetal",
"LP_Mensch_Leather",
"LP_Mensch_Dark",
"LP_Mensch_ClothAccent"
],
"max_wrist_contact_error_m": 0.0,
"worst_sample": [
"walk",
1.1,
"R"
],
"samples": 696,
"contact_validation": "Analytic two-bone arm IK against the grip bones, baked at 30 Hz for all nine clips."
},
{
"id": "p_elf",
"source_parts": 89,
"exported_clips": [
"ability",
"attack_a",
"attack_b",
"death",
"hit",
"idle",
"start",
"stop",
"walk"
],
"skins": 1,
"materials": [
"LP_Elf_Leather",
"LP_Elf_Skin",
"LP_Elf_Cloth",
"LP_Elf_ClothAccent",
"LP_Elf_TrimMetal",
"LP_Elf_Dark",
"LP_Elf_Hair",
"LP_Elf_Glow",
"LP_Elf_Wood"
],
"max_wrist_contact_error_m": 0.0,
"worst_sample": [
"walk",
1.1,
"R"
],
"samples": 696,
"contact_validation": "Analytic two-bone arm IK against the grip bones, baked at 30 Hz for all nine clips."
},
{
"id": "p_zwerg",
"source_parts": 91,
"exported_clips": [
"ability",
"attack_a",
"attack_b",
"death",
"hit",
"idle",
"start",
"stop",
"walk"
],
"skins": 1,
"materials": [
"LP_Zwerg_Cloth",
"LP_Zwerg_Skin",
"LP_Zwerg_Leather",
"LP_Zwerg_Metal",
"LP_Zwerg_TrimMetal",
"LP_Zwerg_Dark",
"LP_Zwerg_Hair",
"LP_Zwerg_Bone",
"LP_Zwerg_Wood",
"LP_Zwerg_Glow"
],
"max_wrist_contact_error_m": 0.0,
"worst_sample": [
"walk",
1.1,
"R"
],
"samples": 696,
"contact_validation": "Analytic two-bone arm IK against the grip bones, baked at 30 Hz for all nine clips."
},
{
"id": "p_troll",
"source_parts": 72,
"exported_clips": [
"ability",
"attack_a",
"attack_b",
"death",
"hit",
"idle",
"start",
"stop",
"walk"
],
"skins": 1,
"materials": [
"LP_Troll_Skin",
"LP_Troll_Leather",
"LP_Troll_Bone",
"LP_Troll_Stone",
"LP_Troll_EyeGlow",
"LP_Troll_Hair",
"LP_Troll_Wood"
],
"max_wrist_contact_error_m": 0.06613055871718698,
"worst_sample": [
"ability",
1.1,
"L"
],
"samples": 696,
"contact_validation": "Analytic two-bone arm IK against the grip bones, baked at 30 Hz for all nine clips."
},
{
"id": "p_fee",
"source_parts": 72,
"exported_clips": [
"ability",
"attack_a",
"attack_b",
"death",
"hit",
"idle",
"start",
"stop",
"walk"
],
"skins": 1,
"materials": [
"LP_Fee_ClothAccent",
"LP_Fee_Skin",
"LP_Fee_Cloth",
"LP_Fee_TrimMetal",
"LP_Fee_Dark",
"LP_Fee_Hair",
"LP_Fee_Glow",
"LP_Fee_Wood"
],
"max_wrist_contact_error_m": 0.0,
"worst_sample": [
"walk",
1.1,
"R"
],
"samples": 696,
"contact_validation": "Analytic two-bone arm IK against the grip bones, baked at 30 Hz for all nine clips."
},
{
"id": "p_ork",
"source_parts": 84,
"exported_clips": [
"ability",
"attack_a",
"attack_b",
"death",
"hit",
"idle",
"start",
"stop",
"walk"
],
"skins": 1,
"materials": [
"LP_Ork_Skin",
"LP_Ork_Leather",
"LP_Ork_Metal",
"LP_Ork_TrimMetal",
"LP_Ork_Bone",
"LP_Ork_Fur",
"LP_Ork_Dark",
"LP_Ork_Hair",
"LP_Ork_Wood"
],
"max_wrist_contact_error_m": 0.0,
"worst_sample": [
"walk",
1.1,
"R"
],
"samples": 696,
"contact_validation": "Analytic two-bone arm IK against the grip bones, baked at 30 Hz for all nine clips."
},
{
"id": "p_biest",
"source_parts": 82,
"exported_clips": [
"ability",
"attack_a",
"attack_b",
"death",
"hit",
"idle",
"start",
"stop",
"walk"
],
"skins": 1,
"materials": [
"LP_Biest_Fur",
"LP_Biest_FurLight",
"LP_Biest_Leather",
"LP_Biest_Metal",
"LP_Biest_Cloth",
"LP_Biest_Bone",
"LP_Biest_Dark",
"LP_Biest_EyeGlow",
"LP_Biest_Skin"
],
"max_wrist_contact_error_m": 0.0,
"worst_sample": [
"walk",
1.1,
"R"
],
"samples": 696,
"contact_validation": "Analytic two-bone arm IK against the grip bones, baked at 30 Hz for all nine clips."
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://bdygvqh1lru4a"
path="res://.godot/imported/map_props.glb-ee8d7dcb8819cf2777bc63c68f327e1d.scn"
[deps]
source_file="res://assets/luneraria/map_props.glb"
dest_files=["res://.godot/imported/map_props.glb-ee8d7dcb8819cf2777bc63c68f327e1d.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

View file

@ -0,0 +1,27 @@
{
"assets": [
{
"id": "map_props",
"resource_path": "res://assets/luneraria/map_props.glb",
"source": "assets-source/luneraria/map_props.blend",
"props": {
"Pole": 74,
"Deck_0": 1088,
"Curb": 12,
"Block_0": 700,
"Trunk.003": 1270,
"Trunk.004": 1270,
"Trunk.005": 1270,
"Trunk": 358,
"Trunk.001": 358,
"Trunk.002": 358,
"Rock": 140,
"Rock.001": 140,
"Rock.002": 140,
"Shrub": 80,
"Shrub.001": 80
},
"sha256": "d997546df3d537dae03ff5d8925f0af9457c3cc5ee63b6f20018baa994e8ff9d"
}
]
}

Binary file not shown.

View file

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://vlty7tphfgnx"
path="res://.godot/imported/p_biest.glb-8e5e6e1fa11c916fb2bef94a33cda329.scn"
[deps]
source_file="res://assets/luneraria/peoples/p_biest.glb"
dest_files=["res://.godot/imported/p_biest.glb-8e5e6e1fa11c916fb2bef94a33cda329.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

Binary file not shown.

View file

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://pw4ristm1wtt"
path="res://.godot/imported/p_elf.glb-d890d18acc6c79e79d4b8598982a53f2.scn"
[deps]
source_file="res://assets/luneraria/peoples/p_elf.glb"
dest_files=["res://.godot/imported/p_elf.glb-d890d18acc6c79e79d4b8598982a53f2.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

Binary file not shown.

View file

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://biourdwo5b8lq"
path="res://.godot/imported/p_fee.glb-84ebd920f33b8ac4eaaa887665f7685d.scn"
[deps]
source_file="res://assets/luneraria/peoples/p_fee.glb"
dest_files=["res://.godot/imported/p_fee.glb-84ebd920f33b8ac4eaaa887665f7685d.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

Binary file not shown.

View file

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://irnp3eyfc180"
path="res://.godot/imported/p_mensch.glb-39d67a910d0ef6afd640de8d0f7f2922.scn"
[deps]
source_file="res://assets/luneraria/peoples/p_mensch.glb"
dest_files=["res://.godot/imported/p_mensch.glb-39d67a910d0ef6afd640de8d0f7f2922.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

Binary file not shown.

View file

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://ch346bo30gv7u"
path="res://.godot/imported/p_ork.glb-2fc1770fe3cbd6425271bd6ed96455c7.scn"
[deps]
source_file="res://assets/luneraria/peoples/p_ork.glb"
dest_files=["res://.godot/imported/p_ork.glb-2fc1770fe3cbd6425271bd6ed96455c7.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

Binary file not shown.

View file

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://cgmg6jsstbn0w"
path="res://.godot/imported/p_troll.glb-1e8b28d4cdbb22a6f14981dad1c5577b.scn"
[deps]
source_file="res://assets/luneraria/peoples/p_troll.glb"
dest_files=["res://.godot/imported/p_troll.glb-1e8b28d4cdbb22a6f14981dad1c5577b.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

Binary file not shown.

View file

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://cl7r1ec10jtmg"
path="res://.godot/imported/p_zwerg.glb-e90f71dd7991679fd78ec39f4df7c5be.scn"
[deps]
source_file="res://assets/luneraria/peoples/p_zwerg.glb"
dest_files=["res://.godot/imported/p_zwerg.glb-e90f71dd7991679fd78ec39f4df7c5be.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

View file

@ -0,0 +1,333 @@
{
"assets": [
{
"id": "p_mensch",
"name": "Ritter",
"people": "Menschen",
"klasse": "Ritter",
"rolle": "front",
"resource_path": "res://assets/luneraria/peoples/p_mensch.glb",
"triangles": 17480,
"mesh_parts": 1,
"parts": [
"MenschBody"
],
"skeletal": true,
"bones": 22,
"clips": [
"idle",
"start",
"walk",
"stop",
"attack_a",
"attack_b",
"hit",
"ability",
"death"
],
"attack_cycle": [
"attack_a",
"attack_b",
"attack_a",
"ability"
],
"contact_seconds": 0.9,
"bounds_godot": {
"min": [
-0.40699902176856995,
-0.01069701835513115,
-0.27477124333381653
],
"max": [
0.42016029357910156,
1.9657350778579712,
0.6130658388137817
]
},
"sha256": "218b6d020a0d70e6693e6b61c9eb2d3090e8365b23afe675268a9d0084bacd73",
"source": "assets-source/luneraria/peoples/p_mensch.blend"
},
{
"id": "p_elf",
"name": "Waldl\u00e4uferin",
"people": "Elfen",
"klasse": "Waldl\u00e4uferin",
"rolle": "ranged",
"resource_path": "res://assets/luneraria/peoples/p_elf.glb",
"triangles": 18502,
"mesh_parts": 1,
"parts": [
"ElfBody"
],
"skeletal": true,
"bones": 24,
"clips": [
"idle",
"start",
"walk",
"stop",
"attack_a",
"attack_b",
"hit",
"ability",
"death"
],
"attack_cycle": [
"attack_a",
"attack_b",
"attack_a",
"ability"
],
"contact_seconds": 0.9,
"bounds_godot": {
"min": [
-0.274183988571167,
0.00043252474279142916,
-0.5287083387374878
],
"max": [
0.29548221826553345,
2.230403423309326,
1.1226369142532349
]
},
"sha256": "9c155a1cf3868185cbabdc4ee26fd23e53006d4a093c2f2d623eb42317da02a6",
"source": "assets-source/luneraria/peoples/p_elf.blend"
},
{
"id": "p_zwerg",
"name": "Schildtr\u00e4ger",
"people": "Zwerge",
"klasse": "Schildtr\u00e4ger",
"rolle": "front",
"resource_path": "res://assets/luneraria/peoples/p_zwerg.glb",
"triangles": 20214,
"mesh_parts": 1,
"parts": [
"ZwergBody"
],
"skeletal": true,
"bones": 22,
"clips": [
"idle",
"start",
"walk",
"stop",
"attack_a",
"attack_b",
"hit",
"ability",
"death"
],
"attack_cycle": [
"attack_a",
"attack_b",
"attack_a",
"ability"
],
"contact_seconds": 0.9,
"bounds_godot": {
"min": [
-0.3604458272457123,
-0.018512045964598656,
-0.17344079911708832
],
"max": [
0.4053660035133362,
1.3439915180206299,
0.4210769236087799
]
},
"sha256": "bb6706d13f8cf28d3142a919f66d69192167577d769a5de781a4ee7ac0b42559",
"source": "assets-source/luneraria/peoples/p_zwerg.blend"
},
{
"id": "p_troll",
"name": "Steinhauer",
"people": "Trolle",
"klasse": "Steinhauer",
"rolle": "splash",
"resource_path": "res://assets/luneraria/peoples/p_troll.glb",
"triangles": 14686,
"mesh_parts": 1,
"parts": [
"TrollBody"
],
"skeletal": true,
"bones": 22,
"clips": [
"idle",
"start",
"walk",
"stop",
"attack_a",
"attack_b",
"hit",
"ability",
"death"
],
"attack_cycle": [
"attack_a",
"attack_b",
"attack_a",
"ability"
],
"contact_seconds": 0.9,
"bounds_godot": {
"min": [
-0.5339592695236206,
-0.03151940554380417,
-0.2999359965324402
],
"max": [
0.49503999948501587,
2.198559045791626,
1.255454421043396
]
},
"sha256": "1c250068745bd7305569fd7b4db2848b86fea486dc5af139798939141597c259",
"source": "assets-source/luneraria/peoples/p_troll.blend"
},
{
"id": "p_fee",
"name": "Lichtheilerin",
"people": "Feen",
"klasse": "Lichtheilerin",
"rolle": "support",
"resource_path": "res://assets/luneraria/peoples/p_fee.glb",
"triangles": 16744,
"mesh_parts": 1,
"parts": [
"FeeBody"
],
"skeletal": true,
"bones": 24,
"clips": [
"idle",
"start",
"walk",
"stop",
"attack_a",
"attack_b",
"hit",
"ability",
"death"
],
"attack_cycle": [
"attack_a",
"attack_b",
"attack_a",
"ability"
],
"contact_seconds": 0.9,
"bounds_godot": {
"min": [
-0.35030224919319153,
0.31140172481536865,
-0.1565617471933365
],
"max": [
0.35030224919319153,
1.6979674100875854,
0.2717953622341156
]
},
"sha256": "f084d1f922d1a19d421b38e8ed68e944582dd0a1c4768e310773eca084f3b236",
"source": "assets-source/luneraria/peoples/p_fee.blend"
},
{
"id": "p_ork",
"name": "Kriegsh\u00e4uptling",
"people": "Orks",
"klasse": "Kriegsh\u00e4uptling",
"rolle": "melee",
"resource_path": "res://assets/luneraria/peoples/p_ork.glb",
"triangles": 15890,
"mesh_parts": 1,
"parts": [
"OrkBody"
],
"skeletal": true,
"bones": 22,
"clips": [
"idle",
"start",
"walk",
"stop",
"attack_a",
"attack_b",
"hit",
"ability",
"death"
],
"attack_cycle": [
"attack_a",
"attack_b",
"attack_a",
"ability"
],
"contact_seconds": 0.9,
"bounds_godot": {
"min": [
-0.5301840901374817,
-0.0254998579621315,
-0.18939527869224548
],
"max": [
0.5364153385162354,
2.0665111541748047,
0.760603666305542
]
},
"sha256": "6d9552f8c4e5fdfbba2a9a933a861c4a59b7dc3ab406e7070a7e2553e7b39bff",
"source": "assets-source/luneraria/peoples/p_ork.blend"
},
{
"id": "p_biest",
"name": "Klauenj\u00e4ger",
"people": "Biestmenschen",
"klasse": "Klauenj\u00e4ger",
"rolle": "melee",
"resource_path": "res://assets/luneraria/peoples/p_biest.glb",
"triangles": 16858,
"mesh_parts": 1,
"parts": [
"BiestBody"
],
"skeletal": true,
"bones": 24,
"clips": [
"idle",
"start",
"walk",
"stop",
"attack_a",
"attack_b",
"hit",
"ability",
"death"
],
"attack_cycle": [
"attack_a",
"attack_b",
"attack_a",
"ability"
],
"contact_seconds": 0.9,
"bounds_godot": {
"min": [
-0.4814721643924713,
0.009468089789152145,
-0.5130493640899658
],
"max": [
0.4814721643924713,
2.072967052459717,
0.6682941913604736
]
},
"sha256": "d990197e3030d34455f8ad070a1f047cccea03d1dcccc81950a4b4b692a5f2d1",
"source": "assets-source/luneraria/peoples/p_biest.blend"
}
]
}

View file

@ -36,9 +36,16 @@ Voraussetzung ist Godot 4.7.2. Blender wird nur zum Neuerzeugen von Assets gebra
## Prüfungen
```bash
godot --headless --path . res://tests/luneraria/test_lune_core.tscn # Regeln (M1: 91)
godot --path . --resolution 1920x1080 res://tools/luneraria/verify_m1.tscn # echte Bedienung, volle Partie
godot --headless --path . res://tests/luneraria/test_lune_core.tscn # Regeln M1 (91, inkl. Spiegeltest)
godot --headless --path . res://tests/luneraria/test_lune_m2.tscn # Regeln M2 (73)
godot --path . --resolution 1280x720 res://tools/luneraria/verify_m1.tscn # echte Bedienung, volle Partie (38)
godot --path . --resolution 1920x1080 res://tools/luneraria/verify_m2.tscn # Helden, Items, Grotte, Boss (15)
godot --headless --path . res://tools/luneraria/sim_match.tscn -- --seeds=1,2,3 --limit=80
godot --headless --path . res://tools/luneraria/balance_run.tscn -- --compositions=20 --limit=60 --out=res://docs/luneraria/logs/m3/balance.json
godot --headless --path . res://tools/luneraria/balance_run.tscn -- --matchups --limit=60 --out=res://docs/luneraria/logs/m3/matchups.json
python3 tools/luneraria/analyze_balance.py docs/luneraria/logs/m3/balance.json
godot --headless --path . res://tools/luneraria/stress_run.tscn # Wellen bis 10^6, Langlauf
godot --path . res://tools/luneraria/people_lineup.tscn -- --out=res://docs/luneraria/screenshots
godot --path . --resolution 1920x1080 res://tools/luneraria/lune_benchmark.tscn
godot --path . --resolution 1920x1080 res://tools/luneraria/lune_review.tscn # Aufnahmen
# Legacy (Saumwacht) unverändert:
@ -48,10 +55,15 @@ godot --headless --path . -- --faction-test
godot --headless --path . -- --expedition-test
```
`verify_m1` und `verify_m2` brauchen ein Fenster (echte Maus-/Tastaturereignisse), nicht `--headless`.
## Assets neu erzeugen
```bash
ALSOFT_DRIVERS=null blender -b --python-exit-code 1 --python assets-source/luneraria/build_tower.py
ALSOFT_DRIVERS=null blender -b --python-exit-code 1 --python assets-source/luneraria/build_grotto.py
ALSOFT_DRIVERS=null blender -b --python-exit-code 1 --python assets-source/luneraria/build_map_props.py
ALSOFT_DRIVERS=null blender -b --python-exit-code 1 --python assets-source/luneraria/build_peoples.py
python3 tools/luneraria/build_asset_matrix.py
godot --headless --editor --import --path .
```

View file

@ -24,3 +24,4 @@ Stand: 27. September 2026 (M0).
5. **Oberfläche** in `scripts/luneraria/ui/` mit dem gemeinsamen `SaumwachtTheme` und seinen Bauteilen. Titel und Menü werden auf Champions of Luneraria umgestellt. Die Eingabeabschirmung aus 20A bleibt.
6. **Benutzereinstellungen:** Der Projektname wird zu „Champions of Luneraria“, dadurch ändert sich der `user://`-Pfad. `Preferences` übernimmt beim ersten Start einmalig die alte `preferences.cfg` aus „Saumwacht · Glutpakt“ und protokolliert das. Fehlt sie, gelten die Standardwerte.
7. **Tests:** Neue Tests liegen unter `tests/luneraria/` und `tools/luneraria/`, die Legacy-Tests bleiben unverändert und werden als „Legacy“ geführt. Neue Referenzen werden erst nach fachlicher Prüfung festgeschrieben.
8. **M3-Nachtrag:** Bots planen Items/Champions vor der Armee und helfen deterministisch (kein geteilter `rng`), damit Spiegelmatches bit-symmetrisch bleiben. Kartenprops stammen aus `map_props.glb` (MultiMesh, ENV_*-Kluftshader). Volksrepräsentanten `p_*` sind Asset- und Datenziele ohne Matcheinbindung; siehe [VOELKER.md](VOELKER.md). Balance- und Stresswerkzeuge liegen unter `tools/luneraria/`.

View file

@ -1,6 +1,6 @@
# Asset-Wiederverwendungsmatrix
Erzeugt mit `python3 tools/luneraria/build_asset_matrix.py` aus den Laufzeitmanifesten. „Volk/Bund“ ist die Datenzuordnung. Die sieben Zielvölker (Menschen, Elfen, Zwerge, Trolle, Feen, Orks, Biestmenschen) haben noch **keine eigenen Modelle**; bestehende Wesen bleiben als eigene Bünde Teil der Welt. Als „vorläufig“ markierte Rollen sind Zuordnungen vorhandener Modelle, keine neu erstellten Völker.
Erzeugt mit `python3 tools/luneraria/build_asset_matrix.py` aus den Laufzeitmanifesten. „Volk/Bund“ ist die Datenzuordnung. Die sieben Zielvölker haben ab M3 **eigene Repräsentantenmodelle** (`p_*`); sie sind noch nicht als spielbare Fraktionen eingebunden. Bestehende Wesen bleiben als eigene Bünde Teil der Welt. Als „vorläufig“ markierte Rollen sind Zuordnungen vorhandener Modelle, keine neu erstellten Völker.
| ID | Name | Pfad | Quelle | Rig / Clips | Dreiecke | bisherige Rolle | neue Rolle | Volk / Bund | Materialzustand | Eingriff |
| --- | --- | --- | --- | --- | ---: | --- | --- | --- | --- | --- |
@ -63,10 +63,18 @@ Erzeugt mit `python3 tools/luneraria/build_asset_matrix.py` aus den Laufzeitmani
| w09 | Tauhüter | res://assets/models/unit_w09.glb | assets-source/phase4/blend/w09.blend | starre Gelenkgruppen | 52040 | Wurzelbund Heiler | Truppe Unterstützung | Wurzelwesen / Wurzelbund | HD, starre Teile | keiner |
| w10 | Quellgeflecht | res://assets/characters/quellgeflecht.glb | assets-source/phase16/quellgeflecht.blend | 17 Knochen · 9 Clips | 14276 | Wurzelbund Heiler+ | Truppenaufwertung; zusätzlich Held „Quellgeflecht“ (vorläufig) | Wurzelwesen / Wurzelbund | gewichtetes Skelett (phase16) | umgesetzt (M2) |
| worker | Funkenleser | res://assets/characters/arbeiter.glb | assets-source/phase12/arbeiter.blend | 27 Knochen · 10 Clips | 7184 | Arbeiter/Funken | nicht im neuen Modus (Arbeitsannahme E); Modell bleibt erhalten | — | gewichtetes Skelett (phase12) | keiner |
| p_biest | Klauenjäger | res://assets/luneraria/peoples/p_biest.glb | assets-source/luneraria/peoples/p_biest.blend | 24 Knochen · 9 Clips | 16858 | — | Volksrepräsentant Nahkampf (Klauenjäger) | Biestmenschen | gewichtetes Skelett (peoples, LP_*-Materialien) | neu (M3) |
| p_elf | Waldläuferin | res://assets/luneraria/peoples/p_elf.glb | assets-source/luneraria/peoples/p_elf.blend | 24 Knochen · 9 Clips | 18502 | — | Volksrepräsentant Fernkampf (Waldläuferin) | Elfen | gewichtetes Skelett (peoples, LP_*-Materialien) | neu (M3) |
| p_fee | Lichtheilerin | res://assets/luneraria/peoples/p_fee.glb | assets-source/luneraria/peoples/p_fee.blend | 24 Knochen · 9 Clips | 16744 | — | Volksrepräsentant Unterstützung (Lichtheilerin) | Feen | gewichtetes Skelett (peoples, LP_*-Materialien) | neu (M3) |
| p_mensch | Ritter | res://assets/luneraria/peoples/p_mensch.glb | assets-source/luneraria/peoples/p_mensch.blend | 22 Knochen · 9 Clips | 17480 | — | Volksrepräsentant Front (Ritter) | Menschen | gewichtetes Skelett (peoples, LP_*-Materialien) | neu (M3) |
| p_ork | Kriegshäuptling | res://assets/luneraria/peoples/p_ork.glb | assets-source/luneraria/peoples/p_ork.blend | 22 Knochen · 9 Clips | 15890 | — | Volksrepräsentant Nahkampf (Kriegshäuptling) | Orks | gewichtetes Skelett (peoples, LP_*-Materialien) | neu (M3) |
| p_troll | Steinhauer | res://assets/luneraria/peoples/p_troll.glb | assets-source/luneraria/peoples/p_troll.blend | 22 Knochen · 9 Clips | 14686 | — | Volksrepräsentant Fläche (Steinhauer) | Trolle | gewichtetes Skelett (peoples, LP_*-Materialien) | neu (M3) |
| p_zwerg | Schildträger | res://assets/luneraria/peoples/p_zwerg.glb | assets-source/luneraria/peoples/p_zwerg.blend | 22 Knochen · 9 Clips | 20214 | — | Volksrepräsentant Front (Schildträger) | Zwerge | gewichtetes Skelett (peoples, LP_*-Materialien) | neu (M3) |
| menu-stage | Menü-Diorama | res://assets/environment/menu-stage.glb | assets-source/phase20/build_menu_stage.py | statisch | 48660 | Hauptmenü Phase 20A | Hauptmenü (Titel angepasst) | — | Kluft-Shader | keiner |
| verdant-rift | Grüne Kluft (2-Bretter-Arena) | res://assets/environment/verdant-rift.glb | assets-source/phase10/verdant-rift.blend | statisch | — | Spielfeld Saumwacht | Legacy-Modus; Materialien/Shader für die neue Karte wiederverwendet | — | triplanare Kluft-Shader | keine neue Nutzung als Karte |
| compare-rock / compare-tree | Fels, Baum | res://assets/compare/ | assets-source/phase14/build_compare_props.py | statisch | 360 / 852 | Vergleichsszene | Kartendekoration Dschungel | — | einfach | keiner |
| lane_tower | Laneturm | res://assets/luneraria/tower.glb | assets-source/luneraria/build_tower.py | statisch | 648 | — | 16 Lanetürme und Basistürme, Kristall zur Laufzeit in Teamfarbe | — | ENV_*-Kluftshader, Kristall emissiv | neu (M1) |
| boss_grotto | Bossgrotte | res://assets/luneraria/grotto.glb | assets-source/luneraria/build_grotto.py | statisch | 1888 | — | Felsinsel mit Höhle auf der Symmetrieachse, zwei gespiegelte Zugänge | — | ENV_*-Kluftshader, violette Kristalle | neu (M2) |
| map_props | Kartenprops (Bäume, Felsen, Büsche, Brücken, Bordsteine, Klippen, Banner) | res://assets/luneraria/map_props.glb | assets-source/luneraria/build_map_props.py | statisch | MultiMesh | — | 3D-Kartendekoration der drei Lanes, Brücken über die Kluft, Klampterrahmen | — | ENV_*-Kluftshader | neu (M3) |
| luneraria-emblem | Emblem Luneraria | res://assets/ui/emblems/luneraria.svg | SVG | — | — | — | Titel und Menü | — | Vektor | neu (M1) |
| Emblem/Theme | Saumwacht-Theme | scripts/ui/theme/, assets/ui/ | Code / SVG | — | — | Menü 20A | Theme weiterverwendet, Titel/Emblem Luneraria | — | Vektor | Titelschrift/Emblem ergänzen |
| compare-rock / compare-tree | Fels, Baum (Alt) | res://assets/compare/ | assets-source/phase14/build_compare_props.py | statisch | 360 / 852 | Vergleichsszene | ab M3 durch map_props ersetzt | — | einfach | abgelöst (M3) |

View file

@ -71,3 +71,49 @@ Identischer Stand nach Runde 7, danach vier Runden mit gewöhnlichen Bots ohne B
- Eine erfolgreiche Eroberung zieht die Mid-Lane so weit ab, dass Blau dort beide Türme verliert. Der Boss richtet danach 20.000–33.000 HP Gebäudeschaden an, stirbt und bringt Rot 1.060 Gold.
- Überinvestition kippt die Partie in beiden Seeds zu Rot, und auch die normale Eroberung verliert bei Seed 7.
- Die Bossstrategie ist damit riskant und nicht dominant. Nach diesen Stichproben wiegt der Boss die geschwächte Lane eher zu wenig auf: ein Balancepunkt für M3 (z. B. mehr Bosswirkung oder schwächerer Grottenboss). Es gibt weder eine kostenlose Sofortrückkehr noch eine Doppelbelohnung (Tests); das Goldrisiko steht im Kopfgeld offen angekündigt.
## M3 · Qualität und Balance
### Geänderte Werte und Bot-Regeln
| Thema | Vorher | Nachher | Begründung |
| --- | --- | --- | --- |
| Keilbrecher Belagerungsfaktor | ×2,5 | ×1,8 | Belagerungs-Champion dominierte Gebäude zu stark. |
| Grottenboss HP | 4.200 | 3.600 | Expeditionen scheiterten zu oft vor Runde 8. |
| Entsandter Boss | 5.200 HP / 70 Schaden | 6.800 HP / 88 Schaden | Die Belohnung wiegt die geschwächte Lane nun besser auf. |
| Bot Item-/Championkauf | nach der Armee | **vor** der Armee (Reserve 110 bzw. 40 Gold) | Die Roster-Schleife verzehrte die gesamte Reserve; Helden blieben ohne Items, Champions wurden nie gebucht (`test_lune_m2` bots_m2). |
| Bot Lane-Hilfe | geteilter Zufall (`rng`) | deterministisch `(Runde + Laneindex) % Periode` | Der geteilte Zufall brach die Spiegelsymmetrie (`test_lune_core` mirror_fairness). |
| Bossjagd-Schwelle | Lanchester 2,0 | 1,35 (+1,25 je Fehlversuch) | Frühere Versuche erst ab Runde 8; Ziel: sinnvolle Risikoabschätzung. |
| Expeditionstärke | 6 Truppen + Held | 5 Truppen + Held | Weniger Lane-Abzug bei der Jagd. |
| Ausgewogen-Held | ab Runde 3 | ab Runde 4 | Reines „ausgewogen“ schlug in Spiegel-Duellen alle Spezialprofile. |
| Verteidigung | kein Champion, 40 % Front | Champion Schutz, 15 % Lane-Hilfe | Reines Verteidigen gewann zu selten (14 %). |
### Bot-Serie (20 Zusammensetzungen × Seitentausch, [balance-step4.json](logs/m3/balance-step4.json))
- 40 Partien, alle regulär durch Ancient-Fall nach 9–14 Wellen (Median 11). Kein Testlimit, kein Zeitfenster-Kampf.
- **Seitentausch 20/20:** dieselbe Zusammensetzung gewinnt beide Male. Keine Seitenbevorzugung.
- Profile (Siege/Einsätze): verteidigung 64 %, ausgewogen 58 %, fernkampf 54 %, druck 53 %, teamhilfe 46 %, bossjagd 24 %.
- Bünde: Glutpakt 55 % / Wurzelbund 45 %.
- Boss: 20 Erfolge, 8 Entsendungen. Heldenstufe am Ende (Median) 4.
### Reine Profil-Duelle ([matchups-step4.json](logs/m3/matchups-step4.json))
15 Paare × 2 Seiten = 30 Partien. Seitentausch 15/15 konsistent.
| Profil | Siege | Duellkette |
| --- | ---: | --- |
| ausgewogen | 10/10 | schlägt alle Spezialprofile |
| verteidigung | 8/10 | verliert nur gegen ausgewogen |
| teamhilfe | 6/10 | schlägt druck, fernkampf, bossjagd |
| fernkampf | 4/10 | schlägt druck, bossjagd |
| druck | 2/10 | schlägt bossjagd |
| bossjagd | 0/10 | verliert gegen jedes Spezialprofil |
**Befund:** In reinen 3-gleichen Spiegeln ergibt sich eine lineare Kette, kein Zyklus. In gemischten Sechser-Aufstellungen (die eigentliche Partie) liegen alle Profile im Band 24–64 %. Kleine Botstichproben beweisen keine ausgewogene Spielerfahrung; menschliche Spieltests bleiben offen. Bossjagd ist als reines Teamprofil schwach, in Mischteams aber spielbar (24 %).
### Belastungstests ([stress.json](logs/m3/stress.json))
- 17/17 Prüfungen, keine Fehler.
- Wellenindizes 10², 10³, 10⁴, 10⁶ enden regulär über Kernfall; Monster-HP endlich (bei 10⁶ ≈ 7,2·10¹¹), kein NaN, kein Arrayfehler, mobile Einheiten gedeckelt (120).
- Langlauf 200 Runden: „Testlimit erreicht / Partie nicht abgeschlossen“ (korrekt, kein Unentschieden). Objektzahl stabil (1706 → 1853), Speicher 52 → 53 MB. Rundenzeit 1,05 s → 2,01 s (wachsende Wellenmenge, kein Leck).

View file

@ -21,6 +21,19 @@ Legende: ✅ automatisiert geprüft · 👁 in echten Aufnahmen visuell geprüft
| 11 | Bots ohne Sonderressourcen und ohne Sicht auf private Befehle | ✅ Bots nutzen dieselben Befehle ohne Sondergold; sie lesen nur den eigenen Entwurf, veröffentlichte Gebäudestände, den öffentlichen Bosszustand und Ankündigungen (Code-Durchsicht, `LuneBot`) | `test_lune_core` · commands; `test_lune_m2` · bots_m2 |
| 12 | Netzwerk: doppelte, veraltete und fremde Befehle; synchroner Phasenwechsel, Disconnect | ⏳ M4 | — |
## M3 · Qualität und Balance
| Nachweis | Stand | Beleg |
| --- | --- | --- |
| Mehrere Seeds und gemischte Teamzusammensetzungen, Seitentausch | ✅ 20 Zusammensetzungen × 2 Seiten, 20/20 konsistent | `balance_run` · `logs/m3/balance-step4.json` |
| Gegenstrategien / Profil-Duelle | ✅ 15 Paare, 15/15 Seitenfair; lineare Kette (Befund) | `balance_run --matchups` · `matchups-step4.json` |
| Hohe Wellenindizes und Langlauf | ✅ 10²–10⁶ ohne Fehler; 200 Runden = Testlimit, keine Objektflut | `stress_run` · `logs/m3/stress.json` |
| Bot kauft Items und Angriffschampions | ✅ Regression `test_lune_m2` bots_m2 (war 0 Buchungen) | `test_lune_m2` 73/73 |
| Spiegelsymmetrie mit erweiterten Bots | ✅ glutpakt/wurzelbund je 12 Runden bit-symmetrisch | `test_lune_core` mirror_fairness |
| Karte mit echten Props (Bäume, Felsen, Brücken, Bordsteine, Banner) | 👁 Übersicht, Kampf Top/Mid, Planung | `screenshots/overview-*.png`, `combat-*.png` |
| Sieben Volksrepräsentanten (Modelle + Clips) | 👁 Ruhe, Kontakt, Laufen, Fähigkeit, Tod, Nahaufnahme | `screenshots/peoples-*.png`, `people_lineup` |
| Assetmatrix mit `p_*` und map_props | ✅ 74 Zeilen | `python3 tools/luneraria/build_asset_matrix.py` |
## Echte Anwendung (M1)
`tools/luneraria/verify_m1.tscn`, 38 Prüfungen mit echten Maus- und Tastaturereignissen:
@ -40,7 +53,7 @@ Nur die Kampfuhr wird dabei beschleunigt (mehr feste Schritte pro Bild), die Reg
`tools/luneraria/verify_m2.tscn`, 15 Prüfungen. Teil 1 bedient das HUD mit echten Klicks: Reiter, Held anwerben, Held-Lane, Truppe kaufen und in die Grotte schicken, Verstärkungsseite, Rückgängig. Teil 2 spielt eine gewöhnliche Partie ohne Sondergold bis zum Ancient-Fall; der menschliche Platz wird vom Bot-Planer über dieselben Befehle gespielt. Aufgenommen: Held mit Items, Held im Feld, Grottenkampf, Ankündigung, Bossentsendung.
Weitere M2-Belege: `test_lune_m2` 73/73, darunter der Nachweis, dass die alte Arbeiter- und Funkenökonomie nicht mitläuft (Arbeitsannahme E).
Weitere M2-Belege: `test_lune_m2` 73/73, darunter der Nachweis, dass die alte Arbeiter- und Funkenökonomie nicht mitläuft (Arbeitsannahme E). M2-App nach M3-Botfix erneut 15/15 (bzw. 14/14, wenn die Partie vor einer Bossentsendung endet).
## Legacy-Regressionen (Saumwacht)
@ -50,6 +63,6 @@ Unverändert über die Umleitung der alten QA-Schalter: 209 · 33 · 463 · 206
| Plattform | Stand |
| --- | --- |
| Fedora 44, Forward+ | ✅ Quellprojekt (Tests, Aufnahmen, Leistung) |
| Fedora 44, Forward+ | ✅ Quellprojekt (Tests, Aufnahmen, Leistung, Balance, Stress) |
| Fedora 44, Kompatibilitätsmodus (OpenGL) | ⏳ M4 (für Saumwacht 0.15.0 geprüft, für Luneraria noch nicht) |
| Windows 11 | ⏳ nicht geprüft (keine Hardware). Ein exportiertes Paket oder ein Wine-Lauf wäre kein nativer Test. |

View file

@ -64,7 +64,7 @@ Alle Zahlen stehen zentral in `data/luneraria/balance_default.tres` (Klasse `Lun
| Talente | Auf Stufe 3 und 6 je eine endgültige Wahl zwischen zwei Richtungen: Eigen- gegen Gruppenschutz oder Einzelziel gegen Fläche, je Held eigene Optionen. |
| Items | Sechs dauerhafte Items, drei Plätze. Jedes Item höchstens einmal pro Held. Kristallsplitter setzt Heldenstufe 3 voraus. Verkauf bringt 50 %, ein Kauf aus derselben Planung wird voll erstattet. Boni verschiedener Items addieren sich; die Schadensminderung ist auf 35 %, das Angriffstempo auf +50 % begrenzt. |
| Reihenfolge im Kampf | Primärtreffer → Grundfähigkeit → Talent → Item-Effekt. Item- und Talenteffekte lösen keine weiteren Treffer-Effekte aus, Heilungen lösen nichts aus; dadurch sind Schleifen ausgeschlossen. Normale Truppen haben kein Inventar. |
| Angriffschampions | Rostschieber (Schutz, 150 Gold), Dunstsänger (Druck auf Unterstützer, 150), Keilbrecher (Belagerung, ×2,5 gegen Gebäude, 180). Ein Kauf in Runde n wird für Runde n+1 auf eine Lane gebucht, höchstens zwei Buchungen pro Runde. Bis zum Ende der Planung lässt sich eine Buchung voll erstatten, danach ist sie weder verschiebbar noch erstattbar. Buchungen werden zu Beginn von n+1 öffentlich angekündigt. Der Champion kämpft einmal und verschwindet. Die Stärke skaliert mit der Einsatzrunde, das Kopfgeld beträgt 70 + 6 × Runde und wird wie Monstergold verteilt. |
| Angriffschampions | Rostschieber (Schutz, 150 Gold), Dunstsänger (Druck auf Unterstützer, 150), Keilbrecher (Belagerung, ×1,8 gegen Gebäude, 180). Ein Kauf in Runde n wird für Runde n+1 auf eine Lane gebucht, höchstens zwei Buchungen pro Runde. Bis zum Ende der Planung lässt sich eine Buchung voll erstatten, danach ist sie weder verschiebbar noch erstattbar. Buchungen werden zu Beginn von n+1 öffentlich angekündigt. Der Champion kämpft einmal und verschwindet. Die Stärke skaliert mit der Einsatzrunde, das Kopfgeld beträgt 70 + 6 × Runde und wird wie Monstergold verteilt. |
| Grotte · Zuweisung | Die Zuweisung „G“ gilt für genau eine Runde. Die Einheiten fehlen ihrer Lane die ganze Kampfphase, starten an festen, gespiegelten Grotteneingängen und kehren bei der Abrechnung auf die Lane ihres Besitzers zurück. In Sperrrunden ist die Zuweisung abgelehnt. |
| Grotte · Kampf | Der neutrale Boss ruht, solange Expeditionen beider Teams leben; die Expeditionen kämpfen zuerst gegeneinander. Erst wenn höchstens ein Team übrig ist, erwacht der Boss mit vollen Lebenspunkten. Tod aller Expeditionen oder Ablauf des Zeitfensters: kein Anspruch. Der nächste Versuch trifft einen vollständig neuen Boss. Todesfälle in der Grotte bringen kein Gold. |
| Anspruch | Genau ein Anspruch pro Sieg; ein wiederholtes Abrechnungssignal ändert nichts. Ziel-Lane: die Lane des beitragenden Spielers mit dem höchsten eingesetzten Armeewert in der Grotte (Held einschließlich Items); bei Gleichstand der niedrigere Slot. Dieser Spieler kann die Lane in der folgenden Planung ändern; ohne Eingabe gilt seine eigene Lane. |

View file

@ -1,13 +1,13 @@
# STATUS · Champions of Luneraria
Stand: 28. September 2026 · Branches `luneraria/m1` (M0/M1) und `luneraria/m2` · Version im Projekt 0.15.0 (Saumwacht-Demo), Luneraria-Paket erst mit M4.
Stand: 28. September 2026 · Branches `luneraria/m1` (M0/M1), `luneraria/m2`, `luneraria/m3` · Version im Projekt 0.15.0 (Saumwacht-Demo), Luneraria-Paket erst mit M4.
| Meilenstein | Zustand |
| --- | --- |
| M0 · Migration vorbereiten | **abgeschlossen** |
| M1 · Spielbarer Drei-Lane-Kern | **abgeschlossen** (siehe unten) |
| M2 · Mechanikdurchlauf | **abgeschlossen** (siehe unten) |
| M3 · Qualität und Balance | offen |
| M1 · Spielbarer Drei-Lane-Kern | **abgeschlossen** |
| M2 · Mechanikdurchlauf | **abgeschlossen** |
| M3 · Qualität und Balance | **abgeschlossen** (siehe unten) |
| M4 · Netzwerk und Pakete | offen |
## M1 · abgeschlossen
@ -55,19 +55,43 @@ Stand: 28. September 2026 · Branches `luneraria/m1` (M0/M1) und `luneraria/m2`
**Ungetestet:** menschliche Spieltests der neuen Systeme, Windows 11.
## M3 · abgeschlossen
**Implementiert**
- Bot-Priorisierung: Items und Angriffschampions werden **vor** der Armee geplant (Reserve), damit Helden Ausrüstung erhalten und Champions überhaupt gebucht werden. Regression `bots_m2` gefixt.
- Deterministische Lane-Hilfe der Bots statt geteiltem Zufall — erhält die exakte Spiegelsymmetrie.
- Bossbalance: Grottenboss 3.600 HP, entsandter Boss 6.800 HP / 88 Schaden, Belagerungsfaktor 1,8. Bossjäger senden 5 Truppen + Held und bewerten Expeditionen per öffentlicher Lanchester-Schätzung.
- Profilbalance: verteidigung erhält Champion und Teamhilfe; ausgewogen startet den Held eine Runde später; teamhilfe hilft seltener.
- 3D-Kartenvisuals: `map_props.glb` (Blender-Generator) mit Kiefern, Eichen, Felsen, Büschen, Brücken über die Kluft, Bordsteinen, Klamprahmen und Team-Bannern an den Ancients. Alte Compare-Props abgelöst.
- Sieben Volksrepräsentanten (`p_mensch` … `p_biest`) mit gewichtetem Skelett, 9 Clips, LP_*-Materialien, Audit und Sichtprüfung. Entwicklungsplan in [VOELKER.md](VOELKER.md). Noch nicht spielbar im Match.
- Balancewerkzeuge: `balance_run` (Zusammensetzungen, Seitentausch, reine Duelle), `analyze_balance.py`, `stress_run`, `people_lineup`.
**Automatisiert geprüft**
- Regeln: Core 91/91 (inkl. Spiegel) und M2 73/73 nach den Bot-Änderungen.
- Echte Anwendung: M1 38/38 und M2 15/15 (nach Fix der Item-Ausrüstung).
- Balance 40 Partien: Seitentausch 20/20, Profile 24–64 %, Bünde 55/45, alle regulär nach 9–14 Wellen.
- Profil-Duelle 30 Partien: Seitentausch 15/15.
- Stress 17/17: Wellen bis 10⁶, Langlauf 200 Runden als „Testlimit erreicht“.
- Legacy unverändert.
**Visuell geprüft:** Kartenübersicht mit Props und Brücken, Kampf Top/Mid, Planung mit Helden-Items (Funkenlanze Stufe 3, Glutklinge), sieben Völker in Ruhe/Kontakt/Laufen/Fähigkeit/Tod und Nahaufnahme (`screenshots/peoples-*`).
**Bekannte Befunde**
- Reine 3-gleichen Profil-Duelle ergeben eine lineare Kette (ausgewogen > verteidigung > teamhilfe > fernkampf > druck > bossjagd), keinen Zyklus. In gemischten Teams sind alle Profile im Band 24–64 %.
- Bossjagd als reines Teamprofil 0/10, in Mischteams 24 %. Die Risikoabschätzung ist besser geworden, die Jagd bleibt teuer.
## Bekannt
- Ein exakt gespiegeltes Match bleibt unentschieden, wird also nicht beendet (Testlimit). Das ist ein Balancebefund für M3.
- Die Figuren der Monsterwellen sind nur über Teamring und Lichtfarbe dem Team zugeordnet.
- Bäume und Felsen stammen aus dem Vergleichspack und sind einfach; das Kartenbild ist funktional, noch nicht endgültig (M3).
- Der Bossjäger-Bot greift zu früh an (Fehlschläge in Runde 5–7, Sieg in Runde 8); nach den Szenarien wiegt der Boss die geschwächte Lane eher zu wenig auf (M3).
- Die Auswertung der Bot-Profile ist verzerrt, weil in jeder Partie dieselben Profilpaare gegeneinander stehen (M3: variierte Teams).
- Ein exakt gespiegeltes Match bleibt unentschieden, wird also nicht beendet (Testlimit). Das ist der erwartbare Grenzfall identischen Spiels; Asymmetrie kommt aus Helden, Champions und Boss.
- Die Monsterwellen sind nur über Teamring und Lichtfarbe dem Team zugeordnet.
- Beim Beenden meldet Godot eine noch belegte Ressource (Hintergrundladen der Menübühne); ohne Folgen im Spiel.
- Die sieben Volksrepräsentanten sind noch nicht spielbar (Daten und Modelle liegen vor, Plan in VOELKER.md).
## Blockiert
- Nativer Windows-11-Test: keine Windows-Hardware.
- Kompatibilitätsmodus (OpenGL) für Luneraria: erst mit M4-Exporten gezielt prüfen.
## Nächster Schritt
M3: mehrere Seeds und Teamzusammensetzungen, Seitentausch, Gegenstrategien, hohe Wellenindizes als Belastungstest, Boss- und Profilbalance, visuelle Überarbeitung der Karte, danach Repräsentanten der fehlenden Völker.
M4: autoritatives Host/Join für sechs Slots (Direktverbindung, Bots für freie Slots), synchronisierte Phasen und Zustandsabgleich, reale Mehrprozessprüfungen (Loopback), reproduzierbare Linux-/Windows-Exports, entpackbare Demo, klare Testmatrix. Öffentliches Matchmaking bleibt außerhalb des Umfangs.

40
docs/luneraria/VOELKER.md Normal file
View file

@ -0,0 +1,40 @@
# Völker und Repräsentanten
Stand: 28. September 2026 (M3). Trennung der Daten: **Volk** · **Bund** · **Klasse** · **Kampfrolle**. Ein Volk ist kein eigener Kampfmechanismus; Rollen kommen aus dem gemeinsamen Truppen-/Heldenkatalog.
## Repräsentanten M3
Jedes der sieben Zielvölker besitzt genau ein eigenständiges Blender-Modell mit gewichtetem Skelett (22–24 Knochen, 9 Clips: idle, start, walk, stop, attack_a, attack_b, hit, ability, death). Erzeugt mit `assets-source/luneraria/build_peoples.py`, exportiert nach `assets/luneraria/peoples/p_*.glb`, Manifest `assets/luneraria/peoples_manifest.json`, Prüfbefund `assets-source/luneraria/peoples-audit.json`.
| Volk | ID | Name | Klasse | Kampfrolle | Besonderheit |
| --- | --- | --- | --- | --- | --- |
| Menschen | `p_mensch` | Ritter | Ritter | Front | Schild + Schwert, Plattenrüstung |
| Elfen | `p_elf` | Waldläuferin | Waldläuferin | Fernkampf | Bogen, leichte Rüstung, spitze Ohren |
| Zwerge | `p_zwerg` | Schildträger | Schildträger | Front | Vollbart, Hornhelm, Rundschild |
| Trolle | `p_troll` | Steinhauer | Steinhauer | Fläche | massive Keule, Felsplatten |
| Feen | `p_fee` | Lichtheilerin | Lichtheilerin | Unterstützung | Flügel, Glüheffekte |
| Orks | `p_ork` | Kriegshäuptling | Kriegshäuptling | Nahkampf | Krallenwaffe, Fell |
| Biestmenschen | `p_biest` | Klauenjäger | Klauenjäger | Nahkampf | Bestienanatomie, Klauen |
Sichtprüfung: `screenshots/peoples-ruhe.png`, `-kontakt`, `-laufen`, `-faehigkeit`, `-tod`, `-detail-a/b`. Werkzeug: `tools/luneraria/people_lineup.tscn`.
## Was noch nicht implementiert ist
- Keine der sieben Figuren ist derzeit **spielbar**. Die laufenden Bünde Glutpakt und Wurzelbund behalten ihre vorhandenen Modelle (Glutkonstrukte, Wurzelwesen).
- Es gibt **keine** Volkswahl im Menü und **keine** volksspezifischen Boni oder Fähigkeiten.
- Die Repräsentanten sind Bestandteil der Assetmatrix und der Entwicklungsplanung, nicht des Matchrosters.
## Entwicklungsplan (nach M4)
1. **Volksdaten in den Katalog:** `people`, `bund`, `klasse`, `rolle` als getrennte Felder in `DataCatalog` / `LuneContent`. Einheitentypen verweisen auf ein Volk, ein Bund bleibt eine spielbare Fraktion mit eigener Aufwertungslinie.
2. **Spielbare Vertretung pro Volk:** je ein normaler Truppentyp und ein Aufwertungsschritt aus den Repräsentanten-Animationen, übernommen in die bestehenden Rollen Front / Nahkampf / Fernkampf / Fläche / Unterstützung. Kein eigenes Kampfsystem pro Volk.
3. **Bündekopplung:** Jeder Bund öffnet eine Teilmenge der Völker (z. B. Wurzelbund: Elfen, Feen, Biestmenschen; Glutpakt: Menschen, Orks, Zwerge, Trolle). Volk formt Startboni und Heldenauswahl, nicht die Grundregeln.
4. **Helden pro Volk:** je ein Held aus dem Repräsentantenmodell mit zwei Talentrichtungen, analog zu Ringborke / Quellgeflecht / Funkenlanze. Vorläufige Bestandshelden bleiben erhalten.
5. **Balancierung über Rollen, nicht Sammelboni:** Volkssynergien sind höchstens eine kleine, sichtbare Verstärkung (z. B. Formationsschild), nie der einzige Hebel.
6. **Inhaltliche Ausweitung:** weitere Klassen pro Volk (Aufwertungen, Champion-Varianten) erst nach stabilen sechs Rollen und laufendem Netzwerkmodus.
## Bestandsschutz
- Ausgearbeitete Modelle (Ringborke, Funkenleser, Basaltbastion, Quellgeflecht, Funkenlanze, Glasballiste, Kernkristalle) bleiben unverändert erhalten.
- Nietenkonvent (`m*`) und Nebelchor (`n*`) bleiben als Reserve in der Assetmatrix und werden nicht als Völker ausgegeben.
- Die LP_*-Materialien der Völkermodelle laufen über denselben Kluft-/Sanctuary-Pfad wie die übrigen Figuren (`asset_library.gd`).

View file

@ -2,9 +2,9 @@
"checks": 38,
"failures": [],
"object_counts": [
3850.0,
3850.0,
3850.0,
3850.0
3363.0,
3363.0,
3363.0,
3363.0
]
}

View file

@ -1,29 +1,5 @@
{
"boss_log": [
{
"event": "failed",
"round": 5
},
{
"event": "failed",
"round": 6
},
{
"event": "failed",
"round": 7
},
{
"chooser": 4,
"event": "won",
"round": 8,
"team": 1
},
{
"event": "deployed",
"lane": "top",
"round": 9,
"team": 1
},
{
"chooser": 4,
"event": "won",
@ -31,14 +7,13 @@
"team": 1
}
],
"checks": 15,
"checks": 14,
"failures": [],
"rounds": 12,
"seen": [
"grotto",
"announce",
"hero_field",
"hero_items",
"announce",
"boss"
"grotto"
]
}

View file

@ -0,0 +1,6 @@
Partien 40 · Ergebnisse {'blau': 20, 'rot': 20} · Testlimit 0 · Zeitfenster-Kämpfe 1 · längster Kampf 180 s
Wellen bis Ende: min 7 · median 9 · max 14
Seitentausch: dieselbe Zusammensetzung gewinnt beide Male in 20/20 Paaren
Profile (Siege/Einsätze): {'ausgewogen': '24/48 (50 %)', 'bossjagd': '2/34 (6 %)', 'druck': '28/34 (82 %)', 'fernkampf': '26/48 (54 %)', 'teamhilfe': '28/48 (58 %)', 'verteidigung': '12/28 (43 %)'}
Bünde: {'glutpakt': '68/124 (55 %)', 'wurzelbund': '52/116 (45 %)'}
Boss: {'won': 18, 'deployed': 10, 'failed': 63} · Heldenstufen am Ende (Median): 4

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,26 @@
Godot Engine v4.7.2.stable.fedora.ed1daf0bf - https://godotengine.org
BALANCE 00 ["ausgewogen", "druck", "teamhilfe"] | ["teamhilfe", "verteidigung", "ausgewogen"] -> blau (7) / swapped rot (8)
BALANCE 01 ["bossjagd", "bossjagd", "teamhilfe"] | ["fernkampf", "teamhilfe", "fernkampf"] -> rot (8) / swapped blau (8)
BALANCE 02 ["bossjagd", "ausgewogen", "teamhilfe"] | ["druck", "ausgewogen", "verteidigung"] -> rot (9) / swapped blau (9)
BALANCE 03 ["fernkampf", "druck", "ausgewogen"] | ["druck", "fernkampf", "verteidigung"] -> blau (13) / swapped rot (13)
BALANCE 04 ["ausgewogen", "teamhilfe", "fernkampf"] | ["ausgewogen", "verteidigung", "fernkampf"] -> blau (9) / swapped rot (9)
BALANCE 05 ["teamhilfe", "fernkampf", "verteidigung"] | ["fernkampf", "bossjagd", "bossjagd"] -> blau (8) / swapped rot (8)
BALANCE 06 ["bossjagd", "ausgewogen", "teamhilfe"] | ["fernkampf", "teamhilfe", "ausgewogen"] -> rot (7) / swapped blau (8)
BALANCE 07 ["ausgewogen", "ausgewogen", "ausgewogen"] | ["teamhilfe", "teamhilfe", "ausgewogen"] -> rot (12) / swapped blau (12)
BALANCE 08 ["teamhilfe", "ausgewogen", "bossjagd"] | ["druck", "ausgewogen", "druck"] -> rot (10) / swapped blau (10)
BALANCE 09 ["verteidigung", "druck", "druck"] | ["bossjagd", "ausgewogen", "teamhilfe"] -> blau (9) / swapped rot (9)
BALANCE 10 ["druck", "ausgewogen", "ausgewogen"] | ["teamhilfe", "bossjagd", "ausgewogen"] -> blau (9) / swapped rot (9)
BALANCE 11 ["bossjagd", "fernkampf", "fernkampf"] | ["teamhilfe", "verteidigung", "teamhilfe"] -> rot (8) / swapped blau (8)
BALANCE 12 ["fernkampf", "fernkampf", "teamhilfe"] | ["teamhilfe", "ausgewogen", "fernkampf"] -> blau (8) / swapped rot (9)
BALANCE 13 ["teamhilfe", "druck", "fernkampf"] | ["fernkampf", "druck", "ausgewogen"] -> rot (12) / swapped blau (12)
BALANCE 14 ["bossjagd", "druck", "fernkampf"] | ["bossjagd", "bossjagd", "bossjagd"] -> blau (8) / swapped rot (8)
BALANCE 15 ["fernkampf", "fernkampf", "verteidigung"] | ["druck", "fernkampf", "ausgewogen"] -> rot (13) / swapped blau (13)
BALANCE 16 ["teamhilfe", "verteidigung", "verteidigung"] | ["teamhilfe", "verteidigung", "ausgewogen"] -> rot (14) / swapped blau (14)
BALANCE 17 ["fernkampf", "verteidigung", "fernkampf"] | ["druck", "fernkampf", "bossjagd"] -> blau (10) / swapped rot (10)
BALANCE 18 ["verteidigung", "ausgewogen", "bossjagd"] | ["druck", "teamhilfe", "druck"] -> rot (8) / swapped blau (8)
BALANCE 19 ["druck", "teamhilfe", "teamhilfe"] | ["fernkampf", "verteidigung", "bossjagd"] -> blau (7) / swapped rot (7)
WARNING: 16 ObjectDB instances were leaked at exit (run with `--verbose` for details).
at: cleanup (core/object/object.cpp:2536)
ERROR: 1 resources still in use at exit (run with --verbose for details).
at: clear (core/io/resource.cpp:822)

View file

@ -0,0 +1,6 @@
Partien 40 · Ergebnisse {'blau': 19, 'rot': 21} · Testlimit 0 · Zeitfenster-Kämpfe 1 · längster Kampf 180 s
Wellen bis Ende: min 7 · median 12 · max 14
Seitentausch: dieselbe Zusammensetzung gewinnt beide Male in 19/20 Paaren
Profile (Siege/Einsätze): {'ausgewogen': '26/48 (54 %)', 'bossjagd': '9/34 (26 %)', 'druck': '22/34 (65 %)', 'fernkampf': '29/48 (60 %)', 'teamhilfe': '28/48 (58 %)', 'verteidigung': '6/28 (21 %)'}
Bünde: {'glutpakt': '69/124 (56 %)', 'wurzelbund': '51/116 (44 %)'}
Boss: {} · Heldenstufen am Ende (Median): 5

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,26 @@
Godot Engine v4.7.2.stable.fedora.ed1daf0bf - https://godotengine.org
BALANCE 00 ["ausgewogen", "druck", "teamhilfe"] | ["teamhilfe", "verteidigung", "ausgewogen"] -> blau (7) / swapped rot (8)
BALANCE 01 ["bossjagd", "bossjagd", "teamhilfe"] | ["fernkampf", "teamhilfe", "fernkampf"] -> rot (10) / swapped blau (9)
BALANCE 02 ["bossjagd", "ausgewogen", "teamhilfe"] | ["druck", "ausgewogen", "verteidigung"] -> blau (9) / swapped rot (9)
BALANCE 03 ["fernkampf", "druck", "ausgewogen"] | ["druck", "fernkampf", "verteidigung"] -> blau (13) / swapped rot (13)
BALANCE 04 ["ausgewogen", "teamhilfe", "fernkampf"] | ["ausgewogen", "verteidigung", "fernkampf"] -> blau (9) / swapped rot (9)
BALANCE 05 ["teamhilfe", "fernkampf", "verteidigung"] | ["fernkampf", "bossjagd", "bossjagd"] -> blau (12) / swapped rot (12)
BALANCE 06 ["bossjagd", "ausgewogen", "teamhilfe"] | ["fernkampf", "teamhilfe", "ausgewogen"] -> rot (9) / swapped rot (9)
BALANCE 07 ["ausgewogen", "ausgewogen", "ausgewogen"] | ["teamhilfe", "teamhilfe", "ausgewogen"] -> rot (12) / swapped blau (12)
BALANCE 08 ["teamhilfe", "ausgewogen", "bossjagd"] | ["druck", "ausgewogen", "druck"] -> rot (13) / swapped blau (13)
BALANCE 09 ["verteidigung", "druck", "druck"] | ["bossjagd", "ausgewogen", "teamhilfe"] -> rot (9) / swapped blau (9)
BALANCE 10 ["druck", "ausgewogen", "ausgewogen"] | ["teamhilfe", "bossjagd", "ausgewogen"] -> blau (13) / swapped rot (13)
BALANCE 11 ["bossjagd", "fernkampf", "fernkampf"] | ["teamhilfe", "verteidigung", "teamhilfe"] -> blau (11) / swapped rot (11)
BALANCE 12 ["fernkampf", "fernkampf", "teamhilfe"] | ["teamhilfe", "ausgewogen", "fernkampf"] -> blau (8) / swapped rot (9)
BALANCE 13 ["teamhilfe", "druck", "fernkampf"] | ["fernkampf", "druck", "ausgewogen"] -> rot (12) / swapped blau (12)
BALANCE 14 ["bossjagd", "druck", "fernkampf"] | ["bossjagd", "bossjagd", "bossjagd"] -> blau (12) / swapped rot (12)
BALANCE 15 ["fernkampf", "fernkampf", "verteidigung"] | ["druck", "fernkampf", "ausgewogen"] -> rot (13) / swapped blau (13)
BALANCE 16 ["teamhilfe", "verteidigung", "verteidigung"] | ["teamhilfe", "verteidigung", "ausgewogen"] -> rot (14) / swapped blau (14)
BALANCE 17 ["fernkampf", "verteidigung", "fernkampf"] | ["druck", "fernkampf", "bossjagd"] -> blau (13) / swapped rot (13)
BALANCE 18 ["verteidigung", "ausgewogen", "bossjagd"] | ["druck", "teamhilfe", "druck"] -> rot (9) / swapped blau (9)
BALANCE 19 ["druck", "teamhilfe", "teamhilfe"] | ["fernkampf", "verteidigung", "bossjagd"] -> blau (7) / swapped rot (7)
WARNING: 18 ObjectDB instances were leaked at exit (run with `--verbose` for details).
at: cleanup (core/object/object.cpp:2536)
ERROR: 1 resources still in use at exit (run with --verbose for details).
at: clear (core/io/resource.cpp:822)

View file

@ -0,0 +1,6 @@
Partien 40 · Ergebnisse {'blau': 20, 'rot': 20} · Testlimit 0 · Zeitfenster-Kämpfe 3 · längster Kampf 180 s
Wellen bis Ende: min 7 · median 10 · max 14
Seitentausch: dieselbe Zusammensetzung gewinnt beide Male in 20/20 Paaren
Profile (Siege/Einsätze): {'ausgewogen': '26/48 (54 %)', 'bossjagd': '10/34 (29 %)', 'druck': '24/34 (71 %)', 'fernkampf': '28/48 (58 %)', 'teamhilfe': '28/48 (58 %)', 'verteidigung': '4/28 (14 %)'}
Bünde: {'glutpakt': '64/124 (52 %)', 'wurzelbund': '56/116 (48 %)'}
Boss: {'won': 21, 'deployed': 12, 'failed': 2} · Heldenstufen am Ende (Median): 3

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,26 @@
Godot Engine v4.7.2.stable.fedora.ed1daf0bf - https://godotengine.org
BALANCE 00 ["ausgewogen", "druck", "teamhilfe"] | ["teamhilfe", "verteidigung", "ausgewogen"] -> blau (7) / swapped rot (8)
BALANCE 01 ["bossjagd", "bossjagd", "teamhilfe"] | ["fernkampf", "teamhilfe", "fernkampf"] -> rot (9) / swapped blau (8)
BALANCE 02 ["bossjagd", "ausgewogen", "teamhilfe"] | ["druck", "ausgewogen", "verteidigung"] -> blau (10) / swapped rot (10)
BALANCE 03 ["fernkampf", "druck", "ausgewogen"] | ["druck", "fernkampf", "verteidigung"] -> blau (13) / swapped rot (13)
BALANCE 04 ["ausgewogen", "teamhilfe", "fernkampf"] | ["ausgewogen", "verteidigung", "fernkampf"] -> blau (9) / swapped rot (9)
BALANCE 05 ["teamhilfe", "fernkampf", "verteidigung"] | ["fernkampf", "bossjagd", "bossjagd"] -> blau (11) / swapped rot (11)
BALANCE 06 ["bossjagd", "ausgewogen", "teamhilfe"] | ["fernkampf", "teamhilfe", "ausgewogen"] -> rot (9) / swapped blau (9)
BALANCE 07 ["ausgewogen", "ausgewogen", "ausgewogen"] | ["teamhilfe", "teamhilfe", "ausgewogen"] -> rot (12) / swapped blau (12)
BALANCE 08 ["teamhilfe", "ausgewogen", "bossjagd"] | ["druck", "ausgewogen", "druck"] -> rot (11) / swapped blau (11)
BALANCE 09 ["verteidigung", "druck", "druck"] | ["bossjagd", "ausgewogen", "teamhilfe"] -> rot (9) / swapped blau (9)
BALANCE 10 ["druck", "ausgewogen", "ausgewogen"] | ["teamhilfe", "bossjagd", "ausgewogen"] -> blau (12) / swapped rot (12)
BALANCE 11 ["bossjagd", "fernkampf", "fernkampf"] | ["teamhilfe", "verteidigung", "teamhilfe"] -> blau (10) / swapped rot (10)
BALANCE 12 ["fernkampf", "fernkampf", "teamhilfe"] | ["teamhilfe", "ausgewogen", "fernkampf"] -> blau (8) / swapped rot (9)
BALANCE 13 ["teamhilfe", "druck", "fernkampf"] | ["fernkampf", "druck", "ausgewogen"] -> rot (12) / swapped blau (12)
BALANCE 14 ["bossjagd", "druck", "fernkampf"] | ["bossjagd", "bossjagd", "bossjagd"] -> blau (10) / swapped rot (10)
BALANCE 15 ["fernkampf", "fernkampf", "verteidigung"] | ["druck", "fernkampf", "ausgewogen"] -> rot (13) / swapped blau (13)
BALANCE 16 ["teamhilfe", "verteidigung", "verteidigung"] | ["teamhilfe", "verteidigung", "ausgewogen"] -> rot (14) / swapped blau (14)
BALANCE 17 ["fernkampf", "verteidigung", "fernkampf"] | ["druck", "fernkampf", "bossjagd"] -> rot (9) / swapped blau (9)
BALANCE 18 ["verteidigung", "ausgewogen", "bossjagd"] | ["druck", "teamhilfe", "druck"] -> rot (8) / swapped blau (8)
BALANCE 19 ["druck", "teamhilfe", "teamhilfe"] | ["fernkampf", "verteidigung", "bossjagd"] -> blau (7) / swapped rot (7)
WARNING: 26 ObjectDB instances were leaked at exit (run with `--verbose` for details).
at: cleanup (core/object/object.cpp:2536)
ERROR: 1 resources still in use at exit (run with --verbose for details).
at: clear (core/io/resource.cpp:822)

View file

@ -0,0 +1,6 @@
Partien 40 · Ergebnisse {'rot': 20, 'blau': 20} · Testlimit 0 · Zeitfenster-Kämpfe 0 · längster Kampf 135 s
Wellen bis Ende: min 9 · median 11 · max 14
Seitentausch: dieselbe Zusammensetzung gewinnt beide Male in 20/20 Paaren
Profile (Siege/Einsätze): {'ausgewogen': '28/48 (58 %)', 'bossjagd': '8/34 (24 %)', 'druck': '18/34 (53 %)', 'fernkampf': '26/48 (54 %)', 'teamhilfe': '22/48 (46 %)', 'verteidigung': '18/28 (64 %)'}
Bünde: {'glutpakt': '68/124 (55 %)', 'wurzelbund': '52/116 (45 %)'}
Boss: {'won': 24, 'deployed': 16} · Heldenstufen am Ende (Median): 4

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
Partien 40 · Ergebnisse {'rot': 20, 'blau': 20} · Testlimit 0 · Zeitfenster-Kämpfe 0 · längster Kampf 157 s
Wellen bis Ende: min 9 · median 11 · max 14
Seitentausch: dieselbe Zusammensetzung gewinnt beide Male in 20/20 Paaren
Profile (Siege/Einsätze): {'ausgewogen': '28/48 (58 %)', 'bossjagd': '8/34 (24 %)', 'druck': '18/34 (53 %)', 'fernkampf': '26/48 (54 %)', 'teamhilfe': '22/48 (46 %)', 'verteidigung': '18/28 (64 %)'}
Bünde: {'glutpakt': '68/124 (55 %)', 'wurzelbund': '52/116 (45 %)'}
Boss: {'won': 20, 'deployed': 8} · Heldenstufen am Ende (Median): 4

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,14 @@
Partien 30 · Ergebnisse {'blau': 15, 'rot': 15} · Testlimit 0 · Zeitfenster-Kämpfe 4 · längster Kampf 180 s
Wellen bis Ende: min 6 · median 10 · max 16
Seitentausch: dieselbe Zusammensetzung gewinnt beide Male in 15/15 Paaren
Profile (Siege/Einsätze): {'ausgewogen': '24/30 (80 %)', 'bossjagd': '0/30 (0 %)', 'druck': '12/30 (40 %)', 'fernkampf': '18/30 (60 %)', 'teamhilfe': '30/30 (100 %)', 'verteidigung': '6/30 (20 %)'}
Bünde: {'glutpakt': '30/60 (50 %)', 'wurzelbund': '60/120 (50 %)'}
Boss: {'won': 8, 'deployed': 4} · Heldenstufen am Ende (Median): 4
Duelle (Siege Zeile gegen Spalte, je 2 Partien mit Seitentausch):
ausgew bossja druck fernka teamhi vertei gesamt
ausgewogen - 2 2 2 0 2 8/10
bossjagd 0 - 0 0 0 0 0/10
druck 0 2 - 0 0 2 4/10
fernkampf 0 2 2 - 0 2 6/10
teamhilfe 2 2 2 2 - 2 10/10
verteidigung 0 2 0 0 0 - 2/10

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
Godot Engine v4.7.2.stable.fedora.ed1daf0bf - https://godotengine.org
BALANCE 00 ["ausgewogen", "ausgewogen", "ausgewogen"] | ["verteidigung", "verteidigung", "verteidigung"] -> blau (11) / swapped rot (11)
BALANCE 01 ["ausgewogen", "ausgewogen", "ausgewogen"] | ["druck", "druck", "druck"] -> blau (13) / swapped rot (13)
BALANCE 02 ["ausgewogen", "ausgewogen", "ausgewogen"] | ["fernkampf", "fernkampf", "fernkampf"] -> blau (14) / swapped rot (14)
BALANCE 03 ["ausgewogen", "ausgewogen", "ausgewogen"] | ["teamhilfe", "teamhilfe", "teamhilfe"] -> rot (8) / swapped blau (8)
BALANCE 04 ["ausgewogen", "ausgewogen", "ausgewogen"] | ["bossjagd", "bossjagd", "bossjagd"] -> blau (9) / swapped rot (9)
BALANCE 05 ["verteidigung", "verteidigung", "verteidigung"] | ["druck", "druck", "druck"] -> rot (16) / swapped blau (16)
BALANCE 06 ["verteidigung", "verteidigung", "verteidigung"] | ["fernkampf", "fernkampf", "fernkampf"] -> rot (12) / swapped blau (12)
BALANCE 07 ["verteidigung", "verteidigung", "verteidigung"] | ["teamhilfe", "teamhilfe", "teamhilfe"] -> rot (8) / swapped blau (8)
BALANCE 08 ["verteidigung", "verteidigung", "verteidigung"] | ["bossjagd", "bossjagd", "bossjagd"] -> blau (10) / swapped rot (10)
BALANCE 09 ["druck", "druck", "druck"] | ["fernkampf", "fernkampf", "fernkampf"] -> rot (12) / swapped blau (12)
BALANCE 10 ["druck", "druck", "druck"] | ["teamhilfe", "teamhilfe", "teamhilfe"] -> rot (6) / swapped blau (6)
BALANCE 11 ["druck", "druck", "druck"] | ["bossjagd", "bossjagd", "bossjagd"] -> blau (10) / swapped rot (10)
BALANCE 12 ["fernkampf", "fernkampf", "fernkampf"] | ["teamhilfe", "teamhilfe", "teamhilfe"] -> rot (8) / swapped blau (8)
BALANCE 13 ["fernkampf", "fernkampf", "fernkampf"] | ["bossjagd", "bossjagd", "bossjagd"] -> blau (9) / swapped rot (9)
BALANCE 14 ["teamhilfe", "teamhilfe", "teamhilfe"] | ["bossjagd", "bossjagd", "bossjagd"] -> blau (6) / swapped rot (6)
WARNING: 10 ObjectDB instances were leaked at exit (run with `--verbose` for details).
at: cleanup (core/object/object.cpp:2536)
ERROR: 1 resources still in use at exit (run with --verbose for details).
at: clear (core/io/resource.cpp:822)

View file

@ -0,0 +1,14 @@
Partien 30 · Ergebnisse {'blau': 15, 'rot': 15} · Testlimit 0 · Zeitfenster-Kämpfe 0 · längster Kampf 169 s
Wellen bis Ende: min 9 · median 10 · max 14
Seitentausch: dieselbe Zusammensetzung gewinnt beide Male in 15/15 Paaren
Profile (Siege/Einsätze): {'ausgewogen': '30/30 (100 %)', 'bossjagd': '0/30 (0 %)', 'druck': '6/30 (20 %)', 'fernkampf': '12/30 (40 %)', 'teamhilfe': '18/30 (60 %)', 'verteidigung': '24/30 (80 %)'}
Bünde: {'glutpakt': '30/60 (50 %)', 'wurzelbund': '60/120 (50 %)'}
Boss: {'won': 10, 'deployed': 2} · Heldenstufen am Ende (Median): 5
Duelle (Siege Zeile gegen Spalte, je 2 Partien mit Seitentausch):
ausgew bossja druck fernka teamhi vertei gesamt
ausgewogen - 2 2 2 2 2 10/10
bossjagd 0 - 0 0 0 0 0/10
druck 0 2 - 0 0 0 2/10
fernkampf 0 2 2 - 0 0 4/10
teamhilfe 0 2 2 2 - 0 6/10
verteidigung 0 2 2 2 2 - 8/10

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,14 @@
Partien 30 · Ergebnisse {'blau': 15, 'rot': 15} · Testlimit 0 · Zeitfenster-Kämpfe 0 · längster Kampf 169 s
Wellen bis Ende: min 9 · median 10 · max 14
Seitentausch: dieselbe Zusammensetzung gewinnt beide Male in 15/15 Paaren
Profile (Siege/Einsätze): {'ausgewogen': '30/30 (100 %)', 'bossjagd': '0/30 (0 %)', 'druck': '6/30 (20 %)', 'fernkampf': '12/30 (40 %)', 'teamhilfe': '18/30 (60 %)', 'verteidigung': '24/30 (80 %)'}
Bünde: {'glutpakt': '30/60 (50 %)', 'wurzelbund': '60/120 (50 %)'}
Boss: {'won': 4, 'deployed': 2} · Heldenstufen am Ende (Median): 5
Duelle (Siege Zeile gegen Spalte, je 2 Partien mit Seitentausch):
ausgew bossja druck fernka teamhi vertei gesamt
ausgewogen - 2 2 2 2 2 10/10
bossjagd 0 - 0 0 0 0 0/10
druck 0 2 - 0 0 0 2/10
fernkampf 0 2 2 - 0 0 4/10
teamhilfe 0 2 2 2 - 0 6/10
verteidigung 0 2 2 2 2 - 8/10

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
{
"checks": 17,
"failures": [],
"high_index": [
{
"end": "core",
"monster_hp": 12763.92,
"peak_mobile": 120,
"phase": "vorbei",
"steps": 2312,
"wall_ms": 2585,
"wave": 100
},
{
"end": "core",
"monster_hp": 771787.92,
"peak_mobile": 120,
"phase": "vorbei",
"steps": 1484,
"wall_ms": 1871,
"wave": 1000
},
{
"end": "core",
"monster_hp": 72514027.92,
"peak_mobile": 120,
"phase": "vorbei",
"steps": 1484,
"wall_ms": 1899,
"wave": 10000
},
{
"end": "core",
"monster_hp": 720051360427.92,
"peak_mobile": 120,
"phase": "vorbei",
"steps": 1484,
"wall_ms": 2032,
"wave": 1000000
}
],
"long_run": {
"final_gold": [
106607,
106626,
106626,
107653,
107653,
107653
],
"final_wave_monster_hp": 39840.0,
"memory_mb_every25": [
52.1640138626099,
53.2806062698364,
53.3198556900024,
53.3384599685669,
53.3838663101196,
53.3969850540161,
53.4318552017212,
53.4756746292114,
53.4982004165649
],
"objects_every25": [
1706.0,
1853.0,
1853.0,
1853.0,
1853.0,
1853.0,
1853.0,
1853.0,
1853.0
],
"result": "Testlimit erreicht / Partie nicht abgeschlossen",
"round_ms_first10": 1049.535,
"round_ms_last10": 2006.0815,
"rounds": 200
}
}

View file

@ -0,0 +1,20 @@
Godot Engine v4.7.2.stable.fedora.ed1daf0bf - https://godotengine.org
STRESS_WAVE {"end":"core","monster_hp":12763.92,"peak_mobile":120,"phase":"vorbei","steps":2312,"wall_ms":2585,"wave":100}
STRESS_WAVE {"end":"core","monster_hp":771787.92,"peak_mobile":120,"phase":"vorbei","steps":1484,"wall_ms":1871,"wave":1000}
STRESS_WAVE {"end":"core","monster_hp":72514027.92,"peak_mobile":120,"phase":"vorbei","steps":1484,"wall_ms":1899,"wave":10000}
STRESS_WAVE {"end":"core","monster_hp":720051360427.92,"peak_mobile":120,"phase":"vorbei","steps":1484,"wall_ms":2032,"wave":1000000}
STRESS_PROGRESS round 26 · 2600 ms · 53.3 MB · 1853 objects
STRESS_PROGRESS round 51 · 2317 ms · 53.3 MB · 1853 objects
STRESS_PROGRESS round 76 · 2211 ms · 53.3 MB · 1853 objects
STRESS_PROGRESS round 101 · 2382 ms · 53.4 MB · 1853 objects
STRESS_PROGRESS round 126 · 2335 ms · 53.4 MB · 1853 objects
STRESS_PROGRESS round 151 · 2153 ms · 53.4 MB · 1853 objects
STRESS_PROGRESS round 176 · 2156 ms · 53.5 MB · 1853 objects
STRESS_PROGRESS round 201 · 1922 ms · 53.5 MB · 1853 objects
STRESS_LONG {"final_gold":[106607,106626,106626,107653,107653,107653],"final_wave_monster_hp":39840.0,"memory_mb_every25":[52.1640138626099,53.2806062698364,53.3198556900024,53.3384599685669,53.3838663101196,53.3969850540161,53.4318552017212,53.4756746292114,53.4982004165649],"objects_every25":[1706.0,1853.0,1853.0,1853.0,1853.0,1853.0,1853.0,1853.0,1853.0],"result":"Testlimit erreicht / Partie nicht abgeschlossen","round_ms_first10":1049.535,"round_ms_last10":2006.0815,"rounds":200}
STRESS_PASS: 17 checks; 0 failures
WARNING: 16 ObjectDB instances were leaked at exit (run with `--verbose` for details).
at: cleanup (core/object/object.cpp:2536)
ERROR: 1 resources still in use at exit (run with --verbose for details).
at: clear (core/io/resource.cpp:822)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://3j55xt0p730y"
path="res://.godot/imported/m2-announcements.png-8845438d876d7dfd9983fee3eccd8c8a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/m2-announcements.png"
dest_files=["res://.godot/imported/m2-announcements.png-8845438d876d7dfd9983fee3eccd8c8a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dxhjccj540c8h"
path="res://.godot/imported/m2-boss-deployed.png-1a935be950c90a5e4c9f495145d22448.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/m2-boss-deployed.png"
dest_files=["res://.godot/imported/m2-boss-deployed.png-1a935be950c90a5e4c9f495145d22448.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dvkm35euexvxh"
path="res://.godot/imported/m2-grotto-fight.png-ee0d0afa6644844ebc078409b5ca52d0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/m2-grotto-fight.png"
dest_files=["res://.godot/imported/m2-grotto-fight.png-ee0d0afa6644844ebc078409b5ca52d0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://fngh7pobxawa"
path="res://.godot/imported/m2-hero-field.png-9bfd17f193f8d06079a9a5e5857e52d5.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/m2-hero-field.png"
dest_files=["res://.godot/imported/m2-hero-field.png-9bfd17f193f8d06079a9a5e5857e52d5.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dfpvffvws1lb6"
path="res://.godot/imported/m2-hero-items.png-226f26a5daf93acf898dd5b8cf0889d9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/m2-hero-items.png"
dest_files=["res://.godot/imported/m2-hero-items.png-226f26a5daf93acf898dd5b8cf0889d9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://begh1xbp2rhed"
path="res://.godot/imported/m2-hud-hero-round1.png-f3e60518b7120373d97e0c22410d91d9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/m2-hud-hero-round1.png"
dest_files=["res://.godot/imported/m2-hud-hero-round1.png-f3e60518b7120373d97e0c22410d91d9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://duftukfvp52td"
path="res://.godot/imported/peoples-detail-a.png-118d5eec104c6029d82c3e3d681d9e75.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/peoples-detail-a.png"
dest_files=["res://.godot/imported/peoples-detail-a.png-118d5eec104c6029d82c3e3d681d9e75.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bmvplruukfavi"
path="res://.godot/imported/peoples-detail-b.png-15cbd8e6c27d49fa094208adf926d286.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/peoples-detail-b.png"
dest_files=["res://.godot/imported/peoples-detail-b.png-15cbd8e6c27d49fa094208adf926d286.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://va4q2eseadfl"
path="res://.godot/imported/peoples-faehigkeit.png-a0b4febe7e6c042745fb5766a530f292.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/peoples-faehigkeit.png"
dest_files=["res://.godot/imported/peoples-faehigkeit.png-a0b4febe7e6c042745fb5766a530f292.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cy6bhq2d77kks"
path="res://.godot/imported/peoples-kontakt.png-af278189a101c072c081c7bddf3c3781.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/peoples-kontakt.png"
dest_files=["res://.godot/imported/peoples-kontakt.png-af278189a101c072c081c7bddf3c3781.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://1ugn3inhkgvg"
path="res://.godot/imported/peoples-laufen.png-b562392a9450bd976498e4afff497b78.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/peoples-laufen.png"
dest_files=["res://.godot/imported/peoples-laufen.png-b562392a9450bd976498e4afff497b78.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cm2ouge0ue0iu"
path="res://.godot/imported/peoples-ruhe.png-eddf9b45053b40c79df430dc349e2dea.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/peoples-ruhe.png"
dest_files=["res://.godot/imported/peoples-ruhe.png-eddf9b45053b40c79df430dc349e2dea.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dda4mvijbb7hm"
path="res://.godot/imported/peoples-tod.png-bd111b2c449299f368237555c9809982.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/luneraria/screenshots/peoples-tod.png"
dest_files=["res://.godot/imported/peoples-tod.png-bd111b2c449299f368237555c9809982.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 650 KiB

After

Width:  |  Height:  |  Size: 735 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 KiB

After

Width:  |  Height:  |  Size: 771 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Some files were not shown because too many files have changed in this diff Show more