Skip to content

Commit ee5ce47

Browse files
tastybentoclaude
andauthored
Add spawner boost and crop growth boost reward types (#61) (#77)
Implements two new passive/ongoing upgrade reward types: - SpawnerReward: spawns extra entities on SpawnerSpawnEvent, proportional to a configurable formula - CropGrowthReward: applies extra applyBoneMeal() on BlockGrowEvent for agricultural crops Both use a fractional bonus approach (e.g. 0.5 = 50% chance of one extra per trigger) and are compatible with any stacker plugin. Two example upgrades (Spawner Boost, Crop Growth Boost) are now seeded on first install (8 total). Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0568919 commit ee5ce47

10 files changed

Lines changed: 677 additions & 1 deletion

File tree

src/main/java/world/bentobox/upgrades/DefaultUpgradeSeeder.java

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
import world.bentobox.upgrades.dataobjects.prices.MoneyPriceDB;
1111
import world.bentobox.upgrades.dataobjects.prices.PermissionPriceDB;
1212
import world.bentobox.upgrades.dataobjects.rewards.CommandRewardDB;
13+
import world.bentobox.upgrades.dataobjects.rewards.CropGrowthRewardDB;
1314
import world.bentobox.upgrades.dataobjects.rewards.LimitsRewardDB;
1415
import world.bentobox.upgrades.dataobjects.rewards.RangeRewardDB;
16+
import world.bentobox.upgrades.dataobjects.rewards.SpawnerRewardDB;
1517

1618
import java.util.ArrayList;
1719
import java.util.List;
@@ -36,7 +38,7 @@ public void seedIfEmpty() {
3638
for (String gm : addon.getHookedGameModes()) {
3739
if (dm.getUpgradeDataByGameMode(gm).isEmpty()) {
3840
seed(dm, gm);
39-
addon.log("Seeded 6 example upgrades for " + gm
41+
addon.log("Seeded 8 example upgrades for " + gm
4042
+ " — edit or delete them via /[gamemode] admin upgrade");
4143
}
4244
}
@@ -49,6 +51,8 @@ private void seed(UpgradesDataManager dm, String gm) {
4951
seedCowLimit(dm, gm);
5052
seedDiamondBorder(dm, gm);
5153
seedDonorPerk(dm, gm);
54+
seedSpawnerBoost(dm, gm);
55+
seedCropBoost(dm, gm);
5256
}
5357

5458
// ─── Example 1: Border Expansion I ───────────────────────────────────────
@@ -222,4 +226,58 @@ private void seedDonorPerk(UpgradesDataManager dm, String gm) {
222226

223227
dm.saveUpgradeTier(tier);
224228
}
229+
230+
// ─── Example 7: Spawner Boost ─────────────────────────────────────────────
231+
// Demonstrates: MoneyPrice → SpawnerRewardDB (5 purchases)
232+
233+
private void seedSpawnerBoost(UpgradesDataManager dm, String gm) {
234+
UpgradeData data = dm.createUpgradeData(gm + "_example_spawner", gm, null);
235+
if (data == null) return;
236+
data.setName("Spawner Boost");
237+
data.setIcon(new ItemStack(Material.SPAWNER));
238+
data.setOrder(7);
239+
data.setDescription(List.of("Example: pay $2000 for +0.5 extra entities per spawner trigger."));
240+
dm.saveUpgradeData(data);
241+
242+
UpgradeTier tier = dm.createUpgradeTier(gm + "_example_spawner_t1", data, 0, 4, null);
243+
if (tier == null) return;
244+
tier.setName("Spawner Boost");
245+
246+
MoneyPriceDB money = new MoneyPriceDB();
247+
money.setAmountEquation("2000");
248+
tier.setPrices(List.of(money));
249+
250+
SpawnerRewardDB spawner = new SpawnerRewardDB();
251+
spawner.setSpawnBonusEquation("0.5");
252+
tier.setRewards(List.of(spawner));
253+
254+
dm.saveUpgradeTier(tier);
255+
}
256+
257+
// ─── Example 8: Crop Growth Boost ─────────────────────────────────────────
258+
// Demonstrates: MoneyPrice → CropGrowthRewardDB (5 purchases)
259+
260+
private void seedCropBoost(UpgradesDataManager dm, String gm) {
261+
UpgradeData data = dm.createUpgradeData(gm + "_example_cropgrowth", gm, null);
262+
if (data == null) return;
263+
data.setName("Crop Growth Boost");
264+
data.setIcon(new ItemStack(Material.WHEAT));
265+
data.setOrder(8);
266+
data.setDescription(List.of("Example: pay $500 for 50% extra growth chance per crop tick."));
267+
dm.saveUpgradeData(data);
268+
269+
UpgradeTier tier = dm.createUpgradeTier(gm + "_example_cropgrowth_t1", data, 0, 4, null);
270+
if (tier == null) return;
271+
tier.setName("Crop Growth Boost");
272+
273+
MoneyPriceDB money = new MoneyPriceDB();
274+
money.setAmountEquation("500");
275+
tier.setPrices(List.of(money));
276+
277+
CropGrowthRewardDB crop = new CropGrowthRewardDB();
278+
crop.setGrowthBonusEquation("0.5");
279+
tier.setRewards(List.of(crop));
280+
281+
dm.saveUpgradeTier(tier);
282+
}
225283
}

src/main/java/world/bentobox/upgrades/UpgradesAddon.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@
3131
import world.bentobox.upgrades.dataobjects.prices.MoneyPrice;
3232
import world.bentobox.upgrades.dataobjects.prices.PermissionPrice;
3333
import world.bentobox.upgrades.dataobjects.rewards.CommandReward;
34+
import world.bentobox.upgrades.dataobjects.rewards.CropGrowthReward;
3435
import world.bentobox.upgrades.dataobjects.rewards.LimitsReward;
3536
import world.bentobox.upgrades.dataobjects.rewards.RangeReward;
37+
import world.bentobox.upgrades.dataobjects.rewards.SpawnerReward;
3638
import world.bentobox.upgrades.DefaultUpgradeSeeder;
3739
import world.bentobox.upgrades.upgrades.DatabaseUpgrade;
40+
import world.bentobox.upgrades.listeners.CropGrowthListener;
3841
import world.bentobox.upgrades.listeners.IslandChangeListener;
3942
import world.bentobox.upgrades.listeners.JoinPermCheckListener;
43+
import world.bentobox.upgrades.listeners.SpawnerUpgradeListener;
4044
import world.bentobox.upgrades.ui.utils.ChatInput;
4145

4246
public class UpgradesAddon extends Addon {
@@ -110,6 +114,8 @@ public void onEnable() {
110114
this.upgradesManager.addReward(new RangeReward());
111115
this.upgradesManager.addReward(new LimitsReward());
112116
this.upgradesManager.addReward(new CommandReward());
117+
this.upgradesManager.addReward(new SpawnerReward());
118+
this.upgradesManager.addReward(new CropGrowthReward());
113119

114120
// Seed example upgrades for any game mode that has none yet
115121
new DefaultUpgradeSeeder(this).seedIfEmpty();
@@ -122,6 +128,8 @@ public void onEnable() {
122128
);
123129

124130
this.registerListener(new IslandChangeListener(this));
131+
this.registerListener(new SpawnerUpgradeListener(this));
132+
this.registerListener(new CropGrowthListener(this));
125133

126134
if (this.isLimitsProvided())
127135
this.registerListener(new JoinPermCheckListener(this));
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package world.bentobox.upgrades.dataobjects.rewards;
2+
3+
import org.bukkit.Material;
4+
import org.eclipse.jdt.annotation.NonNull;
5+
import org.eclipse.jdt.annotation.Nullable;
6+
import world.bentobox.bentobox.api.addons.GameModeAddon;
7+
import world.bentobox.bentobox.api.panels.PanelItem;
8+
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
9+
import world.bentobox.bentobox.api.user.User;
10+
import world.bentobox.bentobox.database.objects.Island;
11+
import world.bentobox.upgrades.UpgradesAddon;
12+
import world.bentobox.upgrades.config.Settings;
13+
import world.bentobox.upgrades.dataobjects.UpgradeTier;
14+
import world.bentobox.upgrades.ui.utils.AbPanel;
15+
16+
import java.security.InvalidParameterException;
17+
import java.util.List;
18+
import java.util.Map;
19+
import java.util.TreeMap;
20+
import java.util.function.Consumer;
21+
22+
public class CropGrowthReward extends Reward {
23+
24+
public CropGrowthReward() {
25+
super("crop_growth_reward", Material.WHEAT);
26+
}
27+
28+
@Override
29+
public String getAdminName(User user) {
30+
return user.getTranslation("upgrades.rewards.cropgrowth.name");
31+
}
32+
33+
@Override
34+
public String getAdminDescription(User user) {
35+
return user.getTranslation("upgrades.rewards.cropgrowth.admindescription");
36+
}
37+
38+
@Override
39+
public String getPublicName(User user) {
40+
return user.getTranslation("upgrades.rewards.cropgrowth.name");
41+
}
42+
43+
@Override
44+
public String getPublicDescription(User user) {
45+
return user.getTranslation("upgrades.rewards.cropgrowth.description");
46+
}
47+
48+
@Override
49+
public String getPublicDescription(User user, RewardDB rewardDB) {
50+
CropGrowthRewardDB db = (CropGrowthRewardDB) rewardDB;
51+
return user.getTranslation("upgrades.rewards.cropgrowth.description",
52+
"[amount]", db.getGrowthBonusEquation());
53+
}
54+
55+
@Override
56+
public void apply(UpgradesAddon addon, User user, Island island, RewardDB rewardDB) {
57+
// No-op: ongoing effect handled by CropGrowthListener
58+
}
59+
60+
@Override
61+
public AbPanel getAdminPanel(UpgradesAddon addon, GameModeAddon gamemode, User user, AbPanel parent,
62+
UpgradeTier tier, @Nullable RewardDB saved) {
63+
CropGrowthRewardDB dbObject;
64+
65+
if (saved == null) {
66+
dbObject = new CropGrowthRewardDB();
67+
List<RewardDB> rewards = tier.getRewards();
68+
rewards.add(dbObject);
69+
tier.setRewards(rewards);
70+
} else if (saved instanceof CropGrowthRewardDB) {
71+
dbObject = (CropGrowthRewardDB) saved;
72+
} else {
73+
throw new InvalidParameterException(
74+
"DB object in CropGrowthReward which is not a CropGrowthRewardDB");
75+
}
76+
77+
return new CropGrowthRewardPanel(addon, gamemode, user, parent, tier, dbObject);
78+
}
79+
80+
private final class CropGrowthRewardPanel extends AbPanel {
81+
private static final String VALID = "valid";
82+
private static final String INVALID = "invalid";
83+
private static final String RULE = "rule";
84+
85+
private final UpgradeTier tier;
86+
private final CropGrowthRewardDB saved;
87+
88+
public CropGrowthRewardPanel(UpgradesAddon addon, GameModeAddon gamemode,
89+
User user, AbPanel parent,
90+
@NonNull UpgradeTier tier,
91+
@NonNull CropGrowthRewardDB saved) {
92+
super(addon, gamemode, user, user.getTranslation("upgrades.rewards.cropgrowth.paneltitle"),
93+
parent);
94+
95+
this.tier = tier;
96+
this.saved = saved;
97+
98+
this.createInterface();
99+
}
100+
101+
private void createInterface() {
102+
this.fillBorder(Material.BLACK_STAINED_GLASS_PANE);
103+
104+
if (this.saved.isValid()) {
105+
this.setItems(VALID, new PanelItemBuilder()
106+
.name(this.getUser().getTranslation("upgrades.rewards.cropgrowth.formulastatus"))
107+
.description(this.saved.getGrowthBonusEquation())
108+
.icon(Material.GREEN_CONCRETE)
109+
.build(), 10);
110+
} else {
111+
this.setItems(INVALID, new PanelItemBuilder()
112+
.name(this.getUser().getTranslation("upgrades.rewards.cropgrowth.formulaneeded"))
113+
.description(this.getUser().getTranslation("upgrades.rewards.cropgrowth.formulaneededdesc"))
114+
.icon(Material.RED_CONCRETE)
115+
.build(), 10);
116+
}
117+
118+
this.setItems(RULE, new PanelItemBuilder()
119+
.name(this.getUser().getTranslation("upgrades.rewards.cropgrowth.setformula"))
120+
.description(this.saved.getGrowthBonusEquation())
121+
.icon(Material.PAPER)
122+
.clickHandler(this.onSetRule())
123+
.build(), 22);
124+
}
125+
126+
private PanelItem.ClickHandler onSetRule() {
127+
return (panel, client, click, slot) -> {
128+
this.getAddon()
129+
.getChatInput()
130+
.askOneInput(this.doSetRule(),
131+
input -> {
132+
try {
133+
Map<String, Double> vars = new TreeMap<>();
134+
vars.put("[level]", 1.0);
135+
vars.put("[islandLevel]", 1.0);
136+
vars.put("[numberPlayer]", 1.0);
137+
Settings.evaluate(input, vars);
138+
return true;
139+
} catch (Exception e) {
140+
return false;
141+
}
142+
},
143+
client.getTranslation("upgrades.rewards.cropgrowth.rulequestion",
144+
"[actual]", this.saved.getGrowthBonusEquation()),
145+
client.getTranslation("upgrades.rewards.cropgrowth.invalidrule"),
146+
client, false);
147+
return true;
148+
};
149+
}
150+
151+
private Consumer<String> doSetRule() {
152+
return (rule) -> {
153+
this.saved.setGrowthBonusEquation(rule);
154+
this.createInterface();
155+
this.getBuild().build();
156+
};
157+
}
158+
}
159+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package world.bentobox.upgrades.dataobjects.rewards;
2+
3+
import com.google.gson.annotations.Expose;
4+
5+
public class CropGrowthRewardDB extends RewardDB {
6+
7+
@Expose
8+
private String growthBonusEquation = "0";
9+
10+
public String getGrowthBonusEquation() {
11+
return growthBonusEquation;
12+
}
13+
14+
public void setGrowthBonusEquation(String growthBonusEquation) {
15+
this.growthBonusEquation = growthBonusEquation;
16+
}
17+
18+
@Override
19+
public boolean isValid() {
20+
return growthBonusEquation != null && !growthBonusEquation.isEmpty();
21+
}
22+
23+
@Override
24+
public Class<CropGrowthReward> getRewardType() {
25+
return CropGrowthReward.class;
26+
}
27+
28+
}

0 commit comments

Comments
 (0)