Added more types, changed how items and stuff will work. Began work on audio and npcs.

This commit is contained in:
Raktbastr 2026-05-15 16:18:51 -05:00
parent 05a97e072a
commit 33957c55dc
28 changed files with 472 additions and 518 deletions

14
TODO.md Normal file
View file

@ -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

View file

@ -1,5 +1,6 @@
plugins { plugins {
id("java") id("java")
id("io.freefair.lombok") version "9.5.0"
} }
group = "net.halfheart" group = "net.halfheart"
@ -14,8 +15,20 @@ dependencies {
testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher") testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation("org.json:json:20231013") 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 { tasks.test {
useJUnitPlatform() useJUnitPlatform()
} }
tasks.jar {
manifest {
attributes(
"Main-Class" to "net.halfheart.Main",
)
}
}

2
readme.md Normal file
View file

@ -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.

View file

@ -2,6 +2,6 @@ package net.halfheart;
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
System.out.print(System.getProperty("user.home"));
} }
} }

View file

@ -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");
}

View file

@ -1,6 +1,6 @@
package net.halfheart.ventricleengine; package net.halfheart.ventricleengine;
import net.halfheart.ventricleengine.objects.AidModifier; import net.halfheart.ventricleengine.objects.AidModifier;
import net.halfheart.lonesomeroad.ID; import net.halfheart.ventricleengine.objects.Player;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -42,28 +42,14 @@ public class AidModifierHandler {
} }
} }
// Applies requested aid modifier to player
public static void applyAid(AidModifier modifier) { public static void applyAid(AidModifier modifier) {
if (modifier.stat.equals("hp")) { Player player = GameSpace.getInstance().getPlayer();
char action = modifier.mod.charAt(0);
if (modifier.getStat().equals("hp")) {
char action = modifier.getMod().charAt(0);
switch (action) { 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;
};
}
} }

View file

@ -1,7 +1,8 @@
package net.halfheart.ventricleengine; package net.halfheart.ventricleengine;
import net.halfheart.ventricleengine.objects.Armor; import net.halfheart.ventricleengine.objects.Armor;
import net.halfheart.lonesomeroad.ID; import org.json.JSONArray;
import org.json.*; import org.json.JSONObject;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
@ -14,67 +15,42 @@ import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class ArmorsHandler { public class ArmorsHandler {
// Creates Armor object by parsing JSON
public static Armor constructArmor(String armorName) { public static Armor constructArmor(String armorName) {
String filename = "/armors.json"; String filename = "/armors.json";
try (InputStream inputStream = WeaponsHandler.class.getResourceAsStream(filename)) { try (InputStream inputStream = ItemsHandler.class.getResourceAsStream(filename); BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8))) {
String jsonText = new BufferedReader(
new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
String jsonText = reader.lines().collect(Collectors.joining("\n"));
JSONArray jsonArray = new JSONArray(jsonText); JSONArray jsonArray = new JSONArray(jsonText);
JSONObject wantedItem = null; JSONObject wantedItem = null;
for (int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject item = jsonArray.getJSONObject(i); JSONObject item = jsonArray.getJSONObject(i);
if (item.opt("name").toString().equals(armorName)) { if (item.opt("name").toString().equals(armorName)) {
wantedItem = item; wantedItem = item;
} }
} }
assert wantedItem != null;
JSONObject resistances = wantedItem.getJSONObject("resistances");
String name = wantedItem.opt("name").toString(); if (wantedItem == null) return null;
String description = wantedItem.opt("desc").toString();
String armorType = wantedItem.opt("type").toString();
String resUnit = wantedItem.opt("unit").toString();
List<Byte> 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);
}
}
// Returns Armor from String of name String name = wantedItem.getString("name");
public static Armor findArmor(String armorName) { String description = wantedItem.getString("description");
return switch (armorName) { byte weight = (byte) wantedItem.getInt("weight");
case "Nothing" -> ID.NOTHING; short cost = (short) wantedItem.getInt("cost");
case "Leather Armor" -> ID.LEATHERARMOR;
case "Sturdy Leather Armor" -> ID.STURDYLEATHERARMOR; String type = wantedItem.getString("type");
case "Raider Armor" -> ID.RAIDERARMOR; String resUnit = wantedItem.getString("resUnit");
case "Metal Armor" -> ID.METALARMOR;
case "Combat Armor" -> ID.COMBATARMOR; JSONArray resArray = wantedItem.getJSONArray("resistances");
case "Centurion Armor" -> ID.CENTURIONARMOR; List<Byte> resistances = new ArrayList<>();
case "NCR Ranger Armor" -> ID.NCRRANGERARMOR; for (int i = 0; i < resArray.length(); i++) {
case "T-45 Power Armor" -> ID.T45POWERARMOR; resistances.add((byte) resArray.getInt(i));
case "T-60 Power Armor" -> ID.T60POWERARMOR; }
case "T-65 Power Armor" -> ID.T65POWERARMOR;
case "X-01 Power Armor" -> ID.X01POWERARMOR; return new Armor(name, description, weight, cost, type, resistances, resUnit);
case "APA MkI Power Armor" -> ID.APAMKIORPOWERARMOR;
case "APA MkII Power Armor" -> ID.APAMKIIPOWERARMOR; } catch (IOException e) {
case "Raider Power Armor" -> ID.RAIDERPOWERARMOR; throw new RuntimeException("Could not load armor data", e);
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;
};
} }
} }

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -1,10 +1,5 @@
package net.halfheart.ventricleengine; 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.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -13,43 +8,44 @@ import java.nio.charset.StandardCharsets;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; 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 { public class ItemsHandler {
// Creates Item by parsing JSON
public static Item constructItem(String itemName) { public static Item constructItem(String itemName) {
String filename = "/items.json"; String filename = "/items.json";
try (InputStream inputStream = WeaponsHandler.class.getResourceAsStream(filename)) { try (InputStream inputStream = ItemsHandler.class.getResourceAsStream(filename); BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8))) {
String jsonText = new BufferedReader(
new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
String jsonText = reader.lines().collect(Collectors.joining("\n"));
JSONArray jsonArray = new JSONArray(jsonText); JSONArray jsonArray = new JSONArray(jsonText);
JSONObject wantedItem = null; JSONObject wantedItem = null;
for (int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject item = jsonArray.getJSONObject(i); JSONObject item = jsonArray.getJSONObject(i);
if (item.opt("name").toString().equals(itemName)) { if (item.getString("name").equals(itemName)) {
wantedItem = item; wantedItem = item;
break;
} }
} }
assert wantedItem != null;
String name = wantedItem.opt("name").toString(); if (wantedItem == null) return null;
String description = wantedItem.opt("desc").toString();
byte weight = (byte) wantedItem.opt("weight"); String name = wantedItem.getString("name");
short cost = (short) wantedItem.opt("cost"); String description = wantedItem.getString("desc");
boolean consumable = (boolean) wantedItem.opt("consumable"); byte weight = (byte) wantedItem.getInt("weight");
String aidModifier = wantedItem.opt("aidModifier").toString(); short cost = (short) wantedItem.getInt("cost");
return new Item(name, description, weight, cost, consumable, aidModifier);
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) { } 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;
};
}
} }

