MidnightMods-ValheimFortress icon

ValheimFortress

Build a base, summon a challenge, defeat it and reap the rewards!

Last updated 5 days ago
Total downloads 46263
Total rating 10 
Categories Mods Enemies Misc Utility Mistlands Update Building Hildir's Request Update Ashlands Update Bog Witch Update
Dependency string MidnightMods-ValheimFortress-0.31.0
Dependants 59 other packages depend on this package

This mod requires the following mods to function

denikson-BepInExPack_Valheim-5.4.2202 icon
denikson-BepInExPack_Valheim

BepInEx pack for Valheim. Preconfigured and includes unstripped Unity DLLs.

Preferred version: 5.4.2202
ValheimModding-Jotunn-2.21.2 icon
ValheimModding-Jotunn

Jötunn (/ˈjɔːtʊn/, 'giant'), the Valheim Library was created with the goal of making the lives of mod developers easier. It enables you to create mods for Valheim using an abstracted API so you can focus on the actual content creation.

Preferred version: 2.21.2

README

ValheimFortress


What is Valheim Fortress

When the Valheim Devs released the blog "Fearsome Foes!" they talked about a concept called "Fortress Time!". They did not go into details about what this idea was, but I was very excited! However, what that ended up being, while exciting was not what I was expecting.

I wanted a system that would encourage building a massive fortress, defending it, and reaping rewards for doing so! The core system this mod presents is wave defense in a few different forms. In addition some new special defensive pieces are added to help you along the way.

Got a bug to report or just want to chat about the mod? Drop by the discord or github. discord logo github logo


Table of Contents

Features

The shrine of challenge

Shrine of Challenge example

The Shrine of Challenge is a buildable piece that allows you to call waves of enemies to attack you. It is highly configurable, and enemies will spawn outside of your build radius.

The goal with the shrine of challenge is to provide a variable but high level of difficulty raid, which the player(s) can invoke in exchange for a promised reward.

The shrine will gradually unlock more levels and rewards as the server defeats the various bosses. The shrine of challenge supports custom waves and rewards.

Shrine of the Arena

Shrine of Arena example

The Shrine of the Arena is somewhat the inverse of the shrine of challenge. Instead of enemies attacking from random remote locations the enemies all spawn on the shrine platform itself.

This shrine is designed to facilitate Arena fights, build yourself an Arena demonstrate your skills!

Again, this shrine is highly configurable and can use the same levels or seperate levels from the shrine of challenge. Build your own custom waves, select your favorite rewards and fight to the death!

Wild Shrines

Wild Shrine example

Wild shrines come in a number of different flavors, one type per biome. Each wild shrine will ask for different tribute, from their respective biome.

Upon providing the shrine with the required tribute it will spawn an easy wave of similar creatures, which will then reward you with resources from that biome upon completion. This is all configurable!

Help! What is the tribute for the wildshrine?!

Wildshrine Tribute Spoiler

The default tribute for wildshrines will be biome specific trophies. For example, the meadows wildshrine will accept boar trophies, deer trophies and neck trophies.

  • The blackforest shrine accepts trophies from the black forest.
  • The swamp shrine accepts trophies from the swamp.
  • The mountain shrine accepts trophies from the mountain.
  • The plains shrine accepts trophies from the plains.
  • The mistland shrine accepts trophies from the mistlands.

Defensive Structures

This mod also adds a few defensive structures to help you with dealing with massive invasions.

Defensive Structures
Name Icon
Stone Stakes Stone Stakes
Automated Ballista Automated Ballista

How to adjust the difficulty

The Shrine of challenge provides a number of key configuration values which can be used to adjust the difficulty level in many different ways.

Name Default What it Does
level_base_challenge_points 200 The base level of points all waves have, this primarily determines early level difficulty.
challenge_slope 15.0 Multiplier used against the slope, increasing will make everything slightly harder (larger impact on later waves) and lowering will make everything easier.
max_challenge_points 3000 This is a cap on how many points a wave can generate with, it primarily limits the max wave sizes (its intentionally relatively low, feel free to tune it upwards. Who needs to keep their base in one piece anyways?)
creature_star_chance 0.15 percentage 0.001-1.0, chance that a creature will spawn as a 1+ star variant, some creatures always spawn as multi-star, others always never spawn at a higher star rate.
Summary of the difficulty equation

And now you want to know how these values are actually used to compute the challenge points right? look at this summary below

allocated_challenge_points = Log(level^2) * (challenge_slope * level) + level_base_challenge_points

if (allocated_challenge_points > max_challenge_points) { allocated_challenge_points = max_challenge_points; }

