mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Per-speces NPC names!
Is also able to refactor some of the uglier code and introduces a framework that (suitably extended) could be useful in removing boilerplate elsewhere.
This commit is contained in:
parent
2d9e60e566
commit
3fa21b3dc7
@ -91,6 +91,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Various performance improvements to world generation.
|
||||
- Nametags now a fixed size and shown in a limited range
|
||||
- Non-humanoid skeletons now utilize configs for hotloading, and skeletal attributes.
|
||||
- Names of NPCs spawned in the wild now include their species.
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -1,322 +1,475 @@
|
||||
{
|
||||
"humanoid": [
|
||||
"Adon",
|
||||
"Agro",
|
||||
"Arlo",
|
||||
"Azamarr",
|
||||
"Baashar",
|
||||
"Barak",
|
||||
"Barton",
|
||||
"Baske",
|
||||
"Baxar",
|
||||
"Blaiz",
|
||||
"Caelan",
|
||||
"Cassian",
|
||||
"Clawsen",
|
||||
"Colborn",
|
||||
"Dagfinn",
|
||||
"Dagrod",
|
||||
"Dimian",
|
||||
"Domnhar",
|
||||
"Ebraheim",
|
||||
"Eldermar",
|
||||
"Embre",
|
||||
"Esdel",
|
||||
"Eune",
|
||||
"Fangar",
|
||||
"Favroe",
|
||||
"Feron",
|
||||
"Feston",
|
||||
"Fintis",
|
||||
"Gatlen",
|
||||
"Gatlin",
|
||||
"Gentar",
|
||||
"Gethrod",
|
||||
"Graff",
|
||||
"Gunnar",
|
||||
"Hagalbar",
|
||||
"Hawke",
|
||||
"Hemm",
|
||||
"Henndar",
|
||||
"Hezra",
|
||||
"Hodus",
|
||||
"Ishmael",
|
||||
"Jakrin",
|
||||
"Jareth",
|
||||
"Jaris",
|
||||
"Jather",
|
||||
"Jerrick",
|
||||
"Jessop",
|
||||
"Jinto",
|
||||
"Joz",
|
||||
"Kadric",
|
||||
"Kagran",
|
||||
"Kent",
|
||||
"Khron",
|
||||
"Kontas",
|
||||
"Krinn",
|
||||
"Lassrin",
|
||||
"Lenox",
|
||||
"Lothe",
|
||||
"Lustros",
|
||||
"Lydan",
|
||||
"Mavrek",
|
||||
"Moki",
|
||||
"Monty",
|
||||
"Nazim",
|
||||
"Nesso",
|
||||
"Ophni",
|
||||
"Pakker",
|
||||
"Paquin",
|
||||
"Paskel",
|
||||
"Pike",
|
||||
"Ptorik",
|
||||
"Quintis",
|
||||
"Rankar",
|
||||
"Renham",
|
||||
"Revvyn",
|
||||
"Riordan",
|
||||
"Rivik",
|
||||
"Rourke",
|
||||
"Roux",
|
||||
"Ryven",
|
||||
"Sarkin",
|
||||
"Sturp",
|
||||
"Straus",
|
||||
"Syrin",
|
||||
"Talon",
|
||||
"Tekren",
|
||||
"Tez",
|
||||
"Turrek",
|
||||
"Tyvrik",
|
||||
"Vadim",
|
||||
"Vale",
|
||||
"Varog",
|
||||
"Verssek",
|
||||
"Weston",
|
||||
"Whit",
|
||||
"Wulfe",
|
||||
"Yorjan",
|
||||
"Zaden",
|
||||
"Zagaroth",
|
||||
"Zenner"
|
||||
],
|
||||
"wolf": [
|
||||
"Achak",
|
||||
"Adalwolf",
|
||||
"Akela",
|
||||
"Alaska",
|
||||
"Aleu",
|
||||
"Amarok",
|
||||
"Apisi",
|
||||
"Archer",
|
||||
"Ares",
|
||||
"Arrax",
|
||||
"Artic",
|
||||
"Aspen",
|
||||
"Aura",
|
||||
"Axel",
|
||||
"Balto",
|
||||
"Barwolf",
|
||||
"Basil",
|
||||
"Beja",
|
||||
"Beowulf",
|
||||
"Borris",
|
||||
"Brassa",
|
||||
"Bruno",
|
||||
"Chronos",
|
||||
"Colt",
|
||||
"Comet",
|
||||
"Cronus",
|
||||
"Czar",
|
||||
"Dakota",
|
||||
"Dash",
|
||||
"Diego",
|
||||
"Dire",
|
||||
"Duke",
|
||||
"Echo",
|
||||
"Elda",
|
||||
"Eskimo",
|
||||
"Essos",
|
||||
"Frey",
|
||||
"Gabu",
|
||||
"Ghost",
|
||||
"Giro",
|
||||
"Grey Wind",
|
||||
"Gunner",
|
||||
"Harou",
|
||||
"Havoc",
|
||||
"Hera",
|
||||
"Hunter",
|
||||
"Inuit",
|
||||
"Jacob",
|
||||
"Jenna",
|
||||
"Juno",
|
||||
"Kar",
|
||||
"Khal",
|
||||
"Kiba",
|
||||
"Kimbra",
|
||||
"Kodi",
|
||||
"Lady",
|
||||
"Lakota",
|
||||
"Larka",
|
||||
"Leah",
|
||||
"Leto",
|
||||
"Lobo",
|
||||
"Loki",
|
||||
"Lotus",
|
||||
"Louve",
|
||||
"Lupa",
|
||||
"Major",
|
||||
"Mathias",
|
||||
"Moro",
|
||||
"Murdock",
|
||||
"Nomad",
|
||||
"Okami",
|
||||
"Orbit",
|
||||
"Palla",
|
||||
"Pyro",
|
||||
"Radolf",
|
||||
"Raven",
|
||||
"Rhea",
|
||||
"Rider",
|
||||
"Rollo",
|
||||
"Rune",
|
||||
"Sable",
|
||||
"Saga",
|
||||
"Sarge",
|
||||
"Shiro",
|
||||
"Siku",
|
||||
"Sky",
|
||||
"Stark",
|
||||
"Storm",
|
||||
"Suki",
|
||||
"Tala",
|
||||
"Thor",
|
||||
"Tiva",
|
||||
"Tyr",
|
||||
"Ubba",
|
||||
"Ulva",
|
||||
"Valor",
|
||||
"Vechro",
|
||||
"Wolf",
|
||||
"Wolfgang",
|
||||
"Yara",
|
||||
"Zeus",
|
||||
"Ziva",
|
||||
"Zylo"
|
||||
],
|
||||
"pig": [
|
||||
"Acorn",
|
||||
"Adeline",
|
||||
"Ajna",
|
||||
"Athena",
|
||||
"Avacado",
|
||||
"Babe",
|
||||
"Bella",
|
||||
"Buddy",
|
||||
"Buttons",
|
||||
"Charlie",
|
||||
"Charlotte",
|
||||
"Chubbs",
|
||||
"Cinnamon",
|
||||
"Clarence",
|
||||
"Clover",
|
||||
"Cookie",
|
||||
"Corky",
|
||||
"Cupcake",
|
||||
"Daisy",
|
||||
"Dani",
|
||||
"Delilah",
|
||||
"Dexter",
|
||||
"Dolly",
|
||||
"Dottie",
|
||||
"Dudley",
|
||||
"Ellie",
|
||||
"Erwin",
|
||||
"Evie",
|
||||
"Gertrude",
|
||||
"Gilly",
|
||||
"Ginger",
|
||||
"Gizmo",
|
||||
"Gwenivere",
|
||||
"Hogrid",
|
||||
"Hazel",
|
||||
"Hector",
|
||||
"Herman",
|
||||
"Hermione",
|
||||
"Hoover",
|
||||
"Huck",
|
||||
"Iggy",
|
||||
"Jake",
|
||||
"Josie",
|
||||
"Leonardo",
|
||||
"Lily",
|
||||
"Lola",
|
||||
"Lottie",
|
||||
"Lucy",
|
||||
"Lulu",
|
||||
"Mabel",
|
||||
"Madeline",
|
||||
"Maisie",
|
||||
"Millie",
|
||||
"Mimzy",
|
||||
"Nooch",
|
||||
"Nutmeg",
|
||||
"Oinkers",
|
||||
"Okja",
|
||||
"Oliver",
|
||||
"Olivia",
|
||||
"Panda",
|
||||
"Pasley",
|
||||
"Peanut",
|
||||
"Penelope",
|
||||
"Peppa",
|
||||
"Petunia",
|
||||
"Phoebe",
|
||||
"Piggie Smalls",
|
||||
"Piggles",
|
||||
"Piglet",
|
||||
"Pinto Bean",
|
||||
"Piper",
|
||||
"Poly",
|
||||
"Popcorn",
|
||||
"Poppy",
|
||||
"Punky",
|
||||
"Rey",
|
||||
"Rooter",
|
||||
"Rosie",
|
||||
"Ruby",
|
||||
"Sadie",
|
||||
"Scouter",
|
||||
"Skittles",
|
||||
"Snowball",
|
||||
"Snuffles",
|
||||
"Sonny",
|
||||
"Sprout",
|
||||
"Squiggles",
|
||||
"Sweetie Pie",
|
||||
"Theo",
|
||||
"Toffuti",
|
||||
"Trixie",
|
||||
"Violet",
|
||||
"Vishnu",
|
||||
"Wee Wee",
|
||||
"Wilbur",
|
||||
"Willow",
|
||||
"Winnie",
|
||||
"Wrinkles",
|
||||
"Ziggy",
|
||||
"Zoe",
|
||||
"Zoinks"
|
||||
],
|
||||
"duck": [
|
||||
"ducky"
|
||||
],
|
||||
"giant": [
|
||||
"leroybrown"
|
||||
],
|
||||
"rat": [
|
||||
"rat"
|
||||
]
|
||||
}
|
||||
"humanoid": {
|
||||
"body": {
|
||||
"keyword": "humanoid",
|
||||
"names": [
|
||||
"Adon",
|
||||
"Agro",
|
||||
"Arlo",
|
||||
"Azamarr",
|
||||
"Baashar",
|
||||
"Barak",
|
||||
"Barton",
|
||||
"Baske",
|
||||
"Baxar",
|
||||
"Blaiz",
|
||||
"Caelan",
|
||||
"Cassian",
|
||||
"Clawsen",
|
||||
"Colborn",
|
||||
"Dagfinn",
|
||||
"Dagrod",
|
||||
"Dimian",
|
||||
"Domnhar",
|
||||
"Ebraheim",
|
||||
"Eldermar",
|
||||
"Embre",
|
||||
"Esdel",
|
||||
"Eune",
|
||||
"Fangar",
|
||||
"Favroe",
|
||||
"Feron",
|
||||
"Feston",
|
||||
"Fintis",
|
||||
"Gatlen",
|
||||
"Gatlin",
|
||||
"Gentar",
|
||||
"Gethrod",
|
||||
"Graff",
|
||||
"Gunnar",
|
||||
"Hagalbar",
|
||||
"Hawke",
|
||||
"Hemm",
|
||||
"Henndar",
|
||||
"Hezra",
|
||||
"Hodus",
|
||||
"Ishmael",
|
||||
"Jakrin",
|
||||
"Jareth",
|
||||
"Jaris",
|
||||
"Jather",
|
||||
"Jerrick",
|
||||
"Jessop",
|
||||
"Jinto",
|
||||
"Joz",
|
||||
"Kadric",
|
||||
"Kagran",
|
||||
"Kent",
|
||||
"Khron",
|
||||
"Kontas",
|
||||
"Krinn",
|
||||
"Lassrin",
|
||||
"Lenox",
|
||||
"Lothe",
|
||||
"Lustros",
|
||||
"Lydan",
|
||||
"Mavrek",
|
||||
"Moki",
|
||||
"Monty",
|
||||
"Nazim",
|
||||
"Nesso",
|
||||
"Ophni",
|
||||
"Pakker",
|
||||
"Paquin",
|
||||
"Paskel",
|
||||
"Pike",
|
||||
"Ptorik",
|
||||
"Quintis",
|
||||
"Rankar",
|
||||
"Renham",
|
||||
"Revvyn",
|
||||
"Riordan",
|
||||
"Rivik",
|
||||
"Rourke",
|
||||
"Roux",
|
||||
"Ryven",
|
||||
"Sarkin",
|
||||
"Sturp",
|
||||
"Straus",
|
||||
"Syrin",
|
||||
"Talon",
|
||||
"Tekren",
|
||||
"Tez",
|
||||
"Turrek",
|
||||
"Tyvrik",
|
||||
"Vadim",
|
||||
"Vale",
|
||||
"Varog",
|
||||
"Verssek",
|
||||
"Weston",
|
||||
"Whit",
|
||||
"Wulfe",
|
||||
"Yorjan",
|
||||
"Zaden",
|
||||
"Zagaroth",
|
||||
"Zenner"
|
||||
]
|
||||
},
|
||||
"species": {
|
||||
"danari": {
|
||||
"generic": "Danari"
|
||||
},
|
||||
"dwarf": {
|
||||
"generic": "Dwarf"
|
||||
},
|
||||
"elf": {
|
||||
"generic": "Elf"
|
||||
},
|
||||
"human": {
|
||||
"generic": "Human"
|
||||
},
|
||||
"orc": {
|
||||
"generic": "Orc"
|
||||
},
|
||||
"undead": {
|
||||
"generic": "Undead"
|
||||
}
|
||||
}
|
||||
},
|
||||
"quadruped_medium": {
|
||||
"body": {
|
||||
"keyword": "wolf",
|
||||
"names": [
|
||||
"Achak",
|
||||
"Adalwolf",
|
||||
"Akela",
|
||||
"Alaska",
|
||||
"Aleu",
|
||||
"Amarok",
|
||||
"Apisi",
|
||||
"Archer",
|
||||
"Ares",
|
||||
"Arrax",
|
||||
"Artic",
|
||||
"Aspen",
|
||||
"Aura",
|
||||
"Axel",
|
||||
"Balto",
|
||||
"Barwolf",
|
||||
"Basil",
|
||||
"Beja",
|
||||
"Beowulf",
|
||||
"Borris",
|
||||
"Brassa",
|
||||
"Bruno",
|
||||
"Chronos",
|
||||
"Colt",
|
||||
"Comet",
|
||||
"Cronus",
|
||||
"Czar",
|
||||
"Dakota",
|
||||
"Dash",
|
||||
"Diego",
|
||||
"Dire",
|
||||
"Duke",
|
||||
"Echo",
|
||||
"Elda",
|
||||
"Eskimo",
|
||||
"Essos",
|
||||
"Frey",
|
||||
"Gabu",
|
||||
"Ghost",
|
||||
"Giro",
|
||||
"Grey Wind",
|
||||
"Gunner",
|
||||
"Harou",
|
||||
"Havoc",
|
||||
"Hera",
|
||||
"Hunter",
|
||||
"Inuit",
|
||||
"Jacob",
|
||||
"Jenna",
|
||||
"Juno",
|
||||
"Kar",
|
||||
"Khal",
|
||||
"Kiba",
|
||||
"Kimbra",
|
||||
"Kodi",
|
||||
"Lady",
|
||||
"Lakota",
|
||||
"Larka",
|
||||
"Leah",
|
||||
"Leto",
|
||||
"Lobo",
|
||||
"Loki",
|
||||
"Lotus",
|
||||
"Louve",
|
||||
"Lupa",
|
||||
"Major",
|
||||
"Mathias",
|
||||
"Moro",
|
||||
"Murdock",
|
||||
"Nomad",
|
||||
"Okami",
|
||||
"Orbit",
|
||||
"Palla",
|
||||
"Pyro",
|
||||
"Radolf",
|
||||
"Raven",
|
||||
"Rhea",
|
||||
"Rider",
|
||||
"Rollo",
|
||||
"Rune",
|
||||
"Sable",
|
||||
"Saga",
|
||||
"Sarge",
|
||||
"Shiro",
|
||||
"Siku",
|
||||
"Sky",
|
||||
"Stark",
|
||||
"Storm",
|
||||
"Suki",
|
||||
"Tala",
|
||||
"Thor",
|
||||
"Tiva",
|
||||
"Tyr",
|
||||
"Ubba",
|
||||
"Ulva",
|
||||
"Valor",
|
||||
"Vechro",
|
||||
"Wolf",
|
||||
"Wolfgang",
|
||||
"Yara",
|
||||
"Zeus",
|
||||
"Ziva",
|
||||
"Zylo"
|
||||
]
|
||||
},
|
||||
"species": {
|
||||
"wolf": {
|
||||
"generic": "Wolf"
|
||||
},
|
||||
"saber": {
|
||||
"generic": "Sabertooth Tiger"
|
||||
},
|
||||
"viper": {
|
||||
"generic": "Lizard"
|
||||
},
|
||||
"tuskram": {
|
||||
"generic": "Tusk Ram"
|
||||
},
|
||||
"alligator": {
|
||||
"generic": "Alligator"
|
||||
},
|
||||
"monitor": {
|
||||
"generic": "Monitor Lizard"
|
||||
},
|
||||
"lion": {
|
||||
"generic": "Lion"
|
||||
},
|
||||
"tarasque": {
|
||||
"generic": "Tarasque"
|
||||
}
|
||||
}
|
||||
},
|
||||
"quadruped_small": {
|
||||
"body": {
|
||||
"keyword": "pig",
|
||||
"names": [
|
||||
"Acorn",
|
||||
"Adeline",
|
||||
"Ajna",
|
||||
"Athena",
|
||||
"Avacado",
|
||||
"Babe",
|
||||
"Bella",
|
||||
"Buddy",
|
||||
"Buttons",
|
||||
"Charlie",
|
||||
"Charlotte",
|
||||
"Chubbs",
|
||||
"Cinnamon",
|
||||
"Clarence",
|
||||
"Clover",
|
||||
"Cookie",
|
||||
"Corky",
|
||||
"Cupcake",
|
||||
"Daisy",
|
||||
"Dani",
|
||||
"Delilah",
|
||||
"Dexter",
|
||||
"Dolly",
|
||||
"Dottie",
|
||||
"Dudley",
|
||||
"Ellie",
|
||||
"Erwin",
|
||||
"Evie",
|
||||
"Gertrude",
|
||||
"Gilly",
|
||||
"Ginger",
|
||||
"Gizmo",
|
||||
"Gwenivere",
|
||||
"Hogrid",
|
||||
"Hazel",
|
||||
"Hector",
|
||||
"Herman",
|
||||
"Hermione",
|
||||
"Hoover",
|
||||
"Huck",
|
||||
"Iggy",
|
||||
"Jake",
|
||||
"Josie",
|
||||
"Leonardo",
|
||||
"Lily",
|
||||
"Lola",
|
||||
"Lottie",
|
||||
"Lucy",
|
||||
"Lulu",
|
||||
"Mabel",
|
||||
"Madeline",
|
||||
"Maisie",
|
||||
"Millie",
|
||||
"Mimzy",
|
||||
"Nooch",
|
||||
"Nutmeg",
|
||||
"Oinkers",
|
||||
"Okja",
|
||||
"Oliver",
|
||||
"Olivia",
|
||||
"Panda",
|
||||
"Pasley",
|
||||
"Peanut",
|
||||
"Penelope",
|
||||
"Peppa",
|
||||
"Petunia",
|
||||
"Phoebe",
|
||||
"Piggie Smalls",
|
||||
"Piggles",
|
||||
"Piglet",
|
||||
"Pinto Bean",
|
||||
"Piper",
|
||||
"Poly",
|
||||
"Popcorn",
|
||||
"Poppy",
|
||||
"Punky",
|
||||
"Rey",
|
||||
"Rooter",
|
||||
"Rosie",
|
||||
"Ruby",
|
||||
"Sadie",
|
||||
"Scouter",
|
||||
"Skittles",
|
||||
"Snowball",
|
||||
"Snuffles",
|
||||
"Sonny",
|
||||
"Sprout",
|
||||
"Squiggles",
|
||||
"Sweetie Pie",
|
||||
"Theo",
|
||||
"Toffuti",
|
||||
"Trixie",
|
||||
"Violet",
|
||||
"Vishnu",
|
||||
"Wee Wee",
|
||||
"Wilbur",
|
||||
"Willow",
|
||||
"Winnie",
|
||||
"Wrinkles",
|
||||
"Ziggy",
|
||||
"Zoe",
|
||||
"Zoinks"
|
||||
]
|
||||
},
|
||||
"species": {
|
||||
"pig": {
|
||||
"generic": "Pig"
|
||||
},
|
||||
"fox": {
|
||||
"generic": "Fox"
|
||||
},
|
||||
"sheep": {
|
||||
"generic": "Sheep"
|
||||
},
|
||||
"boar": {
|
||||
"generic": "Boar"
|
||||
},
|
||||
"jackalope": {
|
||||
"generic": "Jackalope"
|
||||
},
|
||||
"skunk": {
|
||||
"generic": "Skunk"
|
||||
},
|
||||
"cat": {
|
||||
"generic": "Cat"
|
||||
},
|
||||
"batfox": {
|
||||
"generic": "Bat Fox"
|
||||
},
|
||||
"raccoon": {
|
||||
"generic": "Raccoon"
|
||||
},
|
||||
"quokka": {
|
||||
"generic": "Quokka"
|
||||
},
|
||||
"dodarock": {
|
||||
"generic": "Dodarock"
|
||||
},
|
||||
"holladon": {
|
||||
"generic": "Holladon"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bird_medium": {
|
||||
"body": {
|
||||
"keyword": "duck",
|
||||
"names": [
|
||||
"Donald"
|
||||
]
|
||||
},
|
||||
"species": {
|
||||
"duck": {
|
||||
"generic": "Duck"
|
||||
},
|
||||
"chicken": {
|
||||
"generic": "Chicken"
|
||||
},
|
||||
"goose": {
|
||||
"generic": "Goose"
|
||||
},
|
||||
"peacock": {
|
||||
"generic": "Peacock"
|
||||
}
|
||||
}
|
||||
},
|
||||
"biped_large": {
|
||||
"body": {
|
||||
"keyword": "giant",
|
||||
"names": [
|
||||
"Leroy Brown"
|
||||
]
|
||||
},
|
||||
"species": {
|
||||
"giant": {
|
||||
"generic": "Giant"
|
||||
}
|
||||
}
|
||||
},
|
||||
"critter": {
|
||||
"body": {
|
||||
"keyword": "rat",
|
||||
"names": [
|
||||
"Remy"
|
||||
]
|
||||
},
|
||||
"species": {
|
||||
"rat": {
|
||||
"generic": "Rat"
|
||||
},
|
||||
"axolotl": {
|
||||
"generic": "Axolotl"
|
||||
},
|
||||
"gecko": {
|
||||
"generic": "Gecko"
|
||||
},
|
||||
"turtle": {
|
||||
"generic": "Turtle"
|
||||
},
|
||||
"squirrel": {
|
||||
"generic": "Squirrel"
|
||||
},
|
||||
"fungome": {
|
||||
"generic": "Fungome"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use log::error;
|
||||
use serde_json::Value;
|
||||
use std::{
|
||||
any::Any,
|
||||
fmt,
|
||||
fs::{self, File, ReadDir},
|
||||
io::{BufReader, Read},
|
||||
path::PathBuf,
|
||||
@ -18,12 +19,27 @@ use std::{
|
||||
/// The error returned by asset loading functions
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Error {
|
||||
/// An internal error occurred.
|
||||
Internal(Arc<dyn std::error::Error>),
|
||||
/// An asset of a different type has already been loaded with this specifier.
|
||||
InvalidType,
|
||||
/// Asset does not exist.
|
||||
NotFound(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::Internal(err) => err.fmt(f),
|
||||
Error::InvalidType => write!(
|
||||
f,
|
||||
"an asset of a different type has already been loaded with this specifier."
|
||||
),
|
||||
Error::NotFound(s) => write!(f, "{}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<dyn Any + 'static + Sync + Send>> for Error {
|
||||
fn from(_: Arc<dyn Any + 'static + Sync + Send>) -> Self {
|
||||
Error::InvalidType
|
||||
@ -32,7 +48,7 @@ impl From<Arc<dyn Any + 'static + Sync + Send>> for Error {
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Error::NotFound(format!("{:?}", err))
|
||||
Error::NotFound(format!("{}", err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +151,12 @@ pub fn load_cloned<A: Asset + Clone + 'static>(specifier: &str) -> Result<A, Err
|
||||
/// let my_image = assets::load_expect::<DynamicImage>("core.ui.backgrounds.city");
|
||||
/// ```
|
||||
pub fn load_expect<A: Asset + 'static>(specifier: &str) -> Arc<A> {
|
||||
load(specifier).unwrap_or_else(|_| panic!("Failed loading essential asset: {}", specifier))
|
||||
load(specifier).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Failed loading essential asset: {} (error={})",
|
||||
specifier, err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Function used to load essential assets from the filesystem or the cache and return a clone. It will panic if the asset is not found.
|
||||
|
@ -10,8 +10,13 @@ pub mod object;
|
||||
pub mod quadruped_medium;
|
||||
pub mod quadruped_small;
|
||||
|
||||
use crate::{
|
||||
assets::{self, Asset},
|
||||
npc::NpcKind,
|
||||
};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
use std::{fs::File, io::BufReader, sync::Arc};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
@ -29,6 +34,58 @@ pub enum Body {
|
||||
Critter(critter::Body) = 10,
|
||||
}
|
||||
|
||||
/// Data representing data generic to the body together with per-species data.
|
||||
///
|
||||
/// NOTE: Deliberately don't (yet?) implement serialize.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct BodyData<BodyMeta, SpeciesData> {
|
||||
/// Shared metadata for this whole body type.
|
||||
pub body: BodyMeta,
|
||||
/// All the metadata for species with this body type.
|
||||
pub species: SpeciesData,
|
||||
}
|
||||
|
||||
/// Metadata intended to be stored per-body, together with data intended to be stored for each
|
||||
/// species for each body.
|
||||
///
|
||||
/// NOTE: Deliberately don't (yet?) implement serialize.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct AllBodies<BodyMeta, SpeciesMeta> {
|
||||
pub humanoid: BodyData<BodyMeta, humanoid::AllSpecies<SpeciesMeta>>,
|
||||
pub quadruped_small: BodyData<BodyMeta, quadruped_small::AllSpecies<SpeciesMeta>>,
|
||||
pub quadruped_medium: BodyData<BodyMeta, quadruped_medium::AllSpecies<SpeciesMeta>>,
|
||||
pub bird_medium: BodyData<BodyMeta, bird_medium::AllSpecies<SpeciesMeta>>,
|
||||
pub biped_large: BodyData<BodyMeta, biped_large::AllSpecies<SpeciesMeta>>,
|
||||
pub critter: BodyData<BodyMeta, critter::AllSpecies<SpeciesMeta>>,
|
||||
}
|
||||
|
||||
/// Can only retrieve body metadata by direct index.
|
||||
impl<BodyMeta, SpeciesMeta> core::ops::Index<NpcKind> for AllBodies<BodyMeta, SpeciesMeta> {
|
||||
type Output = BodyMeta;
|
||||
|
||||
fn index(&self, index: NpcKind) -> &Self::Output {
|
||||
match index {
|
||||
NpcKind::Humanoid => &self.humanoid.body,
|
||||
NpcKind::Pig => &self.quadruped_small.body,
|
||||
NpcKind::Wolf => &self.quadruped_medium.body,
|
||||
NpcKind::Duck => &self.bird_medium.body,
|
||||
NpcKind::Giant => &self.biped_large.body,
|
||||
NpcKind::Rat => &self.critter.body,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
BodyMeta: Send + Sync + for<'de> serde::Deserialize<'de>,
|
||||
SpeciesMeta: Send + Sync + for<'de> serde::Deserialize<'de>,
|
||||
> Asset for AllBodies<BodyMeta, SpeciesMeta>
|
||||
{
|
||||
const ENDINGS: &'static [&'static str] = &["json"];
|
||||
fn parse(buf_reader: BufReader<File>) -> Result<Self, assets::Error> {
|
||||
serde_json::de::from_reader(buf_reader).map_err(|e| assets::Error::Internal(Arc::new(e)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Body {
|
||||
pub fn is_humanoid(&self) -> bool {
|
||||
match self {
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub species: Species,
|
||||
pub body_type: BodyType,
|
||||
@ -21,6 +20,25 @@ impl Body {
|
||||
pub enum Species {
|
||||
Giant = 0,
|
||||
}
|
||||
|
||||
/// Data representing per-species generic data.
|
||||
///
|
||||
/// NOTE: Deliberately don't (yet?) implement serialize.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct AllSpecies<SpeciesMeta> {
|
||||
pub giant: SpeciesMeta,
|
||||
}
|
||||
|
||||
impl<SpeciesMeta> core::ops::Index<Species> for AllSpecies<SpeciesMeta> {
|
||||
type Output = SpeciesMeta;
|
||||
|
||||
fn index(&self, index: Species) -> &Self::Output {
|
||||
match index {
|
||||
Species::Giant => &self.giant,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALL_SPECIES: [Species; 1] = [Species::Giant];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub species: Species,
|
||||
pub body_type: BodyType,
|
||||
@ -24,6 +23,31 @@ pub enum Species {
|
||||
Goose = 2,
|
||||
Peacock = 3,
|
||||
}
|
||||
|
||||
/// Data representing per-species generic data.
|
||||
///
|
||||
/// NOTE: Deliberately don't (yet?) implement serialize.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct AllSpecies<SpeciesMeta> {
|
||||
pub duck: SpeciesMeta,
|
||||
pub chicken: SpeciesMeta,
|
||||
pub goose: SpeciesMeta,
|
||||
pub peacock: SpeciesMeta,
|
||||
}
|
||||
|
||||
impl<SpeciesMeta> core::ops::Index<Species> for AllSpecies<SpeciesMeta> {
|
||||
type Output = SpeciesMeta;
|
||||
|
||||
fn index(&self, index: Species) -> &Self::Output {
|
||||
match index {
|
||||
Species::Duck => &self.duck,
|
||||
Species::Chicken => &self.chicken,
|
||||
Species::Goose => &self.goose,
|
||||
Species::Peacock => &self.peacock,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALL_SPECIES: [Species; 4] = [
|
||||
Species::Duck,
|
||||
Species::Chicken,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub head: Head,
|
||||
pub torso: Torso,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub species: Species,
|
||||
pub body_type: BodyType,
|
||||
@ -26,6 +25,33 @@ pub enum Species {
|
||||
Squirrel = 4,
|
||||
Fungome = 5,
|
||||
}
|
||||
|
||||
/// Data representing per-species generic data.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct AllSpecies<SpeciesMeta> {
|
||||
pub rat: SpeciesMeta,
|
||||
pub axolotl: SpeciesMeta,
|
||||
pub gecko: SpeciesMeta,
|
||||
pub turtle: SpeciesMeta,
|
||||
pub squirrel: SpeciesMeta,
|
||||
pub fungome: SpeciesMeta,
|
||||
}
|
||||
|
||||
impl<SpeciesMeta> core::ops::Index<Species> for AllSpecies<SpeciesMeta> {
|
||||
type Output = SpeciesMeta;
|
||||
|
||||
fn index(&self, index: Species) -> &Self::Output {
|
||||
match index {
|
||||
Species::Rat => &self.rat,
|
||||
Species::Axolotl => &self.axolotl,
|
||||
Species::Gecko => &self.gecko,
|
||||
Species::Turtle => &self.turtle,
|
||||
Species::Squirrel => &self.squirrel,
|
||||
Species::Fungome => &self.fungome,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALL_SPECIES: [Species; 6] = [
|
||||
Species::Rat,
|
||||
Species::Axolotl,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub head: Head,
|
||||
pub chest_front: ChestFront,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub head: Head,
|
||||
pub torso: Torso,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub torso: Torso,
|
||||
pub tail: Tail,
|
||||
|
@ -1,77 +0,0 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub head: Head,
|
||||
pub shoulder: Shoulder,
|
||||
pub chest: Chest,
|
||||
pub hand: Hand,
|
||||
pub belt: Belt,
|
||||
pub pants: Pants,
|
||||
pub foot: Foot,
|
||||
}
|
||||
|
||||
impl Body {
|
||||
pub fn random() -> Self {
|
||||
let mut rng = thread_rng();
|
||||
Self {
|
||||
head: *(&ALL_HEADS).choose(&mut rng).unwrap(),
|
||||
shoulder: *(&ALL_SHOULDERS).choose(&mut rng).unwrap(),
|
||||
chest: *(&ALL_CHESTS).choose(&mut rng).unwrap(),
|
||||
hand: *(&ALL_HANDS).choose(&mut rng).unwrap(),
|
||||
belt: *(&ALL_BELTS).choose(&mut rng).unwrap(),
|
||||
pants: *(&ALL_PANTS).choose(&mut rng).unwrap(),
|
||||
foot: *(&ALL_FEET).choose(&mut rng).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Head {
|
||||
Default,
|
||||
}
|
||||
const ALL_HEADS: [Head; 1] = [Head::Default];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Shoulder {
|
||||
Default,
|
||||
}
|
||||
const ALL_SHOULDERS: [Shoulder; 1] = [Shoulder::Default];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Chest {
|
||||
Default,
|
||||
}
|
||||
const ALL_CHESTS: [Chest; 1] = [Chest::Default];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Hand {
|
||||
Default,
|
||||
}
|
||||
const ALL_HANDS: [Hand; 1] = [Hand::Default];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Belt {
|
||||
Default,
|
||||
}
|
||||
const ALL_BELTS: [Belt; 1] = [Belt::Default];
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Pants {
|
||||
Default,
|
||||
}
|
||||
const ALL_FEET: [Foot; 1] = [Foot::Default];
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Foot {
|
||||
Default,
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,7 +2,6 @@ use rand::{seq::SliceRandom, thread_rng, Rng};
|
||||
use vek::Rgb;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub race: Race,
|
||||
pub body_type: BodyType,
|
||||
@ -69,6 +68,35 @@ pub enum Race {
|
||||
Orc = 4,
|
||||
Undead = 5,
|
||||
}
|
||||
|
||||
/// Data representing per-species generic data.
|
||||
///
|
||||
/// NOTE: Deliberately don't (yet?) implement serialize.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct AllSpecies<SpeciesMeta> {
|
||||
pub danari: SpeciesMeta,
|
||||
pub dwarf: SpeciesMeta,
|
||||
pub elf: SpeciesMeta,
|
||||
pub human: SpeciesMeta,
|
||||
pub orc: SpeciesMeta,
|
||||
pub undead: SpeciesMeta,
|
||||
}
|
||||
|
||||
impl<SpeciesMeta> core::ops::Index<Race> for AllSpecies<SpeciesMeta> {
|
||||
type Output = SpeciesMeta;
|
||||
|
||||
fn index(&self, index: Race) -> &Self::Output {
|
||||
match index {
|
||||
Race::Danari => &self.danari,
|
||||
Race::Dwarf => &self.dwarf,
|
||||
Race::Elf => &self.elf,
|
||||
Race::Human => &self.human,
|
||||
Race::Orc => &self.orc,
|
||||
Race::Undead => &self.undead,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALL_RACES: [Race; 6] = [
|
||||
Race::Danari,
|
||||
Race::Dwarf,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub species: Species,
|
||||
pub body_type: BodyType,
|
||||
@ -28,6 +27,39 @@ pub enum Species {
|
||||
Lion = 6,
|
||||
Tarasque = 7,
|
||||
}
|
||||
|
||||
/// Data representing per-species generic data.
|
||||
///
|
||||
/// NOTE: Deliberately don't (yet?) implement serialize.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct AllSpecies<SpeciesMeta> {
|
||||
pub wolf: SpeciesMeta,
|
||||
pub saber: SpeciesMeta,
|
||||
pub viper: SpeciesMeta,
|
||||
pub tuskram: SpeciesMeta,
|
||||
pub alligator: SpeciesMeta,
|
||||
pub monitor: SpeciesMeta,
|
||||
pub lion: SpeciesMeta,
|
||||
pub tarasque: SpeciesMeta,
|
||||
}
|
||||
|
||||
impl<SpeciesMeta> core::ops::Index<Species> for AllSpecies<SpeciesMeta> {
|
||||
type Output = SpeciesMeta;
|
||||
|
||||
fn index(&self, index: Species) -> &Self::Output {
|
||||
match index {
|
||||
Species::Wolf => &self.wolf,
|
||||
Species::Saber => &self.saber,
|
||||
Species::Viper => &self.viper,
|
||||
Species::Tuskram => &self.tuskram,
|
||||
Species::Alligator => &self.alligator,
|
||||
Species::Monitor => &self.monitor,
|
||||
Species::Lion => &self.lion,
|
||||
Species::Tarasque => &self.tarasque,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALL_SPECIES: [Species; 8] = [
|
||||
Species::Wolf,
|
||||
Species::Saber,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct Body {
|
||||
pub species: Species,
|
||||
pub body_type: BodyType,
|
||||
@ -32,6 +31,47 @@ pub enum Species {
|
||||
Dodarock = 10,
|
||||
Holladon = 11,
|
||||
}
|
||||
|
||||
/// Data representing per-species generic data.
|
||||
///
|
||||
/// NOTE: Deliberately don't (yet?) implement serialize.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct AllSpecies<SpeciesMeta> {
|
||||
pub pig: SpeciesMeta,
|
||||
pub fox: SpeciesMeta,
|
||||
pub sheep: SpeciesMeta,
|
||||
pub boar: SpeciesMeta,
|
||||
pub jackalope: SpeciesMeta,
|
||||
pub skunk: SpeciesMeta,
|
||||
pub cat: SpeciesMeta,
|
||||
pub batfox: SpeciesMeta,
|
||||
pub raccoon: SpeciesMeta,
|
||||
pub quokka: SpeciesMeta,
|
||||
pub dodarock: SpeciesMeta,
|
||||
pub holladon: SpeciesMeta,
|
||||
}
|
||||
|
||||
impl<SpeciesMeta> core::ops::Index<Species> for AllSpecies<SpeciesMeta> {
|
||||
type Output = SpeciesMeta;
|
||||
|
||||
fn index(&self, index: Species) -> &Self::Output {
|
||||
match index {
|
||||
Species::Pig => &self.pig,
|
||||
Species::Fox => &self.fox,
|
||||
Species::Sheep => &self.sheep,
|
||||
Species::Boar => &self.boar,
|
||||
Species::Jackalope => &self.jackalope,
|
||||
Species::Skunk => &self.skunk,
|
||||
Species::Cat => &self.cat,
|
||||
Species::Batfox => &self.batfox,
|
||||
Species::Raccoon => &self.raccoon,
|
||||
Species::Quokka => &self.quokka,
|
||||
Species::Dodarock => &self.dodarock,
|
||||
Species::Holladon => &self.holladon,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALL_SPECIES: [Species; 12] = [
|
||||
Species::Pig,
|
||||
Species::Fox,
|
||||
|
@ -19,7 +19,7 @@ pub use admin::Admin;
|
||||
pub use agent::{Agent, Alignment};
|
||||
pub use body::{
|
||||
biped_large, bird_medium, bird_small, critter, dragon, fish_medium, fish_small, humanoid,
|
||||
object, quadruped_medium, quadruped_small, Body,
|
||||
object, quadruped_medium, quadruped_small, AllBodies, Body, BodyData,
|
||||
};
|
||||
pub use character_state::{ActionState, CharacterState, MovementState};
|
||||
pub use controller::{
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::assets;
|
||||
use crate::{assets, comp::AllBodies};
|
||||
use lazy_static::lazy_static;
|
||||
use rand::seq::SliceRandom;
|
||||
use serde_json;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -15,50 +14,61 @@ pub enum NpcKind {
|
||||
Rat,
|
||||
}
|
||||
|
||||
impl NpcKind {
|
||||
fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
NpcKind::Humanoid => "humanoid",
|
||||
NpcKind::Wolf => "wolf",
|
||||
NpcKind::Pig => "pig",
|
||||
NpcKind::Duck => "duck",
|
||||
NpcKind::Giant => "giant",
|
||||
NpcKind::Rat => "rat",
|
||||
}
|
||||
}
|
||||
pub const ALL_NPCS: [NpcKind; 6] = [
|
||||
NpcKind::Humanoid,
|
||||
NpcKind::Wolf,
|
||||
NpcKind::Pig,
|
||||
NpcKind::Duck,
|
||||
NpcKind::Giant,
|
||||
NpcKind::Rat,
|
||||
];
|
||||
|
||||
/// Body-specific NPC name metadata.
|
||||
///
|
||||
/// NOTE: Deliberately don't (yet?) implement serialize.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct BodyNames {
|
||||
/// The keyword used to refer to this body type (e.g. via the command console). Should be
|
||||
/// unique per body type.
|
||||
pub keyword: String,
|
||||
/// A list of canonical names for NPCs with this body types (currently used when spawning this
|
||||
/// kind of NPC from the console). Going forward, these names will likely be split up by
|
||||
/// species.
|
||||
pub names: Vec<String>,
|
||||
}
|
||||
|
||||
/// Species-specific NPC name metadata.
|
||||
///
|
||||
/// NOTE: Deliberately don't (yet?) implement serialize.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct SpeciesNames {
|
||||
/// The generic name for NPCs of this species.
|
||||
pub generic: String,
|
||||
}
|
||||
|
||||
/// Type holding configuration data for NPC names.
|
||||
pub type NpcNames = AllBodies<BodyNames, SpeciesNames>;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref NPC_NAMES: Arc<NpcNames> = assets::load_expect("common.npc_names");
|
||||
}
|
||||
|
||||
impl FromStr for NpcKind {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, ()> {
|
||||
match s {
|
||||
"humanoid" => Ok(NpcKind::Humanoid),
|
||||
"wolf" => Ok(NpcKind::Wolf),
|
||||
"pig" => Ok(NpcKind::Pig),
|
||||
"duck" => Ok(NpcKind::Duck),
|
||||
"giant" => Ok(NpcKind::Giant),
|
||||
"rat" => Ok(NpcKind::Rat),
|
||||
|
||||
_ => Err(()),
|
||||
}
|
||||
let npc_names_json = &*NPC_NAMES;
|
||||
ALL_NPCS
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|&npc| npc_names_json[npc].keyword == s)
|
||||
.ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref NPC_NAMES_JSON: Arc<serde_json::Value> = assets::load_expect("common.npc_names");
|
||||
}
|
||||
pub fn get_npc_name(npc_type: NpcKind) -> &'static str {
|
||||
let BodyNames { keyword, names } = &NPC_NAMES[npc_type];
|
||||
|
||||
pub fn get_npc_name(npc_type: NpcKind) -> String {
|
||||
let npc_names = NPC_NAMES_JSON
|
||||
.get(npc_type.as_str())
|
||||
.expect("accessing json using NPC type provided as key")
|
||||
.as_array()
|
||||
.expect("parsing accessed json value into an array");
|
||||
let npc_name = npc_names
|
||||
.choose(&mut rand::thread_rng())
|
||||
.expect("getting a random NPC name")
|
||||
.as_str()
|
||||
.expect("parsing NPC name json value into a &str");
|
||||
String::from(npc_name)
|
||||
// If no pretty name is found, fall back to the keyword.
|
||||
names.choose(&mut rand::thread_rng()).unwrap_or(keyword)
|
||||
}
|
||||
|
@ -487,7 +487,7 @@ fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &C
|
||||
.state
|
||||
.create_npc(
|
||||
pos,
|
||||
comp::Stats::new(get_npc_name(id), body, None),
|
||||
comp::Stats::new(get_npc_name(id).into(), body, None),
|
||||
body,
|
||||
)
|
||||
.with(comp::Vel(vel))
|
||||
|
@ -6,6 +6,7 @@ use common::{
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::EntityKind,
|
||||
msg::ServerMsg,
|
||||
npc::{self, NPC_NAMES},
|
||||
state::TerrainChanges,
|
||||
terrain::TerrainGrid,
|
||||
};
|
||||
@ -100,6 +101,15 @@ impl<'a> System<'a> for Sys {
|
||||
if let EntityKind::Waypoint = entity.kind {
|
||||
server_emitter.emit(ServerEvent::CreateWaypoint(entity.pos));
|
||||
} else {
|
||||
fn get_npc_name<
|
||||
Species,
|
||||
SpeciesData: core::ops::Index<Species, Output = npc::SpeciesNames>,
|
||||
>(
|
||||
body_data: &comp::BodyData<npc::BodyNames, SpeciesData>,
|
||||
species: Species,
|
||||
) -> &str {
|
||||
&body_data.species[species].generic
|
||||
}
|
||||
const SPAWN_NPCS: &'static [fn() -> (
|
||||
String,
|
||||
comp::Body,
|
||||
@ -107,49 +117,58 @@ impl<'a> System<'a> for Sys {
|
||||
comp::Alignment,
|
||||
)] = &[
|
||||
(|| {
|
||||
let body = comp::humanoid::Body::random();
|
||||
(
|
||||
"Traveler".into(),
|
||||
comp::Body::Humanoid(comp::humanoid::Body::random()),
|
||||
format!(
|
||||
"{} Traveler",
|
||||
get_npc_name(&NPC_NAMES.humanoid, body.race)
|
||||
),
|
||||
comp::Body::Humanoid(body),
|
||||
Some(assets::load_expect_cloned("common.items.weapons.staff_1")),
|
||||
comp::Alignment::Npc,
|
||||
)
|
||||
}) as _,
|
||||
(|| {
|
||||
let body = comp::humanoid::Body::random();
|
||||
(
|
||||
"Bandit".into(),
|
||||
comp::Body::Humanoid(comp::humanoid::Body::random()),
|
||||
format!("{} Bandit", get_npc_name(&NPC_NAMES.humanoid, body.race)),
|
||||
comp::Body::Humanoid(body),
|
||||
Some(assets::load_expect_cloned("common.items.weapons.staff_1")),
|
||||
comp::Alignment::Enemy,
|
||||
)
|
||||
}) as _,
|
||||
(|| {
|
||||
let body = comp::quadruped_medium::Body::random();
|
||||
(
|
||||
"Wolf".into(),
|
||||
comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random()),
|
||||
get_npc_name(&NPC_NAMES.quadruped_medium, body.species).into(),
|
||||
comp::Body::QuadrupedMedium(body),
|
||||
None,
|
||||
comp::Alignment::Enemy,
|
||||
)
|
||||
}) as _,
|
||||
(|| {
|
||||
let body = comp::bird_medium::Body::random();
|
||||
(
|
||||
"Duck".into(),
|
||||
comp::Body::BirdMedium(comp::bird_medium::Body::random()),
|
||||
get_npc_name(&NPC_NAMES.bird_medium, body.species).into(),
|
||||
comp::Body::BirdMedium(body),
|
||||
None,
|
||||
comp::Alignment::Wild,
|
||||
)
|
||||
}) as _,
|
||||
(|| {
|
||||
let body = comp::critter::Body::random();
|
||||
(
|
||||
"Rat".into(),
|
||||
comp::Body::Critter(comp::critter::Body::random()),
|
||||
get_npc_name(&NPC_NAMES.critter, body.species).into(),
|
||||
comp::Body::Critter(body),
|
||||
None,
|
||||
comp::Alignment::Wild,
|
||||
)
|
||||
}) as _,
|
||||
(|| {
|
||||
let body = comp::quadruped_small::Body::random();
|
||||
(
|
||||
"Pig".into(),
|
||||
comp::Body::QuadrupedSmall(comp::quadruped_small::Body::random()),
|
||||
get_npc_name(&NPC_NAMES.quadruped_small, body.species).into(),
|
||||
comp::Body::QuadrupedSmall(body),
|
||||
None,
|
||||
comp::Alignment::Wild,
|
||||
)
|
||||
@ -168,10 +187,14 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
if let EntityKind::Boss = entity.kind {
|
||||
if rand::random::<f32>() < 0.65 {
|
||||
body = comp::Body::Humanoid(comp::humanoid::Body::random());
|
||||
let body_new = comp::humanoid::Body::random();
|
||||
body = comp::Body::Humanoid(body_new);
|
||||
alignment = comp::Alignment::Npc;
|
||||
stats = comp::Stats::new(
|
||||
"Fearless Giant".to_string(),
|
||||
format!(
|
||||
"Fearless Giant {}",
|
||||
get_npc_name(&NPC_NAMES.humanoid, body_new.race)
|
||||
),
|
||||
body,
|
||||
Some(assets::load_expect_cloned("common.items.weapons.hammer_1")),
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user