View file

@ -1,138 +1,98 @@
package net.halfheart.ventricleengine; package net.halfheart.ventricleengine;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.halfheart.ventricleengine.objects.*; import net.halfheart.ventricleengine.objects.*;
import org.json.*; import org.json.*;
public class PlayerHandler { public class PlayerHandler {
// Creates Player object by parsing JSON
public static Player constructPlayer(String savePath) { public static Player constructPlayer(String savePath) {
// "none" Used for creating a blank Player for character creation if (savePath == null) {
if (savePath.equals("none")) { return createDefaultPlayer();
String name = "No Player Loaded!"; }
byte strength = 0;
byte perception = 0; try {
byte endurance = 0; String content = new String(Files.readAllBytes(Paths.get(savePath)));
byte charisma = 0; JSONObject saveData = new JSONObject(content);
byte intelligence = 0;
byte agility = 0; String name = saveData.getString("name");
byte luck = 0; byte strength = (byte) saveData.getInt("strength");
short caps = 0; byte perception = (byte) saveData.getInt("perception");
short pwMoney = 0; byte endurance = (byte) saveData.getInt("endurance");
short hpCap = 0; byte charisma = (byte) saveData.getInt("charisma");
short hp = 0; byte intelligence = (byte) saveData.getInt("intelligence");
short food = 0; byte agility = (byte) saveData.getInt("agility");
boolean isRadiated = false; byte luck = (byte) saveData.getInt("luck");
byte radPoints = 0;
int xp = 0; short caps = (short) saveData.getInt("caps");
short level = 0; short pwMoney = (short) saveData.getInt("pwMoney");
List<Weapon> weaponList = new ArrayList<>(); short hpCap = (short) saveData.getInt("hpCap");
List<Armor> armorList = new ArrayList<>(); short hp = (short) saveData.getInt("hp");
List<Item> itemList = new ArrayList<>();
List<AidModifier> aidList = new ArrayList<>(); 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<Item> 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<AidModifier> 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( return new Player(
name, name, strength, perception, endurance, charisma, intelligence, agility, luck,
strength, caps, pwMoney, hpCap, hp, isRadiated, radPoints, xp, level,
perception, inventory, aidModifierList, equippedWeapon, equippedArmor
endurance,
charisma,
intelligence,
agility,
luck,
caps,
pwMoney,
hpCap,
hp,
food,
isRadiated,
radPoints,
xp,
level,
weaponList,
armorList,
itemList,
aidList
); );
} else {
try {
String content = new String(Files.readAllBytes(Paths.get(savePath)));
JSONObject saveData = new JSONObject(content);
String name = saveData.opt("name").toString(); } catch (FileNotFoundException e) {
byte strength = (byte) saveData.opt("strength"); System.err.println("Save file not found at path: " + savePath);
byte perception = (byte) saveData.opt("perception"); return null;
byte endurance = (byte) saveData.opt("endurance"); } catch (IOException e) {
byte charisma = (byte) saveData.opt("charisma"); throw new RuntimeException("Error reading save file", e);
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<Weapon> weaponList = new ArrayList<>();
for (String key : weapons.keySet()) {
weaponList.add(WeaponsHandler.findWeapon(weapons.opt(key).toString()));
}
List<Armor> armorList = new ArrayList<>();
for (String key : armors.keySet()) {
armorList.add(ArmorsHandler.findArmor(armors.opt(key).toString()));
}
List<Item> itemList = new ArrayList<>();
for (String key : items.keySet()) {
itemList.add(ItemsHandler.findItem(items.opt(key).toString()));
}
List<AidModifier> 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);
}
} }
return null; }
private static Player createDefaultPlayer() {
List<Item> 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
);
} }
} }

