Modelo de Dominio - vykymoon/rpg-character-creator GitHub Wiki
Paquete: com.proyecto.rpg.model. Diagrama de clases completo en UML.png (raíz del repositorio).
classDiagram
class Character {
-String id
-String name
-Race race
-CharacterClass characterClass
-List~Skill~ skills
-List~Outfit~ outfits
-int strength
-int dexterity
-int intelligence
-int vitality
+recalculateStats()
+clone() Character
}
class Race { id, name, description, baseStrength.. baseVitality }
class CharacterClass { id, name, description, bonusStrength.. bonusVitality }
class Skill { id, name, description, manaCost, allowedRaces, allowedClasses }
class Outfit { id, name, slot, spriteRef, allowedRaces, allowedClasses }
class CatalogRestriction { <<package-private>> }
Character --> Race
Character --> CharacterClass
Character --> "0..*" Skill
Character --> "0..*" Outfit
Skill ..> CatalogRestriction
Outfit ..> CatalogRestriction
Character
Personaje jugable. Implementa Cloneable (patrón Prototype).
id: UUID generado en el constructor. Es la clave con la que el DAO guarda, busca y elimina.- Stats derivados (
strength,dexterity,intelligence,vitality): se calculan enrecalculateStats():
stat final = stat base de la raza + bonus de la clase
clone(): copia superficial de los campos, pero con nuevoidy listas nuevas de habilidades y vestuario.Race,CharacterClass,SkillyOutfitse comparten porque son datos de catálogo inmutables.
Race y CharacterClass
Objetos inmutables (todos los campos final) creados solo por sus Factories.
Racedefine 4 stats base;CharacterClassdefine 4 bonificaciones.equals/hashCodeporid: permite que elComboBoxdel wizard reselecione correctamente la raza o clase cuando el objeto proviene de otra instancia (por ejemplo, al releer un personaje desde JSON).
Ejemplo de cálculo — Elfo Mago:
| FUE | DES | INT | VIT | |
|---|---|---|---|---|
| Elfo (base) | 3 | 7 | 6 | 4 |
| Mago (bonus) | +0 | +2 | +6 | +1 |
| Personaje | 3 | 9 | 12 | 5 |
Skill y Outfit
Ambos tienen listas allowedRaces y allowedClasses (lista vacía o null = disponible para todos).
| Clase | Campos propios |
|---|---|
Skill |
manaCost |
Outfit |
slot (armadura, casco, capa, escudo, botas) y spriteRef (ruta del PNG) |
Ambas exponen:
isAvailableFor(race, characterClass):truesolo si pasa la restricción de raza y la de clase.getRequirementLabel(): texto corto del requisito (p. ej. "Solo Mago, Druida") onull.
Cada una tiene un constructor "suelto" sin restricciones, usado por las plantillas de CharacterPrototype.
CatalogRestriction
Clase de utilidad package-private que concentra la regla de restricción para que no se duplique entre Skill y Outfit:
- Lista
nullo vacía ⇒ sin restricción. El casonullexiste porque los personajes guardados antes de esta función no tienen el campo encharacters.jsony Gson lo deja ennull. - Las entradas se comparan con el
ido con el nombre visible, ignorando mayúsculas y espacios ("elfo"y"Elfo"funcionan igual). Así, renombrar una raza en el JSON no rompe las restricciones en silencio.
Dónde se valida cada regla
| Regla | Dónde |
|---|---|
| La UI oculta lo que no aplica | Step3SkillsController, Step4OutfitController (filtran con isAvailableFor) |
Validación dura (lanza IllegalStateException) |
CharacterBuilder.addSkill / addOutfit |
| Nombre, raza y clase obligatorios | CharacterBuilder.build() |
| Nombre duplicado | CharacterDAO.existsByName (sin distinguir mayúsculas) |