Skip to content

Commit

Permalink
Support Custom Level Generation
Browse files Browse the repository at this point in the history
* Adjusting menu layout

* Refining menu layout

* Wiring up menu items

* Loading generators dynamically

* Making sure no duplicates get added

* Adding optional TODO

* Restructuring room generator menu item

* Saving WIP

* Using simpler approach

* 💄

* Working on level generator

* Fixing Mac path issues

* Fixing sort mechanism

* Adjusting SetThemeDialog

* 💄

* 💄

* Simplifying backend

* Clearing old levels properly

* Simplifying compare logic

* 💄

* Guarding against invalid theme

* Checking for valid room builders

* Refactoring selection logic checks

Co-authored-by: Joshua Skelton <joshua.skelton@gmail.com>
  • Loading branch information
Felix Siebeneicker and joshuaskelly authored Nov 3, 2020
1 parent a4b312d commit 590fa25
Show file tree
Hide file tree
Showing 9 changed files with 417 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.interrupt.dungeoneer.editor.ui.EditorUi;
import com.interrupt.dungeoneer.editor.ui.SaveChangesDialog;
import com.interrupt.dungeoneer.editor.ui.TextureRegionPicker;
import com.interrupt.dungeoneer.editor.ui.menu.generator.GeneratorInfo;
import com.interrupt.dungeoneer.editor.utils.LiveReload;
import com.interrupt.dungeoneer.entities.*;
import com.interrupt.dungeoneer.entities.Entity.ArtType;
Expand Down Expand Up @@ -319,6 +320,8 @@ protected Decal newObject () {

private TileSelection entireLevelSelection;

public GeneratorInfo generatorInfo;

public EditorApplication() {
frame = new JFrame("DelvEdit");

Expand Down Expand Up @@ -398,11 +401,12 @@ public void init(){
loadEntities();
loadMonsters();

Gdx.input.setCursorCatched(false);
Gdx.input.setCursorCatched(false);
generatorInfo = new GeneratorInfo();
initTextures();

pickedWallTextureAtlas = pickedWallBottomTextureAtlas = pickedFloorTextureAtlas = pickedCeilingTextureAtlas =
TextureAtlas.cachedRepeatingAtlases.firstKey();
TextureAtlas.cachedRepeatingAtlases.firstKey();

createEmptyLevel(17, 17);
}
Expand Down
83 changes: 4 additions & 79 deletions DelvEdit/src/com/interrupt/dungeoneer/editor/ui/EditorUi.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
import com.interrupt.api.steam.SteamApi;
import com.interrupt.dungeoneer.editor.*;
import com.interrupt.dungeoneer.editor.ui.menu.*;
import com.interrupt.dungeoneer.editor.ui.menu.generator.LevelGeneratorMenuItem;
import com.interrupt.dungeoneer.editor.ui.menu.generator.RoomGeneratorMenuItem;
import com.interrupt.dungeoneer.entities.Entity;
import com.interrupt.dungeoneer.game.Game;
import com.interrupt.dungeoneer.game.Level;
import com.interrupt.dungeoneer.generator.RoomGenerator;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
Expand Down Expand Up @@ -55,71 +55,6 @@ public class EditorUi {

Viewport viewport;

private ActionListener makeLevelGeneratorAction(final String theme, final String roomGenerator) {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
Editor.app.getLevel().editorMarkers.clear();
Editor.app.getLevel().entities.clear();
Editor.app.getLevel().theme = theme;
Editor.app.getLevel().generated = true;
Editor.app.getLevel().dungeonLevel = 0;
Editor.app.getLevel().crop(0, 0, 17 * 5, 17 * 5);
Editor.app.getLevel().roomGeneratorChance = 0.4f;
Editor.app.getLevel().roomGeneratorType = roomGenerator;
Editor.app.getLevel().generate(Level.Source.EDITOR);
Editor.app.refresh();

lastGeneratedLevelType = theme;
lastGeneratedLevelRoomType = roomGenerator;
}
};
}

private static String lastGeneratedLevelType = "DUNGEON";
private static String lastGeneratedLevelRoomType = "DUNGEON_ROOMS";
private ActionListener makeAnotherLevelGeneratorAction() {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
makeLevelGeneratorAction(lastGeneratedLevelType, lastGeneratedLevelRoomType).actionPerformed(actionEvent);
}
};
}

