Skip to content

Add a new Game Mode

lafitteque edited this page Dec 3, 2024 · 1 revision

Adding a new Game Mode

Examples

  • CoreSaver mode itself is made using the hooks from All You Can Mine. You can find the repo here

  • EndlessCombat mode is an exemple of how to use All You Can Mine to create your own game mode. It adds a new gamemode where there is no mining and you should resist as long as you can against infinite waves. It also gives rewards after the waves. The repo can be find here

Current issue (editor only)

When in the godot editor, there can be some conflicts due to having two mods at the same time. But the dependency part of All You Can Mine works properly. This means that some of All You Can Mine's features will not work in the editor. If you want to use some of the new tiles from All You Can Mine and you are facing an issue, you will need to test it in the compiled game. For game modes that don't depend on All You Can Mine's features, there should be no issue when developping in the editor.

1) Register your game mode

Just use

Data.registerGameMode(yourGameModeName)
GameWorld.unlockElement(yourGameModeName)

in your modInit (in mod_main.gd). With this, a new button will appear in the loadout, but you will not be able to use it as the configuration of the loadout isn't known by the game.

2) Prepare the loadout

This is where this dependency comes in handy. You will need to add a scene to the tree in the group "gamemode-loadout" with a script attached to it. This script needs to have the following functions and attributes :

var id : String # name of the game mode, should be the same as in step 1

func initialize_from_loadout(loadout_scene) -> void:
    # Called in the _ready of MultiplayerLoadoutStage.gd
    # Use it to modify things from the loadout if needed or connect signals`

func generate_ui_block(loadout_scene) -> Node:
    # Used to add a UI Block in the loadout. Look at the tree of the loadout scene, there are blocks for each game mode, you can basically
    # copy and paste another game mode UI block and rename it

func has_difficulties() -> bool:
    # returns true if the game mode has difficulty choices (like in the relic hunt)

func has_map_sizes() -> bool:
    # returns true if the game mode has Map Size choices (like in the relic hunt)
	
func get_block_ui_name() -> String:
    # returns the name of the UI block given by generate_ui_block()

func has_tiledata() -> bool:
    # returns true if the mod adds an area to the left of the start position in the loadout (where the difficulty choices / assignments) are

func get_loadout_tiledata(stack_name : String) -> Array:
    # returns the tile data info as a list. For a simple game mode (without any difficulty / size choice), just don't add tiledata. If you want a simple
    # tileData, you can always return the vanilla ones 
    # expected result is [ [tileData , vector_offset] ] (with more elements if needed)


func fillGameModes(loadout_scene):
    # Hook in when filling the game modes

func set_gamemode_loadout(loadout_scene) -> void:
    # This section is needed to set the Loadout with loadout_scene.setLoadout(yourLoadoutInfo)
    # for reference, I use these lines :
    # var coresaver_loadout = GameWorld.lastLoadoutsByMode.get("relichunt").duplicate()
    # coresaver_loadout.difficulty = 3
    # coresaver_loadout.modeId = id
    # coresaver_loadout.worldId = GameWorld.getNextRandomWorldId()

3) Create a gamemode scene and add it to the vanilla game.

When a game mode is selected and the run button is pressed, the game looks for a scene in : "res://content/gamemode/gamemodename/Gamemodename.tscn". If the original gamemodes already offer what you need, just use :

var your_gamemode= preload("res://content/gamemode/relichunt/Relichunt.tscn")
your_gamemode.take_over_path("res://content/gamemode/yourgamemode/Yourgamemode.tscn")

This scene is used to trigger the finale wave, or winning conditions. As I didn't want to really look in what was necessary to create my own, I just used the vanilla one and manage my winning condition by giving to the game the winning conditions of the relichunt whenever my winning conditions are fulfilled. Here is an exemple :

Data.apply("inventory.relic", 1)
Data.apply("monsters.wavepresent", false)

I trigger the final battle by giving a relic and then I end the battle, forcing the game to end. This is not beautiful coding and it would be much better to code your own gamemode scene. Yet, it works for simple usecases.

4) Add a gamemode-prepare node to the tree

In order to prepare the gamemodes, the game needs to know which archetype to use and which worldmodifiers to apply, this is done by adding a scene to the tree in the group "gamemodes-prepare". It should have the following method :

func prepareGameMode(modeId, levelStartData):

Have a look at the examples. The CoreSaver gamemode-prepare script can be copy pasted (just change the archetype paths) for simple usecases.

Clone this wiki locally