Skip to content

Commit 007ac74

Browse files
feat: added midas sword
1 parent 3132ca4 commit 007ac74

12 files changed

Lines changed: 279 additions & 25 deletions

File tree

commons/src/main/java/net/swofty/commons/item/ItemType.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ public enum ItemType {
102102
ABIPHONE_CONTACTS_TRIO(Material.COMPARATOR, Rarity.SPECIAL),
103103
PURE_WHITE_DYE(Material.BONE_MEAL, Rarity.EPIC),
104104
PURE_BLACK_DYE(Material.INK_SAC, Rarity.EPIC),
105-
DARK_PURPLE_DYE(Material.PLAYER_HEAD, Rarity.LEGENDARY),ACCESSORY_ENRICHMENT_SWAPPER(Material.COMPARATOR, Rarity.SPECIAL),
105+
DARK_PURPLE_DYE(Material.PLAYER_HEAD, Rarity.LEGENDARY),
106+
MIDAS_SWORD(Material.GOLDEN_SWORD, Rarity.LEGENDARY),
107+
ACCESSORY_ENRICHMENT_SWAPPER(Material.COMPARATOR, Rarity.SPECIAL),
106108
ATTACK_SPEED_ENRICHMENT(Material.PLAYER_HEAD, Rarity.SPECIAL),
107109
CRITICAL_CHANCE_ENRICHMENT(Material.PLAYER_HEAD, Rarity.SPECIAL),
108110
CRITICAL_DAMAGE_ENRICHMENT(Material.PLAYER_HEAD, Rarity.SPECIAL),
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package net.swofty.commons.item.attribute.attributes;
2+
3+
import net.swofty.commons.item.attribute.ItemAttribute;
4+
import net.swofty.commons.statistics.ItemStatistics;
5+
import org.jetbrains.annotations.Nullable;
6+
7+
public class ItemAttributeDarkAuctionPrice extends ItemAttribute<Long> {
8+
@Override
9+
public String getKey() {
10+
return "dark_auction_price";
11+
}
12+
13+
@Override
14+
public Long getDefaultValue(@Nullable ItemStatistics defaultStatistics) {
15+
return 0L;
16+
}
17+
18+
@Override
19+
public Long loadFromString(String string) {
20+
try {
21+
return Long.parseLong(string);
22+
} catch (NumberFormatException e) {
23+
return 0L;
24+
}
25+
}
26+
27+
@Override
28+
public String saveIntoString() {
29+
return String.valueOf(getValue());
30+
}
31+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package net.swofty.commons.item.attribute.attributes;
2+
3+
import net.swofty.commons.item.attribute.ItemAttribute;
4+
import net.swofty.commons.statistics.ItemStatistics;
5+
import org.jetbrains.annotations.Nullable;
6+
7+
/**
8+
* Stores extra dynamic statistics that are added on top of the base item statistics.
9+
*/
10+
public class ItemAttributeExtraDynamicStatistics extends ItemAttribute<ItemStatistics> {
11+
@Override
12+
public String getKey() {
13+
return "extra_dynamic_statistics";
14+
}
15+
16+
@Override
17+
public ItemStatistics getDefaultValue(@Nullable ItemStatistics defaultStatistics) {
18+
return ItemStatistics.empty();
19+
}
20+
21+
@Override
22+
public ItemStatistics loadFromString(String string) {
23+
if (string == null || string.isEmpty()) {
24+
return ItemStatistics.empty();
25+
}
26+
return ItemStatistics.fromString(string);
27+
}
28+
29+
@Override
30+
public String saveIntoString() {
31+
if (getValue() == null) {
32+
return "";
33+
}
34+
return getValue().toString();
35+
}
36+
}

commons/src/main/java/net/swofty/commons/statistics/ItemStatistics.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,24 @@ public String toString() {
3939
StringBuilder builder = new StringBuilder();
4040

4141
for (ItemStatistic stat : ItemStatistic.values()) {
42+
double baseValue = statisticsBase.getOrDefault(stat, 0D);
4243
double additiveValue = statisticsAdditive.getOrDefault(stat, 0D);
4344
double multiplicativeValue = statisticsMultiplicative.getOrDefault(stat, 0D);
4445

45-
if (additiveValue != 0 || multiplicativeValue != 0) {
46+
if (baseValue != 0 || additiveValue != 0 || multiplicativeValue != 0) {
4647
builder.append(stat.name()).append(":");
48+
boolean needsComma = false;
49+
if (baseValue != 0) {
50+
builder.append("B").append(baseValue);
51+
needsComma = true;
52+
}
4753
if (additiveValue != 0) {
54+
if (needsComma) builder.append(",");
4855
builder.append("A").append(additiveValue);
56+
needsComma = true;
4957
}
5058
if (multiplicativeValue != 0) {
51-
if (additiveValue != 0) {
52-
builder.append(",");
53-
}
59+
if (needsComma) builder.append(",");
5460
builder.append("M").append(multiplicativeValue);
5561
}
5662
builder.append(";");
@@ -71,12 +77,15 @@ public static ItemStatistics fromString(String string) {
7177
ItemStatistic stat = ItemStatistic.valueOf(parts[0]);
7278
String[] values = parts[1].split(",");
7379
for (String value : values) {
74-
if (value.startsWith("A")) {
80+
if (value.startsWith("B")) {
81+
double baseValue = Double.parseDouble(value.substring(1));
82+
builder.withBase(stat, baseValue);
83+
} else if (value.startsWith("A")) {
7584
double additiveValue = Double.parseDouble(value.substring(1));
76-
builder.withBase(stat, additiveValue);
85+
builder.withAdditive(stat, additiveValue);
7786
} else if (value.startsWith("M")) {
7887
double multiplicativeValue = Double.parseDouble(value.substring(1));
79-
builder.withMultiplicativePercentage(stat, multiplicativeValue);
88+
builder.withMultiplicative(stat, multiplicativeValue);
8089
}
8190
}
8291
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
items:
2+
- id: DARK_PURPLE_DYE
3+
rarity: LEGENDARY
4+
lore:
5+
- "§7Can be applied to any vanilla Armor"
6+
- "§7piece by combining the two items"
7+
- "§7in an Anvil to change the hex"
8+
- "§7color of that piece to §5#301934§7."
9+
- ""
10+
- "§7Costs §b100 Bits §7to combine."
11+
components:
12+
- id: SKULL_HEAD
13+
texture: e6182adee5276372c2258256d50e69b7d857c675f54765acf73af61690a62c7e
14+
- id: ANVIL_COMBINABLE
15+
handler_id: DARK_PURPLE_DYE
16+
17+
- id: MIDAS_SWORD
18+
material: GOLDEN_SWORD
19+
rarity: LEGENDARY
20+
lore:
21+
- "§6Ability: Greed §e§lPASSIVE"
22+
- "§7The §c❁ Strength §7and §c❁ Damage §7bonus"
23+
- "§7of this item is dependent on the"
24+
- "§7price paid for it at the §5Dark"
25+
- "§5Auction§7! §7The maximum bonus of this item is"
26+
- "§c120 §7if the bid was §650,000,000"
27+
- "§6Coins §7or higher!"
28+
components:
29+
- id: STANDARD_ITEM
30+
standard_item_type: SWORD
31+
- id: MUSEUM
32+
museum_category: WEAPONS
33+
- id: GEMSTONE
34+
gemstones:
35+
- "COMBAT:50000"
36+
- "COMBAT:100000"
37+
- id: LORE_UPDATE
38+
handler_id: MIDAS_SWORD
39+
is_absolute: false
40+
default_statistics:
41+
damage: 170.0

service.darkauction/src/main/java/net/swofty/service/darkauction/loot/DarkAuctionItemPool.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,9 @@ public class DarkAuctionItemPool {
1212
private static final Random random = new Random();
1313

1414
public DarkAuctionItemPool() {
15-
// Artifacts (weight 24)
16-
items.add(new WeightedItem(ItemType.DIRT, 24));
17-
items.add(new WeightedItem(ItemType.COAL, 24));
18-
items.add(new WeightedItem(ItemType.ACACIA_BUTTON, 24));
19-
2015
// Special Items (weight 16)
2116
items.add(new WeightedItem(ItemType.HYPERION, 16));
17+
items.add(new WeightedItem(ItemType.MIDAS_SWORD, 16));
2218

2319
// Epic Pets (weight 16)
2420
items.add(new WeightedItem(ItemType.BEE_PET, 16));
@@ -46,8 +42,8 @@ public ItemType selectAndRemove() {
4642
}
4743
}
4844

49-
// If pool is exhausted, TODO return Midas Sword
50-
return ItemType.HYPERION;
45+
// If pool is exhausted, return Midas Sword
46+
return ItemType.MIDAS_SWORD;
5147
}
5248

5349
/**

type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/darkauction/DarkAuctionHandler.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import net.swofty.commons.auctions.DarkAuctionPhase;
1111
import net.swofty.commons.item.ItemType;
1212
import net.swofty.commons.protocol.objects.darkauction.PlayerLeftAuctionProtocol;
13+
import net.swofty.commons.statistics.ItemStatistic;
14+
import net.swofty.commons.statistics.ItemStatistics;
1315
import net.swofty.proxyapi.ProxyService;
1416
import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader;
1517
import net.swofty.type.skyblockgeneric.item.SkyBlockItem;
@@ -318,7 +320,22 @@ public static void handleRoundEnd(JSONObject msg) {
318320
if (winner != null && playersInAuction.contains(winnerId)) {
319321
try {
320322
ItemType itemType = ItemType.valueOf(itemTypeName);
321-
winner.addAndUpdateItem(new SkyBlockItem(itemType));
323+
SkyBlockItem skyBlockItem = new SkyBlockItem(itemType);
324+
325+
// Set dark auction price on ALL items won at auction
326+
skyBlockItem.getAttributeHandler().setDarkAuctionPrice(bid);
327+
328+
// Apply Greed bonus for Midas' Sword using extra dynamic statistics
329+
if (itemType == ItemType.MIDAS_SWORD) {
330+
int greedBonus = calculateGreedBonus(bid);
331+
ItemStatistics greedStats = ItemStatistics.builder()
332+
.withBase(ItemStatistic.DAMAGE, (double) greedBonus)
333+
.withBase(ItemStatistic.STRENGTH, (double) greedBonus)
334+
.build();
335+
skyBlockItem.getAttributeHandler().setExtraDynamicStatistics(greedStats);
336+
}
337+
338+
winner.addAndUpdateItem(skyBlockItem);
322339
} catch (Exception e) {
323340
Logger.error(e, "Error giving item to winner");
324341
}
@@ -469,6 +486,37 @@ public static void handlePlayerLeft(SkyBlockPlayer player) {
469486
});
470487
}
471488

489+
/**
490+
* Calculates the Greed bonus for Midas' Sword based on the price paid.
491+
* Tiered formula:
492+
* - <1M: price / 50,000 (max 20)
493+
* - 1M-2.5M: 20 + (price - 1M) / 100,000 (max 35 cumulative)
494+
* - 2.5M-7.5M: 35 + (price - 2.5M) / 200,000 (max 60 cumulative)
495+
* - 7.5M-25M: 60 + (price - 7.5M) / 500,000 (max 95 cumulative)
496+
* - 25M-50M: 95 + (price - 25M) / 1,000,000 (max 120 cumulative)
497+
* - >=50M: 120
498+
*/
499+
private static int calculateGreedBonus(long price) {
500+
if (price >= 50_000_000L) return 120;
501+
if (price >= 25_000_000L) {
502+
int bonus = 95 + (int) ((price - 25_000_000L) / 1_000_000L);
503+
return Math.min(120, bonus);
504+
}
505+
if (price >= 7_500_000L) {
506+
int bonus = 60 + (int) ((price - 7_500_000L) / 500_000L);
507+
return Math.min(95, bonus);
508+
}
509+
if (price >= 2_500_000L) {
510+
int bonus = 35 + (int) ((price - 2_500_000L) / 200_000L);
511+
return Math.min(60, bonus);
512+
}
513+
if (price >= 1_000_000L) {
514+
int bonus = 20 + (int) ((price - 1_000_000L) / 100_000L);
515+
return Math.min(35, bonus);
516+
}
517+
return (int) Math.min(20, price / 50_000L);
518+
}
519+
472520
/**
473521
* Tracks local state for the Dark Auction.
474522
*/

type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/GlassDisplay.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import net.swofty.type.generic.entity.InteractionEntity;
1414
import net.swofty.type.generic.user.HypixelPlayer;
1515
import net.swofty.type.skyblockgeneric.item.SkyBlockItem;
16+
import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater;
1617

1718
import java.util.function.BiConsumer;
1819

@@ -53,7 +54,7 @@ public void spawn() {
5354
super.spawn();
5455
itemEntity = new LivingEntity(EntityType.ITEM);
5556
itemEntity.editEntityMeta(ItemEntityMeta.class, meta -> {
56-
meta.setItem(item.getItemStack());
57+
meta.setItem(new NonPlayerItemUpdater(item.getItemStack()).getUpdatedItem().build());
5758
});
5859
itemEntity.setCanPickupItem(false);
5960
itemEntity.setNoGravity(true);

type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import net.swofty.commons.item.ItemType;
66
import net.swofty.commons.item.Rarity;
77
import net.swofty.commons.item.attribute.attributes.*;
8+
import net.swofty.commons.item.attribute.attributes.ItemAttributeExtraDynamicStatistics;
89
import net.swofty.commons.item.reforge.Reforge;
910
import net.swofty.commons.item.reforge.ReforgeLoader;
1011
import net.swofty.commons.protocol.objects.itemtracker.TrackedItemUpdateProtocolObject;
@@ -297,12 +298,33 @@ public void addEnchantment(SkyBlockEnchantment enchantment) {
297298
.addEnchantment(enchantment.toUnderstandable());
298299
}
299300

300-
public ItemStatistics getStatistics() {
301+
/**
302+
* Gets the base statistics from the item's configuration.
303+
* This does NOT include extra dynamic statistics like Greed bonus.
304+
*/
305+
public ItemStatistics getBaseStatistics() {
301306
return ((ItemAttributeStatistics) item.getAttribute("statistics")).getValue().clone();
302307
}
303308

304-
public void setStatistics(ItemStatistics statistics) {
305-
((ItemAttributeStatistics) item.getAttribute("statistics")).setValue(statistics);
309+
/**
310+
* Gets the combined statistics (base + extra dynamic).
311+
* This is what should be used when calculating item stats for display/combat.
312+
*/
313+
public ItemStatistics getStatistics() {
314+
ItemStatistics baseStats = getBaseStatistics();
315+
ItemStatistics extraStats = getExtraDynamicStatistics();
316+
return ItemStatistics.add(baseStats, extraStats);
317+
}
318+
319+
/**
320+
* Gets extra dynamic statistics that are added on top of base stats.
321+
*/
322+
public ItemStatistics getExtraDynamicStatistics() {
323+
return ((ItemAttributeExtraDynamicStatistics) item.getAttribute("extra_dynamic_statistics")).getValue();
324+
}
325+
326+
public void setExtraDynamicStatistics(ItemStatistics statistics) {
327+
((ItemAttributeExtraDynamicStatistics) item.getAttribute("extra_dynamic_statistics")).setValue(statistics);
306328
}
307329

308330
public void setRecombobulated(boolean value) {
@@ -349,6 +371,14 @@ public boolean isMiningTool() {
349371
return getBreakingPower() != 0;
350372
}
351373

374+
public long getDarkAuctionPrice() {
375+
return ((ItemAttributeDarkAuctionPrice) item.getAttribute("dark_auction_price")).getValue();
376+
}
377+
378+
public void setDarkAuctionPrice(long price) {
379+
((ItemAttributeDarkAuctionPrice) item.getAttribute("dark_auction_price")).setValue(price);
380+
}
381+
352382
public SkyBlockItem asSkyBlockItem() {
353383
return item;
354384
}

type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemLore.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,14 +214,15 @@ public void updateLore(@Nullable SkyBlockPlayer player) {
214214
addLoreLine(null);
215215
}
216216

217-
// Handle Custom Item Lore
217+
// Handle Custom Item Lore (BEFORE_ABILITY location)
218218
if (item.hasComponent(LoreUpdateComponent.class)) {
219219
LoreUpdateComponent loreUpdateComponent = item.getComponent(LoreUpdateComponent.class);
220220
if (loreUpdateComponent.getHandler() == null)
221221
throw new RuntimeException("Lore update handler is null for " + item.getAttributeHandler().getTypeAsString());
222222

223-
if (loreUpdateComponent.getHandler().loreGenerator() != null) {
224-
loreUpdateComponent.getHandler().loreGenerator().apply(item, player).forEach(line -> addLoreLine("§7" + line));
223+
LoreConfig loreConfig = loreUpdateComponent.getHandler();
224+
if (loreConfig.loreGenerator() != null && loreConfig.location() == LoreConfig.LoreConfigLocation.BEFORE_ABILITY) {
225+
loreConfig.loreGenerator().apply(item, player).forEach(line -> addLoreLine("§7" + line));
225226
addLoreLine(null);
226227
}
227228
}
@@ -252,6 +253,16 @@ public void updateLore(@Nullable SkyBlockPlayer player) {
252253
});
253254
}
254255

256+
// Handle Custom Item Lore (AFTER_ABILITY location)
257+
if (item.hasComponent(LoreUpdateComponent.class)) {
258+
LoreUpdateComponent loreUpdateComponent = item.getComponent(LoreUpdateComponent.class);
259+
LoreConfig loreConfig = loreUpdateComponent.getHandler();
260+
if (loreConfig != null && loreConfig.loreGenerator() != null && loreConfig.location() == LoreConfig.LoreConfigLocation.AFTER_ABILITY) {
261+
loreConfig.loreGenerator().apply(item, player).forEach(line -> addLoreLine("§7" + line));
262+
addLoreLine(null);
263+
}
264+
}
265+
255266
// Handle full set abilities
256267
if (ArmorSetRegistry.getArmorSet(handler.getPotentialType()) != null) {
257268
ArmorSet armorSet = ArmorSetRegistry.getArmorSet(handler.getPotentialType()).getClazz().getDeclaredConstructor().newInstance();

0 commit comments

Comments
 (0)