Skip to content
Merged
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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number>
<!-- This allows to change between versions. -->
<build.version>0.2.0</build.version>
<build.version>0.2.1</build.version>
<!-- SonarCloud analysis (bentobox-world org). Requires the project to be
registered on SonarCloud as BentoBoxWorld_TradeWinds; the CI Sonar
step is non-fatal so an unregistered project never fails the build. -->
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/world/bentobox/tradewinds/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -742,8 +742,11 @@ private static Map<String, Integer> defaultBoatRanks() {

@ConfigComment("The contraband list: what customs care about, and what black markets pay")
@ConfigComment("the premium for. Only honored while illegal-trade.enabled is true.")
@ConfigComment("List the FEEDSTOCK as well as the finished good, or the law is theatre:")
@ConfigComment("one sugar cane crafts into one sugar, so cane smuggled past a scan is")
@ConfigComment("sugar smuggled past a scan (playtest 2026-08-09).")
@ConfigEntry(path = "illegal-trade.contraband-materials")
private List<String> contrabandMaterials = new ArrayList<>(List.of("SUGAR"));
private List<String> contrabandMaterials = new ArrayList<>(List.of("SUGAR", "SUGAR_CANE"));

@ConfigComment("Career restarts a destitute player may use (/tw restart): fresh kit, starting")
@ConfigComment("balance, chart kept. -1 = unlimited, 0 = none.")
Expand Down Expand Up @@ -1135,8 +1138,8 @@ private static Map<String, Double> defaultEncounterChance() {
@ConfigEntry(path = "encounters.booty-chance")
private double bootyChance = 0.5;

@ConfigComment("Booty materials. Dropped customs-stamped, so salvage can be sold -")
@ConfigComment("fighting is the third way to earn, beside trading and smuggling.")
@ConfigComment("Booty materials. Sellable like any other cargo, so fighting is the third")
@ConfigComment("way to earn, beside trading and smuggling.")
@ConfigEntry(path = "encounters.booty-table")
private List<String> bootyTable = new ArrayList<>(List.of("NAUTILUS_SHELL", "PRISMARINE_SHARD",
"PRISMARINE_CRYSTALS", "GOLD_INGOT", "IRON_INGOT", "EMERALD", "COAL", "COOKED_COD", "TRIDENT",
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/world/bentobox/tradewinds/crime/Contraband.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
/**
* What customs would rather you were not carrying.
* <p>
* Contraband is the one thing a player can <em>make</em> and still sell (spec
* 5.0): everything else traders buy must carry a customs stamp, so money only
* ever enters the game through trade margins. Contraband is the deliberate
* hole in that rule, and scan risk is what it is priced against - crime pays,
* into danger (principle 4).
* Contraband is what a port's law cares about, and what a black market pays
* the premium for. Scan risk is what that premium is priced against - crime
* pays, into danger (principle 4).
* <p>
* It no longer marks the boundary of what may be sold: customs STAMPING was
* removed with the hold plan (2026-08-01), and the market now buys anything
* with a price. What survived is the smuggling risk.
* <p>
* Pure logic, no Bukkit: which bands deal in it, and how likely a search is.
* The material list itself lives in config.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,9 @@ public boolean buysContraband(SecurityBand band) {
}

/**
* Whether an item may be sold at this island - the contraband rule on top
* of the customs stamp.
* Whether an item may be sold at this island. Since customs stamping went
* (hold plan, 2026-08-01) the contraband band rule is the ONLY thing that
* refuses a sale: anything else with a price, a port will take.
*
* @param spec the island
* @param item the item
Expand Down
9 changes: 5 additions & 4 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,6 @@ economy:
# The harbourmaster's charity: a sailor with no cargo space, no boat and no money
# is given the bare minimum to work again. Charity goods cannot be sold. 0 disables.
charity-cooldown-minutes: 15
# Materials traders buy even WITHOUT a customs stamp - the contraband exceptions.
unstamped-sellables:
- SUGAR
# The secondhand shelf: notable goods sold to a trader go back out for sale
# instead of vanishing, so the world feels inhabited. They surface at a DIFFERENT
# port from the one they were sold at (the trader shipped it on), which stops
Expand Down Expand Up @@ -733,7 +730,7 @@ encounters:
PIRATE_CREW: 10
SEA_WITCH: 30
# Chance that a slain encounter mob yields booty, and what it may drop.
# Booty is customs-stamped, so it can be sold: fighting is the third way to earn.
# Booty is sellable like any other cargo: fighting is the third way to earn.
booty-chance: 0.5
booty-table:
- NAUTILUS_SHELL
Expand All @@ -752,8 +749,12 @@ encounters:
illegal-trade:
# The contraband list: what customs care about, and what black markets pay
# the premium for. Only honored while illegal-trade.enabled is true.
# List the FEEDSTOCK as well as the finished good, or the law is theatre:
# one sugar cane crafts into one sugar, so cane smuggled past a scan is
# sugar smuggled past a scan (playtest 2026-08-09).
contraband-materials:
- SUGAR
- SUGAR_CANE
# Master gate for all illegal-goods mechanics: contraband, customs scans, smuggling.
# Set false for family-friendly servers - removes the entire crime layer cleanly.
enabled: true
Expand Down
3 changes: 1 addition & 2 deletions src/main/resources/locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ tradewinds:
selling-body: "<gray>The island pays for goods in your hold</gray>"
selling-truncated: "<gray>(showing the first [number] cargo types - sell some to see the rest)</gray>"
buying-title: "<dark_aqua>[name] - Buying</dark_aqua>"
buying-body: "<gray>Goods sold into your hold - customs stamped</gray>"
buying-body: "<gray>Goods sold into your hold - buy low, sell high elsewhere</gray>"
outfitter-title: "<dark_aqua>[name] - Outfitter</dark_aqua>"
outfitter-body: "<gray>Stores for the sailing life - food, fuel and gear</gray>"
shipwright-title: "<dark_aqua>[name] - Shipwright</dark_aqua>"
Expand Down Expand Up @@ -334,7 +334,6 @@ tradewinds:
pouch-lore: "<gray>Cargo space. Stow goods to sell them.</gray>"
expander: "<gold>Cargo Expander</gold>"
expander-lore: "<gray>Expands your hold. Right-click to open.</gray>"
stamp: "<dark_aqua>Customs Stamped</dark_aqua>"
starchart: "<aqua>Star Chart</aqua>"
ships-compass: "<gold>Ship's Compass</gold>"
ships-compass-lore: "<gray>Points to your island, from anywhere. Guard it - or gift it to a crewmate.</gray>"
Expand Down
12 changes: 12 additions & 0 deletions src/test/java/world/bentobox/tradewinds/crime/ContrabandTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ void testMasterGateRemovesTheWholeMechanic() {
assertFalse(Contraband.isContraband("BREAD", LIST, true));
}

@Test
void testTheFeedstockIsAsIllegalAsTheGood() {
// One cane crafts into one sugar, so cane past a scan is sugar past a
// scan - and the shipped default has to say so, or the whole customs
// layer is theatre for anyone who reads a recipe book (2026-08-09).
// Both lists, because a map/list in config.yml REPLACES the code
// default rather than merging with it.
var shipped = new world.bentobox.tradewinds.Settings().getContrabandMaterials();
assertTrue(shipped.contains("SUGAR"), "SUGAR must be contraband by default");
assertTrue(shipped.contains("SUGAR_CANE"), "SUGAR_CANE must be contraband by default");
}

@Test
void testSafePortsRefuseContraband() {
// Crime pays, into danger: the safe ports will not touch it, so a
Expand Down
Loading