Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Added

- Added the `cannot_modify_cost` tag for patterns that should ignore the `media_consumption` attribute when calculating cost, by Robotgiggle in [987](https://github.com/FallingColors/HexMod/pull/987).
- Added a config option to rescale the cost of specific actions, by Robotgiggle in [#1041](https://github.com/FallingColors/HexMod/pull/1041).

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,15 @@ public void precheckAction(PatternShapeMatch match) throws Mishap {
throw new MishapDisallowedSpell("disallowed", loc);
}

costModifier = this.getCostModifier(match);
costModifier = (loc != null) ? this.getCostModifier(loc) : 1.0;
}

/**
* Casting env subclasses can override this to modify the cost for a given action
* Gets the cost modifier for a given action. By default, this is based on the cost scaling list
* in the config. Casting env subclasses can override this to modify the cost in other ways.
*/
protected double getCostModifier(PatternShapeMatch match) {
return 1.0;
protected double getCostModifier(@NotNull ResourceLocation loc) {
return HexConfig.server().getActionCostScaling(loc);
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameType;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
Expand Down Expand Up @@ -71,12 +72,12 @@ public ServerPlayer getCaster() {
}

@Override
protected double getCostModifier(PatternShapeMatch match) {
ResourceLocation loc = actionKey(match);
if (loc != null && isOfTag(IXplatAbstractions.INSTANCE.getActionRegistry(), loc, HexTags.Actions.CANNOT_MODIFY_COST)) {
return 1.0;
protected double getCostModifier(@NotNull ResourceLocation loc) {
var base = super.getCostModifier(loc);
if (isOfTag(IXplatAbstractions.INSTANCE.getActionRegistry(), loc, HexTags.Actions.CANNOT_MODIFY_COST)) {
return base;
}
return this.caster.getAttributeValue(HexAttributes.MEDIA_CONSUMPTION_MODIFIER);
return base * this.caster.getAttributeValue(HexAttributes.MEDIA_CONSUMPTION_MODIFIER);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ public interface ServerConfigAccess {

boolean isActionAllowedInCircles(ResourceLocation actionID);

double getActionCostScaling(ResourceLocation actionID);

boolean doesGreaterTeleportSplatItems();

boolean doVillagersTakeOffenseAtMindMurder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,11 +393,15 @@
},
actionDenyList: {
"": "Action Deny List",
"@Tooltip": "Resource locations of disallowed actions. Trying to cast one of these will result in a mishap. For example, hexcasting:get_caster will prevent Mind's Reflection",
"@Tooltip": "Resource locations of disallowed actions. Trying to cast one of these will result in a mishap. For example, hexcasting:get_caster will prevent Mind's Reflection.",
},
circleActionDenyList: {
"": "Circle Action Deny List",
"@Tooltip": "Resource locations of disallowed actions within circles. Trying to cast one of these from a circle will result in a mishap.",
"@Tooltip": "Resource locations of disallowed actions within circles. Trying to cast one of these from a circle will result in a mishap. For example, hexcasting:get_caster will prevent Mind's Reflection.",
},
costRescaleListRaw: {
"": "Cost Scaling Factors",
"@Tooltip": "Maps resource locations to the scaling factor for that action's media cost. For example, hexcasting:add_motion 3 will make Impulse cost 3x as much.",
},
greaterTeleportSplatsItems: {
"": "Greater Teleport Splats Items",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import com.google.gson.GsonBuilder;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import me.shedaniel.autoconfig.AutoConfig;
import me.shedaniel.autoconfig.ConfigData;
import me.shedaniel.autoconfig.annotation.Config;
Expand Down Expand Up @@ -209,6 +211,9 @@ public static final class Server implements HexConfig.ServerConfigAccess, Config
@ConfigEntry.Gui.Tooltip
private List<String> circleActionDenyList = List.of();
@ConfigEntry.Gui.Tooltip
private List<String> costRescaleListRaw = List.of();
private transient Object2DoubleMap<ResourceLocation> costRescaleList;
@ConfigEntry.Gui.Tooltip
private boolean greaterTeleportSplatsItems = DEFAULT_GREATER_TELEPORT_SPLATS_ITEMS;
@ConfigEntry.Gui.Tooltip
private boolean villagersOffendedByMindMurder = DEFAULT_VILLAGERS_DISLIKE_MIND_MURDER;
Expand Down Expand Up @@ -257,6 +262,18 @@ public void validatePostLoad() throws ValidationException {
this.maxSpellCircleLength = Math.max(this.maxSpellCircleLength, 4);
this.traderScrollChance = Mth.clamp(this.traderScrollChance, 0.0, 1.0);

this.costRescaleList = new Object2DoubleOpenHashMap<>();
try {
for (var auugh : this.costRescaleListRaw) {
String[] split = auugh.split(" ");
ResourceLocation loc = new ResourceLocation(split[0]);
double scale = Double.parseDouble(split[1]);
this.costRescaleList.put(loc, scale);
}
} catch (Exception e) {
throw new ValidationException("Bad parsing of action cost rescaling", e);
}

this.scrollInjections = new Object2IntOpenHashMap<>();
try {
for (var auugh : this.scrollInjectionsRaw) {
Expand All @@ -265,7 +282,6 @@ public void validatePostLoad() throws ValidationException {
int count = Integer.parseInt(split[1]);
this.scrollInjections.put(loc, count);
}

} catch (Exception e) {
throw new ValidationException("Bad parsing of scroll injects", e);
}
Expand Down Expand Up @@ -320,6 +336,11 @@ public boolean isActionAllowedInCircles(ResourceLocation actionID) {
return noneMatch(circleActionDenyList, actionID);
}

@Override
public double getActionCostScaling(ResourceLocation actionID) {
return this.costRescaleList.getOrDefault(actionID, 1.0);
}

@Override
public boolean doesGreaterTeleportSplatItems() { return greaterTeleportSplatsItems; }

Expand Down
51 changes: 41 additions & 10 deletions Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ public static class Server implements HexConfig.ServerConfigAccess {
private static ForgeConfigSpec.IntValue maxSpellCircleLength;
private static ForgeConfigSpec.ConfigValue<List<? extends String>> actionDenyList;
private static ForgeConfigSpec.ConfigValue<List<? extends String>> circleActionDenyList;
private static ForgeConfigSpec.ConfigValue<List<? extends String>> costRescaleList;

private static ForgeConfigSpec.BooleanValue greaterTeleportSplatsItems;
private static ForgeConfigSpec.BooleanValue villagersOffendedByMindMurder;
Expand All @@ -185,10 +186,25 @@ public Server(ForgeConfigSpec.Builder builder) {
maxOpCount = builder.comment("The maximum number of actions that can be executed in one tick, to avoid " +
"hanging the server.")
.defineInRange("maxOpCount", DEFAULT_MAX_OP_COUNT, 0, Integer.MAX_VALUE);

opBreakHarvestLevel = builder.comment(
"The harvest level of the Break Block spell.",
"0 = wood, 1 = stone, 2 = iron, 3 = diamond, 4 = netherite."
).defineInRange("opBreakHarvestLevel", DEFAULT_OP_BREAK_HARVEST_LEVEL, 0, 4);

greaterTeleportSplatsItems = builder.comment(
"Should items fly out of the player's inventory when using Greater Teleport?"
).define("greaterTeleportSplatsItems", DEFAULT_GREATER_TELEPORT_SPLATS_ITEMS);

actionDenyList = builder.comment(
"Resource locations of disallowed actions. Trying to cast one of these will result in a mishap. " +
"For example, \"hexcasting:get_caster\" will prevent Mind's Reflection.")
.defineList("actionDenyList", List.of(), Server::isValidReslocArg);

costRescaleList = builder.comment(
"Maps resource locations to the scaling factor for that action's media cost. " +
"For example, \"hexcasting:add_motion 3\" will make Impulse cost 3x as much.")
.defineList("costRescaleList", List.of(), Server::isValidReslocDoublePair);
builder.pop();

builder.push("Spell Circles");
Expand All @@ -197,7 +213,7 @@ public Server(ForgeConfigSpec.Builder builder) {

circleActionDenyList = builder.comment(
"Resource locations of disallowed actions within circles. Trying to cast one of these in a circle" +
" will result in a mishap. For example: hexcasting:get_caster will prevent Mind's Reflection.")
" will result in a mishap. For example, \"hexcasting:get_caster\" will prevent Mind's Reflection.")
.defineList("circleActionDenyList", List.of(), Server::isValidReslocArg);
builder.pop();

Expand All @@ -206,17 +222,8 @@ public Server(ForgeConfigSpec.Builder builder) {
.defineInRange("traderScrollChance", DEFAULT_TRADER_SCROLL_CHANCE, 0.0, 1.0);

// builders for loot (eg. scroll/lore/cypher pools and chances) should go here

builder.pop();

actionDenyList = builder.comment(
"Resource locations of disallowed actions. Trying to cast one of these will result in a mishap.")
.defineList("actionDenyList", List.of(), Server::isValidReslocArg);

greaterTeleportSplatsItems = builder.comment(
"Should items fly out of the player's inventory when using Greater Teleport?"
).define("greaterTeleportSplatsItems", DEFAULT_GREATER_TELEPORT_SPLATS_ITEMS);

villagersOffendedByMindMurder = builder.comment(
"Should villagers take offense when you flay the mind of their fellow villagers?")
.define("villagersOffendedByMindMurder", true);
Expand Down Expand Up @@ -254,6 +261,17 @@ public boolean isActionAllowedInCircles(ResourceLocation actionID) {
return noneMatch(circleActionDenyList.get(), actionID);
}

@Override
public double getActionCostScaling(ResourceLocation actionID) {
for (var entry : costRescaleList.get()) {
String[] split = entry.split(" ");
if (actionID.toString().equals(split[0])) {
return Double.parseDouble(split[1]);
}
}
return 1.0;
}

@Override
public boolean doesGreaterTeleportSplatItems() { return greaterTeleportSplatsItems.get(); }

Expand All @@ -280,5 +298,18 @@ public double traderScrollChance() {
private static boolean isValidReslocArg(Object o) {
return o instanceof String s && ResourceLocation.isValidResourceLocation(s);
}

private static boolean isValidReslocDoublePair(Object o) {
if (o instanceof String s) {
String[] split = s.split(" ");
try {
Double.parseDouble(split[1]);
} catch (NumberFormatException e) {
return false;
}
return ResourceLocation.isValidResourceLocation(split[0]);
}
return false;
}
}
}
Loading