View file

@ -1,8 +1,8 @@
package net.halfheart.ventricleengine; 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.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -12,65 +12,36 @@ import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class WeaponsHandler { public class WeaponsHandler {
// Creates Weapon object by parsing JSON
public static Weapon constructWeapon(String weaponName) { public static Weapon constructWeapon(String weaponName) {
String filename = "/weapons.json"; String filename = "/weapons.json";
try (InputStream inputStream = WeaponsHandler.class.getResourceAsStream(filename)) { try (InputStream inputStream = ItemsHandler.class.getResourceAsStream(filename); BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8))) {
String jsonText = new BufferedReader(
new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
String jsonText = reader.lines().collect(Collectors.joining("\n"));
JSONArray jsonArray = new JSONArray(jsonText); JSONArray jsonArray = new JSONArray(jsonText);
JSONObject wantedItem = null; JSONObject wantedItem = null;
for (int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject item = jsonArray.getJSONObject(i); JSONObject item = jsonArray.getJSONObject(i);
if (item.opt("name").toString().equals(weaponName)) { if (item.getString("name").equals(weaponName)) {
wantedItem = item; wantedItem = item;
break;
} }
} }
assert wantedItem != null;
String name = wantedItem.opt("name").toString(); if (wantedItem == null) return null;
String description = wantedItem.opt("desc").toString();
String dmgType = wantedItem.opt("type").toString(); return new Weapon(
String ammoType = wantedItem.opt("ammo").toString(); wantedItem.getString("name"),
short damage = (short) wantedItem.opt("dmg"); wantedItem.getString("description"),
short cost = (short) wantedItem.opt("cost"); (byte) wantedItem.getInt("weight"),
byte weight = (byte) wantedItem.opt("weight"); (short) wantedItem.getInt("cost"),
return new Weapon(name, description, dmgType, ammoType, damage, cost, weight); wantedItem.getString("dmgType"),
wantedItem.getString("ammoType"),
(short) wantedItem.getInt("damage")
);
} catch (IOException e) { } 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.";
}
}
} }

