diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..387d4e0 --- /dev/null +++ b/TODO.md @@ -0,0 +1,14 @@ +# TODO + - Barter system + - Ventor inventories + - Save/load system + - Achievements + - Combat + - NPCs + - Music/sfx + - Redo weapons and ids and stuff + - Strings to things and ids maybe not needed? +- Custom assets +- Installer +- Gameplay +- Graphics \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 94cb5a1..49d89d6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("java") + id("io.freefair.lombok") version "9.5.0" } group = "net.halfheart" @@ -14,8 +15,20 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter") testRuntimeOnly("org.junit.platform:junit-platform-launcher") implementation("org.json:json:20231013") + compileOnly("org.projectlombok:lombok:1.18.46") + annotationProcessor("org.projectlombok:lombok:1.18.46") + testCompileOnly("org.projectlombok:lombok:1.18.46") + testAnnotationProcessor("org.projectlombok:lombok:1.18.46") } tasks.test { useJUnitPlatform() +} + +tasks.jar { + manifest { + attributes( + "Main-Class" to "net.halfheart.Main", + ) + } } \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..d95395a --- /dev/null +++ b/readme.md @@ -0,0 +1,2 @@ +# Fallout Lonesome Road +A fanmade Fallout game. Its really just an excuse for me to do Java right now. Hopefully its engine can be used in a different project of mine. \ No newline at end of file diff --git a/src/main/java/net/halfheart/Main.java b/src/main/java/net/halfheart/Main.java index 916ef06..3501b57 100644 --- a/src/main/java/net/halfheart/Main.java +++ b/src/main/java/net/halfheart/Main.java @@ -2,6 +2,6 @@ package net.halfheart; public class Main { public static void main(String[] args) { - + System.out.print(System.getProperty("user.home")); } } diff --git a/src/main/java/net/halfheart/lonesomeroad/ID.java b/src/main/java/net/halfheart/lonesomeroad/ID.java deleted file mode 100644 index 3f9d2af..0000000 --- a/src/main/java/net/halfheart/lonesomeroad/ID.java +++ /dev/null @@ -1,47 +0,0 @@ -package net.halfheart.lonesomeroad; - -import net.halfheart.ventricleengine.objects.*; -import net.halfheart.ventricleengine.WeaponsHandler; -import net.halfheart.ventricleengine.ArmorsHandler; -import net.halfheart.ventricleengine.AidModifierHandler; -import net.halfheart.ventricleengine.ItemsHandler; -import net.halfheart.ventricleengine.PlayerHandler; - - -public record ID() { - public static Weapon FISTS = WeaponsHandler.constructWeapon("Fists"); - public static Weapon COMBATKNIFE = WeaponsHandler.constructWeapon("Combat Knife"); - public static Weapon RIPPER = WeaponsHandler.constructWeapon("Ripper"); - public static Weapon CHAINSAW = WeaponsHandler.constructWeapon("Chainsaw"); - public static Weapon BASEBALLBAT = WeaponsHandler.constructWeapon("Baseball Bat"); - public static Weapon POWERFIST = WeaponsHandler.constructWeapon("Power Fist"); - public static Weapon SUPERSLEDGE = WeaponsHandler.constructWeapon("Super Sledge"); - public static Weapon PISTOL10MM = WeaponsHandler.constructWeapon("10mm Pistol"); - public static Weapon HUNTINGRIFLE = WeaponsHandler.constructWeapon("Hunting Rifle"); - - public static Armor NOTHING = ArmorsHandler.constructArmor("Nothing"); - public static Armor LEATHERARMOR = ArmorsHandler.constructArmor("Leather Armor"); - public static Armor STURDYLEATHERARMOR = ArmorsHandler.constructArmor("Sturdy Leather Armor"); - public static Armor RAIDERARMOR = ArmorsHandler.constructArmor("Raider Armor"); - public static Armor METALARMOR = ArmorsHandler.constructArmor("Metal Armor"); - public static Armor COMBATARMOR = ArmorsHandler.constructArmor("Combat Armor"); - public static Armor CENTURIONARMOR = ArmorsHandler.constructArmor("Centurion Armor"); - public static Armor NCRRANGERARMOR = ArmorsHandler.constructArmor("NCR Ranger Armor"); - public static Armor T45POWERARMOR = ArmorsHandler.constructArmor("T-45 Power Armor"); - public static Armor T60POWERARMOR = ArmorsHandler.constructArmor("T-60 Power Armor"); - public static Armor T65POWERARMOR = ArmorsHandler.constructArmor("T-65 Power Armor"); - public static Armor X01POWERARMOR = ArmorsHandler.constructArmor("X-01 Power Armor"); - public static Armor APAMKIORPOWERARMOR = ArmorsHandler.constructArmor("APA MkI Power Armor"); - public static Armor APAMKIIPOWERARMOR = ArmorsHandler.constructArmor("APA MkII Power Armor"); - public static Armor RAIDERPOWERARMOR = ArmorsHandler.constructArmor("Raider Power Armor"); - public static Armor ULTRACITEPOWERARMOR = ArmorsHandler.constructArmor("Ultracite Power Armor"); - public static Armor T51POWERARMOR = ArmorsHandler.constructArmor("T-51 Power Armor"); - public static Armor ENCLAVEUNIFORM = ArmorsHandler.constructArmor("Enclave Uniform"); - public static Armor EXCAVATORPOWERARMOR = ArmorsHandler.constructArmor("Excavator Power Armor"); - - public static Player PLAYER = PlayerHandler.constructPlayer("none"); - - public static Item STIMPAK = ItemsHandler.constructItem("Stimpak"); - - public static AidModifier STIMPAK_M = AidModifierHandler.constructAidModifier("Stimpak"); -} diff --git a/src/main/java/net/halfheart/ventricleengine/AidModifierHandler.java b/src/main/java/net/halfheart/ventricleengine/AidModifierHandler.java index 22254a0..51e1a9d 100644 --- a/src/main/java/net/halfheart/ventricleengine/AidModifierHandler.java +++ b/src/main/java/net/halfheart/ventricleengine/AidModifierHandler.java @@ -1,6 +1,6 @@ package net.halfheart.ventricleengine; import net.halfheart.ventricleengine.objects.AidModifier; -import net.halfheart.lonesomeroad.ID; +import net.halfheart.ventricleengine.objects.Player; import org.json.JSONArray; import org.json.JSONObject; import java.io.BufferedReader; @@ -20,7 +20,7 @@ public class AidModifierHandler { new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8)) .lines() .collect(Collectors.joining("\n")); - + JSONArray jsonArray = new JSONArray(jsonText); JSONObject wantedItem = null; @@ -42,28 +42,14 @@ public class AidModifierHandler { } } - // Applies requested aid modifier to player public static void applyAid(AidModifier modifier) { - if (modifier.stat.equals("hp")) { - char action = modifier.mod.charAt(0); + Player player = GameSpace.getInstance().getPlayer(); + + if (modifier.getStat().equals("hp")) { + char action = modifier.getMod().charAt(0); switch (action) { - case '+' -> ID.PLAYER.hp = (short) (ID.PLAYER.hp + modifier.value); + case '+' -> player.setHp((short) (player.getHp() + modifier.getValue())); } } } - - // Removes requested aid modifier from player - public static void removeAid(AidModifier modifier) { - if (modifier.name.equals("Stimpak")) { - System.out.println("Invalid Operation: Tried to remove Stimpak modifier from player"); - } - } - - // Returns aidModifier from String of name - public static AidModifier findAid(String aidModifierName) { - return switch (aidModifierName) { - case "Stimpak" -> ID.STIMPAK_M; - default -> null; - }; - } } diff --git a/src/main/java/net/halfheart/ventricleengine/ArmorsHandler.java b/src/main/java/net/halfheart/ventricleengine/ArmorsHandler.java index 83ba36e..92eb76e 100644 --- a/src/main/java/net/halfheart/ventricleengine/ArmorsHandler.java +++ b/src/main/java/net/halfheart/ventricleengine/ArmorsHandler.java @@ -1,7 +1,8 @@ package net.halfheart.ventricleengine; + import net.halfheart.ventricleengine.objects.Armor; -import net.halfheart.lonesomeroad.ID; -import org.json.*; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; @@ -14,67 +15,42 @@ import java.util.Objects; import java.util.stream.Collectors; public class ArmorsHandler { - // Creates Armor object by parsing JSON + public static Armor constructArmor(String armorName) { String filename = "/armors.json"; - try (InputStream inputStream = WeaponsHandler.class.getResourceAsStream(filename)) { - String jsonText = new BufferedReader( - new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8)) - .lines() - .collect(Collectors.joining("\n")); - + try (InputStream inputStream = ItemsHandler.class.getResourceAsStream(filename); BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8))) { + + String jsonText = reader.lines().collect(Collectors.joining("\n")); JSONArray jsonArray = new JSONArray(jsonText); - JSONObject wantedItem = null; + for (int i = 0; i < jsonArray.length(); i++) { JSONObject item = jsonArray.getJSONObject(i); if (item.opt("name").toString().equals(armorName)) { wantedItem = item; } } - assert wantedItem != null; - JSONObject resistances = wantedItem.getJSONObject("resistances"); - String name = wantedItem.opt("name").toString(); - String description = wantedItem.opt("desc").toString(); - String armorType = wantedItem.opt("type").toString(); - String resUnit = wantedItem.opt("unit").toString(); - List resList = new ArrayList<>(); - for (String key : resistances.keySet()) { - byte res = (byte) resistances.opt(key); - resList.add(res); - } - byte weight = (byte) wantedItem.opt("weight"); - short cost = (short) wantedItem.opt("cost"); - return new Armor(name, description, armorType, resList, resUnit, cost, weight); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + if (wantedItem == null) return null; - // Returns Armor from String of name - public static Armor findArmor(String armorName) { - return switch (armorName) { - case "Nothing" -> ID.NOTHING; - case "Leather Armor" -> ID.LEATHERARMOR; - case "Sturdy Leather Armor" -> ID.STURDYLEATHERARMOR; - case "Raider Armor" -> ID.RAIDERARMOR; - case "Metal Armor" -> ID.METALARMOR; - case "Combat Armor" -> ID.COMBATARMOR; - case "Centurion Armor" -> ID.CENTURIONARMOR; - case "NCR Ranger Armor" -> ID.NCRRANGERARMOR; - case "T-45 Power Armor" -> ID.T45POWERARMOR; - case "T-60 Power Armor" -> ID.T60POWERARMOR; - case "T-65 Power Armor" -> ID.T65POWERARMOR; - case "X-01 Power Armor" -> ID.X01POWERARMOR; - case "APA MkI Power Armor" -> ID.APAMKIORPOWERARMOR; - case "APA MkII Power Armor" -> ID.APAMKIIPOWERARMOR; - case "Raider Power Armor" -> ID.RAIDERPOWERARMOR; - case "Ultracite Power Armor" -> ID.ULTRACITEPOWERARMOR; - case "T-51 Power Armor" -> ID.T51POWERARMOR; - case "Enclave Uniform" -> ID.ENCLAVEUNIFORM; - case "Excavator Power Armor" -> ID.EXCAVATORPOWERARMOR; - default -> null; - }; + String name = wantedItem.getString("name"); + String description = wantedItem.getString("description"); + byte weight = (byte) wantedItem.getInt("weight"); + short cost = (short) wantedItem.getInt("cost"); + + String type = wantedItem.getString("type"); + String resUnit = wantedItem.getString("resUnit"); + + JSONArray resArray = wantedItem.getJSONArray("resistances"); + List resistances = new ArrayList<>(); + for (int i = 0; i < resArray.length(); i++) { + resistances.add((byte) resArray.getInt(i)); + } + + return new Armor(name, description, weight, cost, type, resistances, resUnit); + + } catch (IOException e) { + throw new RuntimeException("Could not load armor data", e); + } } -} +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/AudioPlayer.java b/src/main/java/net/halfheart/ventricleengine/AudioPlayer.java new file mode 100644 index 0000000..5dee705 --- /dev/null +++ b/src/main/java/net/halfheart/ventricleengine/AudioPlayer.java @@ -0,0 +1,52 @@ +package net.halfheart.ventricleengine; +import java.io.File; +import java.io.IOException; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; + +public class AudioPlayer { + Long currentFrame; + Clip clip; + String status; + AudioInputStream audioInputStream; + static String fileName; + + public AudioPlayer() throws UnsupportedAudioFileException, IOException, LineUnavailableException { + audioInputStream = AudioSystem.getAudioInputStream(new File(System.getProperty("user.home")+"/.lonesomeroad/tracks/"+fileName).getAbsoluteFile()); + clip = AudioSystem.getClip(); + clip.open(audioInputStream); + } + + public void play() { + clip.start(); + status = "play"; + } + + public void pause() { + if (status.equals("paused")) + { + return; + } + this.currentFrame = this.clip.getMicrosecondPosition(); + clip.stop(); + status = "paused"; + } + + public void resume() throws UnsupportedAudioFileException, IOException, LineUnavailableException { + if (status.equals("play")) { + return; + } + clip.close(); + resetAudioStream(); + clip.setMicrosecondPosition(currentFrame); + this.play(); + } + + public void resetAudioStream() throws UnsupportedAudioFileException, IOException, LineUnavailableException { + audioInputStream = AudioSystem.getAudioInputStream(new File(System.getProperty("user.home")+"/.lonesomeroad/tracks/"+fileName).getAbsoluteFile()); + clip.open(audioInputStream); + } +} diff --git a/src/main/java/net/halfheart/ventricleengine/GameSpace.java b/src/main/java/net/halfheart/ventricleengine/GameSpace.java new file mode 100644 index 0000000..1f9b043 --- /dev/null +++ b/src/main/java/net/halfheart/ventricleengine/GameSpace.java @@ -0,0 +1,19 @@ +package net.halfheart.ventricleengine; +import net.halfheart.ventricleengine.objects.Player; +import lombok.Getter; + +@Getter +public class GameSpace { + private static GameSpace instance; + + public Player player; + + public GameSpace() { + instance = this; + this.player = PlayerHandler.constructPlayer(null); + } + + public static GameSpace getInstance() { + return instance; + } +} diff --git a/src/main/java/net/halfheart/ventricleengine/ItemsHandler.java b/src/main/java/net/halfheart/ventricleengine/ItemsHandler.java index 130f8a6..e8862ce 100644 --- a/src/main/java/net/halfheart/ventricleengine/ItemsHandler.java +++ b/src/main/java/net/halfheart/ventricleengine/ItemsHandler.java @@ -1,10 +1,5 @@ package net.halfheart.ventricleengine; -import net.halfheart.lonesomeroad.ID; -import net.halfheart.ventricleengine.objects.Item; -import org.json.JSONArray; -import org.json.JSONObject; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -13,43 +8,44 @@ import java.nio.charset.StandardCharsets; import java.util.Objects; import java.util.stream.Collectors; +import org.json.JSONArray; +import org.json.JSONObject; + +import net.halfheart.ventricleengine.objects.Consumable; +import net.halfheart.ventricleengine.objects.Item; +import net.halfheart.ventricleengine.objects.MiscItem; + public class ItemsHandler { - // Creates Item by parsing JSON public static Item constructItem(String itemName) { String filename = "/items.json"; - try (InputStream inputStream = WeaponsHandler.class.getResourceAsStream(filename)) { - String jsonText = new BufferedReader( - new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8)) - .lines() - .collect(Collectors.joining("\n")); - + try (InputStream inputStream = ItemsHandler.class.getResourceAsStream(filename); BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8))) { + + String jsonText = reader.lines().collect(Collectors.joining("\n")); JSONArray jsonArray = new JSONArray(jsonText); - + JSONObject wantedItem = null; for (int i = 0; i < jsonArray.length(); i++) { JSONObject item = jsonArray.getJSONObject(i); - if (item.opt("name").toString().equals(itemName)) { + if (item.getString("name").equals(itemName)) { wantedItem = item; + break; } } - assert wantedItem != null; - String name = wantedItem.opt("name").toString(); - String description = wantedItem.opt("desc").toString(); - byte weight = (byte) wantedItem.opt("weight"); - short cost = (short) wantedItem.opt("cost"); - boolean consumable = (boolean) wantedItem.opt("consumable"); - String aidModifier = wantedItem.opt("aidModifier").toString(); - return new Item(name, description, weight, cost, consumable, aidModifier); + + if (wantedItem == null) return null; + + String name = wantedItem.getString("name"); + String description = wantedItem.getString("desc"); + byte weight = (byte) wantedItem.getInt("weight"); + short cost = (short) wantedItem.getInt("cost"); + + if (wantedItem.optBoolean("consumable", false)) { + return new Consumable(name, description, weight, cost, wantedItem.getString("aidModifier")); + } + + return new MiscItem(name, description, weight, cost); } catch (IOException e) { - throw new RuntimeException(e); + throw new RuntimeException("Failed to load items library", e); } } - - // Returns Item from String of name - public static Item findItem(String itemName) { - return switch (itemName) { - case "Stimpak" -> ID.STIMPAK; - default -> null; - }; - } -} +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/PlayerHandler.java b/src/main/java/net/halfheart/ventricleengine/PlayerHandler.java index 90aeb38..f3b95c5 100644 --- a/src/main/java/net/halfheart/ventricleengine/PlayerHandler.java +++ b/src/main/java/net/halfheart/ventricleengine/PlayerHandler.java @@ -1,138 +1,98 @@ package net.halfheart.ventricleengine; + import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; - import net.halfheart.ventricleengine.objects.*; import org.json.*; public class PlayerHandler { - // Creates Player object by parsing JSON + public static Player constructPlayer(String savePath) { - // "none" Used for creating a blank Player for character creation - if (savePath.equals("none")) { - String name = "No Player Loaded!"; - byte strength = 0; - byte perception = 0; - byte endurance = 0; - byte charisma = 0; - byte intelligence = 0; - byte agility = 0; - byte luck = 0; - short caps = 0; - short pwMoney = 0; - short hpCap = 0; - short hp = 0; - short food = 0; - boolean isRadiated = false; - byte radPoints = 0; - int xp = 0; - short level = 0; - List weaponList = new ArrayList<>(); - List armorList = new ArrayList<>(); - List itemList = new ArrayList<>(); - List aidList = new ArrayList<>(); + if (savePath == null) { + return createDefaultPlayer(); + } + + try { + String content = new String(Files.readAllBytes(Paths.get(savePath))); + JSONObject saveData = new JSONObject(content); + + String name = saveData.getString("name"); + byte strength = (byte) saveData.getInt("strength"); + byte perception = (byte) saveData.getInt("perception"); + byte endurance = (byte) saveData.getInt("endurance"); + byte charisma = (byte) saveData.getInt("charisma"); + byte intelligence = (byte) saveData.getInt("intelligence"); + byte agility = (byte) saveData.getInt("agility"); + byte luck = (byte) saveData.getInt("luck"); + + short caps = (short) saveData.getInt("caps"); + short pwMoney = (short) saveData.getInt("pwMoney"); + short hpCap = (short) saveData.getInt("hpCap"); + short hp = (short) saveData.getInt("hp"); + + boolean isRadiated = saveData.getBoolean("isRadiated"); + byte radPoints = (byte) saveData.getInt("radPoints"); + int xp = saveData.getInt("xp"); + short level = (short) saveData.getInt("level"); + + // 2. Build the Consolidated Inventory + List inventory = new ArrayList<>(); + + JSONObject weapons = saveData.getJSONObject("weapons"); + for (String key : weapons.keySet()) { + inventory.add(WeaponsHandler.constructWeapon(weapons.getString(key))); + } + + JSONObject armors = saveData.getJSONObject("armors"); + for (String key : armors.keySet()) { + inventory.add(ArmorsHandler.constructArmor(armors.getString(key))); + } + + JSONObject items = saveData.getJSONObject("items"); + for (String key : items.keySet()) { + inventory.add(ItemsHandler.constructItem(items.getString(key))); + } + + // 3. Aid Modifiers + List aidModifierList = new ArrayList<>(); + JSONObject aidModifiers = saveData.getJSONObject("aidModifiers"); + for (String key : aidModifiers.keySet()) { + aidModifierList.add(AidModifierHandler.constructAidModifier(aidModifiers.getString(key))); + } + + Weapon equippedWeapon = WeaponsHandler.constructWeapon(saveData.getString("equippedWeapon")); + Armor equippedArmor = ArmorsHandler.constructArmor(saveData.getString("equippedArmor")); return new Player( - name, - strength, - perception, - endurance, - charisma, - intelligence, - agility, - luck, - caps, - pwMoney, - hpCap, - hp, - food, - isRadiated, - radPoints, - xp, - level, - weaponList, - armorList, - itemList, - aidList + name, strength, perception, endurance, charisma, intelligence, agility, luck, + caps, pwMoney, hpCap, hp, isRadiated, radPoints, xp, level, + inventory, aidModifierList, equippedWeapon, equippedArmor ); - } else { - try { - String content = new String(Files.readAllBytes(Paths.get(savePath))); - JSONObject saveData = new JSONObject(content); - String name = saveData.opt("name").toString(); - byte strength = (byte) saveData.opt("strength"); - byte perception = (byte) saveData.opt("perception"); - byte endurance = (byte) saveData.opt("endurance"); - byte charisma = (byte) saveData.opt("charisma"); - byte intelligence = (byte) saveData.opt("intelligence"); - byte agility = (byte) saveData.opt("agility"); - byte luck = (byte) saveData.opt("luck"); - short caps = (short) saveData.opt("caps"); - short pwMoney = (short) saveData.opt("pwMoney"); - short hpCap = (short) saveData.opt("hpCap"); - short hp = (short) saveData.opt("hp"); - short food = (short) saveData.opt("food"); - boolean isRadiated = (boolean) saveData.opt("isRadiated"); - byte radPoints = (byte) saveData.opt("radPoints"); - int xp = (int) saveData.opt("xp"); - short level = (short) saveData.opt("level"); - - JSONObject weapons = saveData.getJSONObject("weapons"); - JSONObject armors = saveData.getJSONObject("armors"); - JSONObject items = saveData.getJSONObject("items"); - JSONObject aidModifiers = saveData.getJSONObject("aidModifiers"); - - List weaponList = new ArrayList<>(); - for (String key : weapons.keySet()) { - weaponList.add(WeaponsHandler.findWeapon(weapons.opt(key).toString())); - } - List armorList = new ArrayList<>(); - for (String key : armors.keySet()) { - armorList.add(ArmorsHandler.findArmor(armors.opt(key).toString())); - } - List itemList = new ArrayList<>(); - for (String key : items.keySet()) { - itemList.add(ItemsHandler.findItem(items.opt(key).toString())); - } - List aidModifierList = new ArrayList<>(); - for (String key : aidModifiers.keySet()) { - aidModifierList.add(AidModifierHandler.findAid(items.opt(key).toString())); - } - - return new Player( - name, - strength, - perception, - endurance, - charisma, - intelligence, - agility, - luck, - caps, - pwMoney, - hpCap, - hp, - food, - isRadiated, - radPoints, - xp, - level, - weaponList, - armorList, - itemList, - aidModifierList - ); - } catch (FileNotFoundException e) { - System.out.println("Save file not found at path: "+savePath); - } catch (IOException e) { - throw new RuntimeException(e); - } + } catch (FileNotFoundException e) { + System.err.println("Save file not found at path: " + savePath); + return null; + } catch (IOException e) { + throw new RuntimeException("Error reading save file", e); } - return null; } -} + + private static Player createDefaultPlayer() { + List initialInventory = new ArrayList<>(); + Weapon fists = WeaponsHandler.constructWeapon("Fists"); + Armor skin = ArmorsHandler.constructArmor("Skin"); + + initialInventory.add(fists); + initialInventory.add(skin); + + return new Player( + "No Player Loaded!", (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, + (short)0, (short)0, (short)0, (short)0, false, (byte)0, 0, (short)0, + initialInventory, new ArrayList<>(), fists, skin + ); + } +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/WeaponsHandler.java b/src/main/java/net/halfheart/ventricleengine/WeaponsHandler.java index d8850d5..c48a6ef 100644 --- a/src/main/java/net/halfheart/ventricleengine/WeaponsHandler.java +++ b/src/main/java/net/halfheart/ventricleengine/WeaponsHandler.java @@ -1,8 +1,8 @@ package net.halfheart.ventricleengine; -import net.halfheart.lonesomeroad.ID; -import net.halfheart.ventricleengine.objects.Weapon; -import org.json.*; +import net.halfheart.ventricleengine.objects.Weapon; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -12,65 +12,36 @@ import java.util.Objects; import java.util.stream.Collectors; public class WeaponsHandler { - // Creates Weapon object by parsing JSON public static Weapon constructWeapon(String weaponName) { String filename = "/weapons.json"; - try (InputStream inputStream = WeaponsHandler.class.getResourceAsStream(filename)) { - String jsonText = new BufferedReader( - new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8)) - .lines() - .collect(Collectors.joining("\n")); - + try (InputStream inputStream = ItemsHandler.class.getResourceAsStream(filename); BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8))) { + + String jsonText = reader.lines().collect(Collectors.joining("\n")); JSONArray jsonArray = new JSONArray(jsonText); - + JSONObject wantedItem = null; for (int i = 0; i < jsonArray.length(); i++) { JSONObject item = jsonArray.getJSONObject(i); - if (item.opt("name").toString().equals(weaponName)) { + if (item.getString("name").equals(weaponName)) { wantedItem = item; + break; } } - assert wantedItem != null; - String name = wantedItem.opt("name").toString(); - String description = wantedItem.opt("desc").toString(); - String dmgType = wantedItem.opt("type").toString(); - String ammoType = wantedItem.opt("ammo").toString(); - short damage = (short) wantedItem.opt("dmg"); - short cost = (short) wantedItem.opt("cost"); - byte weight = (byte) wantedItem.opt("weight"); - return new Weapon(name, description, dmgType, ammoType, damage, cost, weight); + + if (wantedItem == null) return null; + + return new Weapon( + wantedItem.getString("name"), + wantedItem.getString("description"), + (byte) wantedItem.getInt("weight"), + (short) wantedItem.getInt("cost"), + wantedItem.getString("dmgType"), + wantedItem.getString("ammoType"), + (short) wantedItem.getInt("damage") + ); + } catch (IOException e) { - throw new RuntimeException(e); + throw new RuntimeException("Failed to load weapons library", e); } } - - // Finds Weapon from String of name - public static Weapon findWeapon(String weaponName) { - return switch (weaponName) { - case "Fists" -> ID.FISTS; - case "Combat Knife" -> ID.COMBATKNIFE; - case "Ripper" -> ID.RIPPER; - case "Chainsaw" -> ID.CHAINSAW; - case "Baseball Bat" -> ID.BASEBALLBAT; - case "Power Fist" -> ID.POWERFIST; - case "Super Sledge" -> ID.SUPERSLEDGE; - case "10mm Pistol" -> ID.PISTOL10MM; - case "Hunting Rifle" -> ID.HUNTINGRIFLE; - default -> null; - }; - } - - public static void fistCalc() { - switch (ID.PLAYER.strength){ - case 0 -> { - ID.FISTS.description = ID.FISTS.description+"please don't."; - ID.FISTS.damage = -2; - } - case (1|2|3|4) -> ID.FISTS.description = ID.FISTS.description+"a last resort."; - case (5|6|7|8) -> ID.FISTS.description = ID.FISTS.description+"use cautiously."; - case (9|10) -> ID.FISTS.description = ID.FISTS.description+"a formidable weapon."; - } - } - - -} +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/jukebox.java b/src/main/java/net/halfheart/ventricleengine/jukebox.java new file mode 100644 index 0000000..d428ff0 --- /dev/null +++ b/src/main/java/net/halfheart/ventricleengine/jukebox.java @@ -0,0 +1,12 @@ +package net.halfheart.ventricleengine; +import net.halfheart.ventricleengine.AudioPlayer; + +public class Jukebox { + // Remember + + // Music types: + // theme: game theme, credits theme, location theme, boss + // amb: ambience + // combat: combat tracks + // sfx: sound effects +} diff --git a/src/main/java/net/halfheart/ventricleengine/objects/AidModifier.java b/src/main/java/net/halfheart/ventricleengine/objects/AidModifier.java index b77737d..a8f281e 100644 --- a/src/main/java/net/halfheart/ventricleengine/objects/AidModifier.java +++ b/src/main/java/net/halfheart/ventricleengine/objects/AidModifier.java @@ -1,17 +1,13 @@ package net.halfheart.ventricleengine.objects; +import lombok.Getter; +import lombok.AllArgsConstructor; -// AidModifiers are used to break down the JSON data into Java-readable components. +@Getter +@AllArgsConstructor public class AidModifier { - public String name; // Name of the effect, seen in game - public String stat; // Stat that the modifier affects - public String mod; // Operation that the modifier is doing to the stat (e.g. * for multiplying) - public short value; // Value that the operation uses (e.g. 25 for +25 hp) - - public AidModifier(String name, String stat, String mod, short value) { - this.name = name; - this.stat = stat; - this.mod = mod; - this.value = value; - } -} + private String name; + private String stat; + private String mod; + private short value; +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/objects/Armor.java b/src/main/java/net/halfheart/ventricleengine/objects/Armor.java index 595a72d..e039286 100644 --- a/src/main/java/net/halfheart/ventricleengine/objects/Armor.java +++ b/src/main/java/net/halfheart/ventricleengine/objects/Armor.java @@ -1,32 +1,18 @@ package net.halfheart.ventricleengine.objects; + +import lombok.Getter; import java.util.List; -// Armor is used to represent each armor as a Java object with values -public class Armor { - public String name; // Name of the armor, seen in game - public String description; // Description seen in pip-boy - public String type; // Armor type, either skin, uarmor, armor, or parmor - public List resistances; // A list of resistance byte values for each damage type - public String resUnit; // Unit the resistances use, either dt or dr for damage threshold and damage resistance - public short cost; // Buy/Sell price - public byte weight; // Weight of item in inventory +@Getter +public class Armor extends Item { + private String type; + private List resistances; + private String resUnit; - public Armor( - String name, - String description, - String type, - List resistances, - String resUnit, - short cost, - byte weight - ) - { - this.name = name; - this.description = description; + public Armor(String name, String description, byte weight, short cost, String type, List resistances, String resUnit) { + super(name, description, weight, cost); this.type = type; this.resistances = resistances; this.resUnit = resUnit; - this.cost = cost; - this.weight = weight; } -} +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/objects/Consumable.java b/src/main/java/net/halfheart/ventricleengine/objects/Consumable.java new file mode 100644 index 0000000..8c67fe2 --- /dev/null +++ b/src/main/java/net/halfheart/ventricleengine/objects/Consumable.java @@ -0,0 +1,18 @@ +package net.halfheart.ventricleengine.objects; +import lombok.Getter; + +@Getter +public class Consumable extends Item { + private String aidModifier; + + public Consumable( + String name, + String description, + byte weight, + short cost, + String aidModifier + ) { + super(name, description, weight, cost); + this.aidModifier = aidModifier; + } +} diff --git a/src/main/java/net/halfheart/ventricleengine/objects/Item.java b/src/main/java/net/halfheart/ventricleengine/objects/Item.java index 0ca31bb..354ce18 100644 --- a/src/main/java/net/halfheart/ventricleengine/objects/Item.java +++ b/src/main/java/net/halfheart/ventricleengine/objects/Item.java @@ -1,28 +1,13 @@ package net.halfheart.ventricleengine.objects; -// Item is used to represent each armor as a Java object with values -public class Item { - public String name; // Name of item, seen in game - public String description; // Description seen in pip-boy - public byte weight; // Weight of item in inventory - public short cost; // Buy/Sell value of item - public boolean consumable; // Whether the item can be consumed - public String aidModifier; // Aid modifier that the item applies when consumed - - public Item( - String name, - String description, - byte weight, - short cost, - boolean consumable, - String aidModifier - ){ - this.name = name; - this.description = description; - this.weight = weight; - this.cost = cost; - this.consumable = consumable; - this.aidModifier = aidModifier; - } -} +import lombok.Getter; +import lombok.AllArgsConstructor; +@Getter +@AllArgsConstructor +public abstract class Item { + private String name; + private String description; + private byte weight; + private short cost; +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/objects/MiscItem.java b/src/main/java/net/halfheart/ventricleengine/objects/MiscItem.java new file mode 100644 index 0000000..6542729 --- /dev/null +++ b/src/main/java/net/halfheart/ventricleengine/objects/MiscItem.java @@ -0,0 +1,7 @@ +package net.halfheart.ventricleengine.objects; + +public class MiscItem extends Item { + public MiscItem(String name, String description, byte weight, short cost) { + super(name, description, weight, cost); // + } +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/objects/NPC.java b/src/main/java/net/halfheart/ventricleengine/objects/NPC.java new file mode 100644 index 0000000..644741c --- /dev/null +++ b/src/main/java/net/halfheart/ventricleengine/objects/NPC.java @@ -0,0 +1,24 @@ +package net.halfheart.ventricleengine.objects; + +import lombok.Getter; +import lombok.Setter; +import lombok.AllArgsConstructor; +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +public class NPC { + private String name; + private String race; + private byte strength, perception, endurance, charisma, intelligence, agility, luck; + private short caps, pwMoney; + private short hpCap, hp; + + private List inventory; + private List aidModifiers; + + private Weapon equippedWeapon; + private Armor equippedArmor; + private boolean canBarter; +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/objects/Player.java b/src/main/java/net/halfheart/ventricleengine/objects/Player.java index 8207e96..3e25a9e 100644 --- a/src/main/java/net/halfheart/ventricleengine/objects/Player.java +++ b/src/main/java/net/halfheart/ventricleengine/objects/Player.java @@ -1,82 +1,33 @@ package net.halfheart.ventricleengine.objects; + +import lombok.Getter; +import lombok.Setter; +import lombok.AllArgsConstructor; import java.util.List; -// Player is used to represent the save data values as a Java object +@Getter +@Setter +@AllArgsConstructor public class Player { - public String name; // Name of player - // Next 7 lines: S.P.E.C.I.A.L. values of player - public byte strength; - public byte perception; - public byte endurance; - public byte charisma; - public byte intelligence; - public byte agility; - public byte luck; + private String name; + private byte strength, perception, endurance, charisma, intelligence, agility, luck; + private short caps, pwMoney; + private short hpCap, hp; + private boolean isRadiated; + private byte radPoints; + private int xp; + private short level; - public short caps; // Caps the player has, used for vendors - public short pwMoney; // Pre-War Money the player has, used in Enclave vendors + private List inventory; + private List aidModifiers; - public short hpCap; // Player health point cap - public short hp; // Current player health + private Weapon equippedWeapon; + private Armor equippedArmor; - public short food; // Food the player has, eaten each walk cycle - - public boolean isRadiated; // Whether the player is irradiated - // TODO: Decide function of radPoints - public byte radPoints; // Rad points player has - - public int xp; // Current player xp - public short level; // Current level of player - - public List weapons; // Weapons that the player has in inventory - public List armors; // Armors that the player has in inventory - public List items; // Items that the player has in inventory - public List aidModifiers; // Modifiers currently affecting player - - public Player( - String name, - byte strength, - byte perception, - byte endurance, - byte charisma, - byte intelligence, - byte agility, - byte luck, - short caps, - short pwMoney, - short hpCap, - short hp, - short food, - boolean isRadiated, - byte radPoints, - int xp, - short level, - List weapons, - List armors, - List items, - List aidModifiers - ) - { - this.name = name; - this.strength = strength; - this.perception = perception; - this.endurance = endurance; - this.charisma = charisma; - this.intelligence = intelligence; - this.agility = agility; - this.luck = luck; - this.caps = caps; - this.pwMoney = pwMoney; - this.hpCap = hpCap; - this.hp = hp; - this.food = food; - this.isRadiated = isRadiated; - this.radPoints = radPoints; - this.xp = xp; - this.level = level; - this.weapons = weapons; - this.armors = armors; - this.items = items; - this.aidModifiers = aidModifiers; + // Manual setter to override Lombok's default and enforce the HP Cap + public void setHp(short hp) { + if (hp > this.hpCap) this.hp = this.hpCap; + else if (hp < 0) this.hp = 0; + else this.hp = hp; } -} +} \ No newline at end of file diff --git a/src/main/java/net/halfheart/ventricleengine/objects/Weapon.java b/src/main/java/net/halfheart/ventricleengine/objects/Weapon.java index c5ac3a5..4316ba3 100644 --- a/src/main/java/net/halfheart/ventricleengine/objects/Weapon.java +++ b/src/main/java/net/halfheart/ventricleengine/objects/Weapon.java @@ -1,31 +1,17 @@ package net.halfheart.ventricleengine.objects; -// Weapon is used to represent each weapon as a Java object with values -public class Weapon { - public String name; // Name of weapon, seen in game - public String description; // Description of weapon, seen in pip-boy - public String dmgType; // Type of damage the weapon deals. Laser, Bash, Slash. etc. - public String ammoType; // Ammo the weapon uses. "none" for melee weapons - public short damage; // Damage the weapon deals - public short cost; // Buy/Sell value of weapon - public byte weight; // Weight of weapon in inventory +import lombok.Getter; - public Weapon( - String name, - String description, - String dmgType, - String ammoType, - short damage, - short cost, - byte weight - ) - { - this.name = name; - this.description = description; +@Getter +public class Weapon extends Item { + private String dmgType; + private String ammoType; + private short damage; + + public Weapon(String name, String description, byte weight, short cost, String dmgType, String ammoType, short damage) { + super(name, description, weight, cost); this.dmgType = dmgType; this.ammoType = ammoType; this.damage = damage; - this.cost = cost; - this.weight = weight; } -} +} \ No newline at end of file diff --git a/src/main/resources/dialogue/credits.txt b/src/main/resources/dialogue/credits.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/aid_modifiers.json b/src/main/resources/lists/aid_modifiers.json similarity index 100% rename from src/main/resources/aid_modifiers.json rename to src/main/resources/lists/aid_modifiers.json diff --git a/src/main/resources/armors.json b/src/main/resources/lists/armors.json similarity index 86% rename from src/main/resources/armors.json rename to src/main/resources/lists/armors.json index cd948e2..717f134 100644 --- a/src/main/resources/armors.json +++ b/src/main/resources/lists/armors.json @@ -1,6 +1,6 @@ [ { - "name": "Nothing", + "name": "Skin", "desc": "Luckily you have skin, that's enough right?", "type": "skin", "resistances": { @@ -12,7 +12,8 @@ }, "unit": "dr", "weight": 0, - "cost": -1 + "cost": 0, + "immutable": true }, { "name": "Leather Armor", @@ -25,7 +26,8 @@ "plasma": 3}, "unit": "dr", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "Sturdy Leather Armor", "desc": "A set of combat armor, better protection from laser and plasma weapons.", @@ -38,7 +40,8 @@ }, "unit": "dr", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "Raider Armor", "desc": "A set of raider armor, good protection from ballistic damage.", @@ -51,7 +54,8 @@ }, "unit": "dr", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "Metal Armor" , "desc": "A set of raider armor, better protection from ballistic and slash damage.", @@ -64,7 +68,8 @@ }, "unit": "dr", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "Combat Armor", "desc": "A set of combat armor, better protection from all damage types.", @@ -77,7 +82,8 @@ }, "unit": "dr", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "Centurion Armor", "desc": "A set of Centurion armor, great protection from ballistic damage.", @@ -90,7 +96,8 @@ }, "unit": "dr", "cost": 25, - "weight": 25 + "weight": 25, + "immutable": false }, {"name": "NCR Ranger Armor" , "desc": "A set of NCR Ranger armor, great protection from laser and plasma weapons", @@ -103,7 +110,8 @@ }, "unit": "dr", "cost": 30, - "weight": 30 + "weight": 30, + "immutable": false }, {"name": "T-45 Power Armor", "desc": "A set of T-45 Power Armor, protects against all damage types.", @@ -116,7 +124,8 @@ }, "unit": "dt", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "T-60 Power Armor", "desc": "A set of T-60 Power Armor, good protection from all damage types.", @@ -129,7 +138,9 @@ }, "unit": "dt", "cost": 5, - "weight": 5} + "weight": 5, + "immutable": false +} , {"name": "T-65 Power Armor", "desc": "A set of T-60 Power Armor, great protection from all damage types.", @@ -142,7 +153,8 @@ }, "unit": "dt", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "X-01 Power Armor", "desc": "X-01 Power Armor, good protection from energy damage.", @@ -155,7 +167,8 @@ }, "unit": "dt", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "APA MkI Power Armor", "desc": "APA MkI Power Armor, great protection from energy damage.", @@ -168,7 +181,8 @@ }, "unit": "dt", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "APA MkII Power Armor", "desc": "APA MkII Power Armor, excellent protection from energy damage.", @@ -181,7 +195,8 @@ }, "unit": "dt", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "Raider Power Armor", "desc": "Raider Power Armor, good protection from ballistic damage.", @@ -194,7 +209,8 @@ }, "unit": "dt", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "Ultracite Power Armor", "desc": "Ultracite Power Armor, great protection from ballistic damage.", @@ -207,7 +223,8 @@ }, "unit": "dt", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "T-51 Power Armor", "desc": "T-51 Power Armor, excellent protection from ballistic damage.", @@ -220,7 +237,8 @@ }, "unit": "dt", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false }, {"name": "Enclave Uniform", "desc": "Enclave uniform, standard issue", @@ -233,7 +251,8 @@ }, "unit": "dr", "cost": 20, - "weight": 20 + "weight": 20, + "immutable": false }, {"name": "Excavator Power Armor", "desc": "Excavator Power Armor, +25% Chance to find extra loot", @@ -246,6 +265,7 @@ }, "unit": "dt", "cost": 5, - "weight": 5 + "weight": 5, + "immutable": false } ] \ No newline at end of file diff --git a/src/main/resources/lists/inventories.json b/src/main/resources/lists/inventories.json new file mode 100644 index 0000000..4004c94 --- /dev/null +++ b/src/main/resources/lists/inventories.json @@ -0,0 +1,9 @@ +[ + { + "RRC": { + "weapons" : [ + + ] + } + } +] \ No newline at end of file diff --git a/src/main/resources/items.json b/src/main/resources/lists/items.json similarity index 68% rename from src/main/resources/items.json rename to src/main/resources/lists/items.json index b2e812a..cc7a403 100644 --- a/src/main/resources/items.json +++ b/src/main/resources/lists/items.json @@ -5,6 +5,7 @@ "weight": 0, "cost": 0, "consumable": true, - "aidModifier": "food" + "aidModifier": "food", + "immutable": false } ] \ No newline at end of file diff --git a/src/main/resources/lists/tracks.json b/src/main/resources/lists/tracks.json new file mode 100644 index 0000000..7c74fee --- /dev/null +++ b/src/main/resources/lists/tracks.json @@ -0,0 +1,8 @@ +[ + { + "title": "Main Title", + "filename": "maintitle.wav", + "type": "theme", + "area": "meta" + } +] \ No newline at end of file diff --git a/src/main/resources/weapons.json b/src/main/resources/lists/weapons.json similarity index 78% rename from src/main/resources/weapons.json rename to src/main/resources/lists/weapons.json index af58ee8..3ebec27 100644 --- a/src/main/resources/weapons.json +++ b/src/main/resources/lists/weapons.json @@ -5,8 +5,9 @@ "type": "bash", "ammo": "none", "dmg": 2, - "cost": -1, - "weight": 0 + "cost": 0, + "weight": 0, + "immutable": true }, { "name": "Combat Knife", @@ -15,7 +16,8 @@ "ammo": "none", "dmg": 5, "cost": 5, - "weight": 1 + "weight": 1, + "immutable": false }, { "name": "Ripper", @@ -24,7 +26,8 @@ "ammo": "none", "dmg": 5, "cost": 5, - "weight": 1 + "weight": 1, + "immutable": false }, { "name": "Chainsaw", @@ -33,7 +36,8 @@ "ammo": "none", "dmg": 5, "cost": 5, - "weight": 1 + "weight": 1, + "immutable": false }, { "name": "Baseball Bat", @@ -42,7 +46,8 @@ "ammo": "none", "dmg": 5, "cost": 5, - "weight": 1 + "weight": 1, + "immutable": false }, { "name": "Power Fist", @@ -51,7 +56,8 @@ "ammo": "none", "dmg": 15, "cost": 10, - "weight": 2 + "weight": 2, + "immutable": false }, { "name": "Super Sledge", @@ -60,7 +66,8 @@ "ammo": "none", "dmg": 30, "cost": 10, - "weight": 15 + "weight": 15, + "immutable": false }, { "name": "10mm Pistol", @@ -69,7 +76,8 @@ "ammo": "10", "dmg": 10, "cost": 10, - "weight": 2 + "weight": 2, + "immutable": false }, { "name": "Hunting Rifle", @@ -78,6 +86,7 @@ "ammo": "308", "dmg": 10, "cost": 10, - "weight": 2 + "weight": 2, + "immutable": false } ] \ No newline at end of file