diff --git a/src/arena/MatchHost.java b/src/arena/MatchHost.java index 0b0b490..2a543b2 100644 --- a/src/arena/MatchHost.java +++ b/src/arena/MatchHost.java @@ -8,6 +8,7 @@ import java.nio.file.Path; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -15,6 +16,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import megamek.client.bot.princess.BehaviorSettings; import megamek.client.bot.princess.Princess; import megamek.common.Player; import megamek.common.compute.Compute; @@ -25,6 +27,7 @@ import megamek.common.loaders.MekSummaryCache; import megamek.common.net.connections.AbstractConnection; import megamek.common.net.enums.PacketCommand; import megamek.common.net.packets.Packet; +import megamek.common.jacksonAdapters.BotParser; import megamek.common.scenario.Scenario; import megamek.common.scenario.ScenarioLoader; import megamek.server.Server; @@ -100,12 +103,20 @@ public final class MatchHost { // (identity.json, the camo index, --humans), translated through this // one map. Map names = readNamesIndex(a.namesIndex); + // Which scenario slot each player came from, kept because the rename + // below throws it away and the scenario's bot behaviour is keyed by it. + // Looked up under the display name after the rename, so a bot called + // "@lance.blue" can still be matched to the "OPFOR" block that + // configured it. + Map slotOf = new HashMap<>(); for (Player p : game.getPlayersList()) { - String display = names.get(p.getName()); - if (display != null && !display.equals(p.getName())) { - System.out.println("[host] slot " + p.getName() + " plays as " + display); + String slot = p.getName(); + String display = names.get(slot); + if (display != null && !display.equals(slot)) { + System.out.println("[host] slot " + slot + " plays as " + display); p.setName(display); } + slotOf.put(p.getName(), slot); } // Before the Server exists, because constructing one binds the port @@ -169,6 +180,26 @@ public final class MatchHost { List bots = new ArrayList<>(); for (Player p : botSlots) { Princess bot = new Princess(p.getName(), LOCALHOST, a.port); + // The behaviour the scenario asked for, if it asked for one. A V2 + // scenario can give each faction its own `bot:` block - a light + // swarm wants Striker, a gun line wants Sniper - and without this + // every one of them fought on Princess's default profile whatever + // the file said. Only V2 can express it; a V1 scenario has no such + // block and keeps the default. + String slot = slotOf.getOrDefault(p.getName(), p.getName()); + if (scenario.getBotInfo(slot) + instanceof BotParser.PrincessRecord(BehaviorSettings behaviour)) { + bot.setBehaviorSettings(behaviour); + // The knobs, not getDescription(): a behaviour built from a + // scenario's YAML has no description at all, so that logged + // "(No description)" and said nothing about what changed. + System.out.printf( + "[host] %s flies the scenario's behaviour: aggression %d," + + " self-preservation %d, herding %d, bravery %d%n", + p.getName(), behaviour.getHyperAggressionIndex(), + behaviour.getSelfPreservationIndex(), + behaviour.getHerdMentalityIndex(), behaviour.getBraveryIndex()); + } bot.startPrecognition(); bot.connect(); bots.add(bot);