View file

@ -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
}

View file

@ -1,17 +1,13 @@
package net.halfheart.ventricleengine.objects; 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 class AidModifier {
public String name; // Name of the effect, seen in game private String name;
public String stat; // Stat that the modifier affects private String stat;
public String mod; // Operation that the modifier is doing to the stat (e.g. * for multiplying) private String mod;
public short value; // Value that the operation uses (e.g. 25 for +25 hp) private short value;
public AidModifier(String name, String stat, String mod, short value) {
this.name = name;
this.stat = stat;
this.mod = mod;
this.value = value;
}
} }

View file

@ -1,32 +1,18 @@
package net.halfheart.ventricleengine.objects; package net.halfheart.ventricleengine.objects;
import lombok.Getter;
import java.util.List; import java.util.List;
// Armor is used to represent each armor as a Java object with values @Getter
public class Armor { public class Armor extends Item {
public String name; // Name of the armor, seen in game private String type;
public String description; // Description seen in pip-boy private List<Byte> resistances;
public String type; // Armor type, either skin, uarmor, armor, or parmor private String resUnit;
public List<Byte> 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
public Armor( public Armor(String name, String description, byte weight, short cost, String type, List<Byte> resistances, String resUnit) {
String name, super(name, description, weight, cost);
String description,
String type,
List<Byte> resistances,
String resUnit,
short cost,
byte weight
)
{
this.name = name;
this.description = description;
this.type = type; this.type = type;
this.resistances = resistances; this.resistances = resistances;
this.resUnit = resUnit; this.resUnit = resUnit;
this.cost = cost;
this.weight = weight;
} }
} }

View file

@ -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;
}
}

View file

@ -1,28 +1,13 @@
package net.halfheart.ventricleengine.objects; package net.halfheart.ventricleengine.objects;
// Item is used to represent each armor as a Java object with values import lombok.Getter;
public class Item { import lombok.AllArgsConstructor;
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( @Getter
String name, @AllArgsConstructor
String description, public abstract class Item {
byte weight, private String name;
short cost, private String description;
boolean consumable, private byte weight;
String aidModifier private short cost;
){
this.name = name;
this.description = description;
this.weight = weight;
this.cost = cost;
this.consumable = consumable;
this.aidModifier = aidModifier;
}
} }

View file

@ -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); //
}
}

View file

@ -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<Item> inventory;
private List<AidModifier> aidModifiers;
private Weapon equippedWeapon;
private Armor equippedArmor;
private boolean canBarter;
}