private ActionListener makeRoomGeneratorAction(final String generatorType) {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
Editor.app.getLevel().editorMarkers.clear();
Editor.app.getLevel().entities.clear();

Level generatedLevel = new Level(17,17);
generatedLevel.roomGeneratorType = generatorType;

RoomGenerator g = new RoomGenerator(generatedLevel, generatorType);
g.generate(true, true, true, true);

Editor.app.getLevel().crop(0, 0, generatedLevel.width, generatedLevel.height);
Editor.app.getLevel().paste(generatedLevel, 0, 0);

Editor.app.refresh();

lastGeneratedRoomType = generatorType;
}
};
}

private static String lastGeneratedRoomType = "DUNGEON_ROOMS";
private ActionListener makeAnotherRoomGeneratorAction() {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
makeRoomGeneratorAction(lastGeneratedRoomType).actionPerformed(actionEvent);
}
};
}

public EditorUi() {
defaultSkin = new Skin(Game.getInternal("ui/editor/HoloSkin/Holo-dark-hdpi.json"),
new TextureAtlas(Game.getInternal("ui/editor/HoloSkin/Holo-dark-hdpi.atlas")));
Expand Down Expand Up @@ -359,18 +294,8 @@ public void actionPerformed(ActionEvent e) {
.addItem(new MenuItem("Set Theme", smallSkin, setThemeAction))
.addItem(new MenuItem("Set Fog Settings", smallSkin, setFogSettingsAction))
.addSeparator()
.addItem(new MenuItem("Generate Room", smallSkin, makeAnotherRoomGeneratorAction()).setAccelerator(new MenuAccelerator(Keys.G, false, true))
.addItem(new MenuItem("Dungeon Room", smallSkin, makeRoomGeneratorAction("DUNGEON_ROOMS")))
.addItem(new MenuItem("Cave Room", smallSkin, makeRoomGeneratorAction("CAVE_ROOMS")))
.addItem(new MenuItem("Sewer Room", smallSkin, makeRoomGeneratorAction("SEWER_ROOMS")))
.addItem(new MenuItem("Temple Room", smallSkin, makeRoomGeneratorAction("TEMPLE_ROOMS")))
)
.addItem(new MenuItem("Generate Level", smallSkin, makeAnotherLevelGeneratorAction())
.addItem(new MenuItem("Dungeon", smallSkin, makeLevelGeneratorAction("DUNGEON", "DUNGEON_ROOMS")))
.addItem(new MenuItem("Cave", smallSkin, makeLevelGeneratorAction("CAVE", "CAVE_ROOMS")))
.addItem(new MenuItem("Sewer", smallSkin, makeLevelGeneratorAction("SEWER", "SEWER_ROOMS")))
.addItem(new MenuItem("Temple", smallSkin, makeLevelGeneratorAction("UNDEAD", "TEMPLE_ROOMS")))
)
.addItem(new RoomGeneratorMenuItem(smallSkin))
.addItem(new LevelGeneratorMenuItem(smallSkin))
);

if(SteamApi.api.isAvailable()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,57 +1,20 @@
package com.interrupt.dungeoneer.editor.ui;

import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.utils.Array;
import com.interrupt.dungeoneer.game.Game;
import com.interrupt.dungeoneer.editor.Editor;
import com.interrupt.dungeoneer.game.Level;

import java.io.File;
import java.io.FileFilter;

public class SetThemeDialog extends Dialog {

SelectBox themeSelect;
SelectBox<String> themeSelect;

public SetThemeDialog(Skin skin, Level level) {
super("Set Level Theme for Testing", skin);

themeSelect = new SelectBox(skin);

Array<String> mods = Game.getModManager().modsFound;
Array<String> themes = new Array<String>();

// Go find all the mod themes
for(String mod : mods) {
FileHandle dir = Game.getFile(mod + "/generator");
if(dir.isDirectory()) {
FileHandle[] dirs = dir.list(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});

for(int i = 0; i < dirs.length; i++) {
String[] path = dirs[i].path().split("/");
String theme = path[path.length - 1].toUpperCase();
if(!themes.contains(theme, false)) themes.add(theme);
}
}
}

// Now add internally packaged themes
Array<FileHandle> packagedThemes = Game.findPackagedFiles("info.dat");
for(FileHandle f : packagedThemes) {
FileHandle themeDir = f.parent();
if(themeDir.parent().name().equals("generator")) {
String theme = themeDir.name().toUpperCase();
if(!themes.contains(theme, false)) themes.add(theme);
}
}

themes.sort();
themeSelect = new SelectBox<String>(skin);

Array<String> themes = Editor.app.generatorInfo.getThemes();
themeSelect.setItems(themes);

if(level.theme != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.interrupt.dungeoneer.editor.ui.menu.generator;

import java.io.File;
import java.io.FileFilter;
import java.util.Comparator;

import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.interrupt.dungeoneer.game.Game;
import com.interrupt.dungeoneer.game.Level;
import com.interrupt.dungeoneer.generator.SectionDefinition;

public class GeneratorInfo {
private Array<String> themes = new Array<String>();
private Array<String> builders = new Array<String>();

private Array<SectionDefinition> sectionDefinitions = new Array<SectionDefinition>();

public Level lastGeneratedLevelTemplate;
public Level lastGeneratedRoomTemplate;

public GeneratorInfo() {
refresh();
}

public void refresh() {
themes.clear();
sectionDefinitions.clear();

Array<String> mods = Game.getModManager().modsFound;
for (String mod : mods) {
refreshGenerator(mod);
refreshData(mod);
}

themes.sort();
}

private void refreshGenerator(String mod) {
FileHandle parent = Game.getInternal(mod + "/generator");
if (!parent.exists() || !parent.isDirectory()) {
return;
}

FileHandle[] children = parent.list(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isDirectory();
}
});

for (FileHandle child : children) {
// Check for theme definition.
FileHandle info = Game.getInternal(mod + "/generator/" + child.name() + "/info.dat");
if (info.exists()) {
String theme = child.name().toUpperCase();

if (!themes.contains(theme, false)) {
themes.add(theme);
}
}

// Check for room/level definition.
FileHandle section = Game.getInternal(mod + "/generator/" + child.name() + "/section.dat");
if (section.exists()) {
SectionDefinition sectionDefinition = Game.fromJson(SectionDefinition.class, section);

if (!sectionDefinitions.contains(sectionDefinition, false)) {
sectionDefinitions.add(sectionDefinition);
}
}
}
}

private void refreshData(String mod) {
FileHandle parent = Game.getInternal(mod + "/data/room-builders");
if (!parent.exists() || !parent.isDirectory()) {
return;
}

FileHandle[] children = parent.list(new FileFilter() {
@Override
public boolean accept(File file) {
return !file.isDirectory();
}
});

for (FileHandle child : children) {
// Check for room builders.
String builder = child.nameWithoutExtension().toUpperCase();

if (!builders.contains(builder, false)) {
builders.add(builder);
}
}
}

public Array<String> getThemes() {
return themes;
}

public Array<SectionDefinition> getSectionDefinitions() {
Array<SectionDefinition> sortedSectionDefinitions = sectionDefinitions;
sortedSectionDefinitions.sort(new Comparator<SectionDefinition>() {
@Override
public int compare(SectionDefinition o1, SectionDefinition o2) {
return Integer.signum(o1.sortOrder - o2.sortOrder);
}
});

return sortedSectionDefinitions;
}

public boolean isLevelTemplateValid(Level template) {
return template != null && themes.contains(template.theme, false)
&& builders.contains(template.roomGeneratorType, false);
}

public boolean isLastGeneratedLevelTemplateSelected(Level template) {
return lastGeneratedLevelTemplate != null && lastGeneratedLevelTemplate.theme.equals(template.theme)
&& lastGeneratedLevelTemplate.roomGeneratorType.equals(template.roomGeneratorType);
}

public boolean isLastGeneratedRoomTemplateSelected(Level template) {
return lastGeneratedRoomTemplate != null && lastGeneratedRoomTemplate.theme.equals(template.theme)
&& lastGeneratedRoomTemplate.roomGeneratorType.equals(template.roomGeneratorType);
}
}
Loading

0 comments on commit 590fa25

Please sign in to comment.