package ru.deadsoftware.cavedroid
import android.content.Context
-import ru.deadsoftware.cavedroid.prefs.PreferencesStore
+import ru.fredboy.cavedroid.common.api.PreferencesStore
class AndroidPreferencesStore(
private val context: Context
--- /dev/null
+{
+ "main": {
+ "new_game": {
+ "label": "New Game",
+ "actionKey": "new_game_action"
+ },
+ "load_game": {
+ "label": "Load Game",
+ "actionKey": "load_game_action"
+ },
+ "options": {
+ "label": "Settings",
+ "actionKey": "options_action"
+ },
+ "quit": {
+ "label": "Quit",
+ "actionKey": "exit_game_action"
+ }
+ },
+ "new_game": {
+ "creative": {
+ "label": "Creative",
+ "actionKey": "new_game_creative_action"
+ },
+ "survival": {
+ "label": "Survival",
+ "actionKey": "new_game_survival_action"
+ },
+ "back": {
+ "label": "Back",
+ "actionKey": "menu_main_action"
+ }
+ },
+ "options": {
+ "dyncam": {
+ "type": "boolean_option",
+ "label": "Dynamic Camera: %s",
+ "actionKey": "toggle_dyncam_action",
+ "options": ["dyncam"]
+ },
+ "fullscreen": {
+ "type": "boolean_option",
+ "label": "Fullscreen: %s",
+ "actionKey": "toggle_fullscreen_action",
+ "options": ["fullscreen"],
+ "visibility": {
+ "android": false
+ }
+ },
+ "back": {
+ "label": "Back",
+ "actionKey": "menu_main_action"
+ }
+ }
+}
\ No newline at end of file
+++ /dev/null
-{
- "new_game": {
- "label": "New Game"
- },
- "load_game": {
- "label": "Load Game",
- "type": 0
- },
- "options": {
- "label": "Settings"
- },
- "quit": {
- "label": "Quit"
- }
-}
\ No newline at end of file
+++ /dev/null
-{
- "creative": {
- "label": "Creative"
- },
- "survival": {
- "label": "Survival"
- },
- "back": {
- "label": "Back"
- }
-}
\ No newline at end of file
+++ /dev/null
-{
- "dyncam": {
- "option_type": "boolean",
- "label": "Dynamic Camera: %%value%%"
- },
- "fullscreen": {
- "option_type": "boolean",
- "label": "Fullscreen: %%value%%",
- "visible_on_android": false
- },
- "back": {
- "label": "Back"
- }
-}
\ No newline at end of file
useModule(":core:data:assets")
useModule(":core:data:configuration")
useModule(":core:data:items")
+ useModule(":core:data:menu")
useModule(":core:data:save")
}
useModule(":core:domain:configuration")
useModule(":core:domain:items")
useModule(":core:domain:save")
+ useModule(":core:domain:menu")
useModule(":core:domain:world")
}
useModule(":core:ux:rendering")
}
+fun DependencyHandler.useZygoteModule() {
+ useModule(":core:zygote")
+}
+
fun DependencyHandler.useAutomultibind() {
implementation(Dependencies.Automultibind.annotations)
ksp(Dependencies.Automultibind.ksp)
useEntityModules()
useGameModules()
useUxModules()
+ useZygoteModule()
implementation(Dependencies.jetbrainsAnnotations)
}
--- /dev/null
+package ru.fredboy.cavedroid.common
+
+object CaveDroidConstants {
+
+ const val VERSION = "alpha 0.9.2"
+
+}
\ No newline at end of file
fun quitGame()
+ fun newGameCreative()
+
+ fun newGameSurvival()
+
+ fun loadGame()
+
+ fun exitGame()
+
}
\ No newline at end of file
-package ru.deadsoftware.cavedroid.prefs
+package ru.fredboy.cavedroid.common.api
interface PreferencesStore {
fun setPreference(key: String, value: String?)
-}
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.common.di
+
+import javax.inject.Scope
+
+@Scope
+@Retention(AnnotationRetention.RUNTIME)
+annotation class MenuScope
package ru.fredboy.cavedroid.data.configuration.repository
+import com.badlogic.gdx.Gdx
import ru.fredboy.cavedroid.common.model.Joystick
import ru.fredboy.cavedroid.data.configuration.store.GameContextStore
import ru.fredboy.cavedroid.domain.configuration.model.CameraContext
}
override fun setFullscreen(fullscreen: Boolean) {
+ if (fullscreen) {
+ Gdx.graphics.setFullscreenMode(Gdx.graphics.displayMode);
+ } else {
+ Gdx.graphics.setWindowedMode(getWidth().toInt(), getHeight().toInt());
+ }
gameContextStore.isFullscreen = fullscreen
}
--- /dev/null
+plugins {
+ kotlin
+ ksp
+ kotlinxSerialization
+}
+
+java.sourceCompatibility = ApplicationInfo.sourceCompatibility
+java.targetCompatibility = ApplicationInfo.sourceCompatibility
+
+dependencies {
+ useCommonModule()
+ useLibgdx()
+ useKotlinxSerializationJson()
+ useDagger()
+
+ useModule(":core:domain:assets")
+ useModule(":core:domain:menu")
+}
--- /dev/null
+package ru.fredboy.cavedroid.data.menu.di
+
+import dagger.Binds
+import dagger.Module
+import ru.fredboy.cavedroid.data.menu.repository.MenuButtonRepositoryImpl
+import ru.fredboy.cavedroid.domain.menu.repository.MenuButtonRepository
+
+@Module
+abstract class DataMenuModule {
+
+ @Binds
+ internal abstract fun bindMenuButtonsRepository(impl: MenuButtonRepositoryImpl): MenuButtonRepository
+
+}
--- /dev/null
+package ru.fredboy.cavedroid.data.menu.mapper
+
+import com.badlogic.gdx.Application
+import com.badlogic.gdx.Gdx
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.data.menu.model.MenuButtonDto
+import ru.fredboy.cavedroid.data.menu.model.MenuButtonVisibilityDto
+import ru.fredboy.cavedroid.domain.menu.model.MenuButton
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@MenuScope
+class MenuButtonMapper @Inject constructor() {
+
+ fun map(dto: MenuButtonDto): MenuButton {
+ return when (dto.type) {
+ "boolean_option" -> MenuButton.BooleanOption(
+ label = dto.label.toString(),
+ isVisible = mapVisibility(dto.visibility),
+ actionKey = dto.actionKey.orEmpty(),
+ optionKeys = dto.options.orEmpty(),
+ isEnabled = dto.enabled ?: true,
+ )
+
+ "default", null -> MenuButton.Simple(
+ label = dto.label.toString(),
+ isVisible = mapVisibility(dto.visibility),
+ actionKey = dto.actionKey.orEmpty(),
+ isEnabled = dto.enabled ?: true,
+ )
+
+ else ->
+ throw IllegalArgumentException("Unknown button type: ${dto.type}")
+ }
+ }
+
+ fun setButtonEnabled(button: MenuButton, isEnabled: Boolean): MenuButton {
+ return when (button) {
+ is MenuButton.Simple -> button.copy(isEnabled = isEnabled)
+ is MenuButton.BooleanOption -> button.copy(isEnabled = isEnabled)
+ }
+ }
+
+ private fun mapVisibility(dto: MenuButtonVisibilityDto?): Boolean {
+ dto ?: return true
+
+ return when (Gdx.app.type) {
+ Application.ApplicationType.Android -> dto.android
+ else -> dto.desktop
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.data.menu.model
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class MenuButtonDto(
+ val label: String? = null,
+ val actionKey: String? = null,
+ val type: String? = null,
+ val enabled: Boolean? = null,
+ val visibility: MenuButtonVisibilityDto? = null,
+ val options: List<String>? = null,
+)
--- /dev/null
+package ru.fredboy.cavedroid.data.menu.model
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class MenuButtonVisibilityDto(
+ val android: Boolean = true,
+ val desktop: Boolean = true,
+)
--- /dev/null
+package ru.fredboy.cavedroid.data.menu.repository
+
+import com.badlogic.gdx.Gdx
+import kotlinx.serialization.json.Json
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.data.menu.mapper.MenuButtonMapper
+import ru.fredboy.cavedroid.data.menu.model.MenuButtonDto
+import ru.fredboy.cavedroid.domain.menu.model.MenuButton
+import ru.fredboy.cavedroid.domain.menu.repository.MenuButtonRepository
+import javax.inject.Inject
+
+@MenuScope
+class MenuButtonRepositoryImpl @Inject constructor(
+ private val menuButtonMapper: MenuButtonMapper,
+) : MenuButtonRepository {
+
+ private var _initialized = false
+
+ private val menuMap = LinkedHashMap<String, MutableMap<String, MenuButton>>()
+
+ private var currentMenu = "main"
+
+ init {
+ initialize()
+ }
+
+ override fun initialize() {
+ if (_initialized) {
+ Gdx.app.debug(TAG, "Attempted to init when already initialized")
+ return
+ }
+
+ val jsonString = Gdx.files.internal("json/menu.json").readString()
+
+ JsonFormat.decodeFromString<Map<String, Map<String, MenuButtonDto>>>(jsonString)
+ .forEach { (key, value) ->
+ menuMap[key] = value.mapValues { (_, dto) -> menuButtonMapper.map(dto) }.toMutableMap()
+ }
+
+ _initialized = true
+ }
+
+ override fun getButtonsForMenu(menuKey: String): Map<String, MenuButton>? {
+ require(_initialized) { "$TAG was not initialized before access!" }
+
+ return menuMap[menuKey].also {
+ if (it == null) {
+ Gdx.app.debug(TAG, "No buttons for $menuKey menu found")
+ }
+ }
+ }
+
+ override fun setCurrentMenu(menuKey: String) {
+ currentMenu = menuKey
+ }
+
+ override fun getCurrentMenuButtons(): Map<String, MenuButton>? {
+ require(_initialized) { "$TAG was not initialized before access!" }
+
+ return menuMap[currentMenu]?.filterValues { button -> button.isVisible }
+ }
+
+ override fun setButtonEnabled(menuKey: String, buttonKey: String, enabled: Boolean) {
+ val menu = menuMap[menuKey] ?: run {
+ Gdx.app.error(TAG, "setButtonEnabled: menu with key '$menuKey' not found")
+ return
+ }
+
+ val button = menu[buttonKey] ?: run {
+ Gdx.app.error(TAG, "setButtonEnabled: button with key '$buttonKey' not found")
+ return
+ }
+
+ menu[buttonKey] = menuButtonMapper.setButtonEnabled(button, enabled)
+ }
+
+ override fun dispose() {
+ menuMap.clear()
+ _initialized = false
+ }
+
+ companion object {
+ private const val TAG = "MenuButtonsRepositoryImpl"
+
+ private val JsonFormat = Json { ignoreUnknownKeys = true }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+plugins {
+ kotlin
+ ksp
+}
+
+java.sourceCompatibility = ApplicationInfo.sourceCompatibility
+java.targetCompatibility = ApplicationInfo.sourceCompatibility
+
+dependencies {
+ useCommonModule()
+ useLibgdx()
+ useDagger()
+}
--- /dev/null
+package ru.fredboy.cavedroid.domain.menu.model
+
+sealed class MenuButton {
+
+ abstract val label: String
+ abstract val isVisible: Boolean
+ abstract val actionKey: String
+ abstract val isEnabled: Boolean
+
+
+ data class Simple(
+ override val label: String,
+ override val isVisible: Boolean,
+ override val actionKey: String,
+ override val isEnabled: Boolean,
+ ) : MenuButton()
+
+ data class BooleanOption(
+ override val label: String,
+ override val isVisible: Boolean,
+ override val actionKey: String,
+ override val isEnabled: Boolean,
+ val optionKeys: List<String>,
+ ) : MenuButton()
+}
--- /dev/null
+package ru.fredboy.cavedroid.domain.menu.repository
+
+import com.badlogic.gdx.utils.Disposable
+import ru.fredboy.cavedroid.domain.menu.model.MenuButton
+
+interface MenuButtonRepository : Disposable {
+
+ fun initialize()
+
+ fun getButtonsForMenu(menuKey: String): Map<String, MenuButton>?
+
+ fun setCurrentMenu(menuKey: String)
+
+ fun getCurrentMenuButtons(): Map<String, MenuButton>?
+
+ fun setButtonEnabled(menuKey: String, buttonKey: String, enabled: Boolean)
+
+}
\ No newline at end of file
package ru.deadsoftware.cavedroid;
import org.jetbrains.annotations.Nullable;
-import ru.deadsoftware.cavedroid.prefs.PreferencesStore;
import javax.inject.Inject;
import javax.inject.Singleton;
-import java.util.HashMap;
@Singleton
public class MainConfig {
- private final HashMap<String, String> mPreferencesCache = new HashMap<>();
-
- @Nullable
- private FullscreenToggleListener mFullscreenToggleListener = null;
-
- private final CaveGame mCaveGame;
- private final PreferencesStore mPreferencesStore;
-
@Nullable
private MainComponent mMainComponent;
- @Nullable
- private String mAssetsPackPath = null;
-
@Inject
- public MainConfig(CaveGame caveGame, PreferencesStore preferencesStore) {
- mCaveGame = caveGame;
- mPreferencesStore = preferencesStore;
- }
-
- public CaveGame getCaveGame() {
- return mCaveGame;
+ public MainConfig() {
}
public MainComponent getMainComponent() {
public void setMainComponent(MainComponent mainComponent) {
mMainComponent = mainComponent;
}
-
- @Nullable
- public String getAssetsPackPath() {
- return mAssetsPackPath;
- }
-
- @Nullable
- public String getPreference(String key) {
- if (mPreferencesCache.containsKey(key)) {
- return mPreferencesCache.get(key);
- }
-
- String value = mPreferencesStore.getPreference(key);
- mPreferencesCache.put(key, value);
-
- return value;
- }
-
- public void setPreference(String key, String value) {
- mPreferencesCache.put(key, value);
- mPreferencesStore.setPreference(key, value);
-
- if (mFullscreenToggleListener != null && key.equals("fullscreen")) {
- mFullscreenToggleListener.onFullscreenToggled(Boolean.parseBoolean(value));
- }
- }
-
- public void setFullscreenToggleListener(@Nullable FullscreenToggleListener fullscreenToggleListener) {
- mFullscreenToggleListener = fullscreenToggleListener;
- }
-
- public boolean isUseDynamicCamera() {
- return Boolean.parseBoolean(getPreference("dyncam"));
- }
-
- public interface FullscreenToggleListener {
- void onFullscreenToggled(boolean value);
- }
}
import dagger.Component;
import ru.deadsoftware.cavedroid.MainComponent;
+import ru.deadsoftware.cavedroid.generated.module.MenuActionsModule;
+import ru.fredboy.cavedroid.common.di.MenuScope;
+import ru.fredboy.cavedroid.data.menu.di.DataMenuModule;
+import ru.fredboy.cavedroid.domain.menu.repository.MenuButtonRepository;
import ru.fredboy.cavedroid.game.controller.container.di.ControllerContainerModule;
import ru.fredboy.cavedroid.game.controller.drop.di.ControllerDropModule;
+import ru.fredboy.cavedroid.zygote.menu.input.MenuInputProcessor;
+import ru.fredboy.cavedroid.zygote.menu.renderer.MenuRenderer;
+import ru.deadsoftware.cavedroid.generated.module.MenuBooleanOptionsModule;
@MenuScope
@Component(dependencies = MainComponent.class, modules = {ControllerContainerModule.class,
- ControllerDropModule.class})
+ ControllerDropModule.class, DataMenuModule.class, MenuBooleanOptionsModule.class, MenuActionsModule.class})
public interface MenuComponent {
- MenuProc getMenuProc();
+
+ public MenuRenderer menuRenderer();
+
+ public MenuInputProcessor menuInputProcessor();
+
+ public MenuButtonRepository menuButtonsRepository();
}
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu;
-
-import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.utils.ObjectMap;
-import ru.deadsoftware.cavedroid.CaveGame;
-import ru.deadsoftware.cavedroid.MainConfig;
-import ru.deadsoftware.cavedroid.menu.objects.Button;
-import ru.deadsoftware.cavedroid.menu.submenus.*;
-import ru.deadsoftware.cavedroid.misc.Renderer;
-import ru.fredboy.cavedroid.common.utils.RenderingUtilsKt;
-import ru.fredboy.cavedroid.domain.assets.usecase.GetFontUseCase;
-import ru.fredboy.cavedroid.domain.assets.usecase.GetStringHeightUseCase;
-import ru.fredboy.cavedroid.domain.assets.usecase.GetStringWidthUseCase;
-import ru.fredboy.cavedroid.domain.assets.usecase.GetTextureRegionByNameUseCase;
-import ru.fredboy.cavedroid.domain.configuration.repository.GameContextRepository;
-
-import javax.inject.Inject;
-
-import java.lang.reflect.Method;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-@MenuScope
-public class MenuProc extends Renderer {
-
- public class Input {
- private void startNewGame(int gameMode) {
- mMainConfig.getCaveGame().newGame(gameMode);
- }
-
- public void newGameClicked() {
- mCurrentMenu = mMenuNewGame;
- }
-
- public void loadGameClicked() {
- mMainConfig.getCaveGame().loadGame();
- }
-
- public void optionsClicked() {
- mCurrentMenu = mMenuOptions;
- }
-
- public void quitClicked() {
- Gdx.app.exit();
- }
-
- public void survivalClicked() {
- startNewGame(0);
- }
-
- public void creativeClicked() {
- startNewGame(1);
- }
-
- public void backClicked() {
- mCurrentMenu = mMenuMain;
- }
-
- public void setPreference(String key, Object value) {
- mMainConfig.setPreference(key, value.toString());
- }
- }
-
- private final MainConfig mMainConfig;
-
- private final GameContextRepository mGameContextRepository;
-
- private final MenuMain mMenuMain;
- private final MenuNewGame mMenuNewGame;
- private final MenuOptions mMenuOptions;
-
- private final GetFontUseCase mGetFontUseCase;
- private final GetStringWidthUseCase mGetStringWidthUseCase;
- private final GetStringHeightUseCase mGetStringHeightUseCase;
-
- private final GetTextureRegionByNameUseCase mGetTextureRegionByNameUseCase;
-
- private Menu mCurrentMenu;
-
- @Inject
- public MenuProc(
- MainConfig mainConfig,
- GameContextRepository gameContextRepository,
- MenusFactory menusFactory,
- GetFontUseCase getFontUseCase,
- GetStringWidthUseCase getStringWidthUseCase,
- GetStringHeightUseCase getStringHeightUseCase,
- GetTextureRegionByNameUseCase getTextureRegionByNameUseCase
- ) {
- super(gameContextRepository.getWidth(), gameContextRepository.getHeight());
-
- mMainConfig = mainConfig;
- mGameContextRepository = gameContextRepository;
- mGetFontUseCase = getFontUseCase;
- mGetStringWidthUseCase = getStringWidthUseCase;
- mGetStringHeightUseCase = getStringHeightUseCase;
- mGetTextureRegionByNameUseCase = getTextureRegionByNameUseCase;
-
- Input menuInput = new Input();
-
- mMenuMain = menusFactory.getMainMenu(getWidth(), getHeight(), this::drawButton, menuInput);
- mMenuNewGame = menusFactory.getMenuNewGame(getWidth(), getHeight(), this::drawButton, menuInput);
- mMenuOptions = menusFactory.getMenuOptions(getWidth(), getHeight(), this::drawButton, menuInput);
-
- mCurrentMenu = mMenuMain;
- }
-
- private String processVariables(String raw) {
- final Pattern pattern = Pattern.compile("%%([A-Za-z]+)%%", Pattern.CASE_INSENSITIVE);
- final Matcher matcher = pattern.matcher(raw);
- while (matcher.find()) {
- for (int i = 0; i < matcher.groupCount(); i++) {
- try {
- final String group = matcher.group(i);
- final String name = group.replaceAll("%%", "");
- final Method method = mMainConfig.getClass().getMethod(name);
- final String value = method.invoke(mMainConfig).toString();
- raw = raw.replace(group, value);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- return raw;
- }
-
- private void drawButton(Button button) {
- spriter.draw(mGetTextureRegionByNameUseCase.get("button_" + button.getType()), button.getX(), button.getY());
-
- String label = processVariables(button.getLabel());
-
- RenderingUtilsKt.drawString(spriter, mGetFontUseCase.invoke(), label,
- (button.getX() + button.getWidth() / 2) - mGetStringWidthUseCase.invoke(label) / 2,
- (button.getY() + button.getHeight() / 2) - mGetStringHeightUseCase.invoke(label) / 2);
- }
-
- @Override
- public boolean touchUp(int screenX, int screenY, int pointer, int mb) {
- screenX *= getWidth() / Gdx.graphics.getWidth();
- screenY *= getHeight() / Gdx.graphics.getHeight();
- for (ObjectMap.Entry<String, Button> entry : mCurrentMenu.getButtons()) {
- Button button = entry.value;
- if (button.getRect().contains(screenX, screenY)) {
- if (button.getType() > 0) {
- button.clicked();
- }
- break;
- }
- }
- return false;
- }
-
- @Override
- public void render(float delta) {
- spriter.begin();
- mCurrentMenu.draw(spriter);
- RenderingUtilsKt.drawString(spriter, mGetFontUseCase.invoke(), "CaveDroid " + CaveGame.VERSION, 0,
- getHeight() - mGetStringHeightUseCase.invoke("CaveDroid " + CaveGame.VERSION) * 1.5f);
- spriter.end();
- }
-
- public void reset() {
- mCurrentMenu = mMenuMain;
- }
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu;
-
-import javax.inject.Scope;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-@Scope
-@Retention(RetentionPolicy.RUNTIME)
-public @interface MenuScope {
-}
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import ru.deadsoftware.cavedroid.MainConfig;
+import ru.fredboy.cavedroid.domain.menu.repository.MenuButtonRepository;
+import ru.fredboy.cavedroid.zygote.menu.input.MenuInputProcessor;
+import ru.fredboy.cavedroid.zygote.menu.renderer.MenuRenderer;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class MenuScreen implements Screen {
- private final MenuProc mMenuProc;
+ private final MenuRenderer mMenuRenderer;
+
+ private final MenuInputProcessor mMenuInputProcessor;
+
+ private final MenuButtonRepository mMenuButtonsRepository;
@Inject
public MenuScreen(MainConfig mainConfig) {
MenuComponent menuComponent = DaggerMenuComponent.builder()
.mainComponent(mainConfig.getMainComponent()).build();
- mMenuProc = menuComponent.getMenuProc();
+
+ mMenuRenderer = menuComponent.menuRenderer();
+ mMenuInputProcessor = menuComponent.menuInputProcessor();
+ mMenuButtonsRepository = menuComponent.menuButtonsRepository();
+ }
+
+ public void resetMenu() {
+ mMenuButtonsRepository.setCurrentMenu("main");
}
@Override
public void show() {
- mMenuProc.reset();
- Gdx.input.setInputProcessor(mMenuProc);
+ Gdx.input.setInputProcessor(mMenuInputProcessor);
}
@Override
public void render(float delta) {
- mMenuProc.render(delta);
+ mMenuRenderer.render(delta);
}
@Override
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu.objects;
-
-import com.badlogic.gdx.math.Rectangle;
-
-public class Button {
-
- public static final int WIDTH = 200;
- public static final int HEIGHT = 20;
-
- public static final int
- DISABLED = 0,
- NORMAL = 1,
- SELECTED = 2;
- private final Rectangle rect;
- private final String label;
- private ButtonEventListener listener;
- private int type;
-
- /**
- * @param label Label to be shown on button
- * @param type Type of button where 0 - disabled, 1 - normal, 2 - selected.
- * You should use these constants
- * {@link #DISABLED} {@link #NORMAL} {@link #SELECTED}
- */
- public Button(String label, int x, int y, int type, ButtonEventListener listener) {
- this.label = label;
- rect = new Rectangle(x, y, WIDTH, HEIGHT);
- this.type = type;
- this.listener = listener;
- }
-
- public Rectangle getRect() {
- return rect;
- }
-
- public String getLabel() {
- return label;
- }
-
- public float getX() {
- return rect.x;
- }
-
- public float getY() {
- return rect.y;
- }
-
- public float getWidth() {
- return rect.width;
- }
-
- public float getHeight() {
- return rect.height;
- }
-
- public int getType() {
- return type;
- }
-
- public void setType(int type) {
- this.type = type;
- }
-
- public void draw(ButtonRenderer drawer) {
- drawer.draw(this);
- }
-
- public void clicked() {
- listener.buttonClicked();
- }
-
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu.objects;
-
-/**
- * A {@link Button} event listener. Should be sent as lambda to Button's constructor.
- */
-public interface ButtonEventListener {
-
- /**
- * Will be called by {@link Button} when clicked
- */
- void buttonClicked();
-
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu.objects;
-
-public interface ButtonRenderer {
-
- void draw(Button button);
-
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu.submenus;
-
-import com.badlogic.gdx.Application;
-import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.files.FileHandle;
-import com.badlogic.gdx.graphics.g2d.SpriteBatch;
-import com.badlogic.gdx.graphics.g2d.TextureRegion;
-import com.badlogic.gdx.utils.ArrayMap;
-import com.badlogic.gdx.utils.JsonValue;
-import ru.deadsoftware.cavedroid.MainConfig;
-import ru.deadsoftware.cavedroid.menu.MenuProc;
-import ru.deadsoftware.cavedroid.menu.objects.BooleanOptionButton;
-import ru.deadsoftware.cavedroid.menu.objects.Button;
-import ru.deadsoftware.cavedroid.menu.objects.ButtonEventListener;
-import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer;
-import ru.deadsoftware.cavedroid.misc.Assets;
-import ru.deadsoftware.cavedroid.misc.utils.AssetLoader;
-import ru.fredboy.cavedroid.domain.assets.usecase.GetTextureRegionByNameUseCase;
-
-import java.util.HashMap;
-
-public abstract class Menu {
-
- protected final MainConfig mMainConfig;
- protected final MenuProc.Input mMenuInput;
- protected final AssetLoader mAssetLoader;
-
- protected final GetTextureRegionByNameUseCase mGetTextureRegionByNameUseCase;
-
- private final ButtonRenderer mButtonRenderer;
-
- private final float mWidth;
- private final float mHeight;
-
- /**
- * {@link ArrayMap} of {@link Button Buttons} of this menu screen
- */
- private ArrayMap<String, Button> buttons;
-
- /**
- * @param width Viewport width
- * @param height Viewport height
- * @param buttonRenderer {@link ButtonRenderer} that will draw the buttons of this menu
- */
- Menu(float width,
- float height,
- ButtonRenderer buttonRenderer,
- MainConfig mainConfig,
- MenuProc.Input menuInput,
- AssetLoader assetLoader,
- GetTextureRegionByNameUseCase getTextureRegionByNameUseCase) {
- mWidth = width;
- mHeight = height;
- mButtonRenderer = buttonRenderer;
- mMainConfig = mainConfig;
- mMenuInput = menuInput;
- mAssetLoader = assetLoader;
- mGetTextureRegionByNameUseCase = getTextureRegionByNameUseCase;
- }
-
- final void init() {
- initButtons();
- }
-
- /**
- * If you are loading buttons from json,
- * override this method and create a HashMap with buttons' keys from json as keys
- * and {@link ButtonEventListener ButtonEventListeners} as values.
- *
- * @return empty HashMap if not overridden
- */
- protected HashMap<String, ButtonEventListener> getButtonEventListeners() {
- return new HashMap<>();
- }
-
- /**
- * You can call this from {@link #initButtons()} to load buttons from json
- *
- * @param jsonFile A {@link FileHandle} to json file
- */
- void loadButtonsFromJson(FileHandle jsonFile) {
- if (buttons == null) {
- buttons = new ArrayMap<>();
- }
- HashMap<String, ButtonEventListener> eventListeners = getButtonEventListeners();
- JsonValue json = Assets.jsonReader.parse(jsonFile);
- int y = (int) mHeight / 4;
- for (JsonValue key = json.child(); key != null; key = key.next(), y += Button.HEIGHT + 10) {
-
- if (Gdx.app.getType() == Application.ApplicationType.Android &&
- !Assets.getBooleanFromJson(key, "visible_on_android", true)) {
- continue;
- }
-
- String optionType = Assets.getStringFromJson(key, "option_type", "");
- String label = Assets.getStringFromJson(key, "label", "");
- int x = (int) mWidth / 2 - Button.WIDTH / 2;
- int type = Assets.getIntFromJson(key, "type", Button.NORMAL);
- String defaultValue = Assets.getStringFromJson(key, "default_value", "");
-
-
- Button button = switch (optionType) {
- case "boolean" ->
- new BooleanOptionButton(mMainConfig, key.name(), Boolean.parseBoolean(defaultValue), label, x, y, type);
- default ->
- new Button(label, x, y, type, eventListeners.containsKey(key.name()) ? eventListeners.get(key.name()) : () -> {});
- };
-
- buttons.put(key.name(), button);
- }
- }
-
- /**
- * Draws the menu with background, logo and it's buttons
- *
- * @param spriter {@link SpriteBatch} that will draw it. Should be already started.
- */
- public void draw(SpriteBatch spriter) {
- TextureRegion background = mGetTextureRegionByNameUseCase.get("background");
- TextureRegion gamelogo = mGetTextureRegionByNameUseCase.get("gamelogo");
-
- for (int x = 0; x <= mWidth / 16; x++) {
- for (int y = 0; y <= mHeight / 16; y++) {
- spriter.draw(background, x * 16, y * 16);
- }
- }
- spriter.draw(gamelogo, mWidth / 2 - (float) gamelogo.getRegionWidth() / 2, 8);
-
- float inputX = Gdx.input.getX() * mWidth / Gdx.graphics.getWidth();
- float inputY = Gdx.input.getY() * mHeight / Gdx.graphics.getHeight();
- for (Button button : buttons.values()) {
- if (button.getType() > 0) {
- if (button.getRect().contains(inputX, inputY) && (/*!CaveGame.TOUCH || */Gdx.input.isTouched())) {
- button.setType(2);
- } else {
- button.setType(1);
- }
- }
- button.draw(mButtonRenderer);
- }
- }
-
- public ArrayMap<String, Button> getButtons() {
- return buttons;
- }
-
- /**
- * This method is called from constructor and should initialize {@link #buttons} <br>
- * You can run {@link #loadButtonsFromJson(FileHandle)} from it
- */
- protected abstract void initButtons();
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu.submenus;
-
-import ru.deadsoftware.cavedroid.MainConfig;
-import ru.deadsoftware.cavedroid.menu.MenuProc;
-import ru.deadsoftware.cavedroid.menu.objects.Button;
-import ru.deadsoftware.cavedroid.menu.objects.ButtonEventListener;
-import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer;
-import ru.deadsoftware.cavedroid.misc.utils.AssetLoader;
-import ru.fredboy.cavedroid.domain.assets.usecase.GetTextureRegionByNameUseCase;
-import ru.fredboy.cavedroid.domain.configuration.repository.GameContextRepository;
-import ru.fredboy.cavedroid.domain.save.repository.SaveDataRepository;
-
-import java.util.HashMap;
-
-public class MenuMain extends Menu {
-
- private final SaveDataRepository mSaveDataRepository;
-
- private final GameContextRepository mGameContextRepository;
-
- public MenuMain(float width,
- float height,
- ButtonRenderer buttonRenderer,
- MainConfig mainConfig,
- MenuProc.Input menuInput,
- AssetLoader assetLoader,
- GetTextureRegionByNameUseCase getTextureRegionByNameUseCase,
- SaveDataRepository saveDataRepository,
- GameContextRepository gameContextRepository) {
- super(width, height, buttonRenderer, mainConfig, menuInput, assetLoader, getTextureRegionByNameUseCase);
- mSaveDataRepository = saveDataRepository;
- mGameContextRepository = gameContextRepository;
- }
-
- @Override
- protected HashMap<String, ButtonEventListener> getButtonEventListeners() {
- HashMap<String, ButtonEventListener> map = new HashMap<>();
- map.put("new_game", mMenuInput::newGameClicked);
- map.put("load_game", mMenuInput::loadGameClicked);
- map.put("options", mMenuInput::optionsClicked);
- map.put("quit", mMenuInput::quitClicked);
- return map;
- }
-
- @Override
- protected void initButtons() {
- loadButtonsFromJson(mAssetLoader.getAssetHandle("json/menu_main_buttons.json"));
- if (mSaveDataRepository.exists(mGameContextRepository.getGameDirectory())) {
- getButtons().get("load_game").setType(Button.NORMAL);
- }
- }
-
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu.submenus;
-
-import ru.deadsoftware.cavedroid.MainConfig;
-import ru.deadsoftware.cavedroid.menu.MenuProc;
-import ru.deadsoftware.cavedroid.menu.objects.ButtonEventListener;
-import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer;
-import ru.deadsoftware.cavedroid.misc.utils.AssetLoader;
-import ru.fredboy.cavedroid.domain.assets.usecase.GetTextureRegionByNameUseCase;
-
-import java.util.HashMap;
-
-public class MenuNewGame extends Menu {
-
- public MenuNewGame(float width,
- float height,
- ButtonRenderer buttonRenderer,
- MainConfig mainConfig,
- MenuProc.Input menuInput,
- AssetLoader assetLoader,
- GetTextureRegionByNameUseCase getTextureRegionByNameUseCase) {
- super(width, height, buttonRenderer, mainConfig, menuInput, assetLoader, getTextureRegionByNameUseCase);
- }
-
- @Override
- protected HashMap<String, ButtonEventListener> getButtonEventListeners() {
- HashMap<String, ButtonEventListener> map = new HashMap<>();
- map.put("survival", mMenuInput::survivalClicked);
- map.put("creative", mMenuInput::creativeClicked);
- map.put("back", mMenuInput::backClicked);
- return map;
- }
-
- @Override
- protected void initButtons() {
- loadButtonsFromJson(mAssetLoader.getAssetHandle("json/menu_new_game_buttons.json"));
- }
-
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.misc;
-
-import com.badlogic.gdx.utils.JsonReader;
-import com.badlogic.gdx.utils.JsonValue;
-
-
-public class Assets {
-
-
- public static final JsonReader jsonReader = new JsonReader();
-
-
- public static int getIntFromJson(JsonValue json, String name, int defaultValue) {
- return json.has(name) ? json.getInt(name) : defaultValue;
- }
-
-
- public static String getStringFromJson(JsonValue json, String name, String defaultValue) {
- return json.has(name) ? json.getString(name) : defaultValue;
- }
-
- public static boolean getBooleanFromJson(JsonValue json, String name, boolean defaultValue) {
- return json.has(name) ? json.getBoolean(name) : defaultValue;
- }
-
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.misc;
-
-import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.InputProcessor;
-import com.badlogic.gdx.graphics.OrthographicCamera;
-import com.badlogic.gdx.graphics.g2d.SpriteBatch;
-import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
-import com.badlogic.gdx.math.Rectangle;
-
-public abstract class Renderer implements InputProcessor {
-
- protected final ShapeRenderer shaper;
- protected final SpriteBatch spriter;
- private final OrthographicCamera camera;
- private final Rectangle mCameraViewport;
-
- protected Renderer() {
- this(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
- }
-
- protected Renderer(float width, float height) {
- camera = new OrthographicCamera();
- camera.setToOrtho(true, width, height);
- shaper = new ShapeRenderer();
- shaper.setProjectionMatrix(camera.combined);
- spriter = new SpriteBatch();
- spriter.setProjectionMatrix(camera.combined);
-
- mCameraViewport =
- new Rectangle(camera.position.x, camera.position.y, camera.viewportWidth, camera.viewportHeight);
- }
-
- public float getWidth() {
- return camera.viewportWidth;
- }
-
- public float getHeight() {
- return camera.viewportHeight;
- }
-
- public float getCamX() {
- return camera.position.x;
- }
-
- public float getCamY() {
- return camera.position.y;
- }
-
- public void setCamPos(float x, float y) {
- camera.position.set(x, y, 0);
- mCameraViewport.x = x;
- mCameraViewport.y = y;
- }
-
- public OrthographicCamera getCamera() {
- return camera;
- }
-
- public Rectangle getCameraViewport() {
- return mCameraViewport;
- }
-
- public abstract void render(float delta);
-
- @Override
- public boolean keyDown(int keycode) {
- return false;
- }
-
- @Override
- public boolean keyUp(int keycode) {
- return false;
- }
-
- @Override
- public boolean keyTyped(char character) {
- return false;
- }
-
- @Override
- public boolean touchDown(int screenX, int screenY, int pointer, int button) {
- return false;
- }
-
- @Override
- public boolean touchUp(int screenX, int screenY, int pointer, int button) {
- return false;
- }
-
- @Override
- public boolean touchDragged(int screenX, int screenY, int pointer) {
- return false;
- }
-
- @Override
- public boolean mouseMoved(int screenX, int screenY) {
- return false;
- }
-
- @Override
- public boolean scrolled(float amountX, float amountY) {
- return false;
- }
-
- @Override
- public boolean touchCancelled(int i, int i1, int i2, int i3) {
- return false;
- }
-}
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.math.Rectangle
-import ru.deadsoftware.cavedroid.misc.utils.AssetLoader
-import ru.deadsoftware.cavedroid.prefs.PreferencesStore
+import ru.fredboy.cavedroid.common.api.PreferencesStore
import ru.fredboy.cavedroid.common.utils.ratio
import ru.fredboy.cavedroid.domain.configuration.model.CameraContext
import ru.fredboy.cavedroid.domain.configuration.repository.GameContextRepository
private val mGameContextRepository: GameContextRepository
- private val assetLoader: AssetLoader
-
init {
mainComponent = DaggerMainComponent.builder()
.caveGame(this)
.build()
mainConfig = mainComponent.mainConfig
- assetLoader = mainComponent.assetLoader
mGameContextRepository = mainComponent.gameContextRepository
}
}
Gdx.app.logLevel = if (isDebug) Application.LOG_DEBUG else Application.LOG_ERROR
-
- mainConfig.setFullscreenToggleListener { isFullscreen ->
- if (isFullscreen) {
- Gdx.graphics.setFullscreenMode(Gdx.graphics.displayMode);
- } else {
- Gdx.graphics.setWindowedMode(width.toInt(), height.toInt());
- }
- }
}
fun newGame(gameMode: Int) {
setScreen(mainComponent.gameScreen.apply { newGame(gameMode) })
}
- fun loadGame() {
+ override fun newGameCreative() {
+ newGame(1)
+ }
+
+ override fun newGameSurvival() {
+ newGame(0)
+ }
+
+ override fun loadGame() {
setScreen(mainComponent.gameScreen.apply { loadGame() })
}
override fun quitGame() {
screen?.dispose()
- setScreen(mainComponent.menuScreen)
+ setScreen(mainComponent.menuScreen.apply { resetMenu() })
+ }
+
+ override fun exitGame() {
+ Gdx.app.exit()
}
override fun create() {
companion object {
private const val TAG = "CaveGame"
private const val DEFAULT_VIEWPORT_WIDTH = 480f
-
- const val VERSION = "alpha 0.9.2"
}
}
\ No newline at end of file
import dagger.Component
import ru.deadsoftware.cavedroid.game.GameScreen
import ru.deadsoftware.cavedroid.menu.MenuScreen
-import ru.deadsoftware.cavedroid.misc.utils.AssetLoader
-import ru.deadsoftware.cavedroid.prefs.PreferencesStore
+import ru.fredboy.cavedroid.common.api.PreferencesStore
import ru.fredboy.cavedroid.common.api.GameController
import ru.fredboy.cavedroid.data.assets.di.DataAssetsModule
import ru.fredboy.cavedroid.data.configuration.di.DataConfigurationModule
val mainConfig: MainConfig
- val assetLoader: AssetLoader
-
val initializeAssetsUseCase: InitializeAssetsUseCase
val disposeAssetsUseCase: DisposeAssetsUseCase
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu.objects
-
-import ru.deadsoftware.cavedroid.MainConfig
-
-class BooleanOptionButton(
- private val mainConfig: MainConfig,
- private val optionKey: String,
- private val defaultValue: Boolean,
- label: String,
- x: Int,
- y: Int,
- type: Int,
-) : Button(
- label,
- x,
- y,
- type,
- {
- val current = (mainConfig.getPreference(optionKey)?.toBooleanStrictOrNull()) ?: defaultValue
- mainConfig.setPreference(optionKey, (!current).toString())
- }
-) {
-
- override fun getLabel(): String {
- val value = (mainConfig.getPreference(optionKey)?.toBooleanStrictOrNull()) ?: defaultValue
- return super.getLabel().replace("%%value%%", value.toString())
- }
-
-}
\ No newline at end of file
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu.submenus
-
-import ru.deadsoftware.cavedroid.MainConfig
-import ru.deadsoftware.cavedroid.menu.MenuProc
-import ru.deadsoftware.cavedroid.menu.objects.ButtonEventListener
-import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer
-import ru.deadsoftware.cavedroid.misc.utils.AssetLoader
-import ru.fredboy.cavedroid.domain.assets.usecase.GetTextureRegionByNameUseCase
-
-class MenuOptions(
- width: Float,
- height: Float,
- buttonRenderer: ButtonRenderer,
- mainConfig: MainConfig,
- menuInput: MenuProc.Input,
- assetLoader: AssetLoader,
- getTextureRegionByName: GetTextureRegionByNameUseCase,
-) : Menu(width, height, buttonRenderer, mainConfig, menuInput, assetLoader, getTextureRegionByName) {
-
- override fun getButtonEventListeners(): HashMap<String, ButtonEventListener> {
- val map = HashMap<String, ButtonEventListener>()
- map["back"] = ButtonEventListener { mMenuInput.backClicked() }
- return map
- }
-
- override fun initButtons() {
- loadButtonsFromJson(mAssetLoader.getAssetHandle("json/menu_options_buttons.json"))
- }
-}
\ No newline at end of file
+++ /dev/null
-package ru.deadsoftware.cavedroid.menu.submenus
-
-import ru.deadsoftware.cavedroid.MainConfig
-import ru.deadsoftware.cavedroid.menu.MenuProc
-import ru.deadsoftware.cavedroid.menu.MenuScope
-import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer
-import ru.deadsoftware.cavedroid.misc.utils.AssetLoader
-import ru.fredboy.cavedroid.domain.assets.usecase.GetTextureRegionByNameUseCase
-import ru.fredboy.cavedroid.domain.configuration.repository.GameContextRepository
-import ru.fredboy.cavedroid.domain.save.repository.SaveDataRepository
-import javax.inject.Inject
-
-@MenuScope
-class MenusFactory @Inject constructor(
- private val mainConfig: MainConfig,
- private val assetLoader: AssetLoader,
- private val getTextureRegionByName: GetTextureRegionByNameUseCase,
- private val saveDataRepository: SaveDataRepository,
- private val gameContextRepository: GameContextRepository,
-) {
-
- fun getMainMenu(
- width: Float,
- height: Float,
- buttonRenderer: ButtonRenderer,
- menuInput: MenuProc.Input,
- ): MenuMain {
- return MenuMain(
- width,
- height,
- buttonRenderer,
- mainConfig,
- menuInput,
- assetLoader,
- getTextureRegionByName,
- saveDataRepository,
- gameContextRepository,
- ).apply { init() }
- }
-
- fun getMenuNewGame(
- width: Float,
- height: Float,
- buttonRenderer: ButtonRenderer,
- menuInput: MenuProc.Input,
- ): MenuNewGame {
- return MenuNewGame(
- width,
- height,
- buttonRenderer,
- mainConfig,
- menuInput,
- assetLoader,
- getTextureRegionByName
- ).apply { init() }
- }
-
- fun getMenuOptions(
- width: Float,
- height: Float,
- buttonRenderer: ButtonRenderer,
- menuInput: MenuProc.Input,
- ): MenuOptions {
- return MenuOptions(
- width,
- height,
- buttonRenderer,
- mainConfig,
- menuInput,
- assetLoader,
- getTextureRegionByName
- ).apply { init() }
- }
-
-}
\ No newline at end of file
+++ /dev/null
-package ru.deadsoftware.cavedroid.misc.utils
-
-import com.badlogic.gdx.Gdx
-import com.badlogic.gdx.files.FileHandle
-import ru.deadsoftware.cavedroid.MainConfig
-import java.io.File
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class AssetLoader @Inject constructor(
- private val mainConfig: MainConfig,
-) {
-
- fun getAssetHandle(path: String): FileHandle {
- val texturePackPath =
- mainConfig.assetsPackPath?.let { if (!it.endsWith(File.separator)) "$it${File.separator}" else it }
-
- return if (texturePackPath == null) {
- Gdx.files.internal(path)
- } else {
- Gdx.files.absolute("$texturePackPath$path")
- }
- }
-
-}
--- /dev/null
+plugins {
+ kotlin
+ ksp
+}
+
+java.sourceCompatibility = ApplicationInfo.sourceCompatibility
+java.targetCompatibility = ApplicationInfo.sourceCompatibility
+
+dependencies {
+ useAutomultibind()
+ useLibgdx()
+ useDagger()
+
+ useCommonModule()
+ useDomainModules()
+ useEntityModules()
+ useGameModules()
+ useUxModules()
+
+ useModule(":core:domain:menu")
+}
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.action
+
+import ru.fredboy.cavedroid.common.api.GameController
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.zygote.menu.action.annotation.BindsMenuAction
+import javax.inject.Inject
+
+@MenuScope
+@BindsMenuAction(stringKey = ExitGameAction.KEY)
+class ExitGameAction @Inject constructor(
+ private val gameController: GameController,
+) : IMenuAction {
+
+ override fun perform() {
+ gameController.exitGame()
+ }
+
+ companion object {
+ const val KEY = "exit_game_action"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.action
+
+interface IMenuAction {
+
+ fun perform()
+
+ fun canPerform(): Boolean = true
+
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.action
+
+import ru.fredboy.cavedroid.common.api.GameController
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.domain.configuration.repository.GameContextRepository
+import ru.fredboy.cavedroid.domain.save.repository.SaveDataRepository
+import ru.fredboy.cavedroid.zygote.menu.action.annotation.BindsMenuAction
+import javax.inject.Inject
+
+@MenuScope
+@BindsMenuAction(stringKey = LoadGameAction.KEY)
+class LoadGameAction @Inject constructor(
+ private val gameController: GameController,
+ private val saveDataRepository: SaveDataRepository,
+ private val gameContextRepository: GameContextRepository,
+) : IMenuAction {
+
+ override fun perform() {
+ gameController.loadGame()
+ }
+
+ override fun canPerform(): Boolean {
+ return saveDataRepository.exists(gameContextRepository.getGameDirectory())
+ }
+
+ companion object {
+ const val KEY = "load_game_action"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.action
+
+import ru.fredboy.cavedroid.common.api.GameController
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.zygote.menu.action.annotation.BindsMenuAction
+import javax.inject.Inject
+
+@MenuScope
+@BindsMenuAction(stringKey = NewGameCreativeAction.KEY)
+class NewGameCreativeAction @Inject constructor(
+ private val gameController: GameController,
+) : IMenuAction {
+
+ override fun perform() {
+ gameController.newGameCreative()
+ }
+
+ companion object {
+ const val KEY = "new_game_creative_action"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.action
+
+import ru.fredboy.cavedroid.common.api.GameController
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.zygote.menu.action.annotation.BindsMenuAction
+import javax.inject.Inject
+
+@MenuScope
+@BindsMenuAction(stringKey = NewGameSurvivalAction.KEY)
+class NewGameSurvivalAction @Inject constructor(
+ private val gameController: GameController,
+) : IMenuAction {
+
+ override fun perform() {
+ gameController.newGameSurvival()
+ }
+
+ companion object {
+ const val KEY = "new_game_survival_action"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.action
+
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.domain.menu.repository.MenuButtonRepository
+import ru.fredboy.cavedroid.zygote.menu.action.annotation.BindsMenuAction
+import javax.inject.Inject
+
+@MenuScope
+@BindsMenuAction(OpenMainMenuAction.KEY)
+class OpenMainMenuAction @Inject constructor(
+ private val menuButtonRepository: MenuButtonRepository,
+) : IMenuAction {
+
+ override fun perform() {
+ menuButtonRepository.setCurrentMenu("main")
+ }
+
+ companion object {
+ const val KEY = "menu_main_action"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.action
+
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.domain.menu.repository.MenuButtonRepository
+import ru.fredboy.cavedroid.zygote.menu.action.annotation.BindsMenuAction
+import javax.inject.Inject
+
+@MenuScope
+@BindsMenuAction(OpenNewGameMenuAction.KEY)
+class OpenNewGameMenuAction @Inject constructor(
+ private val menuButtonRepository: MenuButtonRepository,
+) : IMenuAction {
+
+ override fun perform() {
+ menuButtonRepository.setCurrentMenu("new_game")
+ }
+
+ companion object {
+ const val KEY = "new_game_action"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.action
+
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.domain.menu.repository.MenuButtonRepository
+import ru.fredboy.cavedroid.zygote.menu.action.annotation.BindsMenuAction
+import javax.inject.Inject
+
+@MenuScope
+@BindsMenuAction(OpenOptionsMenuAction.KEY)
+class OpenOptionsMenuAction @Inject constructor(
+ private val menuButtonRepository: MenuButtonRepository,
+) : IMenuAction {
+
+ override fun perform() {
+ menuButtonRepository.setCurrentMenu("options")
+ }
+
+ companion object {
+ const val KEY = "options_action"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.action.annotation
+
+import ru.fredboy.automultibind.annotations.BindsIntoMapStringKey
+import ru.fredboy.cavedroid.common.automultibind.MultibindingConfig
+import ru.fredboy.cavedroid.zygote.menu.action.IMenuAction
+
+@BindsIntoMapStringKey(
+ interfaceClass = IMenuAction::class,
+ modulePackage = MultibindingConfig.GENERATED_MODULES_PACKAGE,
+ moduleName = "MenuActionsModule",
+)
+annotation class BindsMenuAction(val stringKey: String)
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.input
+
+import com.badlogic.gdx.Gdx
+import com.badlogic.gdx.InputProcessor
+import com.badlogic.gdx.math.Rectangle
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.domain.configuration.repository.GameContextRepository
+import ru.fredboy.cavedroid.domain.menu.model.MenuButton
+import ru.fredboy.cavedroid.domain.menu.repository.MenuButtonRepository
+import ru.fredboy.cavedroid.zygote.menu.action.IMenuAction
+import ru.fredboy.cavedroid.zygote.menu.option.bool.IMenuBooleanOption
+import javax.inject.Inject
+
+@MenuScope
+class MenuInputProcessor @Inject constructor(
+ private val gameContextRepository: GameContextRepository,
+ private val menuButtonRepository: MenuButtonRepository,
+ private val menuButtonActions: Map<String, @JvmSuppressWildcards IMenuAction>,
+ private val menuButtonBooleanOption: Map<String, @JvmSuppressWildcards IMenuBooleanOption>,
+) : InputProcessor {
+
+ override fun touchUp(
+ screenX: Int,
+ screenY: Int,
+ pointer: Int,
+ button: Int
+ ): Boolean {
+ val cameraContext = gameContextRepository.getCameraContext() ?: return false
+
+ val (touchX, touchY) = cameraContext.getViewportCoordinates(screenX, screenY)
+
+ menuButtonRepository.getCurrentMenuButtons()?.values?.forEachIndexed { index, button ->
+ if (!button.isEnabled) {
+ return@forEachIndexed
+ }
+
+ // TODO: Fix magic numbers
+ val rect = Rectangle(
+ /* x = */ gameContextRepository.getWidth() / 2 - 100,
+ /* y = */ gameContextRepository.getHeight() / 4 + index * 30,
+ /* width = */ 200f,
+ /* height = */ 20f
+ )
+
+ if (rect.contains(touchX, touchY)) {
+ when (button) {
+ is MenuButton.Simple -> {
+ val action = menuButtonActions[button.actionKey] ?: run {
+ Gdx.app.error(TAG, "Menu handler for action '${button.actionKey}' not found")
+ return@forEachIndexed
+ }
+
+ if (action.canPerform()) {
+ action.perform()
+ } else {
+ Gdx.app.debug(TAG, "Can't perform action ${button.actionKey}")
+ }
+ }
+
+ is MenuButton.BooleanOption -> {
+ button.optionKeys.forEach { optionKey ->
+ menuButtonBooleanOption[optionKey]?.toggleOption() ?: run {
+ Gdx.app.error(TAG, "Menu option handler for option '$optionKey' not found")
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ return true
+ }
+
+ override fun keyDown(keycode: Int): Boolean {
+ return false
+ }
+
+ override fun keyUp(keycode: Int): Boolean {
+ return false
+ }
+
+ override fun keyTyped(character: Char): Boolean {
+ return false
+ }
+
+ override fun touchDown(
+ screenX: Int,
+ screenY: Int,
+ pointer: Int,
+ button: Int
+ ): Boolean {
+ return false
+ }
+
+ override fun touchCancelled(
+ screenX: Int,
+ screenY: Int,
+ pointer: Int,
+ button: Int
+ ): Boolean {
+ return false
+ }
+
+ override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
+ return false
+ }
+
+ override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
+ return false
+ }
+
+ override fun scrolled(amountX: Float, amountY: Float): Boolean {
+ return false
+ }
+
+ companion object {
+ private const val TAG = "MenuInputProcessor"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.option.annotation
+
+import ru.fredboy.automultibind.annotations.BindsIntoMapStringKey
+import ru.fredboy.cavedroid.common.automultibind.MultibindingConfig
+import ru.fredboy.cavedroid.zygote.menu.option.bool.IMenuBooleanOption
+
+@BindsIntoMapStringKey(
+ interfaceClass = IMenuBooleanOption::class,
+ modulePackage = MultibindingConfig.GENERATED_MODULES_PACKAGE,
+ moduleName = "MenuBooleanOptionsModule",
+)
+annotation class BindsMenuBooleanOption(val stringKey: String)
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.option.bool
+
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.domain.configuration.repository.GameContextRepository
+import ru.fredboy.cavedroid.zygote.menu.option.annotation.BindsMenuBooleanOption
+import javax.inject.Inject
+
+@MenuScope
+@BindsMenuBooleanOption(DynamicCameraMenuBooleanOption.KEY)
+class DynamicCameraMenuBooleanOption @Inject constructor(
+ private val gameContextRepository: GameContextRepository,
+) : IMenuBooleanOption {
+
+ override fun getOption(): Boolean {
+ return gameContextRepository.useDynamicCamera()
+ }
+
+ override fun toggleOption() {
+ gameContextRepository.setUseDynamicCamera(!getOption())
+ }
+
+ companion object {
+ const val KEY = "dyncam"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.option.bool
+
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.domain.configuration.repository.GameContextRepository
+import ru.fredboy.cavedroid.zygote.menu.option.annotation.BindsMenuBooleanOption
+import javax.inject.Inject
+
+@MenuScope
+@BindsMenuBooleanOption(FullscreenMenuBooleanOption.KEY)
+class FullscreenMenuBooleanOption @Inject constructor(
+ private val gameContextRepository: GameContextRepository,
+) : IMenuBooleanOption {
+
+ override fun getOption(): Boolean {
+ return gameContextRepository.isFullscreen()
+ }
+
+ override fun toggleOption() {
+ gameContextRepository.setFullscreen(!getOption())
+ }
+
+ companion object {
+ const val KEY = "fullscreen"
+ }
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.option.bool
+
+interface IMenuBooleanOption {
+
+ fun getOption(): Boolean
+
+ fun toggleOption()
+
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.zygote.menu.renderer
+
+import com.badlogic.gdx.Gdx
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.math.Rectangle
+import ru.fredboy.cavedroid.common.CaveDroidConstants
+import ru.fredboy.cavedroid.common.di.MenuScope
+import ru.fredboy.cavedroid.common.utils.drawString
+import ru.fredboy.cavedroid.domain.assets.usecase.GetFontUseCase
+import ru.fredboy.cavedroid.domain.assets.usecase.GetStringHeightUseCase
+import ru.fredboy.cavedroid.domain.assets.usecase.GetStringWidthUseCase
+import ru.fredboy.cavedroid.domain.assets.usecase.GetTextureRegionByNameUseCase
+import ru.fredboy.cavedroid.domain.configuration.repository.GameContextRepository
+import ru.fredboy.cavedroid.domain.menu.model.MenuButton
+import ru.fredboy.cavedroid.domain.menu.repository.MenuButtonRepository
+import ru.fredboy.cavedroid.zygote.menu.action.IMenuAction
+import ru.fredboy.cavedroid.zygote.menu.option.bool.IMenuBooleanOption
+import javax.inject.Inject
+
+@MenuScope
+class MenuRenderer @Inject constructor(
+ private val menuButtonRepository: MenuButtonRepository,
+ private val gameContextRepository: GameContextRepository,
+ private val getTextureRegionByName: GetTextureRegionByNameUseCase,
+ private val menuButtonActions: Map<String, @JvmSuppressWildcards IMenuAction>,
+ private val buttonBooleanOptions: Map<String, @JvmSuppressWildcards IMenuBooleanOption>,
+ private val getFont: GetFontUseCase,
+ private val getStringWidth: GetStringWidthUseCase,
+ private val getStringHeight: GetStringHeightUseCase,
+) {
+ private val spriter = SpriteBatch()
+
+ init {
+ val cameraContext = requireNotNull(gameContextRepository.getCameraContext()) {
+ "$TAG: CameraContext was not set"
+ }
+
+ spriter.projectionMatrix = cameraContext.camera.combined
+ }
+
+ private fun getButtonTextureRegionKey(button: MenuButton): String {
+ val buttonAction = menuButtonActions[button.actionKey]
+
+ if (buttonAction?.canPerform() != true) {
+ return KEY_BUTTON_DISABLED_TEXTURE
+ }
+
+ return KEY_BUTTON_ENABLED_TEXTURE.takeIf { button.isEnabled } ?: KEY_BUTTON_DISABLED_TEXTURE
+ }
+
+ private fun renderButton(button: MenuButton, position: Int) {
+ val textureRegion = getTextureRegionByName[getButtonTextureRegionKey(button)] ?: run {
+ Gdx.app.error(TAG, "Couldn't render button because region not found")
+ return
+ }
+
+ val label = when (button) {
+ is MenuButton.Simple -> button.label
+ is MenuButton.BooleanOption -> String.format(
+ button.label,
+ button.optionKeys.map { key -> buttonBooleanOptions[key]?.getOption().toString() }
+ )
+ }
+
+ val buttonX = gameContextRepository.getWidth() / 2 - textureRegion.regionWidth / 2
+ val buttonY = gameContextRepository.getHeight() / 4 + position.toFloat() * 30
+
+ val buttonRect = Rectangle(
+ /* x = */ buttonX,
+ /* y = */ buttonY,
+ /* width = */ textureRegion.regionWidth.toFloat(),
+ /* height = */ textureRegion.regionHeight.toFloat(),
+ )
+
+ val inputCoordinates = gameContextRepository.getCameraContext()?.getViewportCoordinates(
+ x = Gdx.input.x,
+ y = Gdx.input.y,
+ )
+
+ spriter.draw(
+ if (button.isEnabled && inputCoordinates != null && buttonRect.contains(
+ /* x = */ inputCoordinates.first,
+ /* y = */ inputCoordinates.second
+ )
+ ) {
+ getTextureRegionByName[KEY_BUTTON_SELECTED_TEXTURE] ?: textureRegion
+ } else {
+ textureRegion
+ },
+ /* x = */ buttonX,
+ /* y = */ buttonY,
+ )
+
+ spriter.drawString(
+ font = getFont(),
+ str = label,
+ x = buttonX + textureRegion.regionWidth / 2 - getStringWidth(label) / 2,
+ y = buttonY + textureRegion.regionHeight / 2 - getStringHeight(label),
+ )
+ }
+
+ private fun drawBackground() {
+ val backgroundRegion = getTextureRegionByName["background"] ?: return
+ val gameLogo = getTextureRegionByName["gamelogo"] ?: return
+
+ val backgroundRegionWidth = backgroundRegion.regionWidth
+ val backgroundRegionHeight = backgroundRegion.regionWidth
+
+ for (x in 0 .. gameContextRepository.getWidth().toInt() / backgroundRegionWidth) {
+ for (y in 0 .. gameContextRepository.getHeight().toInt() / backgroundRegionHeight) {
+ spriter.draw(
+ /* region = */ backgroundRegion,
+ /* x = */ x * backgroundRegionWidth.toFloat(),
+ /* y = */ y * backgroundRegionHeight.toFloat(),
+ )
+ }
+ }
+
+ spriter.draw(
+ /* region = */ gameLogo,
+ /* x = */ gameContextRepository.getWidth() / 2 - gameLogo.regionWidth.toFloat() / 2,
+ /* y = */ 8f,
+ )
+ }
+
+ fun render(delta: Float) {
+ spriter.begin()
+ drawBackground()
+
+ menuButtonRepository.getCurrentMenuButtons()?.values
+ ?.forEachIndexed { position, button -> renderButton(button, position) }
+
+ spriter.drawString(
+ font = getFont(),
+ str = "CaveDroid " + CaveDroidConstants.VERSION,
+ x = 0f,
+ y = gameContextRepository.getHeight() - getStringHeight("CaveDroid " + CaveDroidConstants.VERSION) * 1.5f,
+ );
+ spriter.end()
+
+ }
+
+ fun dispose() {
+ spriter.dispose()
+ }
+
+ companion object {
+ private const val TAG = "MenuRenderer"
+
+ private const val KEY_BUTTON_SELECTED_TEXTURE = "button_2"
+ private const val KEY_BUTTON_ENABLED_TEXTURE = "button_1"
+ private const val KEY_BUTTON_DISABLED_TEXTURE = "button_0"
+ }
+
+}
\ No newline at end of file
package ru.deadsoftware.cavedroid.desktop
-import ru.deadsoftware.cavedroid.prefs.PreferencesStore
+import ru.fredboy.cavedroid.common.api.PreferencesStore
import java.util.prefs.Preferences
class DesktopPreferencesStore : PreferencesStore {
include("core:data:assets")
include("core:data:configuration")
include("core:data:items")
+include("core:data:menu")
include("core:data:save")
/**
include("core:domain:assets")
include("core:domain:configuration")
include("core:domain:items")
+include("core:domain:menu")
include("core:domain:world")
include("core:domain:save")
include("core:ux:controls")
include("core:ux:physics")
include("core:ux:rendering")
+
+/**
+ * Zygote module: initialization, menu, screens...
+ */
+include("core:zygote")