View file

@ -1,82 +1,33 @@
package net.halfheart.ventricleengine.objects; package net.halfheart.ventricleengine.objects;
import lombok.Getter;
import lombok.Setter;
import lombok.AllArgsConstructor;
import java.util.List; import java.util.List;
// Player is used to represent the save data values as a Java object @Getter
@Setter
@AllArgsConstructor
public class Player { public class Player {
public String name; // Name of player private String name;
// Next 7 lines: S.P.E.C.I.A.L. values of player private byte strength, perception, endurance, charisma, intelligence, agility, luck;
public byte strength; private short caps, pwMoney;
public byte perception; private short hpCap, hp;
public byte endurance; private boolean isRadiated;
public byte charisma; private byte radPoints;
public byte intelligence; private int xp;
public byte agility; private short level;
public byte luck;
public short caps; // Caps the player has, used for vendors private List<Item> inventory;
public short pwMoney; // Pre-War Money the player has, used in Enclave vendors private List<AidModifier> aidModifiers;
public short hpCap; // Player health point cap private Weapon equippedWeapon;
public short hp; // Current player health private Armor equippedArmor;
public short food; // Food the player has, eaten each walk cycle // Manual setter to override Lombok's default and enforce the HP Cap
public void setHp(short hp) {
public boolean isRadiated; // Whether the player is irradiated if (hp > this.hpCap) this.hp = this.hpCap;
// TODO: Decide function of radPoints else if (hp < 0) this.hp = 0;
public byte radPoints; // Rad points player has else this.hp = hp;
public int xp; // Current player xp
public short level; // Current level of player
public List<Weapon> weapons; // Weapons that the player has in inventory
public List<Armor> armors; // Armors that the player has in inventory
public List<Item> items; // Items that the player has in inventory
public List<AidModifier> 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<Weapon> weapons,
List<Armor> armors,
List<Item> items,
List<AidModifier> 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;
} }
} }

View file

@ -1,31 +1,17 @@
package net.halfheart.ventricleengine.objects; package net.halfheart.ventricleengine.objects;
// Weapon is used to represent each weapon as a Java object with values import lombok.Getter;
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
public Weapon( @Getter
String name, public class Weapon extends Item {
String description, private String dmgType;
String dmgType, private String ammoType;
String ammoType, private short damage;
short damage,
short cost, public Weapon(String name, String description, byte weight, short cost, String dmgType, String ammoType, short damage) {
byte weight super(name, description, weight, cost);
)
{
this.name = name;
this.description = description;
this.dmgType = dmgType; this.dmgType = dmgType;
this.ammoType = ammoType; this.ammoType = ammoType;
this.damage = damage; this.damage = damage;
this.cost = cost;
this.weight = weight;
} }
} }

View file

View file

