diff --git a/assets/imported/animations/Draw A Great Sword.fbx b/assets/imported/animations/Draw A Great Sword.fbx new file mode 100644 index 0000000..a6ced13 Binary files /dev/null and b/assets/imported/animations/Draw A Great Sword.fbx differ diff --git a/assets/imported/animations/Great Sword Attack 1.fbx b/assets/imported/animations/Great Sword Attack 1.fbx new file mode 100644 index 0000000..3f6aadb Binary files /dev/null and b/assets/imported/animations/Great Sword Attack 1.fbx differ diff --git a/assets/imported/animations/Great Sword Attack 2.fbx b/assets/imported/animations/Great Sword Attack 2.fbx new file mode 100644 index 0000000..6211499 Binary files /dev/null and b/assets/imported/animations/Great Sword Attack 2.fbx differ diff --git a/assets/imported/animations/Great Sword Attack 3.fbx b/assets/imported/animations/Great Sword Attack 3.fbx new file mode 100644 index 0000000..98be5f3 Binary files /dev/null and b/assets/imported/animations/Great Sword Attack 3.fbx differ diff --git a/assets/imported/animations/Great Sword Block Impact.fbx b/assets/imported/animations/Great Sword Block Impact.fbx new file mode 100644 index 0000000..7e807d2 Binary files /dev/null and b/assets/imported/animations/Great Sword Block Impact.fbx differ diff --git a/assets/imported/animations/Great Sword Blocking Idle.fbx b/assets/imported/animations/Great Sword Blocking Idle.fbx new file mode 100644 index 0000000..f62ab24 Binary files /dev/null and b/assets/imported/animations/Great Sword Blocking Idle.fbx differ diff --git a/assets/imported/animations/Great Sword Blocking to Idle.fbx b/assets/imported/animations/Great Sword Blocking to Idle.fbx new file mode 100644 index 0000000..877afc6 Binary files /dev/null and b/assets/imported/animations/Great Sword Blocking to Idle.fbx differ diff --git a/assets/imported/animations/Great Sword Heavy Attack.fbx b/assets/imported/animations/Great Sword Heavy Attack.fbx new file mode 100644 index 0000000..d1b495b Binary files /dev/null and b/assets/imported/animations/Great Sword Heavy Attack.fbx differ diff --git a/assets/imported/animations/Great Sword Idle boring 2.fbx b/assets/imported/animations/Great Sword Idle boring 2.fbx new file mode 100644 index 0000000..a40c560 Binary files /dev/null and b/assets/imported/animations/Great Sword Idle boring 2.fbx differ diff --git a/assets/imported/animations/Great Sword Idle boring 3.fbx b/assets/imported/animations/Great Sword Idle boring 3.fbx new file mode 100644 index 0000000..50b7223 Binary files /dev/null and b/assets/imported/animations/Great Sword Idle boring 3.fbx differ diff --git a/assets/imported/animations/Great Sword Idle boring.fbx b/assets/imported/animations/Great Sword Idle boring.fbx new file mode 100644 index 0000000..0b55ad0 Binary files /dev/null and b/assets/imported/animations/Great Sword Idle boring.fbx differ diff --git a/assets/imported/animations/Great Sword Idle to Blocking.fbx b/assets/imported/animations/Great Sword Idle to Blocking.fbx new file mode 100644 index 0000000..2704907 Binary files /dev/null and b/assets/imported/animations/Great Sword Idle to Blocking.fbx differ diff --git a/assets/imported/animations/Great Sword Idle.fbx b/assets/imported/animations/Great Sword Idle.fbx new file mode 100644 index 0000000..da7f189 Binary files /dev/null and b/assets/imported/animations/Great Sword Idle.fbx differ diff --git a/assets/imported/animations/Great Sword Impact.fbx b/assets/imported/animations/Great Sword Impact.fbx new file mode 100644 index 0000000..890995e Binary files /dev/null and b/assets/imported/animations/Great Sword Impact.fbx differ diff --git a/assets/imported/animations/Great Sword Jump.fbx b/assets/imported/animations/Great Sword Jump.fbx new file mode 100644 index 0000000..ff7dea6 Binary files /dev/null and b/assets/imported/animations/Great Sword Jump.fbx differ diff --git a/assets/imported/animations/Great Sword Parade.fbx b/assets/imported/animations/Great Sword Parade.fbx new file mode 100644 index 0000000..0b736cf Binary files /dev/null and b/assets/imported/animations/Great Sword Parade.fbx differ diff --git a/assets/imported/animations/Great Sword Run.fbx b/assets/imported/animations/Great Sword Run.fbx new file mode 100644 index 0000000..0bd1e72 Binary files /dev/null and b/assets/imported/animations/Great Sword Run.fbx differ diff --git a/assets/imported/animations/Great Sword Running Jump.fbx b/assets/imported/animations/Great Sword Running Jump.fbx new file mode 100644 index 0000000..42fbb8d Binary files /dev/null and b/assets/imported/animations/Great Sword Running Jump.fbx differ diff --git a/assets/imported/animations/Great Sword Strafe Right.fbx b/assets/imported/animations/Great Sword Strafe Right.fbx new file mode 100644 index 0000000..daa4a84 Binary files /dev/null and b/assets/imported/animations/Great Sword Strafe Right.fbx differ diff --git a/assets/imported/animations/Great Sword Strafe left.fbx b/assets/imported/animations/Great Sword Strafe left.fbx new file mode 100644 index 0000000..be04960 Binary files /dev/null and b/assets/imported/animations/Great Sword Strafe left.fbx differ diff --git a/assets/imported/animations/Great Sword Walk backwards.fbx b/assets/imported/animations/Great Sword Walk backwards.fbx new file mode 100644 index 0000000..7219f1d Binary files /dev/null and b/assets/imported/animations/Great Sword Walk backwards.fbx differ diff --git a/assets/imported/animations/Great Sword Walk.fbx b/assets/imported/animations/Great Sword Walk.fbx new file mode 100644 index 0000000..30b95b8 Binary files /dev/null and b/assets/imported/animations/Great Sword Walk.fbx differ diff --git a/assets/imported/animations/Sheath A Great Sword.fbx b/assets/imported/animations/Sheath A Great Sword.fbx new file mode 100644 index 0000000..10295a4 Binary files /dev/null and b/assets/imported/animations/Sheath A Great Sword.fbx differ diff --git a/blight-assets/src/main/resources/Characters/clips/Draw A Great Sword.j3o b/blight-assets/src/main/resources/Characters/clips/Draw A Great Sword.j3o new file mode 100644 index 0000000..b577b76 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Draw A Great Sword.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Attack 1.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Attack 1.j3o new file mode 100644 index 0000000..0a4549a Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Attack 1.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Attack 2.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Attack 2.j3o new file mode 100644 index 0000000..bf9f016 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Attack 2.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Attack 3.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Attack 3.j3o new file mode 100644 index 0000000..f371dec Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Attack 3.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Block Impact.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Block Impact.j3o new file mode 100644 index 0000000..0ccd1c3 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Block Impact.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Blocking Idle.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Blocking Idle.j3o new file mode 100644 index 0000000..15630af Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Blocking Idle.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Blocking to Idle.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Blocking to Idle.j3o new file mode 100644 index 0000000..161f994 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Blocking to Idle.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Heavy Attack.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Heavy Attack.j3o new file mode 100644 index 0000000..53c5f98 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Heavy Attack.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Idle boring 2.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle boring 2.j3o new file mode 100644 index 0000000..3d4b14b Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle boring 2.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Idle boring 3.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle boring 3.j3o new file mode 100644 index 0000000..cf2a2cc Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle boring 3.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Idle boring.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle boring.j3o new file mode 100644 index 0000000..3069f7f Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle boring.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Idle to Blocking.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle to Blocking.j3o new file mode 100644 index 0000000..b3c4163 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle to Blocking.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Idle.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle.j3o new file mode 100644 index 0000000..0b4ac2d Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Idle.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Impact.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Impact.j3o new file mode 100644 index 0000000..61e9448 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Impact.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Jump.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Jump.j3o new file mode 100644 index 0000000..79bd8f5 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Jump.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Parade.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Parade.j3o new file mode 100644 index 0000000..b99eab0 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Parade.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Run.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Run.j3o new file mode 100644 index 0000000..560d911 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Run.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Running Jump.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Running Jump.j3o new file mode 100644 index 0000000..74ff521 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Running Jump.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Strafe Right.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Strafe Right.j3o new file mode 100644 index 0000000..dd2a880 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Strafe Right.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Strafe left.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Strafe left.j3o new file mode 100644 index 0000000..13280a3 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Strafe left.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Walk backwards.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Walk backwards.j3o new file mode 100644 index 0000000..08e1828 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Walk backwards.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Great Sword Walk.j3o b/blight-assets/src/main/resources/Characters/clips/Great Sword Walk.j3o new file mode 100644 index 0000000..5db11e9 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Great Sword Walk.j3o differ diff --git a/blight-assets/src/main/resources/Characters/clips/Sheath A Great Sword.j3o b/blight-assets/src/main/resources/Characters/clips/Sheath A Great Sword.j3o new file mode 100644 index 0000000..67b4423 Binary files /dev/null and b/blight-assets/src/main/resources/Characters/clips/Sheath A Great Sword.j3o differ diff --git a/blight-assets/src/main/resources/Characters/sets/human.animset.json b/blight-assets/src/main/resources/Characters/sets/human.animset.json index d7fbc63..e1c0c2f 100644 --- a/blight-assets/src/main/resources/Characters/sets/human.animset.json +++ b/blight-assets/src/main/resources/Characters/sets/human.animset.json @@ -37,7 +37,30 @@ "Sword And Shield Idle boring 3", "Sword And Shield Jump Running", "Sword And Shield Jump", - "Sword And Shield Slash" + "Sword And Shield Slash", + "Draw A Great Sword", + "Great Sword Attack 1", + "Great Sword Attack 2", + "Great Sword Attack 3", + "Great Sword Block Impact", + "Great Sword Blocking Idle", + "Great Sword Blocking to Idle", + "Great Sword Heavy Attack", + "Great Sword Idle", + "Great Sword Idle boring", + "Great Sword Idle boring 2", + "Great Sword Idle boring 3", + "Great Sword Idle to Blocking", + "Great Sword Impact", + "Great Sword Jump", + "Great Sword Parade", + "Great Sword Run", + "Great Sword Running Jump", + "Great Sword Strafe Right", + "Great Sword Strafe left", + "Great Sword Walk", + "Great Sword Walk backwards", + "Sheath A Great Sword" ], "actionMap": { "DEFAULT": "Idle", @@ -82,7 +105,32 @@ "SWORD_IDLE_BORED": "Sword And Shield Idle boring", "SWORD_IDLE_BORED_2": "Sword And Shield Idle boring 2", "SWORD_IDLE_BORED_3": "Sword And Shield Idle boring 3", - "STAND_TO_CROUCH": "Standing To Crouched" + "STAND_TO_CROUCH": "Standing To Crouched", + "TWO_HAND_DRAW": "Draw A Great Sword", + "TWO_HAND_SHEATHE": "Sheath A Great Sword", + "TWO_HAND_BLOCK": "Great Sword Blocking Idle", + "TWO_HAND_ATTACK_1": "Great Sword Attack 1", + "TWO_HAND_ATTACK_2": "Great Sword Attack 2", + "TWO_HAND_ATTACK_3": "Great Sword Attack 3", + "TWO_HAND_HEAVY_ATTACK": "Great Sword Heavy Attack", + "TWO_HAND_IDLE_TO_BLOCK": "Great Sword Idle to Blocking", + "TWO_HAND_PARADE": "Great Sword Parade", + "TWO_HAND_BLOCK_IMPACT": "Great Sword Block Impact", + "TWO_HAND_IDLE_IMPACT": "Great Sword Impact", + "TWO_HAND_IDLE": "Great Sword Idle", + "TWO_HAND_WALK": "Great Sword Walk", + "TWO_HAND_RUN": "Great Sword Run", + "TWO_HAND_BLOCK_MOVE": "Great Sword Walk", + "TWO_HAND_BLOCK_MOVE_BACKWARD": "Great Sword Walk backwards", + "TWO_HAND_BLOCK_STRAFE_LEFT": "Great Sword Strafe left", + "TWO_HAND_BLOCK_STRAFE_RIGHT": "Great Sword Strafe Right", + "TWO_HAND_JUMP": "Great Sword Jump", + "TWO_HAND_RUNNING_JUMP": "Great Sword Running Jump", + "TWO_HAND_IDLE_BORED": "Great Sword Idle boring", + "TWO_HAND_IDLE_BORED_2": "Great Sword Idle boring 2", + "TWO_HAND_IDLE_BORED_3": "Great Sword Idle boring 3", + "TWO_HAND_DEATH": "Sword And Shield Death", + "TWO_HAND_DEATH_2": "Sword And Shield Death 2" }, "previewModelPath": "Characters/Models/hero.j3o", "animOffsets": { diff --git a/blight-editor/src/main/java/de/blight/editor/state/AnimPreviewState.java b/blight-editor/src/main/java/de/blight/editor/state/AnimPreviewState.java index f7bfb9b..d6fc834 100644 --- a/blight-editor/src/main/java/de/blight/editor/state/AnimPreviewState.java +++ b/blight-editor/src/main/java/de/blight/editor/state/AnimPreviewState.java @@ -664,18 +664,10 @@ public class AnimPreviewState extends BaseAppState { // snap passiert ausschließlich zur Laufzeit im Spiel via AnimationLibrary. boolean isJ3oSource = animAssetPath.matches("(?i).*\\.j3o$"); - // FBX-Import erfordert ein geladenes Charakter-Modell. - // Ohne Ziel-Armatur kann normalizeAndRetargetClip die $AssimpFbx$_Translation-Orphan-Joints - // nicht in den Hips-Track falten → Hips-Translation geht verloren → Charakter schrumpft. - if (!isJ3oSource && srcArm != null && dstArm == null) { - input.animPreviewStatus = - "Fehler: FBX-Import erfordert ein geladenes Charakter-Modell. " + - "Bitte zuerst das Modell laden, dann die Animation importieren."; - LOG.warn("[AnimPreview] FBX-Import ohne Charakter-Modell abgebrochen: {}", animAssetPath); - return; - } - - com.jme3.anim.Armature snapArm = dstArm != null ? dstArm : srcArm; + // Kein Charakter-Modell geladen: Normalisierung gegen eigenes Skelett (Orphan-Fold + Scale-Strip). + // Das erzeugte j3o ist später per redirectAnimClipByName auf jedes kompatible Rig anwendbar. + com.jme3.anim.Armature effectiveDst = dstArm != null ? dstArm : srcArm; + com.jme3.anim.Armature snapArm = effectiveDst; int saved = 0; for (AnimClip clip : sourceAC.getAnimClips()) { @@ -688,7 +680,7 @@ public class AnimPreviewState extends BaseAppState { } } AnimClip result; - if (!retarget) { + if (!retarget && (isJ3oSource || srcArm == null)) { result = clip; } else if (isJ3oSource) { // j3o-Clips wurden bereits beim FBX-Import normalisiert (in Modell-Raum gespeichert). @@ -696,12 +688,15 @@ public class AnimPreviewState extends BaseAppState { result = redirectAnimClipByName(clip, dstArm); } else { // FBX-Import: Normalisierung in Modell-Raum (Orphan-Fold + Bind-Pose-Delta). - // Das resultierende j3o ist dann mit plain redirectAnimClipByName kompatibel. - result = normalizeAndRetargetClip(clip, dstArm); + // Kein Charakter-Modell → effectiveDst == srcArm → reine Normalisierung ohne Retarget. + result = normalizeAndRetargetClip(clip, effectiveDst); if (result == null) { LOG.warn("[AnimPreview] normalizeAndRetarget: keine Joints gemappt, versuche Retargeting"); - result = de.blight.game.animation.RetargetingSystem.retarget(clip, srcArm, dstArm); + if (dstArm != null) { + result = de.blight.game.animation.RetargetingSystem.retarget(clip, srcArm, dstArm); + } } + if (result == null) result = clip; } if (result == null) continue; diff --git a/blight-editor/src/main/java/de/blight/editor/toolset/anim/AnimSetController.java b/blight-editor/src/main/java/de/blight/editor/toolset/anim/AnimSetController.java index 2d87624..a501ff3 100644 --- a/blight-editor/src/main/java/de/blight/editor/toolset/anim/AnimSetController.java +++ b/blight-editor/src/main/java/de/blight/editor/toolset/anim/AnimSetController.java @@ -997,6 +997,11 @@ public class AnimSetController implements ToolController { return; } + // ── Aktions-Combo mit Suchfeld ──────────────────────────────────────── + javafx.scene.control.TextField actionSearch = new javafx.scene.control.TextField(); + actionSearch.setPromptText("Aktion suchen…"); + actionSearch.setMaxWidth(Double.MAX_VALUE); + ComboBox actionCombo = new ComboBox<>(); actionCombo.getItems().addAll(available); javafx.util.Callback, @@ -1013,29 +1018,85 @@ public class AnimSetController implements ToolController { actionCombo.setMaxWidth(Double.MAX_VALUE); actionCombo.getSelectionModel().selectFirst(); - ComboBox clipCombo = new ComboBox<>(); + actionSearch.textProperty().addListener((obs, ov, nv) -> { + String lower = nv == null ? "" : nv.toLowerCase(); + actionCombo.getItems().setAll(available.stream() + .filter(a -> lower.isEmpty() + || a.displayName().toLowerCase().contains(lower) + || a.name().toLowerCase().contains(lower)) + .collect(java.util.stream.Collectors.toList())); + if (!actionCombo.getItems().isEmpty()) actionCombo.getSelectionModel().selectFirst(); + }); + + // ── Clip-Combo mit Suchfeld ─────────────────────────────────────────── java.util.List allClipNames = new java.util.ArrayList<>(animSetClipListView.getItems()); for (String subName : editableSubClips.keySet()) { if (!allClipNames.contains(subName)) allClipNames.add(subName); } + + javafx.scene.control.TextField clipSearch = new javafx.scene.control.TextField(); + clipSearch.setPromptText("Clip suchen…"); + clipSearch.setMaxWidth(Double.MAX_VALUE); + + ComboBox clipCombo = new ComboBox<>(); clipCombo.getItems().addAll(allClipNames); clipCombo.setMaxWidth(Double.MAX_VALUE); clipCombo.getSelectionModel().selectFirst(); + clipSearch.textProperty().addListener((obs, ov, nv) -> { + String lower = nv == null ? "" : nv.toLowerCase(); + clipCombo.getItems().setAll(allClipNames.stream() + .filter(c -> lower.isEmpty() || c.toLowerCase().contains(lower)) + .collect(java.util.stream.Collectors.toList())); + if (!clipCombo.getItems().isEmpty()) clipCombo.getSelectionModel().selectFirst(); + }); + + // ── Layout ──────────────────────────────────────────────────────────── + VBox actionBox = new VBox(4, actionSearch, actionCombo); + VBox clipBox = new VBox(4, clipSearch, clipCombo); + javafx.scene.layout.GridPane grid = new javafx.scene.layout.GridPane(); - grid.setHgap(8); grid.setVgap(6); - grid.add(new Label("Aktion:"), 0, 0); grid.add(actionCombo, 1, 0); - grid.add(new Label("Clip:"), 0, 1); grid.add(clipCombo, 1, 1); + grid.setHgap(8); grid.setVgap(8); + grid.add(new Label("Aktion:"), 0, 0); grid.add(actionBox, 1, 0); + grid.add(new Label("Clip:"), 0, 1); grid.add(clipBox, 1, 1); javafx.scene.layout.ColumnConstraints cc = new javafx.scene.layout.ColumnConstraints(); cc.setHgrow(Priority.ALWAYS); grid.getColumnConstraints().addAll(new javafx.scene.layout.ColumnConstraints(), cc); + CheckBox weitereCB = new CheckBox("Weitere zuordnen"); + + VBox content = new VBox(12, grid, weitereCB); Dialog dlg = new Dialog<>(); dlg.initOwner(ctx.stageSupplier().get()); dlg.setTitle("Aktion zuordnen"); ButtonType ok = new ButtonType("Hinzufügen", ButtonBar.ButtonData.OK_DONE); dlg.getDialogPane().getButtonTypes().addAll(ok, ButtonType.CANCEL); - dlg.getDialogPane().setContent(grid); + dlg.getDialogPane().setContent(content); + dlg.getDialogPane().setPrefWidth(480); + + // Wenn "Weitere zuordnen" aktiv: Dialog offen lassen, nächste Aktion auto-selektieren. + javafx.scene.Node okNode = dlg.getDialogPane().lookupButton(ok); + okNode.addEventFilter(javafx.event.ActionEvent.ACTION, ev -> { + if (!weitereCB.isSelected()) return; + ev.consume(); + var action = actionCombo.getValue(); + var clip = clipCombo.getValue(); + if (action == null || clip == null) return; + String entry = action.name() + " → " + clip; + if (!animSetActionListView.getItems().contains(entry)) { + animSetActionListView.getItems().add(entry); + autoSaveAnimSet(); + } + available.remove(action); + String lower = actionSearch.getText() == null ? "" : actionSearch.getText().toLowerCase(); + actionCombo.getItems().setAll(available.stream() + .filter(a -> lower.isEmpty() + || a.displayName().toLowerCase().contains(lower) + || a.name().toLowerCase().contains(lower)) + .collect(java.util.stream.Collectors.toList())); + if (!actionCombo.getItems().isEmpty()) actionCombo.getSelectionModel().selectFirst(); + }); + dlg.showAndWait().ifPresent(bt -> { if (bt != ok) return; var action = actionCombo.getValue(); diff --git a/blight-game/src/main/java/de/blight/game/animation/AnimationAction.java b/blight-game/src/main/java/de/blight/game/animation/AnimationAction.java index fd1385a..8e022b2 100644 --- a/blight-game/src/main/java/de/blight/game/animation/AnimationAction.java +++ b/blight-game/src/main/java/de/blight/game/animation/AnimationAction.java @@ -53,10 +53,13 @@ public enum AnimationAction { AXE_IDLE, AXE_WALK, AXE_RUN, // ── Zweihänder ──────────────────────────────────────────────────────────── - TWO_HAND_DRAW, TWO_HAND_SHEATHE, TWO_HAND_BLOCK, + TWO_HAND_DRAW, TWO_HAND_SHEATHE, TWO_HAND_BLOCK, TWO_HAND_ATTACK_1, TWO_HAND_ATTACK_2, TWO_HAND_ATTACK_3, TWO_HAND_HEAVY_ATTACK, TWO_HAND_IDLE_TO_BLOCK, TWO_HAND_PARADE, TWO_HAND_BLOCK_IMPACT, TWO_HAND_IDLE_IMPACT, - TWO_HAND_IDLE, TWO_HAND_WALK, TWO_HAND_RUN, + TWO_HAND_IDLE, TWO_HAND_WALK, TWO_HAND_RUN, TWO_HAND_JUMP, TWO_HAND_RUNNING_JUMP, + TWO_HAND_IDLE_BORED, TWO_HAND_IDLE_BORED_2, TWO_HAND_IDLE_BORED_3, + TWO_HAND_DEATH, TWO_HAND_DEATH_2, + TWO_HAND_BLOCK_MOVE, TWO_HAND_BLOCK_MOVE_BACKWARD, TWO_HAND_BLOCK_STRAFE_LEFT, TWO_HAND_BLOCK_STRAFE_RIGHT, // ── Bogen ───────────────────────────────────────────────────────────────── BOW_DRAW, BOW_SHEATHE, BOW_HIT_TAKEN, @@ -157,8 +160,19 @@ public enum AnimationAction { case TWO_HAND_BLOCK_IMPACT -> TextRegistry.resolve(null, key, "Block-Treffer (Zweihänder)"); case TWO_HAND_IDLE_IMPACT -> TextRegistry.resolve(null, key, "Treffer (Zweihänder)"); case TWO_HAND_IDLE -> TextRegistry.resolve(null, key, "Stehen (Zweihänder)"); - case TWO_HAND_WALK -> TextRegistry.resolve(null, key, "Gehen (Zweihänder)"); - case TWO_HAND_RUN -> TextRegistry.resolve(null, key, "Laufen (Zweihänder)"); + case TWO_HAND_WALK -> TextRegistry.resolve(null, key, "Gehen (Zweihänder)"); + case TWO_HAND_RUN -> TextRegistry.resolve(null, key, "Laufen (Zweihänder)"); + case TWO_HAND_JUMP -> TextRegistry.resolve(null, key, "Sprung (Zweihänder)"); + case TWO_HAND_RUNNING_JUMP -> TextRegistry.resolve(null, key, "Sprung Laufend (Zweihänder)"); + case TWO_HAND_IDLE_BORED -> TextRegistry.resolve(null, key, "Idle Gelangweilt (Zweihänder)"); + case TWO_HAND_IDLE_BORED_2 -> TextRegistry.resolve(null, key, "Idle Gelangweilt 2 (Zweihänder)"); + case TWO_HAND_IDLE_BORED_3 -> TextRegistry.resolve(null, key, "Idle Gelangweilt 3 (Zweihänder)"); + case TWO_HAND_DEATH -> TextRegistry.resolve(null, key, "Tod (Zweihänder)"); + case TWO_HAND_DEATH_2 -> TextRegistry.resolve(null, key, "Tod 2 (Zweihänder)"); + case TWO_HAND_BLOCK_MOVE -> TextRegistry.resolve(null, key, "Block Vorwärts (Zweihänder)"); + case TWO_HAND_BLOCK_MOVE_BACKWARD -> TextRegistry.resolve(null, key, "Block Rückwärts (Zweihänder)"); + case TWO_HAND_BLOCK_STRAFE_LEFT -> TextRegistry.resolve(null, key, "Block Strafe Links (Zweihänder)"); + case TWO_HAND_BLOCK_STRAFE_RIGHT -> TextRegistry.resolve(null, key, "Block Strafe Rechts (Zweihänder)"); case BOW_DRAW -> TextRegistry.resolve(null, key, "Ziehen (Bogen)"); case BOW_SHEATHE -> TextRegistry.resolve(null, key, "Wegstecken (Bogen)"); diff --git a/blight-game/src/main/java/de/blight/game/combat/swordshield/SwordShieldCombat.java b/blight-game/src/main/java/de/blight/game/combat/swordshield/SwordShieldCombat.java index 207ac66..f0918a3 100644 --- a/blight-game/src/main/java/de/blight/game/combat/swordshield/SwordShieldCombat.java +++ b/blight-game/src/main/java/de/blight/game/combat/swordshield/SwordShieldCombat.java @@ -31,9 +31,8 @@ public final class SwordShieldCombat extends CombatStyleBase { public static AnimationAction resolveIdleImpactAction(ItemSubCategory weaponType) { if (weaponType == null) { return AnimationAction.SWORD_IDLE_IMPACT; } return switch (weaponType) { - case AXE -> AnimationAction.AXE_IDLE_IMPACT; - case TWO_HANDED_SWORD -> AnimationAction.TWO_HAND_IDLE_IMPACT; - default -> AnimationAction.SWORD_IDLE_IMPACT; + case AXE -> AnimationAction.AXE_IDLE_IMPACT; + default -> AnimationAction.SWORD_IDLE_IMPACT; }; } @@ -44,9 +43,8 @@ public final class SwordShieldCombat extends CombatStyleBase { public static AnimationAction resolveBlockImpactAction(ItemSubCategory weaponType) { if (weaponType == null) { return AnimationAction.SWORD_BLOCK_IMPACT; } return switch (weaponType) { - case AXE -> AnimationAction.AXE_BLOCK_IMPACT; - case TWO_HANDED_SWORD -> AnimationAction.TWO_HAND_BLOCK_IMPACT; - default -> AnimationAction.SWORD_BLOCK_IMPACT; + case AXE -> AnimationAction.AXE_BLOCK_IMPACT; + default -> AnimationAction.SWORD_BLOCK_IMPACT; }; } @@ -57,9 +55,8 @@ public final class SwordShieldCombat extends CombatStyleBase { public static AnimationAction resolveParadeAction(ItemSubCategory weaponType) { if (weaponType == null) { return AnimationAction.SWORD_PARADE; } return switch (weaponType) { - case AXE -> AnimationAction.AXE_PARADE; - case TWO_HANDED_SWORD -> AnimationAction.TWO_HAND_PARADE; - default -> AnimationAction.SWORD_PARADE; + case AXE -> AnimationAction.AXE_PARADE; + default -> AnimationAction.SWORD_PARADE; }; } diff --git a/blight-game/src/main/java/de/blight/game/combat/twohanded/TwoHandedCombat.java b/blight-game/src/main/java/de/blight/game/combat/twohanded/TwoHandedCombat.java new file mode 100644 index 0000000..99680d0 --- /dev/null +++ b/blight-game/src/main/java/de/blight/game/combat/twohanded/TwoHandedCombat.java @@ -0,0 +1,68 @@ +package de.blight.game.combat.twohanded; + +import de.blight.game.animation.AnimationAction; +import de.blight.game.combat.CombatStyleBase; + +/** + * Gemeinsame Kampflogik für den Zweihänder-Stil. + * + * Wird von beiden Seiten genutzt: + * – {@code PlayerInputControl} (Held) + * – {@code WorldNpcsState} (Gegner-KI) + * + * Alle Animations-Auflösungen (welche Animation für welches Ereignis?) und + * alle Reaktions-Anwendungen (Impact, Stagger, Konterparade) sind hier + * zentralisiert. Bug-Fixes gelten damit automatisch für Held und NPC. + * + * Neuer Kampfstil: erbt von {@link CombatStyleBase} und folgt demselben + * Muster in einem eigenen Unter-Package. + */ +public final class TwoHandedCombat extends CombatStyleBase { + + private TwoHandedCombat() {} + + // ── Animations-Auflösung ────────────────────────────────────────────────── + + /** + * Impact-Animation in Idle/Kampf-Haltung (Entität wurde getroffen). + * Identisch für Spieler und NPC. + */ + public static AnimationAction resolveIdleImpactAction() { + return AnimationAction.TWO_HAND_IDLE_IMPACT; + } + + /** + * Block-Impact-Animation (Entität hat einen Treffer abgeblockt). + * Identisch für Spieler und NPC. + */ + public static AnimationAction resolveBlockImpactAction() { + return AnimationAction.TWO_HAND_BLOCK_IMPACT; + } + + /** + * Konterangriff-Animation nach erfolgreicher Parade. + * Identisch für Spieler und NPC. + */ + public static AnimationAction resolveParadeAction() { + return AnimationAction.TWO_HAND_PARADE; + } + + // ── Reaktionen anwenden ─────────────────────────────────────────────────── + + /** + * Normaler Treffer-Impact (Entität wurde getroffen, kein Block). + * Für Held: {@code PlayerInputControl} implementiert {@link AnimReceiver}. + * Für NPC: {@code WorldNpcsState.npcAnimReceiver(s)} liefert den Adapter. + */ + public static void applyNormalImpact(AnimReceiver receiver) { + receiver.receiveBlockingAnim(resolveIdleImpactAction(), IMPACT_SPEED_NORMAL, null); + } + + /** + * Konterparade-Impact (Angreifer wird durch Parade gestoppt – Slow Motion). + * Wird aufgerufen auf dem ANGREIFER, nicht auf dem Parierenden. + */ + public static void applyParriedImpact(AnimReceiver receiver) { + receiver.receiveBlockingAnim(resolveIdleImpactAction(), IMPACT_SPEED_PARRIED, null); + } +} diff --git a/blight-game/src/main/java/de/blight/game/control/PlayerInputControl.java b/blight-game/src/main/java/de/blight/game/control/PlayerInputControl.java index e6a042e..5c93da4 100644 --- a/blight-game/src/main/java/de/blight/game/control/PlayerInputControl.java +++ b/blight-game/src/main/java/de/blight/game/control/PlayerInputControl.java @@ -34,6 +34,7 @@ import de.blight.game.combat.CombatStyleBase; import de.blight.game.combat.MeleeAttackCallback; import de.blight.game.combat.WeaponCombatState; import de.blight.game.combat.swordshield.SwordShieldCombat; +import de.blight.game.combat.twohanded.TwoHandedCombat; import de.blight.game.navigation.CharacterNavigator; import de.blight.game.state.TerrainChunkState; @@ -1254,10 +1255,11 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver { } else if (blockPhase == BlockPhase.HOLDING && !combatAnimActive) { // Beim Blocken: Bewegungsanimation nach Taste, Strafe hat Vorrang AnimationAction blockMoveAnim; - if (right) blockMoveAnim = AnimationAction.SWORD_BLOCK_STRAFE_RIGHT; - else if (left) blockMoveAnim = AnimationAction.SWORD_BLOCK_STRAFE_LEFT; - else if (forward) blockMoveAnim = AnimationAction.SWORD_BLOCK_MOVE; - else if (backward) blockMoveAnim = AnimationAction.SWORD_BLOCK_MOVE_BACKWARD; + boolean twoHand = drawnWeaponType == ItemSubCategory.TWO_HANDED_SWORD; + if (right) blockMoveAnim = twoHand ? AnimationAction.TWO_HAND_BLOCK_STRAFE_RIGHT : AnimationAction.SWORD_BLOCK_STRAFE_RIGHT; + else if (left) blockMoveAnim = twoHand ? AnimationAction.TWO_HAND_BLOCK_STRAFE_LEFT : AnimationAction.SWORD_BLOCK_STRAFE_LEFT; + else if (forward) blockMoveAnim = twoHand ? AnimationAction.TWO_HAND_BLOCK_MOVE : AnimationAction.SWORD_BLOCK_MOVE; + else if (backward) blockMoveAnim = twoHand ? AnimationAction.TWO_HAND_BLOCK_MOVE_BACKWARD : AnimationAction.SWORD_BLOCK_MOVE_BACKWARD; else blockMoveAnim = getMeleeBlockAction(drawnWeaponType); if (blockMoveAnim != currentAnim) { @@ -1861,10 +1863,12 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver { } public static AnimationAction getMeleeBlockImpactAction(ItemSubCategory s) { + if (s == ItemSubCategory.TWO_HANDED_SWORD) { return TwoHandedCombat.resolveBlockImpactAction(); } return SwordShieldCombat.resolveBlockImpactAction(s); } public static AnimationAction getMeleeIdleImpactAction(ItemSubCategory s) { + if (s == ItemSubCategory.TWO_HANDED_SWORD) { return TwoHandedCombat.resolveIdleImpactAction(); } return SwordShieldCombat.resolveIdleImpactAction(s); } @@ -2143,7 +2147,9 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver { SWORD_WALK, AXE_WALK, TWO_HAND_WALK, BOW_WALK, CROSSBOW_WALK, CRYSTAL_WALK, SWORD_BLOCK_MOVE, SWORD_BLOCK_MOVE_BACKWARD, - SWORD_BLOCK_STRAFE_LEFT, SWORD_BLOCK_STRAFE_RIGHT -> "walking"; + SWORD_BLOCK_STRAFE_LEFT, SWORD_BLOCK_STRAFE_RIGHT, + TWO_HAND_BLOCK_MOVE, TWO_HAND_BLOCK_MOVE_BACKWARD, + TWO_HAND_BLOCK_STRAFE_LEFT, TWO_HAND_BLOCK_STRAFE_RIGHT -> "walking"; case RUN, SWORD_RUN, AXE_RUN, TWO_HAND_RUN, BOW_RUN, CROSSBOW_RUN, CRYSTAL_RUN -> "running"; diff --git a/blight-game/src/main/java/de/blight/game/state/WorldNpcsState.java b/blight-game/src/main/java/de/blight/game/state/WorldNpcsState.java index 54e5de2..413f4b8 100644 --- a/blight-game/src/main/java/de/blight/game/state/WorldNpcsState.java +++ b/blight-game/src/main/java/de/blight/game/state/WorldNpcsState.java @@ -55,6 +55,7 @@ import de.blight.game.combat.DamageCalculator; import de.blight.game.combat.MeleeAttackCallback; import de.blight.game.combat.WeaponCombatState; import de.blight.game.combat.swordshield.SwordShieldCombat; +import de.blight.game.combat.twohanded.TwoHandedCombat; import de.blight.game.npc.AggroEvent; import de.blight.game.npc.NpcAggroBehavior; import de.blight.lang.TextResolver; @@ -2036,7 +2037,12 @@ public class WorldNpcsState extends BaseAppState implements MeleeAttackCallback s.combat.phase = WeaponCombatState.Phase.COUNTER_WINDOW; s.combat.timer = dur * 2f; s.paradeFromParry = true; - SwordShieldCombat.applyParriedImpact(playerInput, playerInput.getDrawnWeaponType()); + ItemSubCategory pwt = playerInput.getDrawnWeaponType(); + if (pwt == ItemSubCategory.TWO_HANDED_SWORD) { + TwoHandedCombat.applyParriedImpact(playerInput); + } else { + SwordShieldCombat.applyParriedImpact(playerInput, pwt); + } return; } s.konterParadeAttackId = -1; // Entscheidung war kein Konter → zurücksetzen @@ -2501,11 +2507,19 @@ public class WorldNpcsState extends BaseAppState implements MeleeAttackCallback } private void staggerNpc(SpawnedNpc s) { - SwordShieldCombat.applyNormalImpact(npcAnimReceiver(s), s.combatWeaponType); + if (s.combatWeaponType == ItemSubCategory.TWO_HANDED_SWORD) { + TwoHandedCombat.applyNormalImpact(npcAnimReceiver(s)); + } else { + SwordShieldCombat.applyNormalImpact(npcAnimReceiver(s), s.combatWeaponType); + } } private void staggerNpcSlow(SpawnedNpc s) { - SwordShieldCombat.applyParriedImpact(npcAnimReceiver(s), s.combatWeaponType); + if (s.combatWeaponType == ItemSubCategory.TWO_HANDED_SWORD) { + TwoHandedCombat.applyParriedImpact(npcAnimReceiver(s)); + } else { + SwordShieldCombat.applyParriedImpact(npcAnimReceiver(s), s.combatWeaponType); + } } private void setNpcCurrentActionSpeed(SpawnedNpc s, float speed) { @@ -2575,15 +2589,18 @@ public class WorldNpcsState extends BaseAppState implements MeleeAttackCallback s.paradeFromParry, playerInput.isBlocking()); if (isHeavy) { + ItemSubCategory pwtH = playerInput.getDrawnWeaponType(); if (playerInput.isBlocking()) { // Schwerer Angriff bricht Block — kein HP-Verlust, aber Stagger if (weaponSoundSystem != null) { weaponSoundSystem.play("impact"); } playerInput.triggerBlockImpact(); - SwordShieldCombat.applyNormalImpact(playerInput, playerInput.getDrawnWeaponType()); + if (pwtH == ItemSubCategory.TWO_HANDED_SWORD) { TwoHandedCombat.applyNormalImpact(playerInput); } + else { SwordShieldCombat.applyNormalImpact(playerInput, pwtH); } } else { if (weaponSoundSystem != null) { weaponSoundSystem.play("impact"); } applyPlayerDamage(s, Math.max(1, base * 3)); - SwordShieldCombat.applyNormalImpact(playerInput, playerInput.getDrawnWeaponType()); + if (pwtH == ItemSubCategory.TWO_HANDED_SWORD) { TwoHandedCombat.applyNormalImpact(playerInput); } + else { SwordShieldCombat.applyNormalImpact(playerInput, pwtH); } } return; } @@ -2600,7 +2617,9 @@ public class WorldNpcsState extends BaseAppState implements MeleeAttackCallback // Konterparade: Spieler wurde bereits per applyParriedImpact gestaggert → keine zweite Animation. // Block+Konter: Spieler war NICHT gestaggert → normale Impact-Animation abspielen. if (!s.paradeFromParry) { - SwordShieldCombat.applyNormalImpact(playerInput, playerInput.getDrawnWeaponType()); + ItemSubCategory pwtN = playerInput.getDrawnWeaponType(); + if (pwtN == ItemSubCategory.TWO_HANDED_SWORD) { TwoHandedCombat.applyNormalImpact(playerInput); } + else { SwordShieldCombat.applyNormalImpact(playerInput, pwtN); } } s.paradeFromParry = false; } @@ -2686,14 +2705,17 @@ public class WorldNpcsState extends BaseAppState implements MeleeAttackCallback } private AnimationAction resolveNpcBlockImpactAction(SpawnedNpc s) { + if (s.combatWeaponType == ItemSubCategory.TWO_HANDED_SWORD) { return TwoHandedCombat.resolveBlockImpactAction(); } return SwordShieldCombat.resolveBlockImpactAction(s.combatWeaponType); } private AnimationAction resolveNpcParadeAction(SpawnedNpc s) { + if (s.combatWeaponType == ItemSubCategory.TWO_HANDED_SWORD) { return TwoHandedCombat.resolveParadeAction(); } return SwordShieldCombat.resolveParadeAction(s.combatWeaponType); } private AnimationAction resolveNpcStaggerAction(SpawnedNpc s) { + if (s.combatWeaponType == ItemSubCategory.TWO_HANDED_SWORD) { return TwoHandedCombat.resolveIdleImpactAction(); } return SwordShieldCombat.resolveIdleImpactAction(s.combatWeaponType); }