diff --git a/src/main/java/com/minecolonies/api/entity/citizen/citizenhandlers/ICitizenSkillHandler.java b/src/main/java/com/minecolonies/api/entity/citizen/citizenhandlers/ICitizenSkillHandler.java index 66824a92689..9acb27432d7 100755 --- a/src/main/java/com/minecolonies/api/entity/citizen/citizenhandlers/ICitizenSkillHandler.java +++ b/src/main/java/com/minecolonies/api/entity/citizen/citizenhandlers/ICitizenSkillHandler.java @@ -3,8 +3,8 @@ import com.minecolonies.api.colony.ICitizenData; import com.minecolonies.api.colony.IColony; import com.minecolonies.api.entity.citizen.Skill; +import com.minecolonies.core.entity.citizen.citizenhandlers.CitizenSkillHandler; import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Tuple; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -110,5 +110,5 @@ public interface ICitizenSkillHandler * * @return the skills. */ - Map> getSkills(); + Map getSkills(); } diff --git a/src/main/java/com/minecolonies/api/research/ILocalResearchTree.java b/src/main/java/com/minecolonies/api/research/ILocalResearchTree.java index d39209486cc..7a7e553fb28 100755 --- a/src/main/java/com/minecolonies/api/research/ILocalResearchTree.java +++ b/src/main/java/com/minecolonies/api/research/ILocalResearchTree.java @@ -92,6 +92,13 @@ public interface ILocalResearchTree */ void readFromNBT(final CompoundTag compound, final IResearchEffectManager effects); + /** + * Get the list of all finished researches + * + * @return a copy of the completed list. + */ + List getCompletedList(); + /** * Check if a given research is complete. * @param location the unique id. diff --git a/src/main/java/com/minecolonies/core/client/gui/WindowHireWorker.java b/src/main/java/com/minecolonies/core/client/gui/WindowHireWorker.java index fb604799996..52bc89a8f82 100755 --- a/src/main/java/com/minecolonies/core/client/gui/WindowHireWorker.java +++ b/src/main/java/com/minecolonies/core/client/gui/WindowHireWorker.java @@ -20,6 +20,7 @@ import com.minecolonies.core.colony.buildings.moduleviews.PupilBuildingModuleView; import com.minecolonies.core.colony.buildings.moduleviews.WorkerBuildingModuleView; import com.minecolonies.core.colony.buildings.views.AbstractBuildingView; +import com.minecolonies.core.entity.citizen.citizenhandlers.CitizenSkillHandler; import com.minecolonies.core.network.messages.server.colony.citizen.PauseCitizenMessage; import com.minecolonies.core.network.messages.server.colony.citizen.RestartCitizenMessage; import com.minecolonies.core.util.BuildingUtils; @@ -29,7 +30,6 @@ import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Tuple; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -445,13 +445,13 @@ else if ((selectedModule.isFull()) && !selectedModule.getAssignedCitizens().cont final Skill primary = selectedModule instanceof WorkerBuildingModuleView ? ((WorkerBuildingModuleView) selectedModule).getPrimarySkill() : null; final Skill secondary = selectedModule instanceof WorkerBuildingModuleView ? ((WorkerBuildingModuleView) selectedModule).getSecondarySkill() : null; - final List>> skills = new ArrayList<>(citizen.getCitizenSkillHandler().getSkills().entrySet()); + final List> skills = new ArrayList<>(citizen.getCitizenSkillHandler().getSkills().entrySet()); skills.sort(Comparator.comparingInt(s -> (s.getKey() == primary ? 1 : (s.getKey() == secondary ? 2 : 3)))); - for (final Map.Entry> entry : skills) + for (final Map.Entry entry : skills) { final String skillName = entry.getKey().name().toLowerCase(Locale.US); - final int skillLevel = entry.getValue().getA(); + final int skillLevel = entry.getValue().getLevel(); final Style skillStyle = createColor(primary, secondary, entry.getKey()); textBuilder.append(Component.translatable("com.minecolonies.coremod.gui.citizen.skills." + skillName).setStyle(skillStyle)); diff --git a/src/main/java/com/minecolonies/core/client/gui/citizen/CitizenWindowUtils.java b/src/main/java/com/minecolonies/core/client/gui/citizen/CitizenWindowUtils.java index 98b9b766648..0099e642df2 100644 --- a/src/main/java/com/minecolonies/core/client/gui/citizen/CitizenWindowUtils.java +++ b/src/main/java/com/minecolonies/core/client/gui/citizen/CitizenWindowUtils.java @@ -16,9 +16,10 @@ import com.minecolonies.core.client.gui.AbstractWindowSkeleton; import com.minecolonies.core.colony.buildings.moduleviews.WorkerBuildingModuleView; import com.minecolonies.core.colony.buildings.views.AbstractBuildingView; +import com.minecolonies.core.entity.citizen.citizenhandlers.CitizenSkillHandler; import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Tuple; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -33,8 +34,6 @@ import static com.minecolonies.core.entity.citizen.citizenhandlers.CitizenExperienceHandler.SECONDARY_DEPENDENCY_SHARE; import static net.minecraft.client.gui.Gui.GUI_ICONS_LOCATION; -import net.minecraft.network.chat.Component; - /** * BOWindow for the citizen. */ @@ -387,10 +386,10 @@ public static void createHappinessBar(final ICitizenDataView citizen, final Abst public static void createSkillContent(final ICitizenDataView citizen, final AbstractWindowSkeleton window) { final boolean isCreative = Minecraft.getInstance().player.isCreative(); - for (final Map.Entry> entry : citizen.getCitizenSkillHandler().getSkills().entrySet()) + for (final Map.Entry entry : citizen.getCitizenSkillHandler().getSkills().entrySet()) { final String id = entry.getKey().name().toLowerCase(Locale.US); - window.findPaneOfTypeByID(id, Text.class).setText(Component.literal(Integer.toString(entry.getValue().getA()))); + window.findPaneOfTypeByID(id, Text.class).setText(Component.literal(Integer.toString(entry.getValue().getLevel()))); final Pane buttons = window.findPaneByID(id + "_bts"); if (buttons != null) diff --git a/src/main/java/com/minecolonies/core/client/gui/townhall/WindowCitizenPage.java b/src/main/java/com/minecolonies/core/client/gui/townhall/WindowCitizenPage.java index 29c9d56da4b..0a9151ae6e4 100644 --- a/src/main/java/com/minecolonies/core/client/gui/townhall/WindowCitizenPage.java +++ b/src/main/java/com/minecolonies/core/client/gui/townhall/WindowCitizenPage.java @@ -9,12 +9,12 @@ import com.minecolonies.api.entity.citizen.Skill; import com.minecolonies.core.Network; import com.minecolonies.core.colony.buildings.workerbuildings.BuildingTownHall; +import com.minecolonies.core.entity.citizen.citizenhandlers.CitizenSkillHandler; import com.minecolonies.core.network.messages.server.colony.citizen.RecallSingleCitizenMessage; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Tuple; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Pose; import org.jetbrains.annotations.NotNull; @@ -23,7 +23,7 @@ import java.text.DecimalFormat; import java.util.*; -import static com.minecolonies.api.util.constant.TranslationConstants.*; +import static com.minecolonies.api.util.constant.TranslationConstants.PARTIAL_HAPPINESS_MODIFIER_NAME; import static com.minecolonies.api.util.constant.WindowConstants.*; /** @@ -188,10 +188,10 @@ public void updateElement(final int index, @NotNull final Pane rowPane) button.setText(Component.literal(citizen.getName())); final AbstractTextBuilder.TextBuilder textBuilder = PaneBuilders.textBuilder(); - for (final Map.Entry> entry : citizen.getCitizenSkillHandler().getSkills().entrySet()) + for (final Map.Entry entry : citizen.getCitizenSkillHandler().getSkills().entrySet()) { final String skillName = entry.getKey().name().toLowerCase(Locale.US); - final int skillLevel = entry.getValue().getA(); + final int skillLevel = entry.getValue().getLevel(); textBuilder.append(Component.translatable("com.minecolonies.coremod.gui.citizen.skills." + skillName)); textBuilder.append(Component.literal(": " + skillLevel + " ")); diff --git a/src/main/java/com/minecolonies/core/colony/events/raid/RaidManager.java b/src/main/java/com/minecolonies/core/colony/events/raid/RaidManager.java index 0221bb7d697..3bf1823ce2c 100644 --- a/src/main/java/com/minecolonies/core/colony/events/raid/RaidManager.java +++ b/src/main/java/com/minecolonies/core/colony/events/raid/RaidManager.java @@ -26,6 +26,7 @@ import com.minecolonies.core.colony.events.raid.pirateEvent.*; import com.minecolonies.core.colony.jobs.AbstractJobGuard; import com.minecolonies.core.entity.ai.workers.guard.AbstractEntityAIGuard; +import com.minecolonies.core.entity.citizen.citizenhandlers.CitizenSkillHandler; import com.minecolonies.core.entity.pathfinding.Pathfinding; import com.minecolonies.core.entity.pathfinding.PathfindingUtils; import com.minecolonies.core.entity.pathfinding.pathjobs.PathJobRaiderPathing; @@ -113,13 +114,18 @@ public class RaidManager implements IRaiderManager /** * THe initial raid difficulty */ - private static final int INITIAL_RAID_DIFFICULTY = 5; + private static final int INITIAL_RAID_DIFFICULTY = 7; /** * The dynamic difficulty of raids for this colony */ private int raidDifficulty = INITIAL_RAID_DIFFICULTY; + /** + * The dynamic difficulty of raids for this colony + */ + private double spawnCountAdjustedDifficulty = 1.0; + /** * Whether there will be a raid in this colony tonight. */ @@ -272,17 +278,30 @@ else if (!canRaid(overrideConfig)) return RaidSpawnResult.TOO_SMALL; } + spawnCountAdjustedDifficulty = 1.0; + if (amount >= MineColonies.getConfig().getServer().maxRaiders.get()) + { + // Scales difficulty by the % of raiders we could not spawn due to entity limit + spawnCountAdjustedDifficulty = ((double) amount / MineColonies.getConfig().getServer().maxRaiders.get()); + } + // Splits into multiple raids if too large final int raidCount = Math.max(1, amount / BIG_HORDE_SIZE); final Set spawnPoints = new HashSet<>(); + int retries = 0; for (int i = 0; i < raidCount; i++) { final BlockPos targetSpawnPoint = calculateSpawnLocation(); if (targetSpawnPoint == null || targetSpawnPoint.equals(colony.getCenter()) || !colony.getWorld().getWorldBorder().isWithinBounds(targetSpawnPoint)) { + if (retries < 10) + { + retries++; + i--; + } continue; } @@ -339,7 +358,7 @@ else if ((raidType.isEmpty() || raidType.equals(DrownedPirateRaidEvent.PIRATE_RA final Holder biome = colony.getWorld().getBiome(colony.getCenter()); final int rand = colony.getWorld().random.nextInt(100); if (allowShips && (raidType.isEmpty() && (biome.is(BiomeTags.IS_TAIGA) || rand < IGNORE_BIOME_CHANCE) - || raidType.equals(NorsemenRaidEvent.NORSEMEN_RAID_EVENT_TYPE_ID.getPath())) + || raidType.equals(NorsemenRaidEvent.NORSEMEN_RAID_EVENT_TYPE_ID.getPath())) && ShipBasedRaiderUtils.canSpawnShipAt(colony, targetSpawnPoint, amount, shipRotation, NorsemenShipRaidEvent.SHIP_NAME)) { final NorsemenShipRaidEvent event = new NorsemenShipRaidEvent(colony); @@ -347,20 +366,20 @@ else if ((raidType.isEmpty() || raidType.equals(DrownedPirateRaidEvent.PIRATE_RA event.setShipSize(ShipSize.getShipForRaiderAmount(amount)); event.setShipRotation(shipRotation); event.setSpawnPath(createSpawnPath(targetSpawnPoint, false)); - event.setMaxRaiderCount(amount*2); + event.setMaxRaiderCount(amount * 2); raidEvent = event; colony.getEventManager().addEvent(event); } else if (allowShips && (raidType.isEmpty() && (biome.is(BiomeTags.IS_OCEAN)) - || raidType.equals(DrownedPirateRaidEvent.PIRATE_RAID_EVENT_TYPE_ID.getPath())) - && ShipBasedRaiderUtils.canSpawnShipAt(colony, targetSpawnPoint, amount, shipRotation, DrownedPirateRaidEvent.SHIP_NAME, DrownedPirateRaidEvent.DEPTH_REQ)) + || raidType.equals(DrownedPirateRaidEvent.PIRATE_RAID_EVENT_TYPE_ID.getPath())) + && ShipBasedRaiderUtils.canSpawnShipAt(colony, targetSpawnPoint, amount, shipRotation, DrownedPirateRaidEvent.SHIP_NAME, DrownedPirateRaidEvent.DEPTH_REQ)) { final DrownedPirateRaidEvent event = new DrownedPirateRaidEvent(colony); event.setSpawnPoint(targetSpawnPoint); event.setShipSize(ShipSize.getShipForRaiderAmount(amount)); event.setShipRotation(shipRotation); event.setSpawnPath(createSpawnPath(targetSpawnPoint, true)); - event.setMaxRaiderCount(amount*2); + event.setMaxRaiderCount(amount * 2); raidEvent = event; colony.getEventManager().addEvent(event); } @@ -372,7 +391,7 @@ else if (allowShips && ShipBasedRaiderUtils.canSpawnShipAt(colony, targetSpawnPo event.setShipSize(ShipSize.getShipForRaiderAmount(amount)); event.setShipRotation(shipRotation); event.setSpawnPath(createSpawnPath(targetSpawnPoint, false)); - event.setMaxRaiderCount(amount*2); + event.setMaxRaiderCount(amount * 2); raidEvent = event; colony.getEventManager().addEvent(event); } @@ -385,7 +404,7 @@ else if (allowShips && ShipBasedRaiderUtils.canSpawnShipAt(colony, targetSpawnPo event = new EgyptianRaidEvent(colony); } else if (((biome.is(BiomeTags.IS_JUNGLE) || (rand > IGNORE_BIOME_CHANCE * 2 && rand < IGNORE_BIOME_CHANCE * 3)) - && raidType.isEmpty()) || (raidType.equals(AmazonRaidEvent.AMAZON_RAID_EVENT_TYPE_ID.getPath()))) + && raidType.isEmpty()) || (raidType.equals(AmazonRaidEvent.AMAZON_RAID_EVENT_TYPE_ID.getPath()))) { event = new AmazonRaidEvent(colony); } @@ -415,7 +434,8 @@ else if (raidType.isEmpty() || raidType.equals(BarbarianRaidEvent.BARBARIAN_RAID colony.getEventManager().addEvent(event); } - raidHistories.get(raidHistories.size() - 1).spawnData.add(new RaidSpawnInfo(raidEvent.getEventTypeID(), targetSpawnPoint)); + getLastRaid().spawnData.add(new RaidSpawnInfo(raidEvent.getEventTypeID(), targetSpawnPoint)); + getLastRaid().difficulty = ((int) (getRaidDifficultyModifier() * 100)) / 100.0; } colony.markDirty(); return RaidSpawnResult.SUCCESS; @@ -427,7 +447,7 @@ else if (raidType.isEmpty() || raidType.equals(BarbarianRaidEvent.BARBARIAN_RAID * @param targetSpawnPoint * @return */ - private PathResult createSpawnPath(final BlockPos targetSpawnPoint, final boolean underwater) + private PathResult createSpawnPath(final BlockPos targetSpawnPoint, final boolean underwater) { final BlockPos closestBuildingPos = colony.getBuildingManager().getBestBuilding(targetSpawnPoint, IBuilding.class); final PathJobRaiderPathing job = @@ -661,8 +681,10 @@ public List getLastSpawnPoints() public int calculateRaiderAmount(final int raidLevel) { return 1 + Math.min(MineColonies.getConfig().getServer().maxRaiders.get(), - (int) ((raidLevel / SPAWN_MODIFIER) * getRaidDifficultyModifier() * (1.0 + colony.getMessagePlayerEntities().size() * INCREASE_PER_PLAYER) * (( - colony.getWorld().random.nextDouble() * 0.5d) + 0.75))); + (int) ((raidLevel / SPAWN_MODIFIER) + * getRaidDifficultyModifier() + * (1.0 + colony.getMessagePlayerEntities().size() * INCREASE_PER_PLAYER) + * ((ColonyConstants.rand.nextDouble() * 0.5d) + 0.75))); } @Override @@ -685,7 +707,7 @@ public boolean isRaided() @Override public void onNightFall() { - if (!isRaided()) + if (!isRaided() || passingThroughRaidTime > 0) { if (nightsSinceLastRaid == 0) { @@ -713,10 +735,13 @@ else if (lostPct < LOST_CITIZEN_DIFF_INCREASE_PCT) if (raidTonight) { - raidTonight = false; final boolean overrideConfig = !nextForcedType.isEmpty(); - raiderEvent(nextForcedType, overrideConfig, allowShips); - nextForcedType = INITIAL_NEXT_RAID_TYPE; + RaidSpawnResult result = raiderEvent(nextForcedType, overrideConfig, allowShips); + if (result == RaidSpawnResult.SUCCESS || result == RaidSpawnResult.TOO_SMALL) + { + raidTonight = false; + nextForcedType = INITIAL_NEXT_RAID_TYPE; + } } else { @@ -773,14 +798,35 @@ private void determineRaidForNextDay() */ public int getColonyRaidLevel() { - int levels = colony.getCitizenManager().getCitizens().size() * 10; + // TODO: after competition(civilian vs military) + int levels = 0; + + for (final ICitizenData data : colony.getCitizenManager().getCitizens()) + { + if (!data.isChild()) + { + levels += 5; + int skillSum = 0; + for (final CitizenSkillHandler.SkillData skillData : data.getCitizenSkillHandler().getSkills().values()) + { + skillSum += skillData.getLevel(); + } + levels += skillSum / 100; + } + } for (final IBuilding building : colony.getBuildingManager().getBuildings().values()) { - levels += building.getBuildingLevel() * 2; + if (building.getBuildingLevel() > 0) + { + levels += 5 + (building.getBuildingLevel() * building.getBuildingLevel()) / 5; + } } - return levels; + levels += colony.getResearchManager().getResearchTree().getCompletedList().size() * 3; + + double populationFactor = Math.min(1, (double) colony.getCitizenManager().getCurrentCitizenCount() / colony.getCitizenManager().getMaxCitizens()); + return (int) (levels * populationFactor); } /** @@ -803,7 +849,7 @@ private boolean raidThisNight(final Level world, final IColony colony) } return world.random.nextDouble() < 1.0 / (MineColonies.getConfig().getServer().averageNumberOfNightsBetweenRaids.get() - MineColonies.getConfig() - .getServer().minimumNumberOfNightsBetweenRaids.get()); + .getServer().minimumNumberOfNightsBetweenRaids.get()); } @Override @@ -861,8 +907,10 @@ public BlockPos getRandomBuilding() @Override public double getRaidDifficultyModifier() { - return ((raidDifficulty / (double) 10) + MIN_DIFFICULTY_MODIFIER) * (MinecoloniesAPIProxy.getInstance().getConfig().getServer().raidDifficulty.get() - / (double) DEFAULT_BARBARIAN_DIFFICULTY) * (colony.getWorld().getDifficulty().getId() / 2d); + return ((raidDifficulty / (double) 10) + MIN_DIFFICULTY_MODIFIER) + * (MinecoloniesAPIProxy.getInstance().getConfig().getServer().raidDifficulty.get() / (double) DEFAULT_BARBARIAN_DIFFICULTY) + * (colony.getWorld().getDifficulty().getId() / 2d) + * spawnCountAdjustedDifficulty; } @Override @@ -990,6 +1038,7 @@ public void setPassThroughRaid() /** * Gets all raid histories + * * @return */ public List getAllRaids() @@ -1008,6 +1057,7 @@ public static class RaidHistory static final String TAG_LOSTCITIZENS = "lostCitizens"; static final String TAG_RAIDERAMOUNT = "raiderAmount"; static final String TAG_RAIDTIME = "raidTime"; + static final String TAG_DIFFICULTY = "difficulty"; static final String TAG_SPAWNINFO = "spawnInfo"; /** @@ -1030,6 +1080,11 @@ public static class RaidHistory */ public final long raidTime; + /** + * The difficulty modifier of the raid + */ + public double difficulty = 0; + /** * List of raid types and their spawnpoints */ @@ -1047,6 +1102,7 @@ private CompoundTag write() tag.putInt(TAG_LOSTCITIZENS, lostCitizens); tag.putInt(TAG_RAIDERAMOUNT, raiderAmount); tag.putLong(TAG_RAIDTIME, raidTime); + tag.putDouble(TAG_DIFFICULTY, difficulty); ListTag nbtList = new ListTag(); for (final RaidSpawnInfo raidSpawnInfo : spawnData) { @@ -1060,6 +1116,7 @@ private static RaidHistory fromNBT(final CompoundTag tag) { RaidHistory history = new RaidHistory(tag.getInt(TAG_RAIDERAMOUNT), tag.getLong(TAG_RAIDTIME)); history.lostCitizens = tag.getInt(TAG_LOST_CITIZENS); + history.difficulty = tag.getDouble(TAG_DIFFICULTY); ListTag nbtList = tag.getList(TAG_SPAWNINFO, Tag.TAG_COMPOUND); for (final Tag entry : nbtList) { @@ -1076,6 +1133,7 @@ public String toString() + "\nRaiders spawned: " + raiderAmount + "\nRaiders killed: " + deadRaiders + "\nCitizens lost: " + lostCitizens + + "\nDifficulty: " + difficulty + "\nSpawns:" + spawnData.stream().map(Object::toString).collect(Collectors.joining("\n")); } } diff --git a/src/main/java/com/minecolonies/core/colony/managers/CitizenManager.java b/src/main/java/com/minecolonies/core/colony/managers/CitizenManager.java index b70d89af673..87a5e160677 100755 --- a/src/main/java/com/minecolonies/core/colony/managers/CitizenManager.java +++ b/src/main/java/com/minecolonies/core/colony/managers/CitizenManager.java @@ -529,7 +529,7 @@ public double maxCitizensFromResearch() @Override public int getCurrentCitizenCount() { - return citizens.size() + colony.getGraveManager().getGraves().size(); + return citizens.size(); } @Override diff --git a/src/main/java/com/minecolonies/core/commands/citizencommands/CommandCitizenInfo.java b/src/main/java/com/minecolonies/core/commands/citizencommands/CommandCitizenInfo.java index 3a348371fb5..356ca0820c6 100755 --- a/src/main/java/com/minecolonies/core/commands/citizencommands/CommandCitizenInfo.java +++ b/src/main/java/com/minecolonies/core/commands/citizencommands/CommandCitizenInfo.java @@ -89,12 +89,13 @@ public int onExecute(final CommandContext context) context.getSource().sendSuccess(() -> Component.translatable(CommandTranslationConstants.COMMAND_CITIZEN_INFO_HEALTH, entityCitizen.getHealth(), entityCitizen.getMaxHealth()), true); Object[] skills = - new Object[] {citizenData.getCitizenSkillHandler().getSkills().get(Skill.Athletics).getA(), citizenData.getCitizenSkillHandler().getSkills().get(Skill.Dexterity).getA(), - citizenData.getCitizenSkillHandler().getSkills().get(Skill.Strength).getA(), citizenData.getCitizenSkillHandler().getSkills().get(Skill.Agility).getA(), - citizenData.getCitizenSkillHandler().getSkills().get(Skill.Stamina).getA(), citizenData.getCitizenSkillHandler().getSkills().get(Skill.Mana).getA(), - citizenData.getCitizenSkillHandler().getSkills().get(Skill.Adaptability).getA(), citizenData.getCitizenSkillHandler().getSkills().get(Skill.Focus).getA(), - citizenData.getCitizenSkillHandler().getSkills().get(Skill.Creativity).getA(), citizenData.getCitizenSkillHandler().getSkills().get(Skill.Knowledge).getA(), - citizenData.getCitizenSkillHandler().getSkills().get(Skill.Intelligence).getA()}; + new Object[] {citizenData.getCitizenSkillHandler().getSkills().get(Skill.Athletics).getLevel(), + citizenData.getCitizenSkillHandler().getSkills().get(Skill.Dexterity).getLevel(), + citizenData.getCitizenSkillHandler().getSkills().get(Skill.Strength).getLevel(), citizenData.getCitizenSkillHandler().getSkills().get(Skill.Agility).getLevel(), + citizenData.getCitizenSkillHandler().getSkills().get(Skill.Stamina).getLevel(), citizenData.getCitizenSkillHandler().getSkills().get(Skill.Mana).getLevel(), + citizenData.getCitizenSkillHandler().getSkills().get(Skill.Adaptability).getLevel(), citizenData.getCitizenSkillHandler().getSkills().get(Skill.Focus).getLevel(), + citizenData.getCitizenSkillHandler().getSkills().get(Skill.Creativity).getLevel(), citizenData.getCitizenSkillHandler().getSkills().get(Skill.Knowledge).getLevel(), + citizenData.getCitizenSkillHandler().getSkills().get(Skill.Intelligence).getLevel()}; context.getSource().sendSuccess(() -> Component.translatable(CommandTranslationConstants.COMMAND_CITIZEN_INFO_SKILLS, skills), true); if (entityCitizen.getCitizenJobHandler().getColonyJob() == null) diff --git a/src/main/java/com/minecolonies/core/commands/colonycommands/CommandListColonies.java b/src/main/java/com/minecolonies/core/commands/colonycommands/CommandListColonies.java index f2745ebafd3..f65795b2afe 100755 --- a/src/main/java/com/minecolonies/core/commands/colonycommands/CommandListColonies.java +++ b/src/main/java/com/minecolonies/core/commands/colonycommands/CommandListColonies.java @@ -104,9 +104,10 @@ private int executeCommand(final CommandContext context, fin String.format(COMMAND_COLONY_INFO, colony.getID())))), true); final BlockPos center = colony.getCenter(); - final MutableComponent teleport = Component.literal(COORDINATES_TEXT + String.format(COORDINATES_XYZ, center.getX(), center.getY(), center.getZ())); - teleport.setStyle(Style.EMPTY.withBold(true).withColor(ChatFormatting.GOLD).withClickEvent( - new ClickEvent(ClickEvent.Action.RUN_COMMAND, TELEPORT_COMMAND + colony.getID()))); + final MutableComponent teleport = Component.literal("Citizens:" + colony.getCitizenManager().getCurrentCitizenCount() + " ") + .append(Component.literal(COORDINATES_TEXT + String.format(COORDINATES_XYZ, center.getX(), center.getY(), center.getZ())) + .setStyle(Style.EMPTY.withBold(true).withColor(ChatFormatting.GOLD).withClickEvent( + new ClickEvent(ClickEvent.Action.RUN_COMMAND, TELEPORT_COMMAND + colony.getID())))); context.getSource().sendSuccess(() -> teleport, true); } diff --git a/src/main/java/com/minecolonies/core/entity/citizen/citizenhandlers/CitizenSkillHandler.java b/src/main/java/com/minecolonies/core/entity/citizen/citizenhandlers/CitizenSkillHandler.java index 5f94d86e915..592c8b5b8ea 100755 --- a/src/main/java/com/minecolonies/core/entity/citizen/citizenhandlers/CitizenSkillHandler.java +++ b/src/main/java/com/minecolonies/core/entity/citizen/citizenhandlers/CitizenSkillHandler.java @@ -1,6 +1,5 @@ package com.minecolonies.core.entity.citizen.citizenhandlers; -import com.google.common.collect.ImmutableMap; import com.minecolonies.api.colony.ICitizenData; import com.minecolonies.api.colony.IColony; import com.minecolonies.api.colony.buildings.IBuilding; @@ -14,11 +13,11 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; -import net.minecraft.util.Tuple; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; +import java.util.Collections; +import java.util.EnumMap; import java.util.Map; import java.util.Random; @@ -36,7 +35,7 @@ public class CitizenSkillHandler implements ICitizenSkillHandler /** * Skill map. */ - public Map> skillMap = new HashMap<>(); + public Map skillMap = new EnumMap<>(Skill.class); @Override public void init(final int levelCap) @@ -45,7 +44,7 @@ public void init(final int levelCap) { for (final Skill skill : Skill.values()) { - skillMap.put(skill, new Tuple<>(1, 0.0D)); + skillMap.put(skill, new SkillData(1, 0.0D)); } } else @@ -53,7 +52,7 @@ public void init(final int levelCap) final Random random = new Random(); for (final Skill skill : Skill.values()) { - skillMap.put(skill, new Tuple<>(random.nextInt(levelCap - 1) + 1, 0.0D)); + skillMap.put(skill, new SkillData(random.nextInt(levelCap - 1) + 1, 0.0D)); } } } @@ -90,19 +89,18 @@ public void init(@NotNull final IColony colony, @Nullable final ICitizenData fir int totalPoints = 0; for (final Skill skill : Skill.values()) { - final int firstRoleModelLevel = roleModelA.getCitizenSkillHandler().getSkills().get(skill).getA(); - final int secondRoleModelLevel = roleModelB.getCitizenSkillHandler().getSkills().get(skill).getA(); + final int firstRoleModelLevel = roleModelA.getCitizenSkillHandler().getSkills().get(skill).level; + final int secondRoleModelLevel = roleModelB.getCitizenSkillHandler().getSkills().get(skill).level; totalPoints += firstRoleModelLevel + secondRoleModelLevel; } for (final Skill skill : Skill.values()) { - final double firstRoleModelLevel = roleModelA.getCitizenSkillHandler().getSkills().get(skill).getA(); - final double secondRoleModelLevel = roleModelB.getCitizenSkillHandler().getSkills().get(skill).getA(); + final double firstRoleModelLevel = roleModelA.getCitizenSkillHandler().getSkills().get(skill).level; + final double secondRoleModelLevel = roleModelB.getCitizenSkillHandler().getSkills().get(skill).level; int newPoints = (int) (((firstRoleModelLevel + secondRoleModelLevel) / totalPoints) * bonusPoints); - - skillMap.put(skill, new Tuple<>(skillMap.get(skill).getA() + newPoints, 0.0D)); + skillMap.get(skill).level += newPoints; } } @@ -113,14 +111,14 @@ public CompoundTag write() final CompoundTag compoundNBT = new CompoundTag(); @NotNull final ListTag levelTagList = new ListTag(); - for (@NotNull final Map.Entry> entry : skillMap.entrySet()) + for (@NotNull final Map.Entry entry : skillMap.entrySet()) { if (entry.getKey() != null && entry.getValue() != null) { @NotNull final CompoundTag levelCompound = new CompoundTag(); levelCompound.putInt(TAG_SKILL, entry.getKey().ordinal()); - levelCompound.putInt(TAG_LEVEL, entry.getValue().getA()); - levelCompound.putDouble(TAG_EXPERIENCE, entry.getValue().getB()); + levelCompound.putInt(TAG_LEVEL, entry.getValue().level); + levelCompound.putDouble(TAG_EXPERIENCE, entry.getValue().experience); levelTagList.add(levelCompound); } } @@ -137,7 +135,7 @@ public void read(@NotNull final CompoundTag compoundNBT) { final CompoundTag levelExperienceAtJob = levelTagList.getCompound(i); skillMap.put(Skill.values()[levelExperienceAtJob.getInt(TAG_SKILL)], - new Tuple<>(Math.max(1, Math.min(levelExperienceAtJob.getInt(TAG_LEVEL), MAX_CITIZEN_LEVEL)), levelExperienceAtJob.getDouble(TAG_EXPERIENCE))); + new SkillData(Math.max(1, Math.min(levelExperienceAtJob.getInt(TAG_LEVEL), MAX_CITIZEN_LEVEL)), levelExperienceAtJob.getDouble(TAG_EXPERIENCE))); } } @@ -150,7 +148,7 @@ public boolean tryLevelUpIntelligence(@NotNull final Random random, final double } final int levelCap = (int) citizen.getCitizenHappinessHandler().getHappiness(citizen.getColony(), citizen); - if (skillMap.get(Skill.Intelligence).getA() < levelCap * 9) + if (skillMap.get(Skill.Intelligence).level < levelCap * 9) { addXpToSkill(Skill.Intelligence, 10, citizen); } @@ -160,50 +158,50 @@ public boolean tryLevelUpIntelligence(@NotNull final Random random, final double @Override public int getLevel(@NotNull final Skill skill) { - return skillMap.get(skill).getA(); + return skillMap.get(skill).level; } @Override public void incrementLevel(@NotNull final Skill skill, final int level) { - final Tuple current = skillMap.get(skill); - skillMap.put(skill, new Tuple<>(Math.min(MAX_CITIZEN_LEVEL, Math.max(current.getA() + level, 1)), current.getB())); + final SkillData current = skillMap.get(skill); + current.level = Math.min(MAX_CITIZEN_LEVEL, Math.max(current.level + level, 1)); } @Override public void addXpToSkill(final Skill skill, final double xp, final ICitizenData data) { - final Tuple tuple = skillMap.getOrDefault(skill, new Tuple<>(0, 0.0D)); - int level = tuple.getA(); - final double currentXp = tuple.getB(); + final SkillData skillData = skillMap.getOrDefault(skill, new SkillData(0, 0.0D)); final IBuilding home = data.getHomeBuilding(); final double citizenHutLevel = home == null ? 0 : home.getBuildingLevel(); final double citizenHutMaxLevel = home == null ? MAX_BUILDING_LEVEL : home.getMaxBuildingLevel(); - if (((citizenHutLevel < citizenHutMaxLevel || citizenHutMaxLevel < MAX_BUILDING_LEVEL) && (citizenHutLevel + 1) * 10 <= level) || level >= MAX_CITIZEN_LEVEL) + if (((citizenHutLevel < citizenHutMaxLevel || citizenHutMaxLevel < MAX_BUILDING_LEVEL) && (citizenHutLevel + 1) * 10 <= skillData.level) + || skillData.level >= MAX_CITIZEN_LEVEL) { return; } - double xpToLevelUp = Math.min(Double.MAX_VALUE, currentXp + xp); + final int orgLevel = skillData.level; + double xpToLevelUp = Math.min(Double.MAX_VALUE, skillData.experience + xp); while (xpToLevelUp > 0) { - final double nextLevel = ExperienceUtils.getXPNeededForNextLevel(level); + final double nextLevel = ExperienceUtils.getXPNeededForNextLevel(skillData.level); if (nextLevel > xpToLevelUp) { - skillMap.put(skill, new Tuple<>(Math.min(MAX_CITIZEN_LEVEL, level), xpToLevelUp)); - xpToLevelUp = 0; + skillData.experience = xpToLevelUp; + break; } else { xpToLevelUp = xpToLevelUp - nextLevel; - level++; + skillData.level++; } } - if (level > tuple.getA()) + if (skillData.level > orgLevel) { levelUp(data); data.markDirty(10); @@ -213,30 +211,24 @@ public void addXpToSkill(final Skill skill, final double xp, final ICitizenData @Override public void removeXpFromSkill(@NotNull final Skill skill, final double xp, @NotNull final ICitizenData data) { - final Tuple tuple = skillMap.get(skill); - int level = tuple.getA(); - double currentXp = tuple.getB(); + final SkillData skillData = skillMap.get(skill); - double xpToDiscount = xp; - while (xpToDiscount > 0) + double xpToRemove = xp; + while (xpToRemove > 0) { - if (currentXp >= xpToDiscount || level <= 1) + if (skillData.experience >= xpToRemove || skillData.level <= 1) { - skillMap.put(skill, new Tuple<>(Math.max(1, level), Math.max(0, currentXp - xpToDiscount))); + skillData.experience = Math.max(0, skillData.experience - xpToRemove); break; } else { - xpToDiscount -= currentXp; - currentXp = ExperienceUtils.getXPNeededForNextLevel(level - 1); - level--; + xpToRemove -= skillData.experience; + skillData.experience = ExperienceUtils.getXPNeededForNextLevel(skillData.level - 1); + skillData.level--; + data.markDirty(40); } } - - if (level < tuple.getA()) - { - data.markDirty(10); - } } @Override @@ -262,16 +254,48 @@ public void levelUp(final ICitizenData data) public double getTotalXP() { double totalXp = 0; - for (final Tuple tuple : skillMap.values()) + for (SkillData tuple : skillMap.values()) { - totalXp += tuple.getB(); + totalXp += tuple.experience; } return totalXp; } @Override - public Map> getSkills() + public Map getSkills() { - return ImmutableMap.copyOf(skillMap); + return Collections.unmodifiableMap(skillMap); + } + + public static class SkillData + { + private int level; + private double experience; + + private SkillData(final int level, final double experience) + { + this.level = level; + this.experience = experience; + } + + public int getLevel() + { + return level; + } + + public void setLevel(final int level) + { + this.level = level; + } + + public double getExperience() + { + return experience; + } + + public void setExperience(final double experience) + { + this.experience = experience; + } } } diff --git a/src/main/java/com/minecolonies/core/research/LocalResearchTree.java b/src/main/java/com/minecolonies/core/research/LocalResearchTree.java index c3f0b5effa8..ab84ee4d193 100644 --- a/src/main/java/com/minecolonies/core/research/LocalResearchTree.java +++ b/src/main/java/com/minecolonies/core/research/LocalResearchTree.java @@ -415,11 +415,7 @@ public void readFromNBT(final CompoundTag compound, final IResearchEffectManager }); } - /** - * Get the list of all finished researches - * - * @return a copy of the completed list. - */ + @Override public List getCompletedList() { return new ArrayList<>(isComplete);