Configuration

This mod is HIGHLY configurable. All buildings have configurable crafting recipes and many aspects about the shrine of challenge can be configured to your liking.

This mod uses almost exclusively server sided configuration. The server supports configuration syncing for Rewards, Monsters and the main config file. However, all configurations related to building pieces (like the ballista cost etc) are not reloaded during runtime, and will require a game restart.

This mod does support BepinEx in-game Configuration Configurations can also be edited in the config file within your Bepinex folder BepinEx\Config\com.midnightsfx.ValheimFortress.cfg

Finally Creature & Rewards configurations are handled seperatly through yaml, which is defined below.

Example in-game configuration

Basic configuration view in-game. basic configs

Admin Shrine configuration

If you are registered as an admin on your server (or hosting locally) you can edit shrine specific admin settings.

Currently this supports the following function, filtername which allows you to filter which levels can be selected at this specific shrine.

Filtername uses the following format:

filtername:level_name1,level_name2

Any levels which have the value levelName: level_name1 or levelName: level_name2 will show up as selectable levels at this shrine. This will not limit levels for any other shrines.

Adding Rewards

Rewards can be added through yaml definitions. You can add anything, but invalid prefabs will cause errors when spawning your reward, and you will recieve nothing. Many mods list their resouces prefabs, if you desire to have rewards from the shrine be from another mod. The Valheim Wiki is a great resource to find prefabs of vanilla componets.

The yaml configuration can be found within your mods configuration folder, under VFortress eg: BepInEx\config\VFortress

Rewards have the following structure, which is also listed inside the configuration file itself.

#################################################
# Shrine of Challenge Rewards Configuration
#################################################
# The below configuration values are loaded at the start of the game, and they are not actively watched for changes beyond that. You must restart your game for any changes to take effect.
#
# Rewards configurations have a number of key values
#  Coin:                               |- The name of the reward, this will be the diplayed name if there is no localization for this reward, which is likely the case for any custom entries.
#    enabled: true                     |- Whether or not the reward is enabled, you can use this to disable any vanilla rewards you do not want. At least 1 reward must be available at ALL times.
#    resource_cost: 5                  |- This is the cost to gain 1 of the particular reward. Points are generated based on how many monsters are spawned.
#    resource_prefab: "Coins"          |- This is the unity prefab name for a resource, you will often see mods list the prefabs they have added. Prefabs are also listed on the valheim wiki.
#    required_boss: "None"             |- This must be one of the following values: "None" "Eikythr" "TheElder" "BoneMass" "Moder" "Yagluth" "TheQueen"
#    rewardMinLevelIndex: 0            |- (OPTIONAL) This will require that a wave is of a certain strength in order to allow selecting this reward, disabled when set to 0.
#    rewardMaxLevelIndex: 0            |- (OPTIONAL) This reward will not be available on waves above a certain difficulty, disabled when set to 0.

Adding Monsters

Monsters can be added through yaml definitions. You can add any monster you want, but some custom creatures might have issues with the spawn modifications, its advised to test custom creature additions in singleplayer before adding them to a server.

Almost all vanilla creatures are already included in the available spawn pool. But their definitions can also be tuned through these configuration files. Don't want to face golemns? Disable them. The configuration for spawnable creatures can be found under your mods configuration folder under VFortress eg: BepInEx\config\VFortress

Creatures have the following definition structure, which is also listed inside the configuration file itself.

#################################################
# Shrine of Challenge Creature Configuration
#################################################
# The below configuration values are loaded at the start of the game, and they are not actively watched for changes beyond that. You must restart your game for any changes to take effect.
#
# Creature configurations have a number of key values
# Neck:                    |- This is the name of the creature being added, it is primarily used for display purposes and lookups
#  spawnCost: 5            |- This is how many points from the wave pool it costs to spawn one creature, smaller values allow many more spawns.
#  prefab: "Neck"          |- This is the creatures prefab, which will be used to spawn it.
#  spawnType: "common"     |- This can either be: "common" or "rare" or "unique", uniques are "bosses", most of the wave will be made up of common spawns, with a few rare spawns per wave.
#  biome: "Meadows"        |- This must be one of the following values: "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands". The biome determines the levels that will recieve this spawn, and how the spawn might be adjusted to
#                             fit higher difficulty waves. eg: a greydwarf spawning into a swamp level wave will recieve 1 bonus star, since it is from the black forest, which is 1 biome behind the swamp.

Add/Editing Levels

All of the levels used by the shrine of challenge and all other related shrines are collectively defined in the Levels.yaml file, which can be found under your mods configuration folder under VFortress eg: BepInEx\config\VFortress