@ -1,6 +1,6 @@
[ [
{ {
"name": "Nothing", "name": "Skin",
"desc": "Luckily you have skin, that's enough right?", "desc": "Luckily you have skin, that's enough right?",
"type": "skin", "type": "skin",
"resistances": { "resistances": {
@ -12,7 +12,8 @@
}, },
"unit": "dr", "unit": "dr",
"weight": 0, "weight": 0,
"cost": -1 "cost": 0,
"immutable": true
}, },
{ {
"name": "Leather Armor", "name": "Leather Armor",
@ -25,7 +26,8 @@
"plasma": 3}, "plasma": 3},
"unit": "dr", "unit": "dr",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "Sturdy Leather Armor", {"name": "Sturdy Leather Armor",
"desc": "A set of combat armor, better protection from laser and plasma weapons.", "desc": "A set of combat armor, better protection from laser and plasma weapons.",
@ -38,7 +40,8 @@
}, },
"unit": "dr", "unit": "dr",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "Raider Armor", {"name": "Raider Armor",
"desc": "A set of raider armor, good protection from ballistic damage.", "desc": "A set of raider armor, good protection from ballistic damage.",
@ -51,7 +54,8 @@
}, },
"unit": "dr", "unit": "dr",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "Metal Armor" , {"name": "Metal Armor" ,
"desc": "A set of raider armor, better protection from ballistic and slash damage.", "desc": "A set of raider armor, better protection from ballistic and slash damage.",
@ -64,7 +68,8 @@
}, },
"unit": "dr", "unit": "dr",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "Combat Armor", {"name": "Combat Armor",
"desc": "A set of combat armor, better protection from all damage types.", "desc": "A set of combat armor, better protection from all damage types.",
@ -77,7 +82,8 @@
}, },
"unit": "dr", "unit": "dr",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "Centurion Armor", {"name": "Centurion Armor",
"desc": "A set of Centurion armor, great protection from ballistic damage.", "desc": "A set of Centurion armor, great protection from ballistic damage.",
@ -90,7 +96,8 @@
}, },
"unit": "dr", "unit": "dr",
"cost": 25, "cost": 25,
"weight": 25 "weight": 25,
"immutable": false
}, },
{"name": "NCR Ranger Armor" , {"name": "NCR Ranger Armor" ,
"desc": "A set of NCR Ranger armor, great protection from laser and plasma weapons", "desc": "A set of NCR Ranger armor, great protection from laser and plasma weapons",
@ -103,7 +110,8 @@
}, },
"unit": "dr", "unit": "dr",
"cost": 30, "cost": 30,
"weight": 30 "weight": 30,
"immutable": false
}, },
{"name": "T-45 Power Armor", {"name": "T-45 Power Armor",
"desc": "A set of T-45 Power Armor, protects against all damage types.", "desc": "A set of T-45 Power Armor, protects against all damage types.",
@ -116,7 +124,8 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "T-60 Power Armor", {"name": "T-60 Power Armor",
"desc": "A set of T-60 Power Armor, good protection from all damage types.", "desc": "A set of T-60 Power Armor, good protection from all damage types.",
@ -129,7 +138,9 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5} "weight": 5,
"immutable": false
}
, ,
{"name": "T-65 Power Armor", {"name": "T-65 Power Armor",
"desc": "A set of T-60 Power Armor, great protection from all damage types.", "desc": "A set of T-60 Power Armor, great protection from all damage types.",
@ -142,7 +153,8 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "X-01 Power Armor", {"name": "X-01 Power Armor",
"desc": "X-01 Power Armor, good protection from energy damage.", "desc": "X-01 Power Armor, good protection from energy damage.",
@ -155,7 +167,8 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "APA MkI Power Armor", {"name": "APA MkI Power Armor",
"desc": "APA MkI Power Armor, great protection from energy damage.", "desc": "APA MkI Power Armor, great protection from energy damage.",
@ -168,7 +181,8 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "APA MkII Power Armor", {"name": "APA MkII Power Armor",
"desc": "APA MkII Power Armor, excellent protection from energy damage.", "desc": "APA MkII Power Armor, excellent protection from energy damage.",
@ -181,7 +195,8 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "Raider Power Armor", {"name": "Raider Power Armor",
"desc": "Raider Power Armor, good protection from ballistic damage.", "desc": "Raider Power Armor, good protection from ballistic damage.",
@ -194,7 +209,8 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "Ultracite Power Armor", {"name": "Ultracite Power Armor",
"desc": "Ultracite Power Armor, great protection from ballistic damage.", "desc": "Ultracite Power Armor, great protection from ballistic damage.",
@ -207,7 +223,8 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "T-51 Power Armor", {"name": "T-51 Power Armor",
"desc": "T-51 Power Armor, excellent protection from ballistic damage.", "desc": "T-51 Power Armor, excellent protection from ballistic damage.",
@ -220,7 +237,8 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
}, },
{"name": "Enclave Uniform", {"name": "Enclave Uniform",
"desc": "Enclave uniform, standard issue", "desc": "Enclave uniform, standard issue",
@ -233,7 +251,8 @@
}, },
"unit": "dr", "unit": "dr",
"cost": 20, "cost": 20,
"weight": 20 "weight": 20,
"immutable": false
}, },
{"name": "Excavator Power Armor", {"name": "Excavator Power Armor",
"desc": "Excavator Power Armor, +25% Chance to find extra loot", "desc": "Excavator Power Armor, +25% Chance to find extra loot",
@ -246,6 +265,7 @@
}, },
"unit": "dt", "unit": "dt",
"cost": 5, "cost": 5,
"weight": 5 "weight": 5,
"immutable": false
} }
] ]

View file

@ -0,0 +1,9 @@
[
{
"RRC": {
"weapons" : [
]
}
}
]

View file

@ -5,6 +5,7 @@
"weight": 0, "weight": 0,
"cost": 0, "cost": 0,
"consumable": true, "consumable": true,
"aidModifier": "food" "aidModifier": "food",
"immutable": false
} }
] ]

