diff --git a/build.gradle b/build.gradle index e34b0983..3f249396 100644 --- a/build.gradle +++ b/build.gradle @@ -1,56 +1,57 @@ allprojects { - apply plugin: "eclipse" + apply plugin: "eclipse" - version = '1.0' - ext { - appName = "MadSand" - gdxVersion = '1.9.13' - roboVMVersion = '2.3.12' - box2DLightsVersion = '1.5' - ashleyVersion = '1.7.3' - aiVersion = '1.6.0' - } + version = 'Alpha v0.49.5-rc1' + + ext { + appName = "MadSand" + gdxVersion = '1.9.13' + roboVMVersion = '2.3.12' + box2DLightsVersion = '1.5' + ashleyVersion = '1.7.3' + aiVersion = '1.6.0' + } - repositories { - mavenLocal() - mavenCentral() - jcenter() - google() - maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } - maven { url "https://oss.sonatype.org/content/repositories/releases/" } - } + repositories { + mavenLocal() + mavenCentral() + jcenter() + google() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } + maven { url "https://oss.sonatype.org/content/repositories/releases/" } + } } project(":desktop") { - apply plugin: "java-library" + apply plugin: "java-library" - dependencies { - implementation project(":core") - api "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion" - api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" - api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop" - } + dependencies { + implementation project(":core") + api "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion" + api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" + api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop" + } } project(":core") { - apply plugin: "java-library" + apply plugin: "java-library" - dependencies { - api "com.badlogicgames.gdx:gdx:$gdxVersion" - api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" - compile group: 'com.badlogicgames.gdx', name: 'gdx-ai', version: '1.6.0' - - compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.9' - compile group: 'org.apache.commons', name: 'commons-text', version: '1.9' + dependencies { + api "com.badlogicgames.gdx:gdx:$gdxVersion" + api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" + compile group: 'com.badlogicgames.gdx', name: 'gdx-ai', version: '1.6.0' + + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.9' + compile group: 'org.apache.commons', name: 'commons-text', version: '1.9' implementation group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1' - - compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.12.1' - compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.12.1' - compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.12.1' - - implementation 'me.xdrop:fuzzywuzzy:1.3.1' - - compile files('../lib/luaj-jse-3.0.2.jar') - compile files('../lib/jrand-0.2.7-alpha.jar') - } + + compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.12.1' + compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.12.1' + compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.12.1' + + implementation 'me.xdrop:fuzzywuzzy:1.3.1' + + compile files('../lib/luaj-jse-3.0.2.jar') + compile files('../lib/jrand-0.2.7-alpha.jar') + } } diff --git a/core/src/hitonoriol/madsand/entities/Player.java b/core/src/hitonoriol/madsand/entities/Player.java index 41c4815d..1a7f2412 100644 --- a/core/src/hitonoriol/madsand/entities/Player.java +++ b/core/src/hitonoriol/madsand/entities/Player.java @@ -17,6 +17,8 @@ import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -78,23 +80,24 @@ import hitonoriol.madsand.world.WorkerType; import hitonoriol.madsand.world.World; +@JsonAutoDetect(fieldVisibility = Visibility.ANY) public class Player extends Entity { @JsonIgnore public PlayerStats stats; // Reference to the same Stats object as super.stats float elapsedTime;// For player animation float origMoveSpeed = 0, runSpeedCoef = 3.5f; - public int targetedByNpcs = 0; - public Set unlockedItems = new HashSet<>(); // set of items player obtained at least once - public List craftRecipes = new ArrayList<>(); // list of items which recipes are available to the player - public List buildRecipes = new ArrayList<>(); - public QuestWorker quests = new QuestWorker(); - public Set luaActions = new HashSet<>(); // Set for one-time lua actions - public HashMap killCount = new HashMap<>(); - public Reputation reputation = new Reputation(); - public List abilities = new ArrayList<>(); - public LinkedHashMap abilityKeyBinds = new LinkedHashMap<>(); - public int settlementsEstablished = 0; + private int targetedByNpcs = 0; + private Set unlockedItems = new HashSet<>(); // set of items player obtained at least once + private List craftRecipes = new ArrayList<>(); // list of items which recipes are available to the player + private List buildRecipes = new ArrayList<>(); + private QuestWorker quests = new QuestWorker(); + private Set luaActions = new HashSet<>(); // Set for one-time lua actions + private HashMap killCount = new HashMap<>(); + private Reputation reputation = new Reputation(); + private List abilities = new ArrayList<>(); + private LinkedHashMap abilityKeyBinds = new LinkedHashMap<>(); + private int settlementsEstablished = 0; private TimedAction scheduledAction; @@ -127,6 +130,38 @@ public void postLoadInit() { abilityKeyBinds.forEach((key, abilityId) -> bindAbility(key, abilityId)); } + public int getEstablishedSettlements() { + return settlementsEstablished; + } + + public void establishSettlement() { + ++settlementsEstablished; + } + + public QuestWorker getQuestWorker() { + return quests; + } + + public List getAbilities() { + return abilities; + } + + public HashMap getTotalKillCount() { + return killCount; + } + + public Reputation getReputation() { + return reputation; + } + + public List getBuildRecipes() { + return buildRecipes; + } + + public List getCraftRecipes() { + return craftRecipes; + } + public PlayerStats stats() { return (PlayerStats) super.stats(); } @@ -173,6 +208,10 @@ public int getAbilityKey(int id) { } public void bindAbility(int key, int abilityId) { + int oldKey; + if ((oldKey = getAbilityKey(abilityId)) != -1 && oldKey != key) + unbindAbility(oldKey); + if (abilityKeyBinds.getOrDefault(key, -1) != abilityId) abilityKeyBinds.put(key, abilityId); @@ -183,6 +222,7 @@ public void bindAbility(int key, int abilityId) { public void unbindAbility(int key) { abilityKeyBinds.remove(key); Keyboard.getKeyBindManager().unbind(key); + Gui.overlay.hotbar.refresh(); } public void refreshEquipment() { diff --git a/core/src/hitonoriol/madsand/entities/ability/ActiveAbility.java b/core/src/hitonoriol/madsand/entities/ability/ActiveAbility.java index 6dc23a7f..f5193f39 100644 --- a/core/src/hitonoriol/madsand/entities/ability/ActiveAbility.java +++ b/core/src/hitonoriol/madsand/entities/ability/ActiveAbility.java @@ -42,7 +42,7 @@ public ActiveAbility addBonusCost(float cost) { @Override public String toString() { return super.toString() + Resources.LINEBREAK - + "[" + staminaCost + " stamina]"; + + "(" + staminaCost + " stamina)"; } public String getBindKeyString() { diff --git a/core/src/hitonoriol/madsand/entities/npc/AbstractNpc.java b/core/src/hitonoriol/madsand/entities/npc/AbstractNpc.java index c471df3c..9b54d0e6 100644 --- a/core/src/hitonoriol/madsand/entities/npc/AbstractNpc.java +++ b/core/src/hitonoriol/madsand/entities/npc/AbstractNpc.java @@ -375,7 +375,7 @@ else if (dst <= OPTIMAL_DST && dst >= meleeAttackDst) } public void act(float time) { - boolean badRep = World.player.reputation.isHostile(stats.faction); + boolean badRep = World.player.getReputation().isHostile(stats.faction); tickCharge += (timePassed = time); if (pauseFlag) { diff --git a/core/src/hitonoriol/madsand/entities/quest/ProceduralQuest.java b/core/src/hitonoriol/madsand/entities/quest/ProceduralQuest.java index fd1e6573..87e0ed27 100644 --- a/core/src/hitonoriol/madsand/entities/quest/ProceduralQuest.java +++ b/core/src/hitonoriol/madsand/entities/quest/ProceduralQuest.java @@ -70,7 +70,7 @@ public void generate() { randomHuntQuest(); break; case Craft: - if (World.player.craftRecipes.isEmpty()) { + if (World.player.getCraftRecipes().isEmpty()) { generate(); return; } @@ -166,7 +166,7 @@ private void randomResourceQuest() { } private void randomCraftQuest() { - randomItemQuest(World.player.craftRecipes); + randomItemQuest(World.player.getCraftRecipes()); } private void randomFetchQuest() { diff --git a/core/src/hitonoriol/madsand/entities/quest/QuestWorker.java b/core/src/hitonoriol/madsand/entities/quest/QuestWorker.java index c1a88910..aa1a4369 100644 --- a/core/src/hitonoriol/madsand/entities/quest/QuestWorker.java +++ b/core/src/hitonoriol/madsand/entities/quest/QuestWorker.java @@ -189,7 +189,7 @@ private void completeQuest(Quest quest) { player.inventory.delItem(quest.removeOnCompletion); player.inventory.putItem(quest.rewardItems); player.addExp(quest.exp); - player.reputation.change(quest.getNpc().stats.faction, Reputation.QUEST_REWARD); + player.getReputation().change(quest.getNpc().stats.faction, Reputation.QUEST_REWARD); MadSand.notice("You get " + quest.exp + " EXP!"); if (!quest.repeatable) diff --git a/core/src/hitonoriol/madsand/gui/OverlayMouseoverListener.java b/core/src/hitonoriol/madsand/gui/OverlayMouseoverListener.java index e42bbea7..bc2c010e 100644 --- a/core/src/hitonoriol/madsand/gui/OverlayMouseoverListener.java +++ b/core/src/hitonoriol/madsand/gui/OverlayMouseoverListener.java @@ -1,7 +1,9 @@ package hitonoriol.madsand.gui; import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.Event; import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputEvent.Type; import com.badlogic.gdx.scenes.scene2d.InputListener; import hitonoriol.madsand.Gui; @@ -11,19 +13,29 @@ */ public class OverlayMouseoverListener extends InputListener { - + private static final OverlayMouseoverListener instance = new OverlayMouseoverListener(); - + private InputEvent.Type prevEvent = null; + public OverlayMouseoverListener() { super(); } @Override public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) { + if (prevEvent == Type.touchDown) + return; + Gui.gameUnfocused = true; Gui.overlay.hideTooltip(); } + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { + event.cancel(); + return false; + } + @Override public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) { if (!Gui.dialogActive) { @@ -31,7 +43,17 @@ public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) Gui.overlay.showTooltip(); } } - + + @Override + public boolean handle(Event e) { + boolean result = super.handle(e); + + if (e instanceof InputEvent) + prevEvent = ((InputEvent) e).getType(); + + return result; + } + public static OverlayMouseoverListener instance() { return instance; } diff --git a/core/src/hitonoriol/madsand/gui/dialogs/AbilityDialog.java b/core/src/hitonoriol/madsand/gui/dialogs/AbilityDialog.java index b5de3166..83c36855 100644 --- a/core/src/hitonoriol/madsand/gui/dialogs/AbilityDialog.java +++ b/core/src/hitonoriol/madsand/gui/dialogs/AbilityDialog.java @@ -79,6 +79,7 @@ private void addAbilityButton(Ability abstrAbility) { .ifPresent( ability -> { Player player = MadSand.player(); + int currentKey = player.getAbilityKey(ability.id); addButton(abstrAbility, () -> { @@ -90,10 +91,15 @@ private void addAbilityButton(Ability abstrAbility) { () -> new KeyDialog(key -> { player.bindAbility(key, ability.id); refresh(); - }).show()) - .size(75, BTN_HEIGHT) - .padRight(5) - .row(); + }, currentKey).setRemoveBindingAction( + () -> { + player.unbindAbility(currentKey); + refresh(); + }) + .show()) + .size(75, BTN_HEIGHT) + .padRight(5) + .row(); }); abstrAbility.as(PassiveAbility.class) diff --git a/core/src/hitonoriol/madsand/gui/dialogs/BestiaryDialog.java b/core/src/hitonoriol/madsand/gui/dialogs/BestiaryDialog.java index bdd1c10b..6f72b057 100644 --- a/core/src/hitonoriol/madsand/gui/dialogs/BestiaryDialog.java +++ b/core/src/hitonoriol/madsand/gui/dialogs/BestiaryDialog.java @@ -1,103 +1,103 @@ -package hitonoriol.madsand.gui.dialogs; - -import java.util.HashMap; -import java.util.Map.Entry; - -import com.badlogic.gdx.scenes.scene2d.ui.Image; -import com.badlogic.gdx.scenes.scene2d.ui.Label; -import com.badlogic.gdx.scenes.scene2d.ui.Table; -import com.badlogic.gdx.utils.Align; - -import hitonoriol.madsand.Gui; -import hitonoriol.madsand.Resources; -import hitonoriol.madsand.dialog.GameDialog; -import hitonoriol.madsand.entities.Player; -import hitonoriol.madsand.gui.widgets.AutoFocusScrollPane; -import hitonoriol.madsand.properties.NpcContainer; -import hitonoriol.madsand.properties.NpcProp; - -public class BestiaryDialog extends GameDialog { - - float PAD_BOTTOM = 20; - float ENTRY_PAD = 5; - float ENTRY_WIDTH = 120; - float ENTRY_HEIGHT = 160; - int ENTRIES_PER_ROW = 4; - - float WIDTH = (ENTRY_WIDTH * ENTRIES_PER_ROW) + (ENTRY_PAD * ENTRIES_PER_ROW); - float HEIGHT = (ENTRY_HEIGHT * 2) + PAD_BOTTOM; - - Table scrollTable = new Table(); - AutoFocusScrollPane scroll; - Label emptyLabel = new Label("You haven't killed any monsters yet", Gui.skin); - - public BestiaryDialog(Player player) { - super(Gui.overlay); - super.getTitleLabel().setAlignment(Align.center); - super.setTitle("Bestiary"); - super.add().padBottom(15).row(); - emptyLabel.setAlignment(Align.center); - scroll = new AutoFocusScrollPane(scrollTable); - scrollTable.align(Align.topLeft); - HashMap killCount = player.killCount; - - if (killCount.isEmpty()) - scrollTable.add(emptyLabel).align(Align.center).expand(); - - int i = 1; - for (Entry entry : killCount.entrySet()) { - scrollTable.add(createNpcEntry(entry.getKey(), entry.getValue())) - .width(ENTRY_WIDTH).height(ENTRY_HEIGHT) - .padRight(ENTRY_PAD).padBottom(PAD_BOTTOM); - - if (i % ENTRIES_PER_ROW == 0) { - scrollTable.row(); - i = 1; - } - - ++i; - } - - super.add(scroll).size(WIDTH, HEIGHT).pad(ENTRY_PAD).row(); - super.addCloseButton(175, 40); - } - - int STAT_KILLS = 10; - - Table createNpcEntry(int id, int kills) { - NpcContainer npc = NpcProp.npcs.get(id); - Table entry = new Table(); - Label topLabel = new Label(npc.name, Gui.skin); - Label bottomLabel = new Label("Kills: " + kills, Gui.skin); - - topLabel.setWrap(true); - bottomLabel.setWrap(true); - topLabel.setAlignment(Align.center); - bottomLabel.setAlignment(Align.center); - - entry.add(topLabel).align(Align.center).width(ENTRY_WIDTH).row(); - entry.add(new Image(Resources.npc[id])).expandY().row(); - - if (kills >= STAT_KILLS) { - entry.add(new Label("HP: " + npc.hp, Gui.skin)).align(Align.center).row(); - entry.add(new Label("Def: " + npc.defense, Gui.skin)).align(Align.center).row(); - entry.add(new Label("Str: " + npc.strength, Gui.skin)).align(Align.center).row(); - entry.add(new Label("Acc: " + npc.accuracy, Gui.skin)).align(Align.center).row(); - entry.add(new Label("Dex: " + npc.dexterity, Gui.skin)).align(Align.center).padBottom(10).row(); - } else { - Label killMoreLbl = new Label("Kill " + (STAT_KILLS - kills) + " more to unlock its stats", Gui.skin); - killMoreLbl.setWrap(true); - killMoreLbl.setAlignment(Align.center); - entry.add(killMoreLbl) - .width(ENTRY_WIDTH) - .align(Align.center) - .pad(10).row(); - } - - entry.add(bottomLabel).row(); - - entry.setBackground(Gui.darkBackgroundSizeable); - return entry; - } - -} +package hitonoriol.madsand.gui.dialogs; + +import java.util.HashMap; +import java.util.Map.Entry; + +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.utils.Align; + +import hitonoriol.madsand.Gui; +import hitonoriol.madsand.Resources; +import hitonoriol.madsand.dialog.GameDialog; +import hitonoriol.madsand.entities.Player; +import hitonoriol.madsand.gui.widgets.AutoFocusScrollPane; +import hitonoriol.madsand.properties.NpcContainer; +import hitonoriol.madsand.properties.NpcProp; + +public class BestiaryDialog extends GameDialog { + + float PAD_BOTTOM = 20; + float ENTRY_PAD = 5; + float ENTRY_WIDTH = 120; + float ENTRY_HEIGHT = 160; + int ENTRIES_PER_ROW = 4; + + float WIDTH = (ENTRY_WIDTH * ENTRIES_PER_ROW) + (ENTRY_PAD * ENTRIES_PER_ROW); + float HEIGHT = (ENTRY_HEIGHT * 2) + PAD_BOTTOM; + + Table scrollTable = new Table(); + AutoFocusScrollPane scroll; + Label emptyLabel = new Label("You haven't killed any monsters yet", Gui.skin); + + public BestiaryDialog(Player player) { + super(Gui.overlay); + super.getTitleLabel().setAlignment(Align.center); + super.setTitle("Bestiary"); + super.add().padBottom(15).row(); + emptyLabel.setAlignment(Align.center); + scroll = new AutoFocusScrollPane(scrollTable); + scrollTable.align(Align.topLeft); + HashMap killCount = player.getTotalKillCount(); + + if (killCount.isEmpty()) + scrollTable.add(emptyLabel).align(Align.center).expand(); + + int i = 1; + for (Entry entry : killCount.entrySet()) { + scrollTable.add(createNpcEntry(entry.getKey(), entry.getValue())) + .width(ENTRY_WIDTH).height(ENTRY_HEIGHT) + .padRight(ENTRY_PAD).padBottom(PAD_BOTTOM); + + if (i % ENTRIES_PER_ROW == 0) { + scrollTable.row(); + i = 1; + } + + ++i; + } + + super.add(scroll).size(WIDTH, HEIGHT).pad(ENTRY_PAD).row(); + super.addCloseButton(175, 40); + } + + int STAT_KILLS = 10; + + Table createNpcEntry(int id, int kills) { + NpcContainer npc = NpcProp.npcs.get(id); + Table entry = new Table(); + Label topLabel = new Label(npc.name, Gui.skin); + Label bottomLabel = new Label("Kills: " + kills, Gui.skin); + + topLabel.setWrap(true); + bottomLabel.setWrap(true); + topLabel.setAlignment(Align.center); + bottomLabel.setAlignment(Align.center); + + entry.add(topLabel).align(Align.center).width(ENTRY_WIDTH).row(); + entry.add(new Image(Resources.npc[id])).expandY().row(); + + if (kills >= STAT_KILLS) { + entry.add(new Label("HP: " + npc.hp, Gui.skin)).align(Align.center).row(); + entry.add(new Label("Def: " + npc.defense, Gui.skin)).align(Align.center).row(); + entry.add(new Label("Str: " + npc.strength, Gui.skin)).align(Align.center).row(); + entry.add(new Label("Acc: " + npc.accuracy, Gui.skin)).align(Align.center).row(); + entry.add(new Label("Dex: " + npc.dexterity, Gui.skin)).align(Align.center).padBottom(10).row(); + } else { + Label killMoreLbl = new Label("Kill " + (STAT_KILLS - kills) + " more to unlock its stats", Gui.skin); + killMoreLbl.setWrap(true); + killMoreLbl.setAlignment(Align.center); + entry.add(killMoreLbl) + .width(ENTRY_WIDTH) + .align(Align.center) + .pad(10).row(); + } + + entry.add(bottomLabel).row(); + + entry.setBackground(Gui.darkBackgroundSizeable); + return entry; + } + +} diff --git a/core/src/hitonoriol/madsand/gui/dialogs/BuildDialog.java b/core/src/hitonoriol/madsand/gui/dialogs/BuildDialog.java index d73d6a4f..06eb75b0 100644 --- a/core/src/hitonoriol/madsand/gui/dialogs/BuildDialog.java +++ b/core/src/hitonoriol/madsand/gui/dialogs/BuildDialog.java @@ -54,7 +54,7 @@ public BuildDialog() { BuildDialogEntry buildEntry; Player player = World.player; for (Entry object : ObjectProp.buildRecipes.entrySet()) { - if (player.buildRecipes.contains(object.getKey())) { + if (player.getBuildRecipes().contains(object.getKey())) { buildEntry = new BuildDialogEntry(this, object.getKey(), object.getValue()); buildTable.add(buildEntry).size(buildEntry.WIDTH, buildEntry.HEIGHT).padBottom(PAD).row(); } @@ -66,7 +66,7 @@ public BuildDialog() { emptyLabel.setWrap(true); emptyLabel.setAlignment(Align.center); - if (player.buildRecipes.isEmpty()) + if (player.getBuildRecipes().isEmpty()) buildTable.add(emptyLabel).width(WIDTH); buildScroll = new AutoFocusScrollPane(buildTable); diff --git a/core/src/hitonoriol/madsand/gui/dialogs/CharacterInfoWindow.java b/core/src/hitonoriol/madsand/gui/dialogs/CharacterInfoWindow.java index 6effb974..90be8464 100644 --- a/core/src/hitonoriol/madsand/gui/dialogs/CharacterInfoWindow.java +++ b/core/src/hitonoriol/madsand/gui/dialogs/CharacterInfoWindow.java @@ -107,7 +107,7 @@ private Table createMiscInfoTable() { info.defaults().align(Align.left).padBottom(LINE_PAD); Player player = World.player; info.add("Creatures killed: " + player.getKillCount()).row(); - info.add("Settlements established: " + player.settlementsEstablished).row(); + info.add("Settlements established: " + player.getEstablishedSettlements()).row(); return info; } @@ -138,7 +138,7 @@ private Table createRepTable() { .setRange(-Reputation.RANGE, Reputation.RANGE) .roundValues(false) .setStatText("") // TODO: Reputation levels - .setValue(World.player.reputation.get(faction)) + .setValue(World.player.getReputation().get(faction)) .setProgressSize(BAR_WIDTH, BAR_HEIGHT)) .size(BAR_WIDTH, BAR_HEIGHT) .padBottom(LINE_PAD) diff --git a/core/src/hitonoriol/madsand/gui/dialogs/KeyDialog.java b/core/src/hitonoriol/madsand/gui/dialogs/KeyDialog.java index 4797aa38..09ccfad5 100644 --- a/core/src/hitonoriol/madsand/gui/dialogs/KeyDialog.java +++ b/core/src/hitonoriol/madsand/gui/dialogs/KeyDialog.java @@ -17,20 +17,29 @@ public class KeyDialog extends GameDialog { private int key = 0; private Label keyLabel = new Label("None", Gui.skin); + private Runnable removeBindingAction; public KeyDialog(Consumer keyConsumer) { + this(keyConsumer, -1); + } + + public KeyDialog(Consumer keyConsumer, int initKey) { super(); super.setTitle("Set keybinding"); super.centerTitle(); super.skipLine(); keyLabel.setAlignment(Align.center); super.add(Gui.setFontSize(keyLabel, Gui.FONT_XL)).size(200).row(); + super.add(new Label("[ESC] to unbind", Gui.skin)).row(); super.addButton(Functional.with(new TextButton("Apply", Gui.skin), button -> Gui.setAction(button, () -> applySelectedKey(keyConsumer)))) .size(Gui.BTN_WIDTH, Gui.BTN_HEIGHT); super.addCloseButton(); + if (initKey > 0) + keyLabel.setText(Keys.toString(initKey)); + super.addListener(new InputListener() { @Override @@ -44,11 +53,19 @@ public boolean keyDown(InputEvent event, int keycode) { }); } + public KeyDialog setRemoveBindingAction(Runnable action) { + removeBindingAction = action; + return this; + } + private void applySelectedKey(Consumer keyConsumer) { if (key == 0) return; - keyConsumer.accept(key); + if (key == Keys.ESCAPE && removeBindingAction != null) + removeBindingAction.run(); + else + keyConsumer.accept(key); remove(); } diff --git a/core/src/hitonoriol/madsand/gui/dialogs/LandDialog.java b/core/src/hitonoriol/madsand/gui/dialogs/LandDialog.java index 0ed104cb..bc7acf69 100644 --- a/core/src/hitonoriol/madsand/gui/dialogs/LandDialog.java +++ b/core/src/hitonoriol/madsand/gui/dialogs/LandDialog.java @@ -102,7 +102,7 @@ private void addSettlementCreationMenu(Table container) { public void changed(ChangeEvent event, Actor actor) { player.inventory.delItem(reqItems); location.createSettlement().setPlayerOwned(); - ++player.settlementsEstablished; + player.establishSettlement(); settlement = location.settlement; Gui.overlay.refresh(); refreshDialogContents(); diff --git a/core/src/hitonoriol/madsand/gui/dialogs/TraderDialog.java b/core/src/hitonoriol/madsand/gui/dialogs/TraderDialog.java index 8b726156..5e235ad8 100644 --- a/core/src/hitonoriol/madsand/gui/dialogs/TraderDialog.java +++ b/core/src/hitonoriol/madsand/gui/dialogs/TraderDialog.java @@ -36,7 +36,7 @@ public TraderDialog(Player player, Trader npc) { helpButton.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { - ProceduralQuest quest = player.quests.startProceduralQuest(npc.uid); + ProceduralQuest quest = player.getQuestWorker().startProceduralQuest(npc.uid); if (quest != ProceduralQuest.timeoutQuest) addQuestReward(quest); remove(); diff --git a/core/src/hitonoriol/madsand/gui/stages/CraftStage.java b/core/src/hitonoriol/madsand/gui/stages/CraftStage.java index 0e90402f..34f4ba7f 100644 --- a/core/src/hitonoriol/madsand/gui/stages/CraftStage.java +++ b/core/src/hitonoriol/madsand/gui/stages/CraftStage.java @@ -64,7 +64,7 @@ public void refreshCraftMenu(int craftStationId) { String stationName = titleString; if (craftStationId == 0) { - itemList = player.craftRecipes; + itemList = player.getCraftRecipes(); unlockProgressLabel = new Label("Craft recipes unlocked: " + player.craftRecipeProgress(), Gui.skin); unlockProgressLabel.setAlignment(Align.center); } else { diff --git a/core/src/hitonoriol/madsand/gui/stages/Overlay.java b/core/src/hitonoriol/madsand/gui/stages/Overlay.java index a04c5541..7ccece1d 100644 --- a/core/src/hitonoriol/madsand/gui/stages/Overlay.java +++ b/core/src/hitonoriol/madsand/gui/stages/Overlay.java @@ -24,6 +24,7 @@ import hitonoriol.madsand.entities.equipment.EquipSlot; import hitonoriol.madsand.entities.inventory.item.Item; import hitonoriol.madsand.entities.quest.Quest; +import hitonoriol.madsand.entities.quest.QuestWorker; import hitonoriol.madsand.entities.skill.Skill; import hitonoriol.madsand.gui.dialogs.CharacterCreationDialog; import hitonoriol.madsand.gui.dialogs.CharacterInfoWindow; @@ -240,11 +241,12 @@ private void refreshQuestArrows() { QuestArrow arrow; boolean objectiveDone; HashSet hasArrow = new HashSet<>(); + QuestWorker quests = player.getQuestWorker(); while (it.hasNext()) { arrow = it.next(); objectiveDone = arrow.quest.isComplete(); - if (!player.quests.isQuestInProgress(arrow.quest.id) || !objectiveDone) { + if (!quests.isQuestInProgress(arrow.quest.id) || !objectiveDone) { arrow.remove(); it.remove(); } else if (objectiveDone) { @@ -253,7 +255,7 @@ private void refreshQuestArrows() { } } - for (Quest quest : player.quests.questsInProgress) { + for (Quest quest : quests.questsInProgress) { if (quest.isComplete() && !hasArrow.contains(quest.id)) { quest.completionNotice(); arrow = new QuestArrow(quest); @@ -289,6 +291,7 @@ public void refresh() { timeLabel.setText(getTimeString()); overlayStatLabel.setText(info); + hotbar.refreshVisibility(); refreshQuestArrows(); } diff --git a/core/src/hitonoriol/madsand/gui/widgets/Hotbar.java b/core/src/hitonoriol/madsand/gui/widgets/Hotbar.java index 93c16727..7503e00a 100644 --- a/core/src/hitonoriol/madsand/gui/widgets/Hotbar.java +++ b/core/src/hitonoriol/madsand/gui/widgets/Hotbar.java @@ -1,9 +1,12 @@ package hitonoriol.madsand.gui.widgets; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Optional; +import org.apache.commons.lang3.mutable.MutableBoolean; + import com.badlogic.gdx.Gdx; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; @@ -11,10 +14,13 @@ import hitonoriol.madsand.Gui; import hitonoriol.madsand.HotbarAssignable; +import hitonoriol.madsand.MadSand; import hitonoriol.madsand.gui.OverlayMouseoverListener; +import hitonoriol.madsand.util.Functional; public class Hotbar extends Table { - static float E_WIDTH = 175, HEIGHT = OverlayBottomMenu.HEIGHT; + static float E_WIDTH = 175, HEIGHT = OverlayBottomMenu.HEIGHT + Gui.FONT_XXS; + static final String NO_BIND = "None"; private List hotEntries = new ArrayList<>(); @@ -25,13 +31,24 @@ public Hotbar() { AutoFocusScrollPane scroll = new AutoFocusScrollPane(container); scroll.setScrollingDisabled(false, true); - super.add(scroll).size(Gdx.graphics.getWidth(), HEIGHT); + super.add(scroll).size(Gdx.graphics.getWidth(), HEIGHT + Gui.FONT_XXS); - container.defaults().padRight(5); + container.defaults().padRight(5).padLeft(5).size(E_WIDTH, HEIGHT); container.align(Align.left); super.align(Align.bottomLeft); + super.setBackground(Gui.darkBackgroundSizeable); super.pack(); - super.moveBy(0, HEIGHT + OverlayBottomMenu.BUTTON_PADDING * 2); + super.moveBy(0, OverlayBottomMenu.HEIGHT + OverlayBottomMenu.BUTTON_PADDING * 2); + container.moveBy(5, 0); + } + + public void refreshVisibility() { + boolean visible = super.isVisible(); + boolean noAbilities = MadSand.player().getAbilities().isEmpty(); + if (visible && noAbilities) + super.setVisible(false); + else if (!visible && !noAbilities) + super.setVisible(true); } public void addEntry(HotbarAssignable hotAssignable) { @@ -40,7 +57,7 @@ public void addEntry(HotbarAssignable hotAssignable) { Entry entry = new Entry(hotAssignable); hotEntries.add(entry); - container.add(entry.button).padLeft(5).size(E_WIDTH, HEIGHT); + container.add(entry.button); } public void removeEntry(HotbarAssignable hotAssignable) { @@ -58,7 +75,23 @@ Optional getEntry(HotbarAssignable hotAssignable) { } public void refresh() { - hotEntries.forEach(entry -> entry.refresh()); + MutableBoolean layoutChanged = new MutableBoolean(false); + Iterator it = hotEntries.iterator(); + while (it.hasNext()) { + Functional.with(it.next(), entry -> { + entry.refresh(); + if (entry.button.getText().toString().contains(NO_BIND)) { + it.remove(); + layoutChanged.setTrue(); + } + }); + } + + if (layoutChanged.isTrue()) { + container.clear(); + hotEntries.forEach(entry -> container.add(entry.button)); + } + refreshVisibility(); } private static class Entry { diff --git a/core/src/hitonoriol/madsand/gui/widgets/OverlayBottomMenu.java b/core/src/hitonoriol/madsand/gui/widgets/OverlayBottomMenu.java index e996d64c..de428261 100644 --- a/core/src/hitonoriol/madsand/gui/widgets/OverlayBottomMenu.java +++ b/core/src/hitonoriol/madsand/gui/widgets/OverlayBottomMenu.java @@ -1,5 +1,6 @@ package hitonoriol.madsand.gui.widgets; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; @@ -25,8 +26,8 @@ public class OverlayBottomMenu extends Table { static float BUTTON_PADDING = 5; static float TABLE_PADDING_LEFT = 25; - NinePatchDrawable background; Overlay overlay; + Table container = new Table(); public OverlayBottomMenu(Overlay overlay) { super(); @@ -35,17 +36,16 @@ public OverlayBottomMenu(Overlay overlay) { addButton("Character", Keys.Q, () -> overlay.toggleStatsWindow()); addButton("Inventory", Keys.E, () -> Gui.toggleInventory()); - addButton("Abilities", Keys.R, () -> new AbilityDialog(World.player.abilities).show()); - addButton("Journal", Keys.J, () -> new QuestJournal(World.player.quests).show()); + addButton("Abilities", Keys.R, () -> new AbilityDialog(World.player.getAbilities()).show()); + addButton("Journal", Keys.J, () -> new QuestJournal(World.player.getQuestWorker()).show()); addButton("Build", Keys.B, () -> new BuildDialog().show()); addButton("Bestiary", Keys.X, () -> new BestiaryDialog(World.player).show()); addButton("Land", Keys.L, () -> new LandDialog(MadSand.world.getLocation()).show()); - background = new NinePatchDrawable(Gui.darkBackgroundSizeable); + container.setBackground(new NinePatchDrawable(Gui.darkBackgroundSizeable)); - super.setBackground(background); - - super.align(Align.bottomLeft); + super.add(container).size(Gdx.graphics.getWidth(), HEIGHT + BUTTON_PADDING * 2); + container.align(Align.bottomLeft); super.pack(); super.padLeft(TABLE_PADDING_LEFT); } @@ -53,7 +53,7 @@ public OverlayBottomMenu(Overlay overlay) { private void addButton(String text, int key, Runnable action) { TextButton button = new TextButton(text + " [" + Keys.toString(key) + "]", Gui.skin); button.addListener(OverlayMouseoverListener.instance()); - super.add(button).size(WIDTH, HEIGHT).pad(BUTTON_PADDING); + container.add(button).size(WIDTH, HEIGHT).pad(BUTTON_PADDING); Gui.setAction(button, action); Keyboard.getKeyBindManager().bind(key, () -> action.run()); } diff --git a/core/src/hitonoriol/madsand/properties/Globals.java b/core/src/hitonoriol/madsand/properties/Globals.java index ec5d07ab..82e1d65c 100644 --- a/core/src/hitonoriol/madsand/properties/Globals.java +++ b/core/src/hitonoriol/madsand/properties/Globals.java @@ -10,7 +10,7 @@ import hitonoriol.madsand.entities.quest.ProceduralQuest; public class Globals { - public static final String VERSION = "Alpha v0.49.5-pre6"; + public static final String VERSION = getVersion(); public static String TRAVEL_ITEM = "travelItem", TIMESKIP_ITEM = "timeSkipItem"; @@ -38,6 +38,15 @@ public class Globals { public HashMap values; + private static String getVersion() { + String version = Globals.class.getPackage().getImplementationVersion(); + + if (version == null) + version = "[Development Build]"; + + return version; + } + public static void loadGlobals() throws Exception { instance = Resources.mapper.readValue(Resources.readInternal(Resources.GLOBALS_FILE), Globals.class); instance.abilities.entrySet().stream().forEach(entry -> entry.getValue().id = entry.getKey()); diff --git a/core/src/hitonoriol/madsand/world/Settlement.java b/core/src/hitonoriol/madsand/world/Settlement.java index 28fb40a9..45e2d06d 100644 --- a/core/src/hitonoriol/madsand/world/Settlement.java +++ b/core/src/hitonoriol/madsand/world/Settlement.java @@ -53,7 +53,7 @@ public boolean upgradeSize() { @JsonIgnore public int getHireCost() { return (int) (Math.sqrt(getPopulation() + 1d) * BASE_HIRE_COST - * (1d + Math.sqrt(World.player.settlementsEstablished) / 25d)); + * (1d + Math.sqrt(World.player.getEstablishedSettlements()) / 25d)); } public boolean isOccupied(long npcUid) { diff --git a/desktop/build.gradle b/desktop/build.gradle index 6710b31d..f03e3812 100644 --- a/desktop/build.gradle +++ b/desktop/build.gradle @@ -4,37 +4,40 @@ sourceSets.test.java.srcDirs = [] project.ext.mainClassName = "hitonoriol.madsand.desktop.Launcher" project.ext.assetsDir = new File("../core/assets") +archivesBaseName = appName compileJava { options.release = 8 } task run(dependsOn: classes, type: JavaExec) { - main = project.mainClassName - classpath = sourceSets.main.runtimeClasspath - standardInput = System.in - workingDir = project.assetsDir - ignoreExitValue = true + main = project.mainClassName + classpath = sourceSets.main.runtimeClasspath + standardInput = System.in + workingDir = project.assetsDir + ignoreExitValue = true } task debug(dependsOn: classes, type: JavaExec) { - main = project.mainClassName - classpath = sourceSets.main.runtimeClasspath - standardInput = System.in - workingDir = project.assetsDir - ignoreExitValue = true - debug = true + main = project.mainClassName + classpath = sourceSets.main.runtimeClasspath + standardInput = System.in + workingDir = project.assetsDir + ignoreExitValue = true + debug = true } task dist(type: Jar) { - manifest { - attributes 'Main-Class': project.mainClassName - } - dependsOn configurations.runtimeClasspath - from { - configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } - } - with jar + manifest { + attributes 'Main-Class': project.mainClassName, + 'Implementation-Title': appName, + 'Implementation-Version': version + } + dependsOn configurations.runtimeClasspath + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } + with jar } diff --git a/test/src/hitonoriol/madsand/tests/QuestTest.java b/test/src/hitonoriol/madsand/tests/QuestTest.java index 37a7a472..a0087743 100644 --- a/test/src/hitonoriol/madsand/tests/QuestTest.java +++ b/test/src/hitonoriol/madsand/tests/QuestTest.java @@ -19,7 +19,7 @@ public class QuestTest { Player player = MadSand.player(); - QuestWorker quests = player.quests; + QuestWorker quests = player.getQuestWorker(); Overlay overlay = Gui.overlay; SkillContainer skills = player.stats().skills, expectedSkills = new SkillContainer();