diff --git a/src/10th/Roster.jsx b/src/10th/Roster.jsx
index a007fad..850e5cc 100644
--- a/src/10th/Roster.jsx
+++ b/src/10th/Roster.jsx
@@ -3,10 +3,16 @@ import factionBackground from "../assets/factionBackground.png";
import keywordsBackground from "../assets/keywordsBackground.png";
import cardBackground from "../assets/cardBackground.png";
import dgBackground from "../assets/dgBackground.png";
+import tauBackground from "../assets/tauBackground.png";
+import tyranidBackground from "../assets/tyranidBackground.png";
+import mechanicusBackground from "../assets/mechanicusBackground.png";
+import orkBackground from "../assets/orkBackground.png";
+import necronBackground from "../assets/necronBackground.png";
import { Arrow, wavyLine } from "../assets/icons";
import { Weapons, hasDifferentProfiles } from "./Weapons";
import { useIndexedDB } from "../helpers/useIndexedDB"; // New hook for IndexedDB
import { ImgEditor } from "./ImgEditor";
+import { trySettingLocalStorage } from "../helpers/useLocalStorage";
export const Roster = ({ roster, onePerPage, colorUserChoice }) => {
if (!roster) {
@@ -249,10 +255,7 @@ const Unit = ({
paddingBottom: 4,
background:
"linear-gradient(90deg, rgba(20,21,25,1) 0%, rgba(48,57,62,1) 45%, rgba(73,74,79,1) 100%)",
- backgroundImage:
- catalog === "Chaos - Death Guard"
- ? `url(${dgBackground})`
- : `url(${factionBackground})`,
+ backgroundImage: `url(${backgrounds[catalog] ? backgrounds[catalog] : factionBackground})`,
backgroundSize: "cover",
color: "#fff",
position: "relative",
@@ -371,7 +374,7 @@ const Unit = ({
top: 0,
height: "100%",
bottom: 0,
- width: "50%",
+ width: "60%",
zIndex: 100,
overflow: "hidden",
}}
@@ -437,6 +440,9 @@ const Unit = ({
reader.onload = function (ev) {
setImage(ev.target.result);
setBgRemoved(false);
+ // reset position of the image
+ trySettingLocalStorage(`positionX_${name}`, 0, () => {});
+ trySettingLocalStorage(`positionY_${name}`, 0, () => {});
}.bind(this);
reader.readAsDataURL(e.target.files[0]);
}
@@ -569,6 +575,15 @@ const Unit = ({
);
};
+const backgrounds = {
+ "Imperium - Adeptus Mechanicus": mechanicusBackground,
+ "Chaos - Death Guard": dgBackground,
+ "Xenos - T'au Empire": tauBackground,
+ "Xenos - Tyranids": tyranidBackground,
+ "Xenos - Orks": orkBackground,
+ "Xenos - Necrons": necronBackground,
+};
+
const checkAbilitiesForInvul = (abilitiesMap, name) => {
const abilities = [...(abilitiesMap?.keys?.() || [])];
for (let ability of abilities) {
@@ -583,7 +598,9 @@ const checkAbilitiesForInvul = (abilitiesMap, name) => {
continue;
}
}
- switch (abilitiesMap.get(ability)?.trim()?.toLowerCase().replace(".", "")) {
+ switch (
+ abilitiesMap.get(ability)?.trim()?.toLowerCase().replaceAll(".", "")
+ ) {
case "2+":
if (ability?.toLowerCase().includes("invulnerable save")) return "2+";
break;
@@ -662,15 +679,15 @@ const checkAbilitiesForInvul = (abilitiesMap, name) => {
case "this model has a 6+ invulnerable save against ranged weapons":
return "6+*";
- case "this model has a 2+ invulnerable save. you cannot re-roll invulnerable saving throws made for this model":
+ case "this model has a 2+ invulnerable save you cannot re-roll invulnerable saving throws made for this model":
return "2+*";
- case "this model has a 3+ invulnerable save. you cannot re-roll invulnerable saving throws made for this model":
+ case "this model has a 3+ invulnerable save you cannot re-roll invulnerable saving throws made for this model":
return "3+*";
- case "this model has a 4+ invulnerable save. you cannot re-roll invulnerable saving throws made for this model":
+ case "this model has a 4+ invulnerable save you cannot re-roll invulnerable saving throws made for this model":
return "4+*";
- case "this model has a 5+ invulnerable save. you cannot re-roll invulnerable saving throws made for this model":
+ case "this model has a 5+ invulnerable save you cannot re-roll invulnerable saving throws made for this model":
return "5+*";
- case "this model has a 6+ invulnerable save. you cannot re-roll invulnerable saving throws made for this model":
+ case "this model has a 6+ invulnerable save you cannot re-roll invulnerable saving throws made for this model":
return "6+*";
}
}
@@ -696,14 +713,17 @@ const ModelStats = ({ modelStat, index, showName, abilities }) => {
{showName && (
),
+ "Xenos - Necrons": (
+
+ ),
+ "Xenos - T'au Empire": (
+
+ ),
};
const Keywords = ({ keywords }) => {
@@ -972,7 +1020,7 @@ const Rules = ({ rules }) => {
const removeInvulnsWithoutSpecialRules = (abilities) => {
const filteredAbilities = new Map();
for (let [key, value] of abilities) {
- switch (value?.trim()?.toLowerCase().replace(".", "")) {
+ switch (value?.trim()?.toLowerCase().replaceAll(".", "")) {
case "2+":
if (!key?.toLowerCase().includes("invulnerable save"))
filteredAbilities.set(key, value);
@@ -1048,10 +1096,13 @@ const boldKeywords = [
"heretic astartes",
"adeptus astartes",
"adeptus mechanicus",
+ "halo override",
"adeptus custodes",
"adeptus sororitas",
"tyranids",
+ "termagants",
"orks",
+ "necrons",
];
const weaponKeywords = [
@@ -1064,43 +1115,47 @@ const weaponKeywords = [
"indirect fire",
"sustained hits 1",
"sustained hits 2",
+ "sustained hits x",
"devastating wounds",
+ "precision",
+ "ignores cover",
];
const Abilities = ({ abilities }) => {
if (!abilities) return null;
- const filteredAbilities = removeInvulnsWithoutSpecialRules(abilities);
+ let filteredAbilities = removeInvulnsWithoutSpecialRules(abilities);
- let keys = [...filteredAbilities.keys()];
+ // sort abilites so that "Leader" is always at the bottom, "Supreme Commander" also bottom but before "Leader", same for any invulnerable save
+ let abilitiesForEnd = new Map();
+ for (let [key, value] of filteredAbilities) {
+ if (key.toLowerCase().includes("invulnerable save")) {
+ filteredAbilities.delete(key);
+ abilitiesForEnd.set(key, value);
+ }
+ if (key.toLowerCase().includes("damaged: ")) {
+ filteredAbilities.delete(key);
+ abilitiesForEnd.set(key, value);
+ }
+ }
+ if (filteredAbilities.has("Supreme Commander")) {
+ const supremeCommander = filteredAbilities.get("Supreme Commander");
+ filteredAbilities.delete("Supreme Commander");
+ abilitiesForEnd.set("Supreme Commander", supremeCommander);
+ }
+ if (filteredAbilities.has("Leader")) {
+ const leader = filteredAbilities.get("Leader");
+ filteredAbilities.delete("Leader");
+ abilitiesForEnd.set("Leader", leader);
+ }
+ filteredAbilities = new Map([...filteredAbilities, ...abilitiesForEnd]);
const replacedAbilities = new Map();
// in the value of the filtered abilites, make certain keywords bold
for (let [key, value] of filteredAbilities) {
- let newValue = value;
- for (let keyword of boldKeywords) {
- newValue = newValue.replace(
- new RegExp(`\\b${keyword}\\b`, "gi"),
- `${keyword.toUpperCase()}`,
- );
- }
-
- // weaponKeywords could be with [] or without
- for (let keyword of weaponKeywords) {
- newValue = newValue.replace(
- new RegExp(`\\[${keyword}\\]`, "gi"),
- `[${keyword.toUpperCase()}]`,
- );
- if (keyword !== "assault") {
- newValue = newValue.replace(
- new RegExp(`\\b${keyword}\\b`, "gi"),
- `${keyword.toUpperCase()}`,
- );
- }
- }
-
- replacedAbilities.set(key, newValue);
+ replacedAbilities.set(key, makeKeywordsBold(value));
}
+ let keys = [...filteredAbilities.keys()];
return (
{
);
};
+const makeKeywordsBold = (text) => {
+ let newValue = text;
+ for (let keyword of boldKeywords) {
+ newValue = newValue.replace(
+ new RegExp(`\\b${keyword}\\b`, "gi"),
+ `${keyword.toUpperCase()}`,
+ );
+ }
+
+ // weaponKeywords could be with [] or without
+ for (let keyword of weaponKeywords) {
+ newValue = newValue.replace(
+ new RegExp(`\\[${keyword}\\]`, "gi"),
+ `[${keyword.toUpperCase()}]`,
+ );
+ if (keyword !== "assault") {
+ // replace without [] only if it is not "assault" and not already replaced
+ newValue = newValue.replace(
+ new RegExp(`(?[${keyword.toUpperCase()}]`,
+ );
+ }
+ }
+ // replace two newlines with one but only if there are two newlines in a row
+ return newValue.replace(/\n\n+/g, "\n\n");
+};
+
const Characteristic = ({ title, characteristic, index }) => {
return (