View file

@ -0,0 +1,8 @@
[
{
"title": "Main Title",
"filename": "maintitle.wav",
"type": "theme",
"area": "meta"
}
]

View file

@ -5,8 +5,9 @@
"type": "bash", "type": "bash",
"ammo": "none", "ammo": "none",
"dmg": 2, "dmg": 2,
"cost": -1, "cost": 0,
"weight": 0 "weight": 0,
"immutable": true
}, },
{ {
"name": "Combat Knife", "name": "Combat Knife",
@ -15,7 +16,8 @@
"ammo": "none", "ammo": "none",
"dmg": 5, "dmg": 5,
"cost": 5, "cost": 5,
"weight": 1 "weight": 1,
"immutable": false
}, },
{ {
"name": "Ripper", "name": "Ripper",
@ -24,7 +26,8 @@
"ammo": "none", "ammo": "none",
"dmg": 5, "dmg": 5,
"cost": 5, "cost": 5,
"weight": 1 "weight": 1,
"immutable": false
}, },
{ {
"name": "Chainsaw", "name": "Chainsaw",
@ -33,7 +36,8 @@
"ammo": "none", "ammo": "none",
"dmg": 5, "dmg": 5,
"cost": 5, "cost": 5,
"weight": 1 "weight": 1,
"immutable": false
}, },
{ {
"name": "Baseball Bat", "name": "Baseball Bat",
@ -42,7 +46,8 @@
"ammo": "none", "ammo": "none",
"dmg": 5, "dmg": 5,
"cost": 5, "cost": 5,
"weight": 1 "weight": 1,
"immutable": false
}, },
{ {
"name": "Power Fist", "name": "Power Fist",
@ -51,7 +56,8 @@
"ammo": "none", "ammo": "none",
"dmg": 15, "dmg": 15,
"cost": 10, "cost": 10,
"weight": 2 "weight": 2,
"immutable": false
}, },
{ {
"name": "Super Sledge", "name": "Super Sledge",
@ -60,7 +66,8 @@
"ammo": "none", "ammo": "none",
"dmg": 30, "dmg": 30,
"cost": 10, "cost": 10,
"weight": 15 "weight": 15,
"immutable": false
}, },
{ {
"name": "10mm Pistol", "name": "10mm Pistol",
@ -69,7 +76,8 @@
"ammo": "10", "ammo": "10",
"dmg": 10, "dmg": 10,
"cost": 10, "cost": 10,
"weight": 2 "weight": 2,
"immutable": false
}, },
{ {
"name": "Hunting Rifle", "name": "Hunting Rifle",
@ -78,6 +86,7 @@
"ammo": "308", "ammo": "308",
"dmg": 10, "dmg": 10,
"cost": 10, "cost": 10,
"weight": 2 "weight": 2,
"immutable": false
} }
] ]