Looting & loot tables

This commit is contained in:
kuroppoi 2021-05-30 22:46:09 +02:00
parent 0a0ec311fb
commit a9968c69ee
9 changed files with 1742 additions and 1 deletions

View file

@ -42,6 +42,7 @@ public class GameConfiguration {
long startTime = System.currentTimeMillis();
logger.info("Loading game configuration ...");
mapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true);
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true);
LoaderOptions options = new LoaderOptions();
options.setMaxAliasesForCollections(Short.MAX_VALUE);

View file

@ -8,6 +8,7 @@ import org.apache.logging.log4j.Logger;
import brainwine.gameserver.command.CommandManager;
import brainwine.gameserver.entity.player.PlayerManager;
import brainwine.gameserver.loot.LootManager;
import brainwine.gameserver.msgpack.MessagePackHelper;
import brainwine.gameserver.server.NetworkRegistry;
import brainwine.gameserver.server.Server;
@ -21,6 +22,7 @@ public class GameServer {
private static GameServer instance;
private final Thread handlerThread;
private final Queue<Runnable> tasks = new ConcurrentLinkedQueue<>();
private final LootManager lootManager;
private final ZoneManager zoneManager;
private final PlayerManager playerManager;
private final Server server;
@ -34,8 +36,9 @@ public class GameServer {
logger.info("Starting GameServer ...");
CommandManager.init();
GameConfiguration.init();
StaticZoneGenerator.init();
MessagePackHelper.init();
lootManager = new LootManager();
StaticZoneGenerator.init();
zoneManager = new ZoneManager();
playerManager = new PlayerManager();
NetworkRegistry.init();
@ -99,6 +102,10 @@ public class GameServer {
return shutdownRequested;
}
public LootManager getLootManager() {
return lootManager;
}
public ZoneManager getZoneManager() {
return zoneManager;
}

View file

@ -2,9 +2,11 @@ package brainwine.gameserver.entity.player;
import java.beans.ConstructorProperties;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@ -24,6 +26,8 @@ import brainwine.gameserver.entity.EntityType;
import brainwine.gameserver.entity.FacingDirection;
import brainwine.gameserver.item.Item;
import brainwine.gameserver.item.ItemRegistry;
import brainwine.gameserver.item.LootGraphic;
import brainwine.gameserver.loot.Loot;
import brainwine.gameserver.server.Message;
import brainwine.gameserver.server.messages.BlockMetaMessage;
import brainwine.gameserver.server.messages.ConfigurationMessage;
@ -525,6 +529,44 @@ public class Player extends Entity implements CommandExecutor {
return MathUtils.clamp(skills.getOrDefault(skill, 1), 1, MAX_NATURAL_SKILL_LEVEL);
}
public void awardLoot(Loot loot) {
awardLoot(loot, LootGraphic.LOOT);
}
public void awardLoot(Loot loot, LootGraphic graphic) {
List<Map<String, Object>> notifications = new ArrayList<>();
loot.getItems().forEach((item, quantity) -> {
inventory.addItem(item, quantity);
Map<String, Object> notification = new HashMap<>();
notification.put("item", item.getId());
notification.put("text", String.format("%s x %s", item.getTitle(), quantity));
notifications.add(notification);
});
Map<String, Object> dialog = new HashMap<>();
Map<String, Object> section = new HashMap<>();
section.put("list", notifications);
dialog.put("sections", Arrays.asList(section));
int crowns = loot.getCrowns();
if(crowns > 0) {
addCrowns(crowns);
section.put("text", isV3() ? String.format("<color=#ffd95f>%s shiny crowns!</color>", crowns) : String.format("%s shiny crowns!", crowns));
}
if(isV3()) {
dialog.put("title", "You found:");
dialog.put("type", graphic);
sendMessage(new DialogMessage(0, dialog));
} else {
section.put("title", "You found:");
section.put("text-color", "ffd95f");
notify(dialog, NotificationType.REWARD);
sendMessage(new EffectMessage(x, y, "chime", 1));
}
}
public Inventory getInventory() {
return inventory;
}

View file

@ -36,6 +36,9 @@ public class Item {
@JsonProperty("title")
private String title;
@JsonProperty("loot_graphic")
private LootGraphic lootGraphic = LootGraphic.NONE;
@JsonProperty("action")
private Action action = Action.NONE;
@ -78,6 +81,9 @@ public class Item {
@JsonProperty("crafting quantity")
private int craftingQuantity = 1;
@JsonProperty("loot")
private String[] lootCategories = {};
@JsonProperty("ingredients")
private List<CraftingIngredient> ingredients = new ArrayList<>();
@ -128,6 +134,10 @@ public class Item {
return id == 0;
}
public LootGraphic getLootGraphic() {
return lootGraphic;
}
public Action getAction() {
return action;
}
@ -200,6 +210,10 @@ public class Item {
return decayInventoryItem == null ? this : decayInventoryItem.get();
}
public String[] getLootCategories() {
return lootCategories;
}
public int getCraftingQuantity() {
return craftingQuantity;
}

View file

@ -6,9 +6,11 @@ import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
public enum ItemUseType {
AFTERBURNER,
CONTAINER,
CREATE_DIALOG,
DIALOG,
CHANGE,
FIELDABLE,
FLY,
TELEPORT,
ZONE_TELEPORT,

View file

@ -0,0 +1,22 @@
package brainwine.gameserver.item;
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
import brainwine.gameserver.msgpack.EnumValue;
import brainwine.gameserver.msgpack.RegisterEnum;
@RegisterEnum
public enum LootGraphic {
LOOT,
LOOT_RED,
LOOT_MECH,
@JsonEnumDefaultValue
NONE;
@EnumValue
public String getId() {
return toString().toLowerCase();
}
}

View file

@ -0,0 +1,46 @@
package brainwine.gameserver.loot;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import brainwine.gameserver.item.Item;
import brainwine.gameserver.zone.Biome;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Loot {
@JsonProperty("items")
private Map<Item, Integer> items = new HashMap<>();
@JsonProperty("crowns")
private int crowns;
@JsonProperty("frequency")
private int frequency = 1;
@JsonProperty("biome")
private Biome biome;
@JsonCreator
private Loot() {}
public Map<Item, Integer> getItems() {
return items;
}
public int getCrowns() {
return crowns;
}
public int getFrequency() {
return frequency;
}
public Biome getBiome() {
return biome;
}
}

View file

@ -0,0 +1,79 @@
package brainwine.gameserver.loot;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import brainwine.gameserver.util.WeightedList;
import brainwine.gameserver.zone.Biome;
public class LootManager {
private static final Logger logger = LogManager.getLogger();
private final Map<String, List<Loot>> lootTables = new HashMap<>();
public LootManager() {
loadLootTables();
}
private void loadLootTables() {
logger.info("Loading loot tables ...");
ObjectMapper mapper = new ObjectMapper();
File file = new File("loottables.json");
try {
if(!file.exists()) {
Files.copy(LootManager.class.getResourceAsStream("/loottables.json"), file.toPath());
}
Map<String, List<Loot>> loot = mapper.readValue(file, new TypeReference<Map<String, List<Loot>>>(){});
lootTables.putAll(loot);
} catch (IOException e) {
logger.error("Failed to load loot tables", e);
}
}
public List<Loot> getLootTable(String category) {
return lootTables.getOrDefault(category, Collections.emptyList());
}
public List<Loot> getEligibleLoot(int level, Biome biome, String... categories) {
List<Loot> eligibleLoot = new ArrayList<>();
for(String category : categories) {
eligibleLoot.addAll(getLootTable(category));
}
eligibleLoot.removeIf(loot -> loot.getBiome() != null && loot.getBiome() != biome);
if(Math.random() > level * 0.015) {
int[] frequencies = {18, 15, 12, 9, 7, 5, 4, 3, 2};
int minFrequency = level > frequencies.length ? 1 : frequencies[level - 1];
eligibleLoot.removeIf(loot -> loot.getFrequency() < minFrequency);
}
return eligibleLoot;
}
public Loot getRandomLoot(int level, Biome biome, String... categories) {
WeightedList<Loot> weightedLoot = new WeightedList<>();
List<Loot> eligibleLoot = getEligibleLoot(level, biome, categories);
for(Loot loot : eligibleLoot) {
weightedLoot.addEntry(loot, loot.getFrequency());
}
return weightedLoot.next();
}
}

File diff suppressed because it is too large Load diff