diff --git a/PLATFORM.md b/PLATFORM.md index fcf2c36..19e15c2 100644 --- a/PLATFORM.md +++ b/PLATFORM.md @@ -78,6 +78,7 @@ consumer set. Source builds must pass clean verification before publication. | [ArmourShop](projects/ArmourShop/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [BarterShops](projects/BarterShops/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [BirdMessenger](projects/BirdMessenger/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | +| [CompanionPets](projects/CompanionPets/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [Cooking](projects/Cooking/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [CoreProtect](projects/CoreProtect/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [DenarEconomy](projects/DenarEconomy/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | diff --git a/README.md b/README.md index aecd2d6..0419d30 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Choose a project to open its technical documentation and source repository link. | --- | --- | | [ActivityTF](projects/ActivityTF/README.md) | Daily activity tasks, weekly progress, and player rewards. | | [BirdMessenger](projects/BirdMessenger/README.md) | Bird-delivered letters and interactive mailboxes. | +| [CompanionPets](projects/CompanionPets/README.md) | Companion pet scaffold and designs for hatching, care, training, and play. | | [Games](projects/Games/README.md) | Tabletop games, card games, and wagering. | | [GeigerCounters](projects/GeigerCounters/README.md) | Geiger counter treasure hunts with proximity signals and tiered loot. | | [Magic](projects/Magic/README.md) | Magic, resonance, artifacts, and shrines. | diff --git a/projects/CompanionPets/README.md b/projects/CompanionPets/README.md new file mode 100644 index 0000000..8d24807 --- /dev/null +++ b/projects/CompanionPets/README.md @@ -0,0 +1,44 @@ +# CompanionPets + +[Source repository](https://github.com/TF-Minecraft/CompanionPets) · [All projects](../../README.md) + +CompanionPets is an early scaffold for companion pet hatching, care, training, +and play. The current plugin only logs startup and shutdown. The design notes +below describe planned systems, not implemented gameplay. + +TFMC runs Minecraft **1.21.10**. See the [shared platform and build baseline](../../PLATFORM.md) +for runtime, build, and validation conventions. + +## Build and dependencies + +Build the source repository with Java **21** and Maven: + +```sh +mvn clean verify -DskipTests=false -Dmaven.test.skip=false +python3 .github/scripts/plugin-artifact.py --jar target/companionpets-main-SNAPSHOT.jar --version main-SNAPSHOT +``` + +The build uses `io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT` with +`provided` scope. No private jars or shared TFMC plugin artifacts are required. +The plugin entry point is `net.tfminecraft.companionpets.PetsPlugin`. + +The descriptor declares MythicMobs, ModelEngine, ItemsAdder, and MMOItems as +optional integrations. The scaffold does not currently call their APIs. +There is no unit-test suite yet. + +## Design notes + +The original design notes are preserved in Spanish: + +- [Pet identity, entities, and movement](docs/design/nucleo-mascota.md) +- [Care and needs](docs/design/cuidado.md) +- [Training and tricks](docs/design/entrenamiento.md) +- [Play and toys](docs/design/juego.md) +- [Hatching, ownership, and management](docs/design/gestion.md) + +## Builds and releases + +See the [shared pipeline guide](../../PIPELINES.md). Pull requests build +`companionpets-DEV--.jar`; `main` uses `main-SNAPSHOT`. +Version tags trigger a verified draft release containing the runtime jar, +checksums, and build metadata. diff --git a/projects/CompanionPets/docs/design/cuidado.md b/projects/CompanionPets/docs/design/cuidado.md new file mode 100644 index 0000000..9f12345 --- /dev/null +++ b/projects/CompanionPets/docs/design/cuidado.md @@ -0,0 +1,139 @@ +# Cuidado de la mascota + +La mascota se cuida como un Tamagotchi dentro de la partida. El jugador la saca, las necesidades bajan mientras está con él, la mascota avisa, y una acción corta la recupera al momento. El diseño de entidad, estados y hooks está en [nucleo-mascota.md](nucleo-mascota.md). + +El reloj de las necesidades depende de dónde está y de si el dueño está jugando. El detalle está en [gestion.md](gestion.md). + +- En la caseta, las necesidades se quedan quietas. +- Fuera, con el dueño cerca, bajan al ritmo normal. +- Fuera, con el dueño lejos pero conectado, bajan a un ritmo lento. Otro jugador al lado no lo acelera. +- Al salir el dueño del servidor, las necesidades se congelan aunque la mascota se haya quedado fuera. Al volver, siguen donde estaban. + +La muerte por abandono queda apagada. Si la salud llega a cero, la mascota queda debilitada hasta que se la cuide. Un servidor puede activar la muerte más adelante en la configuración. + +## El ciclo + +1. La mascota acompaña al jugador y sus necesidades bajan poco a poco. +2. Al cruzar un umbral avisa una sola vez, con comportamiento, sonido y un mensaje en la action bar. +3. El jugador la atiende en el mundo o desde la pantalla de cuidado. +4. La necesidad sube al instante y la mascota responde con corazones y su animación. +5. Si un aviso se ignora, pasa de molestia a enfermedad. + +Qué tarda cada necesidad, cada cuánto se ensucia y cuánto aguanta en crítico antes de enfermar no forma parte del diseño fijo. Son opciones de configuración, con un valor de ejemplo para que un servidor pueda jugar sin tocar nada. El diseño fija las necesidades, los tramos, los avisos, las acciones y las etapas de la enfermedad. + +## Necesidades + +Cada una va de 0 a 100. + +| Necesidad | Baja cuando | Qué se siente | +| --- | --- | --- | +| Hambre | Está fuera de la caseta | Pide comida | +| Ánimo | Está fuera de la caseta y no se juega con ella | Pide atención | +| Energía | Camina siguiendo al dueño. Se recupera mientras duerme | Se vuelve lenta y quiere echarse | +| Limpieza | Un suceso puntual, no un goteo constante. Cada suceso resta un trozo de golpe | Hay que limpiarla | +| Salud | Una necesidad lleva suficiente tiempo en crítico | Es la consecuencia de no atenderla | + +Tramos: + +- **Estable**, 60–100. Sigue con normalidad. +- **Bajo**, 25–59. Avisa una vez. +- **Crítico**, 0–24. Insiste y cambia de comportamiento. + +Si varias están mal a la vez, expresa solo la más urgente: enferma, luego hambre, energía, limpieza y ánimo. El jugador ve un problema claro, no cuatro avisos juntos. + +## Cómo se le nota + +Funciona con una entidad vanilla. ModelEngine, si está, solo cambia la animación del estado. El plugin no depende de un icono ni de un modelo. + +**Al cruzar a bajo.** Un sonido ambiente de su entidad, una partícula y una línea en la action bar: "Luna tiene hambre". No se repite hasta que esa necesidad se recupere y vuelva a bajar. + +**En crítico.** Se sienta o se queda corta de paso, mira al jugador y repite un sonido suave de vez en cuando. Cada cuánto se repite ese sonido también es configuración. La action bar, mientras lo miras de cerca, dice la necesidad dominante. + +**Contenta, justo después de atenderla.** Corazones, el sonido de comer o de jugar, y la animación del estado si hay modelo. + +**Al mirarla** a unos pocos bloques, la action bar resume las necesidades. El nombre flotante sigue siendo solo su nombre. + +Partículas de referencia: + +- Hambre crítica: `ANGRY_VILLAGER` +- Sucia: `DUST_PLUME` sobre ella +- Enferma: `SNEEZE` +- Atendida: `HEART` +- Durmiendo: partículas de dormir cada pocos segundos + +## Cómo la atiende el jugador + +Clic derecho con la mano vacía abre la pantalla de cuidado. Con un objeto útil en la mano, el clic derecho hace la acción directa y no abre el menú. + +| Acción | En el mundo | Efecto | +| --- | --- | --- | +| Alimentar | Clic derecho con una comida aceptada | Sube el hambre según el alimento. La comida favorita sube también un poco de ánimo | +| Jugar | Botón Jugar en la pantalla | Pasa a `PLAYING` un rato corto, sin objeto: salta, suenan notas y sube el ánimo. Gasta un poco de energía. La duración y cuánto sube el ánimo son configuración. Lanzar un juguete es la otra forma de jugar, en [juego.md](juego.md) | +| Acostar | Botón Acostar en la pantalla | Pasa a `SLEEPING`, deja de seguir y recupera energía. El hambre baja más despacio. Cuánto tarda en llenarse es configuración. Despierta sola al llenar la energía, o si el jugador la despierta | +| Limpiar | Clic derecho con un cepillo | Quita la suciedad y deja la limpieza llena | +| Curar | Clic derecho con la medicina, solo si está enferma | Empieza a recuperar salud | + +La pantalla muestra el nombre, las cinco necesidades y los mismos botones. Alimentar y curar consumen el objeto del inventario. Jugar y acostar no consumen nada. Limpiar pide el cepillo en el inventario. + +Si no puede hacer la acción, lo dice en la action bar: está enferma y no quiere jugar, o no tiene sueño, o eso no se lo come. + +## Enfermedad + +1. Una necesidad permanece en crítico el tiempo configurado. La mascota entra en **malestar**. Sigue al jugador más despacio, estornuda y la salud empieza a bajar. +2. Si en ese rato se corrige la causa (come, juega, duerme o se limpia), el malestar se pasa solo y la salud vuelve. +3. Si el crítico continúa otro tramo configurado, pasa a **enferma**. Rechaza el juego, se para a menudo y ya no se cura solo. +4. Enferma se cura con la medicina configurada (por defecto, frasco de miel). Después hace falta tener las demás necesidades fuera de crítico para que la salud termine de subir. +5. Salud a 0: **debilitada**. Se echa, no sigue y no juega. Se recupera con medicina, comida y descanso. No desaparece. + +Un jugador que responde a los avisos no llega a verla enferma. La enfermedad es la escena de haberla dejado pasar, no el estado normal. + +## Estados y órdenes del jugador + +`FOLLOWING` y `SITTING` siguen siendo órdenes del jugador. `PLAYING` y `SLEEPING` son cuidados. + +- Si la mandas seguir mientras duerme, despierta. +- Con la energía crítica se echa aunque no se lo pidas. Despertarla en ese momento baja un poco el ánimo. +- Enferma o debilitada obedece peor: camina más lenta y no entra en `PLAYING`. +- `SITTING` ordenado por el jugador se mantiene. Sentarse porque tiene hambre es un aviso, y al comer vuelve a seguir si esa era la orden. + +## Vínculo + +El vínculo es una sexta cifra de 0 a 100, distinta de las necesidades. Sube despacio mientras las necesidades se quedan en estable y ella está contigo. No cae por una comida tarde. Cae si permanece enferma o en crítico mucho rato. + +Con el vínculo alto se pega más al caminar y suelta corazones de vez en cuando. Con el vínculo bajo se queda un paso más atrás. Es la sensación de haberla criado, sin evoluciones ni etapas todavía. + +## Configuración + +El ritmo no se define en el código. Todo intervalo, toda cantidad que sube o baja una necesidad y la duración de jugar o dormir salen de la configuración. Cambiarlos no cambia las reglas de arriba: las mismas necesidades, los mismos tramos, los mismos avisos y las mismas etapas. + +Los números del ejemplo son un punto de partida cómodo para una sesión normal, en la que la mascota pide atención unas pocas veces. Un servidor puede alargarlos o acortarlos. Los alimentos y la medicina dependen del tipo de mascota. Los juguetes y el lanzamiento están en [juego.md](juego.md). El ejemplo amplía el de [nucleo-mascota.md](nucleo-mascota.md): + +```yaml +care: + hunger-minutes-to-critical: 30 + mood-minutes-to-critical: 30 + energy-minutes-to-critical: 40 + dirty-every-minutes: 20 + minutes-until-unwell: 3 + minutes-until-sick: 3 + decay-while-stored: false + death-on-neglect: false + +pets: + wolf: + entity: WOLF + care: + foods: + BEEF: 35 + COOKED_BEEF: 55 + favorite: COOKED_BEEF + medicine: HONEY_BOTTLE + animations: + FOLLOWING: walk + SITTING: sit + PLAYING: play + SLEEPING: sleep + SICK: sick +``` + +`SICK` es un estado visual más, por si el modelo tiene animación de enferma. Sin modelo basta con las partículas y el cambio de paso. diff --git a/projects/CompanionPets/docs/design/entrenamiento.md b/projects/CompanionPets/docs/design/entrenamiento.md new file mode 100644 index 0000000..d327015 --- /dev/null +++ b/projects/CompanionPets/docs/design/entrenamiento.md @@ -0,0 +1,46 @@ +# Entrenamiento + +La mascota aprende trucos con paciencia. La palabra la elige el dueño. El significado se muestra una sola vez. Las repeticiones, premiadas solo cuando lo hace bien, fijan el truco. El cuidado está en [cuidado.md](cuidado.md) y la entidad en [nucleo-mascota.md](nucleo-mascota.md). + +Un truco funciona con una entidad vanilla. ModelEngine, si el tipo tiene animación para ese truco, la reproduce en lugar de la pose genérica. La action bar confirma la reacción también cuando la pose ya se ve. + +## Qué es un truco + +Una reacción definida por el plugin: pose, movimiento, sonido y, cuando el cuerpo no puede enseñarlo, una línea en la action bar. No es una animación ni una skill de MythicMobs. + +| Truco | En cualquier mob | Pose vanilla cuando existe | +| --- | --- | --- | +| Sentarse | Se para y deja de seguir. Usa el estado `SITTING` | Lobo, gato, loro y zorro se sientan | +| Venir | Camina hasta el dueño | | +| Quieto | Se queda donde está | | +| Hablar | Reproduce su sonido ambiente | | +| Saltar | Da un salto | | +| Girar | Da una vuelta sobre sí | | +| Pedir | Levanta la mirada | El lobo usa la cabeza interesada. El gato, la cabeza alta | +| Dar la pata | Mira al dueño, suelta una partícula y la action bar dice que da la pata | Con modelo, la animación de la pata | + +Sentarla o acostarla desde el cuidado sigue siendo una orden directa. Obedecer la palabra es el truco, y solo existe cuando ya lo ha aprendido. + +Cada mascota guarda sus propias palabras. El lobo de un jugador puede usar `sit` y el de otro `siéntate` para el mismo truco. Una palabra corresponde a un solo truco. + +## Cómo se le enseña + +1. Con una golosina en la mano, clic derecho sobre la mascota. La comida favorita sirve de golosina. Entra en entrenamiento: mira al dueño y deja de vagar. +2. El dueño la mira y escribe en el chat la orden entera: `sit`, `siéntate` o `dale la pata`. El mensaje sigue viéndose en el chat. El plugin lo escucha solo si el jugador está cerca y mira a su mascota. +3. Si la palabra es nueva, la mascota inclina la cabeza y aparece una fila de botones: Sentarse, Venir, Quieto, Hablar, Saltar, Girar, Pedir y Dar la pata. Un clic ata esa palabra a ese truco. No vuelve a preguntarse. Agacharse, saltar o girar es lo que hace ella al obedecer, no lo que hace el dueño para enseñárselo. +4. Luego se repite la palabra. Al principio no entiende, o lo hace a medias (se sienta y se levanta enseguida). Si lo hace bien, hay un momento corto para premiarla con la golosina. Premiar un fallo casi no hace avanzar. Un acierto sin premio no se fija. +5. El truco pasa de no entender a obedecer a veces y, al final, a obedecer. El ánimo alto y el vínculo aceleran un poco el avance. + +Hambre crítica, enfermedad o agotamiento impiden la sesión: no presta atención. Tras varios intentos se aburre y la sesión termina. También termina si el dueño se aleja o guarda la golosina. + +Cuántos intentos aguanta, cuánto avanza cada premio y cuánto dura la ventana para premiar son configuración. No forman parte de las reglas de arriba. + +## Cómo se le ordena + +Con el truco aprendido, el dueño mira a la mascota y escribe solo esa palabra. La línea de chat es la orden completa, así `sit` no se dispara dentro de otra frase. Obedece la mascota mirada. Si el jugador no mira a ninguna, ninguna obedece. + +Fuera del entrenamiento, una palabra desconocida no provoca reacción y el mensaje de chat sigue su curso. + +## Qué queda fuera + +No hay conversación libre con la mascota. No aprende trucos que el servidor no tenga definidos. MythicMobs no participa en la orden: sus skills siguen siendo del mob, y el truco es de este plugin. diff --git a/projects/CompanionPets/docs/design/gestion.md b/projects/CompanionPets/docs/design/gestion.md new file mode 100644 index 0000000..b0616ff --- /dev/null +++ b/projects/CompanionPets/docs/design/gestion.md @@ -0,0 +1,90 @@ +# Gestión de las mascotas + +Cada mascota es un individuo: nombre, sexo, tipo, necesidades, trucos y juguete favorito. El mismo tipo puede repetirse. Cuatro golden retriever son cuatro mascotas, cada una con su nombre. El cuidado de las necesidades está en [cuidado.md](cuidado.md). + +## Dónde puede estar + +Hay dos cupos, los dos de configuración. Un ejemplo de partida es 20 en la caseta y 4 fuera. Fuera cuenta igual si te sigue o si se quedó en un sitio. + +| Dónde | Qué se ve | Necesidades | +| --- | --- | --- | +| Caseta | No está en el mundo | Quietas, esté el dueño conectado o no, esté cerca o lejos | +| Contigo | Te sigue | Ritmo normal | +| Dejada | Se queda donde la sentaste | Ritmo normal si el dueño está cerca. Ritmo lento si está lejos y sigue conectado | + +El ritmo normal y el lento son configuración. La distancia que separa cerca de lejos es `owner-near-radius`: vale para el ritmo y para el llanto. Otro jugador al lado no devuelve el ritmo normal: ese ritmo es que el dueño está ahí para atenderla. + +Al salir del servidor, las necesidades se congelan aunque se haya quedado fuera. Al volver, sigue en el mismo sitio y con las mismas necesidades. Si el dueño aparece lejos de ella, el ritmo lento vuelve a contar. Olvidarse de guardarla se nota al entrar: sigue fuera, ocupa un hueco y está donde la dejó. No enferma por el tiempo que el dueño pasó desconectado. + +La muerte por abandono sigue apagada. Como mucho llega a debilitada, como en el cuidado. + +## Caseta y silbato + +La caseta es un bloque. Al usarla se abre la lista: nombre, tipo, sexo, un resumen de las necesidades y si está fuera o guardada. Desde ahí se saca, se guarda o se le cambia el nombre. + +El silbato abre el mismo menú en cualquier lugar. Sirve para guardar una que se quedó lejos o para llamarla, sin volver andando. Llamarla carga su chunk y teletransporta a esa misma entidad. + +## Huevo + +El objeto que hace de huevo sale de la configuración de cada tipo. El crafteo y el permiso para craftearlo los resuelve el sistema de profesiones, fuera de este plugin. + +Al usarlo, el chat pide el nombre. Cuando se confirma, el huevo se gasta y la mascota aparece al lado del jugador, dentro del cupo de las que están fuera. Si ese cupo está lleno, el huevo no se gasta y el chat lo dice. Si el nombre no llega a confirmarse, el huevo tampoco se gasta. + +El sexo se sortea al nacer y se anuncia en ese momento. Si la configuración del tipo es `choose`, el chat lo pregunta después del nombre. Es identidad: no cambia el cuidado ni los trucos. + +## Quién puede atenderla + +El dueño la entrena, la nombra, la guarda y la saca. Cualquier otro jugador puede darle los cuidados básicos si la tiene delante: alimentar, limpiar y curar. Jugar, los trucos y el silbato siguen siendo del dueño. + +## Llanto + +Si está fuera y el dueño está conectado pero lejos, llora de vez en cuando: un sonido suave y una partícula. El intervalo es configuración. Para cuando el dueño vuelve cerca, o justo después de que alguien la atienda. En la caseta no llora. Con el chunk descargado tampoco se oye, porque el mob no está en memoria. Al cargar el chunk, si el dueño sigue lejos, el llanto vuelve con él. + +## El cuerpo lo guarda el chunk + +Una mascota que está fuera se comporta como un lobo domesticado. El chunk la escribe en disco al descargarse y la vuelve a crear al cargarse, con el mismo UUID, la posición y si estaba sentada o siguiendo. El plugin no la borra al descargar el chunk ni la vuelve a spawnear cuando hay un jugador cerca. Ese ciclo duplicaría el mob: uno lo traería el archivo del chunk y otro el plugin. + +La ficha del plugin guarda lo que Minecraft no sabe: id de la mascota, dueño, tipo, nombre, sexo, necesidades, trucos, juguete favorito y si está en la caseta o fuera. Ese id se escribe también en los datos persistentes de la entidad. Al cargar el chunk, la entidad ya está; el plugin la reconoce por ese id y reengancha el comportamiento. El UUID de la entidad identifica el cuerpo mientras existe. El id de la mascota es el que no cambia, también si al sacarla de la caseta aparece un cuerpo nuevo. + +Mientras el cuerpo existe, la ficha apunta de vez en cuando su mundo y su posición. Sirve para que el silbato encuentre el chunk y teletransporte a esa misma entidad. No sirve para crear otra. + +El reloj de las necesidades no depende de que el mob esté en memoria. Sigue la tabla de arriba: quieto en la caseta, normal con el dueño cerca, lento si está lejos y conectado, y parado si el dueño se desconecta. Un chunk descargado no piensa, pero la ficha sí actualiza las necesidades. + +La caseta es la única vez que el plugin quita la entidad del mundo. Al guardarla se borra, para que el chunk no la conserve. Al sacarla se crea una vez, persiste, y a partir de ahí la guarda el chunk. + +El UUID se conserva porque el chunk guarda la entidad. Eso lo decide `setPersistent(true)`, que ya es el valor por defecto: no hace falta tocarlo salvo que algo lo hubiera puesto en false. `setTamed(true)` no interviene en el UUID. Solo marca dueño y la pose de domesticado en un lobo, un gato o un loro. Un mob que Minecraft borraría al alejarse, como muchos de MythicMobs que no son animales, lleva además `setRemoveWhenFarAway(false)`, para que no desaparezca antes de que el chunk lo escriba. + +## El modelo sin MythicMobs + +MythicMobs no hace falta para tener modelo. Si el servidor tiene ModelEngine y el tipo declara un blueprint, este plugin pone el modelo al crear el cuerpo: al usar el huevo y al sacarla de la caseta. Crea el `ModeledEntity`, añade el blueprint y deja `setSaved(true)`. + +Ese guardado escribe en la entidad el id del blueprint. Minecraft lo mete en el chunk junto con el mob. Al cargar el chunk, ModelEngine lee ese id y monta el modelo otra vez. No mira el tipo de entidad y no espera a MythicMobs. + +El id del blueprint sigue en la configuración del tipo. Si la entidad carga y el modelo no está, el plugin lo aplica de nuevo, sobre el mismo cuerpo. + +Si el tipo es un MythicMob y ese mob ya pone el modelo con `model{save=true}`, el plugin no añade otro. Busca el `ModeledEntity` que ya existe y solo le pide la animación del estado. + +Sin ModelEngine no hay modelo: se ve la entidad vanilla, y el resto del plugin funciona igual. + +## Configuración + +Los cupos, la distancia a la que el dueño cuenta como cerca y el ritmo lento son un punto de partida. + +```yaml +limits: + max-stored: 20 + max-out: 4 + +presence: + owner-near-radius: 32 + away-rate: 0.25 + +pets: + wolf: + entity: WOLF + egg: WOLF_SPAWN_EGG + sex: random + model: wolf_custom +``` + +`sex` puede ser `random` o `choose`. `away-rate` es la fracción del ritmo normal mientras el dueño está lejos y conectado. No hay radio de aparición: el chunk carga el mob cuando le toca a Minecraft. `model` es el id del blueprint de ModelEngine. Si ModelEngine no está instalado, se ignora. `owner-near-radius` es la distancia a partir de la cual el dueño cuenta como lejos. diff --git a/projects/CompanionPets/docs/design/juego.md b/projects/CompanionPets/docs/design/juego.md new file mode 100644 index 0000000..c63f11b --- /dev/null +++ b/projects/CompanionPets/docs/design/juego.md @@ -0,0 +1,71 @@ +# Juego y juguetes + +Jugar tiene dos formas. El botón Jugar de la pantalla de cuidado es un juego corto, sin objeto. Lanzar un juguete es la forma larga: ella lo persigue, lo trae y lo suelta delante del dueño. El ánimo y la energía son las necesidades de [cuidado.md](cuidado.md). Recoger el juguete es jugar, no un truco de [entrenamiento.md](entrenamiento.md). + +## Qué es un juguete + +Un juguete es un objeto de la lista del tipo de mascota. Un lobo puede tener el palo y la pluma. Lo que no está en esa lista no se lanza y ella no lo persigue, aunque se caiga al suelo. + +El objeto no tiene que ser un proyectil de Minecraft. El plugin aparta uno de la mano y lo dispara como una bola de nieve con la apariencia del juguete. Se ve el palo en el aire. Al tocar el suelo o a una criatura, la bola desaparece y queda el objeto. El tiro no hace daño. + +Ese objeto es el mismo que salió de la mano. No se duplica. Otro jugador no puede quedárselo mientras dura el juego: solo lo recoge la mascota. Ella ignora los objetos del suelo que no son ese lanzamiento. + +## Cómo se lanza + +Clic derecho al aire, con un juguete de la lista en la mano y la mascota invocada. + +La trayectoria, la gravedad y el choque los resuelve la bola de nieve. El plugin decide que ese objeto es un juguete, elige la velocidad y la recorta entre un mínimo y un máximo. Esos límites viven en la configuración: un tiro a plena fuerza se queda en la zona. + +La fuerza, dentro de esos límites, sale de cómo se apunta y de si el jugador se agacha: + +- Hacia delante el tiro cae cerca. Un poco hacia arriba llega más lejos. En vertical cae al lado. +- Sin agacharse sale a la velocidad alta. Agachado, a la baja. + +Un palo no se tensa como un arco. El cliente solo mantiene el clic en objetos que ya se usan así, y un arco, un tridente o una comida arrastrarían su propio efecto. Por eso el gesto es apuntar y, si se quiere un tiro corto, agacharse. + +Un segundo lanzamiento cancela el primero. El primer objeto se suelta delante del dueño y empieza el nuevo tiro. + +## El recorrido + +1. El juguete sale. La mascota pasa a `PLAYING` y corre a por él. +2. Lo recoge del suelo. En la vuelta no hace falta mostrarlo encima: basta con que deje de estar en el suelo y ella vuelva. +3. Se acerca y lo suelta en el suelo, delante del dueño. No entra en la mano ni en el inventario. +4. Vuelve a la orden que tenía, seguir o sentada. Sube el ánimo y gasta un poco de energía. Cuánto sube y cuánto gasta es configuración, como el resto del cuidado. + +Llevar el objeto en la cabeza durante la vuelta es un detalle visual aparte, para más adelante. No forma parte de este recorrido. Si se añade, en un mob que ya use el casco por MythicMobs ese casco no se toca. + +Si el tiro no se puede completar y el dueño sigue ahí, el objeto también se suelta delante. Si en ese momento no está, queda guardado con la mascota y se suelta delante la próxima vez que estén juntos. + +## El favorito + +Al crear la mascota se sortea uno de los juguetes de su tipo. Lanzar más veces otro no lo cambia. Dos mascotas del mismo tipo pueden preferir objetos distintos. + +En la pantalla de cuidado se muestra desde el principio. Cuando se lanza ese, corre más, suelta más corazones y el ánimo sube más. Los demás de la lista también los trae, con una reacción más tranquila. + +Si la lista de la configuración cambia: + +- El suyo sigue en la lista: se queda con él. +- Se añaden juguetes: no se vuelve a sortear. +- Quitan el suyo y quedan otros: se sortea otro entre los que siguen, y se avisa una vez. +- La lista queda vacía: no tiene favorito y no hay lanzamiento. Cuando vuelva a haber juguetes, se sortea. + +## Qué queda fuera + +Cualquier objeto del inventario como juguete. Proyectiles de verdad, como perlas, tridentes o pociones. Un favorito escrito por el administrador para cada mascota. Distinguir el mismo objeto por nombre o encantamiento. Una bolsa de juguetes en la mascota. Enseñarle a buscarlo como un truco. Varias mascotas corriendo al mismo objeto: lo busca la que está invocada con el dueño. + +## Configuración + +La lista de juguetes es del tipo. El favorito de cada mascota no se escribe aquí. Las velocidades son un punto de partida, no una regla fija. + +```yaml +play: + throw-speed-low: 0.6 + throw-speed-high: 1.1 + +pets: + wolf: + entity: WOLF + toys: + - STICK + - FEATHER +``` diff --git a/projects/CompanionPets/docs/design/nucleo-mascota.md b/projects/CompanionPets/docs/design/nucleo-mascota.md new file mode 100644 index 0000000..d2f662b --- /dev/null +++ b/projects/CompanionPets/docs/design/nucleo-mascota.md @@ -0,0 +1,109 @@ +# Núcleo de la mascota + +Documento vivo del diseño. Lo que acordemos después se añade aquí. El código todavía no implementa este núcleo. + +Servidor objetivo: Paper 1.21. El seguimiento usa `Mob#getPathfinder()` (`moveTo`, `stopPathfinding`), que está en la API de Paper. La dependencia de compilación pasa de `spigot-api` a `paper-api`, en scope `provided`. + +## Idea + +La mascota es un objeto del plugin, con dueño, tipo y estado. La entidad de Minecraft es el cuerpo que está en el mundo en ese momento. MythicMobs y ModelEngine se usan solo si el servidor los tiene instalados. Un lobo, gato o zorro vanilla funciona en un servidor que solo tiene este plugin. + +## Tres capas + +```mermaid +flowchart LR + pet[Pet] + behavior[PetBehavior] + entity[PetEntity] + visual[PetVisual] + pet --> behavior + behavior --> entity + behavior --> visual + entity --> bukkit[Bukkit_Entity] + entity --> mythic[MythicMobs_opcional] + visual --> vanilla[Sin_modelo] + visual --> meg[ModelEngine_opcional] +``` + +### Pet + +Identidad de la mascota. Guarda el identificador, el dueño, el tipo y el estado. Sigue existiendo cuando la entidad sale del mundo: el jugador se desconecta, cambia de mundo o el mob se descarga. El seguimiento y las interacciones no dependen de que el UUID de la entidad siga vivo. + +Estados iniciales: + +- `FOLLOWING` +- `SITTING` +- `PLAYING` +- `SLEEPING` + +`PLAYING` y `SLEEPING` son estados de cuidado. Cómo come, juega, duerme, se ensucia y enferma está en [cuidado.md](cuidado.md). + +### PetEntity + +Cuerpo de la mascota. Sabe aparecer, moverse, pararse, teletransportarse y desaparecer. El núcleo solo habla con esta interfaz. + +**Vanilla.** Spawnea un `EntityType` (`WOLF`, `CAT`, `FOX`, etc.). El movimiento usa el pathfinder de Paper. Si la entidad es `Sittable` o `Tameable`, el adaptador marca sentado o domesticado para que la pose vanilla coincida con el estado. + +**MythicMobs.** Spawnea el mob por id (`getMythicMob(id)` y luego `spawn`) y recupera la entidad de Bukkit. Atributos, habilidades e IA de combate siguen definidos por el administrador en MythicMobs. Este plugin aplica la misma locomoción que a una entidad vanilla. + +Si un tipo declara `mythic-mob` y MythicMobs no está instalado, ese tipo no se registra. El resto del plugin arranca igual. + +### PetVisual + +Reacciona a cambios de estado. No conoce bones ni geometría del modelo. + +Sin ModelEngine, la implementación no hace nada: se ve la entidad vanilla. + +Con ModelEngine, y si el tipo tiene un blueprint, este plugin lo aplica al crear el cuerpo y lo deja guardado en la entidad. Al cargar el chunk, ModelEngine lo monta otra vez. Si MythicMobs ya lo puso, el hook no crea otro: busca el `ModeledEntity` existente y llama a `playAnimation` con el nombre del estado (`FOLLOWING` → `walk`, `SITTING` → `sit`). El detalle está en [gestion.md](gestion.md). + +## Quién mueve a la mascota + +El comportamiento de mascota es de este plugin. En cada tick, `PetBehavior` mira el estado y habla con la entidad y con la representación: + +| Estado | Entidad | Visual | +| --- | --- | --- | +| `FOLLOWING` | Camina hacia el dueño. Si la distancia pasa un umbral, se teletransporta. | Animación de seguimiento, si existe | +| `SITTING` | Para el pathfinder y, si puede, se sienta | Animación de sentarse, si existe | +| `PLAYING` | Se queda junto al dueño y juega unos segundos | Animación de juego, si existe | +| `SLEEPING` | Se echa y recupera energía | Animación de dormir, si existe | + +En un mob de MythicMobs pensado como mascota, los goals de vagar o de seguir se dejan vacíos. Esas locomociones y el pathfinder de Paper escriben el mismo movimiento y se pisan. Las skills de MythicMobs se mantienen: atributos, habilidades por timer, señal o interacción. + +## Integraciones opcionales + +`plugin.yml` las declara como `softdepend: [MythicMobs, ModelEngine]`. + +Al arrancar, el plugin comprueba si están activos y solo entonces carga la clase del adaptador. El núcleo solo ve `PetEntityFactory` y `PetVisual`. Las clases de MythicMobs y ModelEngine no se referencian desde el núcleo, así que no hace falta tenerlos para compilar ni para arrancar. + +MythicMobs y ModelEngine no entran en el classpath obligatorio del núcleo. Sus adaptadores se compilan aparte cuando se implementen. + +## Configuración de tipos + +```yaml +pets: + wolf: + entity: WOLF + blaze_buddy: + mythic-mob: BlazeBuddy + animations: + FOLLOWING: walk + SITTING: sit + PLAYING: play + SLEEPING: sleep +``` + +`wolf` funciona solo con este plugin. `blaze_buddy` exige MythicMobs. Las animaciones se usan si además está ModelEngine y el mob lleva ese modelo. + +## Relacionado + +- [cuidado.md](cuidado.md): hambre, ánimo, energía, limpieza, enfermedad y cómo la atiende el jugador. +- [entrenamiento.md](entrenamiento.md): trucos, la palabra que elige el dueño y cómo se enseñan con paciencia. +- [juego.md](juego.md): el juego corto, lanzar un juguete y el favorito sorteado de cada mascota. +- [gestion.md](gestion.md): huevo, caseta, silbato, cupos y cuándo corren las necesidades. + +## Fuera de este núcleo + +Aún no está diseñado: + +- Comandos y permisos propios de este plugin, aparte del permiso de crafteo que resuelve el sistema de profesiones +- Qué pasa si el cuerpo muere por el mundo (lava, caída, un mob)