diff --git a/build.gradle b/build.gradle index 6721b28..6104eeb 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { project.ext.modID = "fair.examplemod" // The unique id of your mod. Must be all lowercase and cannot use special characters. project.ext.modName = "Example Mod" // The display name of your mod. project.ext.modVersion = "1.0" // Your current builds version. Must follow the xx.xx... format. -project.ext.gameVersion = "1.0.2" // The target game version. +project.ext.gameVersion = "1.1.1" // The target game version. project.ext.modDescription = "Just an example mod" // Short description of what your mod is. project.ext.author = "Fair" // Your name @@ -157,4 +157,4 @@ task buildModJar(type: Jar) { archiveName "${jarName}.jar" destinationDir file(buildLocation) -} \ No newline at end of file +} diff --git a/src/main/java/examplemod/ExampleMod.java b/src/main/java/examplemod/ExampleMod.java index 349a9e3..bd38e2f 100644 --- a/src/main/java/examplemod/ExampleMod.java +++ b/src/main/java/examplemod/ExampleMod.java @@ -1,5 +1,6 @@ package examplemod; + import examplemod.examples.*; import necesse.engine.commands.CommandsManager; import necesse.engine.modLoader.annotations.ModEntry; @@ -9,6 +10,7 @@ import necesse.inventory.recipe.Recipe; import necesse.inventory.recipe.Recipes; import necesse.level.maps.biomes.Biome; +import examplemod.examples.items.*; @ModEntry public class ExampleMod { @@ -16,6 +18,13 @@ public class ExampleMod { public void init() { System.out.println("Hello world from my example mod!"); + // Register a simple biome that will not appear in natural world gen. + BiomeRegistry.registerBiome("exampleincursion", new ExampleBiome(), false); + // Register the incursion biome with tier requirement 1. + IncursionBiomeRegistry.registerBiome("exampleincursion", new ExampleIncursionBiome(), 1); + // Register the level class used for the incursion. + LevelRegistry.registerLevel("exampleincursionlevel", ExampleIncursionLevel.class); + // Register our tiles TileRegistry.registerTile("exampletile", new ExampleTile(), 1, true); @@ -24,8 +33,12 @@ public void init() { // Register our items ItemRegistry.registerItem("exampleitem", new ExampleMaterialItem(), 10, true); + ItemRegistry.registerItem("examplehuntincursionitem", new ExampleHuntIncursionMaterialItem(), 50, true); ItemRegistry.registerItem("examplesword", new ExampleSwordItem(), 20, true); ItemRegistry.registerItem("examplestaff", new ExampleProjectileWeapon(), 30, true); + ItemRegistry.registerItem("examplepotionitem", new ExamplePotionItem(), 10, true); + + ItemRegistry.registerItem("examplefooditem", new ExampleFoodItem(),15, true); // Register our mob MobRegistry.registerMob("examplemob", ExampleMob.class, true); @@ -37,6 +50,8 @@ public void init() { BuffRegistry.registerBuff("examplebuff", new ExampleBuff()); PacketRegistry.registerPacket(ExamplePacket.class); + + } public void initResources() { @@ -80,7 +95,19 @@ public void postInit() { } ).showAfter("exampleitem")); // Show the recipe after example item recipe - // Add out example mob to default cave mobs. + // Example food item recipe + Recipes.registerModRecipe(new Recipe( + "examplefooditem", + 1, + RecipeTechRegistry.COOKING_POT, + new Ingredient[]{ + new Ingredient("bread", 1), + new Ingredient("strawberry", 2), + new Ingredient("sugar", 1) + } + )); + + // Add our example mob to default cave mobs. // Spawn tables use a ticket/weight system. In general, common mobs have about 100 tickets. Biome.defaultCaveMobs .add(100, "examplemob"); diff --git a/src/main/java/examplemod/examples/ExampleBiome.java b/src/main/java/examplemod/examples/ExampleBiome.java new file mode 100644 index 0000000..7b2516c --- /dev/null +++ b/src/main/java/examplemod/examples/ExampleBiome.java @@ -0,0 +1,34 @@ +package examplemod.examples; + +import necesse.engine.AbstractMusicList; +import necesse.engine.MusicList; +import necesse.engine.registries.MusicRegistry; +import necesse.entity.mobs.PlayerMob; +import necesse.level.maps.Level; +import necesse.level.maps.biomes.Biome; +import necesse.level.maps.biomes.MobSpawnTable; + +// A minimalist biome used solely for the ExampleIncursion +// the Example Mob is used here as the spawn +public class ExampleBiome extends Biome { + public static MobSpawnTable critters = (new MobSpawnTable()) + .include(Biome.defaultCaveCritters); + public static MobSpawnTable mobs = new MobSpawnTable() + .add(100,"examplemob"); + + @Override + public AbstractMusicList getLevelMusic(Level level, PlayerMob perspective) { + return new MusicList(MusicRegistry.ForestPath); + } + + @Override + public MobSpawnTable getCritterSpawnTable(Level level) { + return critters; + } + + @Override + public MobSpawnTable getMobSpawnTable(Level level) { + + return mobs; + } +} \ No newline at end of file diff --git a/src/main/java/examplemod/examples/ExampleIncursionBiome.java b/src/main/java/examplemod/examples/ExampleIncursionBiome.java new file mode 100644 index 0000000..8d42083 --- /dev/null +++ b/src/main/java/examplemod/examples/ExampleIncursionBiome.java @@ -0,0 +1,98 @@ +package examplemod.examples; + +import necesse.engine.network.server.Server; +import necesse.engine.registries.ItemRegistry; +import necesse.engine.util.LevelIdentifier; +import necesse.engine.util.TicketSystemList; +import necesse.engine.world.WorldEntity; +import necesse.entity.objectEntity.FallenAltarObjectEntity; +import necesse.inventory.item.Item; +import necesse.inventory.lootTable.LootItemInterface; +import necesse.inventory.lootTable.lootItem.ChanceLootItem; +import necesse.level.maps.IncursionLevel; +import necesse.level.maps.incursion.*; +import necesse.inventory.lootTable.LootTable; + +import java.util.Collection; +import java.util.Collections; +import java.util.function.Supplier; +import java.awt.Color; +import java.util.ArrayList; + +/** + * An example incursion biome. + * This class defines how the incursion behaves: rewards, available objectives, + * altar appearance, and which level class is used. + */ +public class ExampleIncursionBiome extends IncursionBiome { + + // String ID passed to the IncursionBiome base class + public ExampleIncursionBiome() { + super("reaper"); + } + + // Items required to be obtained when completing an extraction objective in this incursion + @Override + public Collection getExtractionItems(IncursionData data) { + return Collections.singleton(ItemRegistry.getItem("tungstenore")); + } + + /** + * Loot dropped from mobs during hunt-type incursion objectives. + * This example returns a custom item to demonstrate adding new drops. + */ + @Override + public LootTable getHuntDrop(IncursionData incursionData) { + return new LootTable(new LootItemInterface[] { + (LootItemInterface) new ChanceLootItem(0.66F, "examplehuntincursionitem") + }); + } + + // Defines which incursion types are available and their relative chances + @Override + public TicketSystemList> getAvailableIncursions(int tabletTier, IncursionData incursionData) { + TicketSystemList> system = new TicketSystemList(); + + // Base ticket weights for each incursion type + int huntTickets = 100; + int extractionTickets = 100; + + // Apply modifiers from the previous incursion, if present + if (incursionData != null) { + huntTickets = (int)(huntTickets * ((Float)incursionData.nextIncursionModifiers + .getModifier(IncursionDataModifiers.MODIFIER_HUNT_DROPS)).floatValue()); + extractionTickets = (int)(extractionTickets * ((Float)incursionData.nextIncursionModifiers + .getModifier(IncursionDataModifiers.MODIFIER_EXTRACTION_DROPS)).floatValue()); + } + + // Register hunt and extraction incursions with their calculated weights + system.addObject(huntTickets, () -> new BiomeHuntIncursionData(1.0F, this, tabletTier)); + system.addObject(extractionTickets, () -> new BiomeExtractionIncursionData(1.0F, this, tabletTier)); + return system; + } + + // Creates a new incursion level instance when players enter through the fallen altar + @Override + public IncursionLevel getNewIncursionLevel(FallenAltarObjectEntity altar, LevelIdentifier identifier, + BiomeMissionIncursionData incursion, Server server, + WorldEntity world, AltarData altarData) { + return new ExampleIncursionLevel(identifier, incursion, world, altarData); + } + + /** + * Colors used for the glowing gateway lights on the fallen altar. + * IncursionBiome requires this method; at least 4 colors are needed. + */ + @Override + public ArrayList getFallenAltarGatewayColorsForBiome() { + ArrayList colors = new ArrayList<>(); + // Repeat colors to satisfy the altar rendering requirements + colors.add(new Color(181, 80, 120)); + colors.add(new Color(215, 42, 52)); + colors.add(new Color(181, 92, 59)); + colors.add(new Color(181, 80, 120)); + colors.add(new Color(215, 42, 52)); + colors.add(new Color(181, 92, 59)); + return colors; + } +} diff --git a/src/main/java/examplemod/examples/ExampleIncursionLevel.java b/src/main/java/examplemod/examples/ExampleIncursionLevel.java new file mode 100644 index 0000000..8835d6d --- /dev/null +++ b/src/main/java/examplemod/examples/ExampleIncursionLevel.java @@ -0,0 +1,87 @@ +package examplemod.examples; + +import necesse.engine.GameEvents; +import necesse.engine.events.GameEvent; +import necesse.engine.events.PreventableGameEvent; +import necesse.engine.events.worldGeneration.GenerateCaveLayoutEvent; +import necesse.engine.events.worldGeneration.GeneratedCaveOresEvent; +import necesse.engine.registries.BiomeRegistry; +import necesse.engine.registries.ObjectRegistry; +import necesse.engine.util.LevelIdentifier; +import necesse.engine.world.WorldEntity; +import necesse.level.maps.IncursionLevel; +import necesse.level.maps.Level; +import necesse.level.maps.generationModules.CaveGeneration; +import necesse.level.maps.generationModules.PresetGeneration; +import necesse.level.maps.incursion.AltarData; +import necesse.level.maps.incursion.BiomeExtractionIncursionData; +import necesse.level.maps.incursion.BiomeMissionIncursionData; +import necesse.level.maps.incursion.IncursionBiome; + +/** + * Example incursion level. + * Demonstrates what is required for a working incursion: + * cave generation, entrance creation, and ore placement. + */ +public class ExampleIncursionLevel extends IncursionLevel { + + /** + * this constructor has to be formed in this way and present otherwise the game wont register the level to the registry + */ + public ExampleIncursionLevel(LevelIdentifier identifier, int width, int height, WorldEntity worldEntity) { + super(identifier, width, height, worldEntity); + this.baseBiome = BiomeRegistry.getBiome("exampleincursion"); + this.isCave = true; + } + + /** + * Constructor used when an incursion is entered. + * Creates a fixed-size level and immediately generates its contents. + */ + public ExampleIncursionLevel(LevelIdentifier identifier, BiomeMissionIncursionData incursionData, WorldEntity worldEntity, AltarData altarData) { + super(identifier, 150, 150, incursionData, worldEntity); + this.baseBiome = BiomeRegistry.getBiome("exampleincursion"); + this.isCave = true; + generateLevel(incursionData, altarData); + } + + public void generateLevel(BiomeMissionIncursionData incursionData, AltarData altarData) { + + // Create the cave generator using deep rock tiles for floors and walls + CaveGeneration cg = new CaveGeneration(this, "deeprocktile", "deeprock"); + + // Seed the generator so this incursion layout is deterministic per mission + cg.random.setSeed(incursionData.getUniqueID()); + + // Fire the cave layout generation event, allowing mods or perks to modify + // or cancel cave generation before the default logic runs + GameEvents.triggerEvent( + (PreventableGameEvent) new GenerateCaveLayoutEvent(this, cg), + e -> cg.generateLevel(0.38F, 4, 3, 6) + ); + + // Used to reserve space so later generation steps avoid overwriting the entrance + PresetGeneration entranceAndPerkPresets = new PresetGeneration(this); + + // Generate a incursion entrance that clears terrain, + // blends edges, reserves space, and places the return portal + IncursionBiome.generateEntrance( + this, + entranceAndPerkPresets, + cg.random, + 32, + cg.rockTile, + "exampletile", + "exampletile", + "exampleobject" + ); + + // For extraction incursions, guarantee tungsten ore veins for objectives + if (incursionData instanceof BiomeExtractionIncursionData) { + cg.generateGuaranteedOreVeins(40, 4, 8, ObjectRegistry.getObjectID("tungstenoredeeprock")); + } + + // Notify listeners that cave ore generation has completed + GameEvents.triggerEvent((GameEvent) new GeneratedCaveOresEvent((Level) this, cg)); + } +} \ No newline at end of file diff --git a/src/main/java/examplemod/examples/items/ExampleFoodItem.java b/src/main/java/examplemod/examples/items/ExampleFoodItem.java new file mode 100644 index 0000000..130f01b --- /dev/null +++ b/src/main/java/examplemod/examples/items/ExampleFoodItem.java @@ -0,0 +1,25 @@ +package examplemod.examples.items; + +import necesse.engine.modifiers.ModifierValue; +import necesse.entity.mobs.buffs.BuffModifiers; +import necesse.inventory.item.Item; +import necesse.inventory.item.placeableItem.consumableItem.food.FoodConsumableItem; +import necesse.level.maps.levelData.settlementData.settler.Settler; + +public class ExampleFoodItem extends FoodConsumableItem { + public ExampleFoodItem() { + super( + 250, // stack size + Item.Rarity.COMMON, // rarity + Settler.FOOD_FINE, // food tier + 20, // nutrition + 480, // buff duration in seconds + new ModifierValue<>(BuffModifiers.MAX_HEALTH_FLAT, 10), + new ModifierValue<>(BuffModifiers.SPEED, 0.05f) + ); + + // Configure additional properties after super() + this.spoilDuration(480); // spoil duration in minutes + this.addGlobalIngredient("anycookedfood");// NOTE: returns Item + } +} \ No newline at end of file diff --git a/src/main/java/examplemod/examples/items/ExampleHuntIncursionMaterialItem.java b/src/main/java/examplemod/examples/items/ExampleHuntIncursionMaterialItem.java new file mode 100644 index 0000000..8c15c37 --- /dev/null +++ b/src/main/java/examplemod/examples/items/ExampleHuntIncursionMaterialItem.java @@ -0,0 +1,11 @@ +package examplemod.examples.items; + +import necesse.inventory.item.matItem.MatItem; + +public class ExampleHuntIncursionMaterialItem extends MatItem { + + public ExampleHuntIncursionMaterialItem() { + super(100, Rarity.RARE); + } + +} diff --git a/src/main/java/examplemod/examples/ExampleMaterialItem.java b/src/main/java/examplemod/examples/items/ExampleMaterialItem.java similarity index 83% rename from src/main/java/examplemod/examples/ExampleMaterialItem.java rename to src/main/java/examplemod/examples/items/ExampleMaterialItem.java index 347d2f2..a20ddb6 100644 --- a/src/main/java/examplemod/examples/ExampleMaterialItem.java +++ b/src/main/java/examplemod/examples/items/ExampleMaterialItem.java @@ -1,4 +1,4 @@ -package examplemod.examples; +package examplemod.examples.items; import necesse.inventory.item.matItem.MatItem; diff --git a/src/main/java/examplemod/examples/items/ExamplePotionItem.java b/src/main/java/examplemod/examples/items/ExamplePotionItem.java new file mode 100644 index 0000000..87dcd4d --- /dev/null +++ b/src/main/java/examplemod/examples/items/ExamplePotionItem.java @@ -0,0 +1,11 @@ +package examplemod.examples.items; +import necesse.inventory.item.Item; +import necesse.inventory.item.placeableItem.consumableItem.potionConsumableItem.SimplePotionItem; +import examplemod.examples.ExampleBuff; + +public class ExamplePotionItem extends SimplePotionItem { + public ExamplePotionItem() { + super(100,Rarity.COMMON,"examplebuff",100, new String[] { "examplepotionitemtip" }); + } + +} \ No newline at end of file diff --git a/src/main/resources/items/examplefooditem.png b/src/main/resources/items/examplefooditem.png new file mode 100644 index 0000000..fbb1243 Binary files /dev/null and b/src/main/resources/items/examplefooditem.png differ diff --git a/src/main/resources/items/examplehuntincursionitem.png b/src/main/resources/items/examplehuntincursionitem.png new file mode 100644 index 0000000..d05149e Binary files /dev/null and b/src/main/resources/items/examplehuntincursionitem.png differ diff --git a/src/main/resources/items/exampleincursiontablet.png b/src/main/resources/items/exampleincursiontablet.png new file mode 100644 index 0000000..5e6bfd2 Binary files /dev/null and b/src/main/resources/items/exampleincursiontablet.png differ diff --git a/src/main/resources/items/examplepotionitem.png b/src/main/resources/items/examplepotionitem.png new file mode 100644 index 0000000..c7eeadd Binary files /dev/null and b/src/main/resources/items/examplepotionitem.png differ diff --git a/src/main/resources/locale/en.lang b/src/main/resources/locale/en.lang index 741a504..3306996 100644 --- a/src/main/resources/locale/en.lang +++ b/src/main/resources/locale/en.lang @@ -6,14 +6,24 @@ exampleobject=Example Object [item] exampleitem=Example Item +examplehuntincursionitem=Example Hunt Incursion Item +examplepotionitem=Example Potion examplesword=Example Sword examplestaff=Example Staff +examplefooditem=Example Food [itemtooltip] examplestafftip=Shoots a homing, piercing projectile +examplepotionitemtip= An example potion [mob] examplemob=Example Mob [buff] -examplebuff=Example Buff \ No newline at end of file +examplebuff=Example Buff + +[biome] +exampleincursion=Example Incursion + +[incursion] +exampleincursion=Example Incursion \ No newline at end of file