There are many options available for configuring levels via the config files. Most of which is explained directly below.

However some additional context could be useful, one of the key componets to these level definitions is waveFormat which is defined in a similarly associated file and covered in a section below this. Wave formats are a collection of definitions that make up the percentages and creature catagories in a wave. For example, a wave could be composed of 30% COMMON enemies, 25% RARE enemies and another batch of 45% COMMON enemies. Each of these segments will select a different creature and the different catagories (COMMON, RARE, ELITE, UNIQUE) can be manipulated seperately.

#################################################
# Shrines of Challenge Levels Configuration
#################################################
# levels:
# - levelIndex: 1                                                  |- LevelIndex is the difficulty this wave is set at, valid values are 1+
#   levelForShrineTypes:                                           |- What shrines will host this level, multiple definitions can be applied
#     challenge: true                                              |-   Shrine of challenge will host this level
#     arena: true                                                  |-   Shrine of the arena will host this level
#   levelMenuLocalization: $shrine_menu_meadow                     |- This is the localization that will be displayed when selecting the level, if no key matches the $lookup the literal string will be used
#   requiredGlobalKey: NONE                                        |- This is the global key required to unlock this level more available here (https://valheim.fandom.com/wiki/Global_Keys)
#   biome: Meadows                                                 |- This is the biome used for this level. This determines what creatures are considered
#   waveFormat: Tutorial                                           |- This is the format of the wave, formates are defined in WaveStyles.yaml, it determines how many creatures, what catagory and percentage of total points they use
#   bossWaveFormat: TutorialBoss                                   |- This is the format if the wave is modified to be a boss wave
#   maxCreatureFromPreviousBiomes: 0                               |- This is the maximum number of creatures that can be selected from prior biomes
#   levelWarningLocalization: $shrine_warning_meadows              |- This is the announcement text that plays when the challenge starts as a normal wave, uses literal value if the localization does not exist
#   bossLevelWarningLocalization: $shrine_warning_meadows_boss     |- This is the announcement text that plays when the challenge starts as a boss wave, localizations are available here https://github.com/MidnightsFX/Valheim_Fortress/blob/master/JotunnModStub/Localizations/English.json
#   onlySelectMonsters: []                                         |- This is an array of monsters that are the only valid targets for this wave
#   excludeSelectMonsters: []                                      |- This is an array of monsters that are to be avoided for the wave
#   levelRewardOptionsLimitedTo:                                   |- When set, only the available rewards can be selected for this level, rewards still have their normal global key requirements
#     - Coin                                                       |- The rewards entry name of rewards that should be available for this level
#   commonSpawnModifiers:                                          |- Spawn modifiers are functions applied to each part of the wave, they can be different per catagory of monster
#     linearIncreaseRandomWaveAdjustment: true                     |-   In general, it is best to only use one type of spawn modifier per creature type
#     linearDecreaseRandomWaveAdjustment: false                    |- Linear Decrease/Increase will frontload or backload this creature in the various phase of the wave, meaning more of it will appear earlier or later depending on the modifier
#     partialRandomWaveAdjustment: false                           |- Partial random adjustment will add more significant random variance to the number of creatures that will spawn
#     onlyGenerateInSecondHalf: false                              |- Only generate in second half will prevent this type of creature from spawning in the earlier waves, this is useful for Elites/Rares when LinearDecrease is set for commons
#   rareSpawnModifiers:                                            |-   The start of the wave will have many commons, and they will taper off till the end, while elites would come into play only on the second half of the wave
#     linearIncreaseRandomWaveAdjustment: true
#     linearDecreaseRandomWaveAdjustment: false
#     partialRandomWaveAdjustment: false
#     onlyGenerateInSecondHalf: false
#   eliteSpawnModifiers:
#     linearIncreaseRandomWaveAdjustment: true
#     linearDecreaseRandomWaveAdjustment: false
#     partialRandomWaveAdjustment: false
#     onlyGenerateInSecondHalf: false
#   uniqueSpawnModifiers: 

Adding/Editing WaveStyles

Wavestyles are the percentage breakdowns of what catagories of creatures make up a wave. This is useful for balancing waves and for providing variety to the way that waves spawn.

For example, a wave with multiple COMMON entries will select as many of the available common entries as it can for the defined level (level restricts biome, potential creature selection etc). In the meadows this might result in: two groups of boars, or one group of boars and one group of Necks, or one boars and greylings or two boars. (since all creatures in the meadows are common by default). It is important to pay attention to how waves are defined and how you might have customized your creature definitions. For example if you made every creature common, many waves would spawn with less than the full amount of creatures and the amount of randomness would increase- but it might feel more like chance and less balanced.

