Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add processing of multiple fluff images (WIP) #5490

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added megamek/data/images/fluff/fluff_placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
#building block data file
<BlockVersion>
1
</BlockVersion>

# Write the version number just in case...
<Version>
MAM0
</Version>

#Saved from version 0.50.0-SNAPSHOT on 2024-08-05
<UnitType>
Tank
</UnitType>
Expand All @@ -16,9 +7,9 @@ Tank
Destrier Siege Vehicle
</Name>

<model>
<Model>

</model>
</Model>

<mul id:>
6329
Expand All @@ -28,6 +19,10 @@ Destrier Siege Vehicle
3100
</year>

<originalBuildYear>
3100
</originalBuildYear>

<type>
IS Level 3
</type>
Expand All @@ -36,6 +31,13 @@ IS Level 3
Sniper
</role>

<quirks>
imp_target_long
oversized
non_standard
poor_performance
</quirks>

<motion_type>
Tracked
</motion_type>
Expand Down Expand Up @@ -71,8 +73,9 @@ troopspace:4.0
</armor>

<Body Equipment>
SponsonTurret
ISCASE
Communications Equipment (1 ton)
Communications Equipment:SIZE:1.0
ISGuardianECMSuite
ISC3SlaveUnit
ISAMS Ammo
Expand All @@ -97,7 +100,6 @@ IS Light Machine Gun Ammo - Full
ISAntiMissileSystem(ST)
Light Machine Gun(ST)
Light Machine Gun(ST)
ISSponsonTurret
</Front Right Equipment>

<Front Left Equipment>
Expand Down Expand Up @@ -127,6 +129,34 @@ ISERMediumLaser
ISAntiMissileSystem
</Turret Equipment>

<capabilities>
Twice the mass of a conventional assault tank, wrapped in almost forty tons of hardened armor, and armed with a pair of turreted Long Tom assault cannons, the Destrier excels at reducing enemy fortifications to dust within minutes of its arrival. Heavy defensive weaponry and thick armor just barely compensate for its slow speed, however.
</capabilities>

<overview>
Despite the formation of its light combat teams and its public declarations of defensive doctrine, the adoption of the Destrier Siege Vehicle at the turn of the thirty-second century proved that the AFFS hadn’t completely rejected offensive warfare. The Federated Suns' involvement in the Victoria War, where it acted as the aggressor, demonstrated to the Inner Sphere that it had not forgotten Hanse Davion’s lessons.
</overview>

<history>
Given the relative scarcity of AFFS invasions, the most notable engagement to feature the Destrier came on Spica in 3104. The Eighth Avalon Hussars light combat team, the world’s garrison, was attacked by the Third McCarron’s Armored Cavalry. Unable to stand against the Third directly, the Eighth planned an ambush with the company of Destriers assigned to it. Using her ’Mechs as bait and her hovertanks as harassers, General Stasi Ivanova led the Capellan vanguard into a valley and destroyed it with concentrated Long Tom fire. As missile artillery began to fall from the Destriers’ attached Ballista trailers, the Hussars ’Mechs counterattacked and drove the Capellans into retreat.
<p>Several times during the Kuritan invasion, Destriers and their crews have been sacrificed—voluntarily or not—as forlorn hopes to let battered Davion units escape. Too slow to retreat and too large to be easily evacuated, the Destriers make fine last-line holders. On Barlow’s End, for instance, a platoon of Destriers set itself outside the gates of the Princess Melissa spaceport. As the DCMS advanced, the Second New Ivaarsen Chasseurs withdrew to their DropShips. A small group of lottery-chosen VTOLs and hovertanks remained to designate targets for the Ballistas’ Arrow IV missiles, while the Destriers hid themselves among the spaceport buildings. As the lead ’Mechs of Ryuken-roku advanced, the Destriers fired from cover, causing enough confusion that the DropShips could escape. None of the Destrier crews survived to be captured.</p>
</history>

<manufacturer>
General Motors
</manufacturer>

<primaryFactory>
Salem
</primaryFactory>

<systemManufacturers>
ENGINE:GM SuperLoad 400 XL Fusion
ARMOR:Johnston Bastion Plate 530 Hardened with CASE
COMMUNICATIONS:Electronics HICS-17 with C3 Slave and Guardian ECM Suite
TARGETING:Federated Bombard Mk. II
</systemManufacturers>

<source>
TRO: 3145 Federated Suns
</source>
Expand All @@ -135,10 +165,3 @@ TRO: 3145 Federated Suns
200.0
</tonnage>

<quirks>
imp_target_long
oversized
poor_performance
non_standard
</quirks>

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Disclaimer
Version 1.0 | Date: August 9th, 2024

Content Creation Notice

Some of the lore and narrative content within MegaMek has been generated using OpenAI's ChatGPT. This AI-assisted content creation aims to enhance the game's depth and provide players with a richer experience.

Important Points to Note:

Accuracy and Consistency: While we strive to maintain the accuracy and consistency of the BattleTech universe, there may be occasional deviations or errors in the AI-generated content. We appreciate your understanding and welcome feedback to improve these elements.

Intellectual Property: All AI-generated content is created with respect to the intellectual property holders and those that license the Tabletop properties of the BattleTech universe. However, it is important to note that this content is unofficial and not directly endorsed by these entities. Additionally, MechWarrior, BattleMech, ‘Mech, and AeroTech are registered trademarks of The Topps Company, Inc. All Rights Reserved.

Ethical Use: We ensure that all AI-generated content adheres to ethical standards and does not contain inappropriate or sensitive material. Our team reviews and moderates this content to ensure it aligns with the community's expectations.

Use of AI: We use AI specifically for certain art in splash screens, editing fluff text within the programs, and developing news articles for MekHQ.

Feedback and Contributions: We value the input of our community. If you notice any issues or have suggestions for improving the AI-generated content, please reach out to us. Your feedback helps us refine and enhance the game.

Thank you for being a part of the MegaMek community and for supporting our efforts to bring a more immersive experience to the BattleTech universe.
130 changes: 130 additions & 0 deletions megamek/src/megamek/client/ui/swing/FluffImageTooltip.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2024 - The MegaMek Team. All Rights Reserved.
*
* This file is part of MegaMek.
*
* MegaMek is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MegaMek is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MegaMek. If not, see <http://www.gnu.org/licenses/>.
*/
package megamek.client.ui.swing;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import megamek.client.ui.swing.util.FluffImageHelper;
import megamek.client.ui.swing.util.UIUtil;
import org.apache.logging.log4j.LogManager;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

/**
* This class is very specialized. It provides tooltip information for the fluff image tooltip in the
* MechViewPanel, taken from yaml files that are supplied with painted minis images.
*/
public class FluffImageTooltip {

private static final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());

public static String styles() {
int labelSize = UIUtil.scaleForGUI(UIUtil.FONT_SCALE1);
Color color = GUIPreferences.getInstance().getToolTipLightFGColor();
String styleColor = Integer.toHexString(color.getRGB() & 0xFFFFFF);
return "span { font-family:Noto Sans; font-size:" + labelSize + "; }"
+ ".label { color:" + styleColor + "; }";
}

/**
* Returns the tooltip text for the supplied FluffImageRecord, if any can be found, null otherwise.
*
* @param record The FluffImageRecord that is currently shown as an image
* @return A tooltip text or null if no yaml info is available
*/
public static String getTooltip(FluffImageHelper.FluffImageRecord record) {
return findYamlInfo(record).map(FluffImageTooltip::getTooltip).orElse(null);
}

private static Optional<File> findYamlInfo(FluffImageHelper.FluffImageRecord record) {
return (record.file() == null) ? Optional.empty() : getYamlFile(record.file());
}

private static String getTooltip(File yamlFile) {
try {
JsonNode node = yamlMapper.readTree(yamlFile);

StringBuilder result = new StringBuilder("<HTML><HEAD><STYLE>" + styles() + "</STYLE></HEAD><BODY>");
int width = UIUtil.scaleForGUI(360);
result.append("<div width=").append(width).append(">");

if (node.has("title")) {
String unit = node.get("title").asText();
if (!unit.isBlank()) {
result.append(UIUtil.spanCSS("label", "Unit: "))
.append(UIUtil.spanCSS("value", unit));
}
}
if (node.has("author")) {
String artist = node.get("author").asText();
if (!artist.isBlank()) {
result.append(UIUtil.spanCSS("label", "<BR>Artist: "))
.append(UIUtil.spanCSS("value", artist));
}
}
if (node.has("content")) {
JsonNode contentNode = node.get("content");
String description = findInsignia(contentNode);
if (!description.isBlank()) {
result.append(UIUtil.spanCSS("label", "<BR>Insignia: "))
.append(UIUtil.spanCSS("value", description));
}
}
result.append("</div></BODY></HTML>");
return result.toString();
} catch (IOException e) {
return null;
}
}

private static String findInsignia(JsonNode contentNode) {
List<JsonNode> nodes = new ArrayList<>();
contentNode.iterator().forEachRemaining(nodes::add);
for (JsonNode node : nodes) {
if (node.has("type") && node.get("type").asText().equals("insignia")) {
return node.get("content").asText();
}
}
return "";
}

private static Optional<File> getYamlFile(File imageFile) {
try (Stream<Path> entries = Files.walk(imageFile.getParentFile().toPath())) {
return entries.filter(p -> isSuitableYamlFile(p, imageFile)).map(Path::toFile).findFirst();
} catch (Exception e) {
LogManager.getLogger().warn("Error while reading files from {}", imageFile.getParentFile(), e);
return Optional.empty();
}
}

private static boolean isSuitableYamlFile(Path yamlFile, File imageFile) {
String yamlFileName = yamlFile.getFileName().toString();
return !Files.isDirectory(yamlFile) && yamlFileName.endsWith("data.yaml")
&& imageFile.getName().contains(yamlFileName.substring(0, yamlFileName.length() - 9));
}
}
Loading