#################################################
# Shrine of Challenge WaveStyles Configuration
#################################################
# WaveStyles configurations have a number of key values
# Easy:                      |- This is the key used to lookup this wave definition
#  WaveConfig                |- The wave configuration for each segment of the wave
#   - type: COMMON           |- This is the catagory of creature that will be selected
#     percent: 30            |- This is the percentage of the waves total point pool that will be used for this spawn

Adding/Editing Wildshrine configuration

Wildshrine configuration is split into three important parts. First part is the top level definition that defines which shrine this configuration will be applied to. There should only be one configuration per shrine type. If there are multiple configurations per shrine type it is likely that the first defined one will load. If there are no configurations for a shrine, and that shrine is enabled, you will likey experiance errors.

The second important part here is the wildShrineLevelsConfig array, which is the definition for what tribute and rewards a defined wave will have, in addition to the warning and finish messages. There can be as many levels defined for a shrine as you desire, but they should all have unique tribute requirements (the tribute prefab must be unique).

The third part of this definition is the wildLevelDefinition definition, these are abbreviated level definitions which will build out levels for the specified wildshrine based on the tributed required to activate it. In the example below here there is a wave of boars and greywdarfs that will spawn using the the 'Tutorial' wavestyle, at a difficulty of 2, with a maximum of 15 creatures per phase (4 phases by default, 8 for siege mode) The final part of the wave definition here are the spawn modifiers, you can find a full list of these modifiers on the Level definitions. linearIncreaseRandomWaveAdjustment will start the number of spawns out small, and increase them until the final wave (with random noise, making the increases less linear).

###################################################################################################################################################
# Wild Shrine Configuration
###################################################################################################################################################
# wildShrines:
# - definitionForWildShrine: VF_wild_shrine_green1                    |- The prefab that this set of configuration will be applied to
#   wildShrineNameLocalization: $wild_shrine_green                    |- The localization for the prefabs name (when hovered over) this uses a lookup value but defaults to its literal value
#   wildShrineRequestLocalization: $wild_shrine_green_request         |- What the shrine says when you interact with it
#   shrineUnacceptedTributeLocalization: $wild_shrine_not_interested  |- What the shrine says when you offer an incorrect tribute
#   shrineLargerTributeRequiredLocalization: $wild_shrine_hungry      |- What the shrine says when you do not offer enough tribute
#   wildShrineLevelsConfig:                                           |- Level configurations related to this shrine
#   - tributeName: TrophyBoar                                         |- The prefab name of the tribute required to activate this level
#     tributeAmount: 4                                                |- Amount of the tribute required to activate this level
#     rewards:                                                        |- Rewards for this level in the format of Prefab: cost eg: RawMeat: 14.
#       LeatherScraps: 14
#       RawMeat: 12
#     hardMode: false                                                 |- If hardmode should be enabled for this level (doubles the spawn point pool and gives 50% more rewards)
#     siegeMode: false                                                |- If siege mode should be enabled for this level (double the number of waves 4->8 and gives 50% more rewards)
#     wildshrineWaveStartLocalization: $wild_boars_attack             |- Localization text to display when this wave starts
#     wildshrineWaveEndLocalization: $wild_boars_defeated             |- Localization text to display when this wave is finished
#     wildLevelDefinition:
#       levelIndex: 2                                                 |- The difficulty level for this wave, valid values are 1+ (Refer to the readme for a breakdown of this equation)
#       biome: Meadows                                                |- The biome this wave is for, this impacts creature selection
#       waveFormat: Tutorial                                          |- The wavestyle this uses (from wavestyles.yml), this governs which catagories and the percentage makeup of the wave
#       levelWarningLocalization: $meadows_warning_wilderness         |- Localization for a between phase warning (often not used)
#       maxCreaturesPerPhaseOverride: 15                              |- Overrides the max creatures per wave to be this value (overrides the global config)
#       onlySelectMonsters:                                           |- Set of monsters that can be selected (From monsters.yml)
#       - Boar
#       - Greyling
#       excludeSelectMonsters:                                        |- Set of monsters that can't be selected (from monsters.yml) best used when OnlySelected is not set.
#       commonSpawnModifiers:                                         |- Spawn modifiers for common creatures
#         linearIncreaseRandomWaveAdjustment: true
#       rareSpawnModifiers:                                           |- Spawn modifiers for rare creatures
#       eliteSpawnModifiers:                                          |- Spawn modifiers for elite creatures

FAQ

Q. I am running an older version and do not see any of the wildshrines, what gives? A. You need to run genloc (as an admin on the server), this will freeze your client for a little, and add any missing locations to your world (IN UNEXPLORED AREAS). Please keep in mind that genloc can move existing locations etc and is generally advised against running it on large existing servers.

Q. I can't craft all of the pieces from this mod! They arn't visible in the hammer A . You should install and use SearsCatalog, this will allow the hammer panels to be resized/scrolled to fit any and all prefabs added. This may no longer be necessary on newer Valheim versions.

Q. There are remaining creatures and I can't find them!? A . Interacting with the shrine while the challenge is active gives you the option to summon fireworks on creatures or teleport them to the shrine (if there are only a few left, this is configurable)

Q. I broke my configuration files and want to try again. A. You can delete any/all yaml configuration (or the primary config file) from this mod and it will be automatically generated again for you on startup.

Q. Wave generation seems insanely unbalanced, what gives? A. Delete your configurations (SpawnableCreatures.yaml in the VFortress folder) and MidnightsFX.ValheimFortress.cfg, this will regenerate new configurations with the defaults. If you are trying to increase or lower the difficulty from this base point, it is recommended you start by decreasing/increasing the difficulty slope in small increments

Q. The skeltons are attacking the greydwarfs again A. The faction changes (and drop removal etc) are not persisted across game restarts. So if you save/quit during a challenge the remaining creatures will not act the same when you log back in, and will revert back to their vanilla settings. Loosing stars, gaining their loot, loosing their connection to the shrine. It won't cause issues for your game. But you will still have to kill them normally, and won't get shrine rewards for it.

Q. My game freezes or becomes very slow for some period of time during waves or when creatures are spawning, what do I do? A. This mod is fairly intensive on the CPU (during wave generation), in order to perform all of the calculations that go into creating an interesting and varied wave- then actually spawning all of those creatures (and the potentially massive number of interactions with them) can be very taxing on your computer. If you find this to be an issue consider reducing the configured number of maximum creatures to spawn or increasing the number of cores used for GC collection. A. Reduce max_creatures_per_wave A. Optionally, Increase GC collection duration. From Steam, Right Click on Valheim -> Manage -> Browse Local Files. Go to valheim_Data folder and open boot config file. change gc-max-time-slice=3 to gc-max-time-slice=10 this will allow scripts to execute for a longer timeperiod, which will allow these long-running scripts to execute without killing your game.

Q. My game freezes, crashes or becomes very slow when the reward is spawned, what do I do? A. Reduce the value of MaxRewardsPerSecond, this will spread out reward spawning over a longer period and reduce the impact on your game. A. Optionally, Increase GC collection duration. From Steam, Right Click on Valheim -> Manage -> Browse Local Files. Go to valheim_Data folder and open boot config file. change gc-max-time-slice=3 to gc-max-time-slice=10 this will allow scripts to execute for a longer timeperiod, which will allow these long-running scripts to execute without killing your game.

Q. Rewards are too generous / rewards arn't rewarding enough! A. You can configure all of the reward costs, and the bonuses that are applied to determine the pool for rewards. I suggest you read the main mods configuration file and look at the rewards config file.

Localizations - Translations

I accept community translations! Existing localizations can be found here. I will keep the English translation up to date, if you would like to provide a translation feel free to reach out to me on discord or open up a github issue.

Future Features / Incomplete things

There are a number of things that I plan on adding in the future. Here is the current list.

  • Shrine of Challenge

    • Add ward support checking to ensure that the player interacting with the shrine is allowed
    • Add a failsafe for waves to despawn after a long period of time (if the player is unable to kill them etc)
  • defenses

    • Another tier of trap for the plains
    • Another tier of walls

Other Mods

If you like this mod maybe you'll like my other work

Valheim Armory

Credits

  • A big thank you to Margmas, Venture, Redseiko and Probablykory for providing some examples and answers to my silly questions (and continuing to do so!)
  • The valheim team for continuing to develop valheim, even after their initial roadmap!
    • The continued blogposts about upcoming Valheim content, which got my gears grinding to make this mod
  • Unity Ultimate VFX for some or partial visual effects
  • Traslations credits to: Azathoth

Known issues

  • Building pieces sometimes don't have destructable bits
  • Building pieces don't have wear and tear
  • Mobs can form a 'spawn tower' (especially common when using the Arena spawner with high spawn limits)
  • Automated turret likes to fire off into space instead of hitting its target occassionally (its aim isn't perfect, so sometimes this is intended)
    • If you can reliably reproduce this issue please report it on the Github or Discord