Misiones personalizadas
Las misiones personalizadas son sagas, misiones de saga y misiones secundarias que escribes tú mismo solo con JSON, sin código Java ni un jar de addon. El contenido de la historia son datos de cada mundo (a diferencia de las razas y las formas, que están en config/dragonminez), así que estos archivos viven dentro del mundo guardado.
Dónde van los archivos
<world save>/dragonminez/
sagas/ # saga manifests
quests/<questFolder>/ # quest files for one saga, loaded alphabetically
sidequests/ # standalone side quests (any subfolder layout, e.g. sidequests/<category>/)
Código fuente: QuestRegistry.loadAll(server) (src/main/java/com/dragonminez/common/quest/QuestRegistry.java). Consulta Encontrar carpetas para ver el mapa completo de carpetas.
Opciones de la historia
gameplayEstas opciones están en general-server.json → gameplay, y todas son true por defecto:
| Campo | Tipo | Qué hace |
|---|---|---|
storyModeEnabled |
Booleano | Interruptor general del sistema de sagas y misiones. |
createDefaultSagas |
Booleano | Genera los archivos por defecto de sagas y misiones de saga de DragonMineZ (también necesita storyModeEnabled).
|
sideQuestsEnabled |
Booleano | Interruptor general del sistema de misiones secundarias. |
createDefaultSideQuests |
Booleano | Genera los archivos por defecto de misiones secundarias de DragonMineZ. |
autoUpdateQuests |
Booleano | Actualiza en su lugar los archivos por defecto de DragonMineZ cuando una nueva versión de DragonMineZ los cambia (consulta Actualización de los archivos por defecto). |
Los archivos por defecto se generan uno a uno, por nombre de archivo, cada vez que faltan, así que un archivo por defecto que borres vuelve en la siguiente carga mientras su opción createDefault... esté activada. Tus propios archivos (cualquier otro nombre de archivo) nunca se tocan.
Paso 1: crea un manifiesto de saga
Crea un archivo por saga en dragonminez/sagas/, por ejemplo my_saga.json:
{
"id": "my_saga",
"name": "dmz.saga.my_saga",
"requirements": {
"previousSaga": "saiyan_saga"
},
"questFolder": "saga_my_saga"
}
| Campo | Tipo | Qué hace |
|---|---|---|
id |
Texto | Id único de la saga. |
name |
Texto | Clave de traducción del nombre visible de la saga. |
requirements.previousSaga |
Texto | Id de la saga que se debe completar antes, o "" si no hay ninguna.
|
questFolder |
Texto | Nombre de la subcarpeta dentro de dragonminez/quests/ que contiene los archivos de misiones de esta saga.
|
Los ids de saga por defecto son classic_saga, saiyan_saga, frieza_saga, android_saga, future_saga, buu_saga, movies_saga, gt_saga y daima_saga (consulta Sagas).
Código fuente: SagaDefaults.java, Saga.java.
Paso 2: añade archivos de misiones
Dentro de dragonminez/quests/saga_my_saga/, añade un archivo por misión, con nombres que ordenen los archivos según el orden de juego (01_...json, 02_...json, ...). El orden de los nombres de archivo es el orden de las misiones dentro de la saga.
{
"id": 1,
"title": "dmz.quest.my_saga1.name",
"description": "dmz.quest.my_saga1.desc",
"type": "SAGA",
"category": "saga_my_saga",
"parallel_objectives": false,
"party_scaling": true,
"secret": false,
"claim_mode": "TREE_OR_NPC",
"requirements": {
"operator": "AND",
"conditions": [
{ "type": "LEVEL", "minLevel": 1 },
{ "type": "DIMENSION", "dimension": "minecraft:overworld" }
]
},
"objectives": [
{ "type": "KILL", "entity": "dragonminez:saga_raditz", "count": 1, "health": 450.0, "meleeDamage": 22.0, "kiDamage": 39.0 }
],
"rewards": [
{ "type": "ATTRIBUTES", "amount": 10 },
{ "type": "ITEM", "item": "dragonminez:senzu_bean", "count": 1 }
]
}
Una misión de saga se identifica como <sagaId>:<id> (por ejemplo my_saga:1), usando el id numérico, no el nombre del archivo. Dos archivos con el mismo id en una carpeta se sobrescriben entre sí.
Para insertar una misión entre dos existentes, dale un id nuevo que no se use y un nombre de archivo que quede entre ellas al ordenar. Las sagas de DragonMineZ lo hacen así: la misión 17 de la Saga Freezer es 01b_scout_the_ruined_village.json, entre 01_... y 02_.... Renumerar las misiones existentes rompería el progreso guardado y todas las condiciones SAGA_QUEST o requisitos de forma que apunten a ellas.
Campos de una misión
Las misiones de saga y las misiones secundarias comparten exactamente el mismo esquema, así que estos campos sirven para ambas.
| Campo | Tipo | Qué hace |
|---|---|---|
id |
Número o texto | Numérico para las misiones de saga. Las misiones secundarias usan un id de texto. |
title / description |
Texto | Claves de traducción (también sirve texto simple). |
type |
Texto | SAGA, SIDEQUEST, DAILY o EVENT. Una misión DAILY se puede repetir una vez por día real (zona horaria del servidor).
|
category |
Texto | Etiqueta de agrupación libre. Por defecto "general".
|
parallel_objectives |
Booleano | Si es true, todos los objetivos avanzan a la vez en lugar de uno tras otro.
|
party_scaling |
Booleano | Si es true, las cantidades de objetos y de muertes aumentan por cada miembro extra del grupo (defaultQuestPartyMultiplier en general-server.json, por defecto 1.45), y los enemigos de la misión ganan más vida y daño por cada miembro extra (enemyHealthPerPartyPlayer 1.25, enemyDamagePerPartyPlayer 1.1).
|
secret |
Booleano | Oculta la misión del registro de misiones hasta que se inicia o queda disponible. |
claim_mode |
Texto | TREE_OR_NPC (se reclama desde la pantalla de misiones o desde un NPC) o NPC_ONLY (el jugador tiene que hablar con el NPC de entrega).
|
quest_giver |
Texto o null |
Id del NPC que ofrece la misión (consulta NPCs que dan y reciben misiones). |
turn_in |
Texto o null |
Id del NPC que recibe la misión completada. |
prerequisites |
Objeto | Decide si la misión se puede desbloquear en absoluto. Mismo esquema que requirements (consulta Prerrequisitos y requisitos).
|
requirements |
Objeto | Decide si la misión se puede iniciar en este momento (por ejemplo, la dimensión, el bioma o el nivel actuales). |
repeatable |
Booleano | Si es true, la misión se puede volver a iniciar después de completarla. Por defecto false.
|
repeat_cooldown_seconds |
Entero | Segundos reales antes de que una misión repetible se pueda volver a iniciar. 0 (por defecto) significa de inmediato.
|
time_limit_seconds |
Entero | Tiempo límite después de aceptar la misión, en segundos del juego. Cuando se agota, la misión falla. 0 (por defecto) significa sin límite.
|
objectives |
Array | Consulta Tipos de objetivos. |
rewards |
Array | Consulta Tipos de recompensas. |
defaultsVersion |
Texto | Solo se usa en los archivos por defecto de DragonMineZ (consulta Actualización de los archivos por defecto). |
Cuando una misión repetible o diaria se vuelve a iniciar, su progreso de objetivos y las recompensas reclamadas se reinician, así que las recompensas se pueden reclamar de nuevo.
Código fuente: QuestParser.parseQuest, Quest.java.
Tipos de objetivos
Cada entrada de objectives necesita un type más los campos de ese tipo. Los campos marcados con * son opcionales y tienen valores por defecto razonables.
type |
Campos | Qué hace |
|---|---|---|
ITEM |
item, count |
Tener esta cantidad de un objeto en tu inventario. Los objetos no se quitan; para eso usa DELIVER.
|
KILL |
entity, count, health*, meleeDamage*, kiDamage*, spawn*, count_mode*, AITier*, TextureVariant*, canTransform*, TransformHealth*, TransformMeleeDamage*, TransformKiDamage*, TransformHealthMultiplier*, TransformMeleeDamageMultiplier*, TransformKiMultiplier*, TransformTriggerPercent* |
entity puede ser un id de registro o un tag de entidad (#minecraft:zombies; las apariciones de la misión eligen un miembro al azar). health, meleeDamage y kiDamage valen por defecto 20, 1 y 1. spawn: QUEST (por defecto, aparecen cuando empieza la misión) o NATURAL. count_mode: QUEST_SPAWNED_ONLY (por defecto) o ANY_MATCHING. Consulta Objetivo de eliminar: nivel de IA y transformaciones.
|
SPAR |
Igual que KILL, sin los campos Transform* |
Una pelea no letal: cuando un compañero generado por la misión iba a bajar del 15% de vida, la pelea termina, cuenta como victoria para todo el grupo y el compañero se va. |
INTERACT |
entity*, entityName* |
Interactuar con clic derecho con una entidad que coincida. |
TALK_TO |
npcId |
El jugador tiene que hablar con un NPC o maestro concreto. |
DELIVER |
item, count* (por defecto 1), npcId (alias npc_id y npc) |
Haz clic derecho en el NPC para entregarle los objetos. Se quitan del inventario, y las entregas parciales cuentan. |
STRUCTURE |
structure |
El jugador tiene que entrar en una estructura generada. |
BIOME |
biome |
El jugador tiene que estar en este bioma (o tag de bioma). |
DIMENSION |
dimension |
El jugador tiene que estar en esta dimensión. |
COORDS |
x, y, z, radius* |
El jugador tiene que estar a menos de radius bloques (por defecto 10) de un punto.
|
CHECKPOINT_RACE |
checkpoints (lista de { "x", "y", "z" }), radius* (por defecto 8) |
Llegar a cada punto de control en orden. |
SURVIVE_WAVES |
entity, waves* (por defecto 3), mobs_per_wave* (por defecto 3), wave_delay_seconds* (por defecto 10), health*, meleeDamage*, kiDamage*, AITier*, TextureVariant*, CanTransform* |
Aparecen oleadas de enemigos alrededor del jugador; la siguiente llega tras una breve pausa cuando se termina con una oleada. Cada oleada superada cuenta como un paso de progreso. |
ESCORT |
entity, x, y, z, radius* (por defecto 6), health* |
Aparece un escoltado junto al jugador y lo sigue; llévalo a menos de radius del objetivo. Si muere, la misión falla. health reemplaza su vida máxima.
|
DRAGON_SUMMON |
dragon*, ball_set* |
El jugador tiene que invocar un dragón y/o un juego de esferas concreto (alias: dragon_id y dragonId; ballSet, ball_set_id, ballSetId y set).
|
SKILL |
skill, level* |
El jugador tiene que alcanzar un nivel de habilidad (alias: skillId y id; minLevel y required; nivel por defecto 1).
|
Código fuente: QuestParser.parseObjective y las clases de common/quest/objectives/.
Mientras se sigue un objetivo COORDS, ESCORT o CHECKPOINT_RACE, el HUD de misiones muestra la distancia y la dirección al objetivo (o al siguiente punto de control).
En una misión con parallel_objectives: false, los objetivos de eliminar que van seguidos se desbloquean juntos, así que un par "eliminar A, eliminar B" se puede pelear en cualquier orden. Los objetivos de los demás tipos siguen yendo de uno en uno.
Objetivo de eliminar: nivel de IA y transformaciones
AITieres opcional:1Novato,2Inteligente,3Élite,4Experto. Si se omite (o se pone en0o en un valor negativo), el nivel sale de la dificultad con la que se inició la misión:EASYda 1,NORMALda 2,HARDda 3, yHARDcontra el jefe final de una saga da 4. DefineAITierde forma explícita para forzar un nivel concreto sin importar la dificultad.TextureVariantelige una de las texturas de las entidades que tienen varias.canTransform(booleano, por defectotrue) controla si el enemigo puede transformarse durante la pelea. Ponlo enfalsepara impedir por completo que el enemigo se transforme; esto se aplica en el servidor, no es solo estético.SURVIVE_WAVESlo lee comoCanTransform.- Cuando
canTransformestrue, los siete camposTransform*ajustan las estadísticas del enemigo transformado sin tocar los valores por defecto de la configuración global. Todos son opcionales (nullusa los valores por defecto globales de transformación deentities.json):TransformHealth,TransformMeleeDamage,TransformKiDamage: valores absolutos de las estadísticas de la forma transformada.TransformHealthMultiplier,TransformMeleeDamageMultiplier,TransformKiMultiplier: multiplicadores que se aplican a las estadísticas base (antes de transformarse) en lugar de valores absolutos.- Los valores absolutos tienen prioridad sobre los multiplicadores cuando ambos se definen para la misma estadística.
TransformTriggerPercent: fracción de la vida máxima (0.0–1.0) a la que el enemigo activa su transformación.
{ "type": "KILL", "entity": "dragonminez:saga_vegeta", "count": 1, "health": 900.0, "meleeDamage": 40.0, "kiDamage": 60.0,
"canTransform": true, "TransformTriggerPercent": 0.5, "TransformHealthMultiplier": 1.8, "TransformMeleeDamageMultiplier": 1.6 }
Cómo puede fallar una misión
Una misión fallida pierde el progreso de sus objetivos, y se eliminan sus enemigos y escoltados generados por la misión. Se puede volver a iniciar desde el registro de misiones o desde su NPC (los requisitos de inicio se vuelven a comprobar).
- Grupo derrotado: cuando el jugador (o todos los miembros de su grupo) muere, fallan las misiones aceptadas que tengan un objetivo
KILL,SPAR,SURVIVE_WAVESoESCORT. - Murió el escoltado: el objetivo de
ESCORTmurió. - Se acabó el tiempo: pasó
time_limit_secondsdesde que se aceptó la misión.
Tipos de recompensas
Cada entrada de rewards necesita un type más sus campos. Todos los tipos de recompensa aceptan además un campo opcional difficulty que limita las dificultades en las que se otorga (ver abajo).
type |
Campos | Qué hace |
|---|---|---|
ITEM |
item, count* (por defecto 1) |
Otorga una pila de objetos. |
GENERIC_ITEM |
itemReward (un objeto de ítem) |
Otorga un objeto con encantamientos, datos de poción o un adorno de armadura. Consulta Objetos de ítem. |
ATTRIBUTES |
amount |
Otorga Atributos, la recompensa que usan todas las misiones por defecto: amount × attributeRewardPointRatio (por defecto la mitad, redondeando hacia abajo) como Puntos de Atributo, y el resto como el TP que esos puntos de estadística le costarían al jugador al reclamarla. Ese TP no se vuelve a potenciar ni se comparte con el grupo. El tooltip muestra el reparto. Consulta Estadísticas y atributos.
|
ATTRIBUTE_POINTS |
amount |
Otorga solo Puntos de Atributo (que el jugador reparte en el menú de estadísticas). |
TPS |
amount |
Otorga una cantidad fija de puntos de entrenamiento (pasa por los aumentos de TP STORY del servidor).
|
ALIGNMENT |
amount |
Ajusta el alineamiento del jugador (puede ser negativo). Consulta Alineamiento. |
SKILL |
skill, level |
Sube una habilidad hasta al menos este nivel. |
TRANSFORMATION |
formGroup, formName, mastery* (por defecto 100.0), stack* (por defecto false) |
Desbloquea una forma de la raza del jugador (o una forma acumulable si stack es true): sube la habilidad de forma del grupo hasta esa forma y otorga al menos esa maestría. Las formas indicadas en el formRequisite de la forma también suben a la maestría que requieren. Alias: form_group y group; form_name y form.
|
KI_TECHNIQUE |
code |
Otorga una técnica de ki a partir de un código de técnica exportado (alias: techniqueCode y technique_code). Consulta Técnicas.
|
COMMAND |
command, translationKey* |
Ejecuta un comando en el servidor (nivel de operador), reemplazando %player% por el nombre del jugador. translationKey es el texto que se muestra en la lista de recompensas en lugar del comando.
|
Las recompensas TRANSFORMATION y SKILL actúan sobre los grupos de raza y las habilidades del propio jugador. Para dar recompensas específicas de una raza o clase, ponlas en misiones bloqueadas con una condición RACE o CLASS (consulta Prerrequisitos y requisitos).
Código fuente: QuestParser.parseReward, las clases de common/quest/rewards/, Difficulty.java.
Limitar una recompensa por dificultad
El campo opcional difficulty de una recompensa es un conjunto permitido de las dificultades en las que se otorga esa recompensa (alias: difficulties, difficultyType y minDifficulty). Acepta un array JSON (["NORMAL","HARD"]), un texto separado por comas o espacios ("NORMAL, HARD") o un solo valor ("HARD"). Los valores válidos son EASY, NORMAL y HARD. Si se omite o está vacío, la recompensa se otorga en todas las dificultades.
Es una comprobación de pertenencia al conjunto, no un umbral mínimo: "EASY" por sí solo significa únicamente Fácil, y ["EASY","HARD"] (saltándose Normal) es válido. Los valores desconocidos se descartan.
{ "type": "ITEM", "item": "dragonminez:senzu_bean", "count": 1, "difficulty": ["NORMAL", "HARD"] }
"hard:ITEM", "normal:ITEM"). Esos archivos se siguen cargando: hard: significa solo Difícil y normal: significa Fácil y Normal, salvo que la recompensa también tenga un campo difficulty. Los archivos nuevos deberían usar el campo difficulty.
Escalado de recompensas
Las cantidades de ITEM, GENERIC_ITEM, TPS, ATTRIBUTES, ATTRIBUTE_POINTS y ALIGNMENT se escalan con el multiplicador de recompensas de misiones de la dificultad con la que se inició la misión (easyModeQuestRewardMultiplier y hardModeQuestRewardMultiplier en general-server.json). Las recompensas TPS, ATTRIBUTES y ATTRIBUTE_POINTS también se multiplican por storyResetTPMultiplier (por defecto 0.5) una vez por cada reinicio de la historia. SKILL, TRANSFORMATION, KI_TECHNIQUE y COMMAND son recompensas de desbloqueo y nunca se escalan.
Las recompensas son por jugador. Cada miembro del grupo reclama sus propias recompensas cuando se completa la misión (desde el registro de misiones, o desde el NPC de entrega con claim_mode: NPC_ONLY).
Objetos de ítem
Las recompensas GENERIC_ITEM (y los deseos item_list_wish, consulta Deseos personalizados) describen los objetos con un objeto tipado. itemType elige el tipo de objeto; itemId y count siempre están disponibles.
itemType |
Campos extra | Qué hace |
|---|---|---|
generic_item (por defecto) |
— | Cualquier objeto. |
enchanted_item |
enchantments |
enchantments es un mapa de id de encantamiento a nivel, por ejemplo { "minecraft:sharpness": 3 }.
|
enchanted_book |
enchantments |
Encantamientos guardados en un libro encantado (itemId minecraft:enchanted_book).
|
potion, splash_potion, lingering_potion, tipped_arrow |
potion*, mobEffects* |
potion es un id de poción (por ejemplo minecraft:strong_healing). mobEffects es una lista de { "effect", "duration", "amplifier", "ambient", "visible", "showIcon" } (duración en ticks, al menos 1). Pon en itemId el objeto vanilla correspondiente (minecraft:potion, minecraft:splash_potion, minecraft:lingering_potion o minecraft:tipped_arrow).
|
trimmed_armor |
material, pattern, enchantments* |
Armadura con adorno, por ejemplo "material": "minecraft:gold" y "pattern": "minecraft:coast".
|
itemId es obligatorio y count tiene que ser al menos 1. Un objeto de ítem no válido (falta itemId, un itemType desconocido, un nivel o una duración incorrectos) hace que todo el archivo de la misión no se cargue, y el archivo aparece en el informe de carga del JSON. Los ids de encantamiento, poción o efecto desconocidos solo omiten esa entrada, con una advertencia en el log.
{ "type": "GENERIC_ITEM", "itemReward": {
"itemType": "enchanted_item", "itemId": "minecraft:diamond_sword", "count": 1,
"enchantments": { "minecraft:sharpness": 5, "minecraft:unbreaking": 3 } } }
Código fuente: src/main/java/com/dragonminez/common/util/types/items/, GenericItemTypeAdapterFactory.java.
Prerrequisitos y requisitos
Tanto prerequisites (si la misión se puede desbloquear alguna vez) como requirements (si se puede iniciar ahora mismo) usan el mismo esquema de árbol de condiciones:
{
"operator": "AND",
"conditions": [
{ "type": "LEVEL", "minLevel": 30 },
{ "type": "SAGA_QUEST", "sagaId": "saiyan_saga", "questId": 8 },
{ "operator": "OR", "conditions": [ ... ] }
]
}
operator es AND u OR. conditions puede anidar otro bloque { "operator": ..., "conditions": [...] }.
type |
Campos |
|---|---|
SAGA_QUEST |
sagaId, questId (int): hay que completar una misión de saga concreta.
|
QUEST |
questId (string): hay que completar una misión secundaria concreta.
|
LEVEL |
minLevel
|
STAT |
stat (STR, SKP, RES, VIT, PWR o ENE), minValue
|
RACE |
race (alias: raceName y race_name): el id de la raza del jugador, sin distinguir mayúsculas y minúsculas. Ids incluidos: human, saiyan, namekian, frostdemon, bioandroid, majin, glind. Ojo: es frostdemon (no frieza ni colddemon) y bioandroid (no android ni cell). Las razas personalizadas usan el nombre de su carpeta en config/dragonminez/races/.
|
CLASS |
class (alias: className, class_name y characterClass): el id de la clase del jugador, sin distinguir mayúsculas y minúsculas.
|
SKILL |
skill, minLevel* (alias: skillId y id; level y required)
|
BIOME |
biome
|
DIMENSION |
dimension
|
STRUCTURE |
structure, hint* ({ "dimension", "x", "y", "z" }, todos opcionales; ayuda a guiar al jugador hacia la estructura)
|
ALIGNMENT |
min*, max*
|
TIME |
mode (GAME_TIME con ticks, o REAL_TIME con milliseconds): tiempo transcurrido desde que la misión pasó a estar disponible.
|
Código fuente: QuestParser.parseCondition, QuestPrerequisites.java. Los mismos bloques de condiciones controlan las opciones de los Diálogos de NPCs.
Misiones secundarias
Las misiones secundarias pueden estar en cualquier lugar dentro de dragonminez/sidequests/ (también se revisan las subcarpetas) y usan el mismo esquema de misión que las misiones de saga, con algunas diferencias prácticas:
"id"es un texto en lugar de un número (por ejemplo"bulma_gero_blueprints")."type"es"SIDEQUEST"(o"DAILY"o"EVENT") en lugar de"SAGA".- No hay carpeta de saga ni manifiesto que las agrupe: cada archivo es independiente.
quest_giveryturn_inse usan mucho más, ya que las misiones secundarias suelen depender de NPCs.prerequisitessuele usar condicionesSAGA_QUESToQUESTpara bloquear una misión secundaria hasta cierto progreso de la historia.
Ejemplo (dragonminez/sidequests/collection/bulma_gero_blueprints.json):
{
"id": "bulma_gero_blueprints",
"title": "dmz.sidequest.bulma_gero.name",
"description": "dmz.sidequest.bulma_gero.desc",
"type": "SIDEQUEST",
"category": "collection",
"parallel_objectives": false,
"party_scaling": true,
"secret": false,
"claim_mode": "TREE_OR_NPC",
"quest_giver": "bulma",
"turn_in": "bulma",
"prerequisites": {
"operator": "AND",
"conditions": [
{ "type": "SAGA_QUEST", "sagaId": "android_saga", "questId": 6 }
]
},
"objectives": [
{ "type": "STRUCTURE", "structure": "dragonminez:gero_lab" },
{ "type": "ITEM", "item": "minecraft:redstone", "count": 32 },
{ "type": "ITEM", "item": "dragonminez:kikono_shard", "count": 8 },
{ "type": "TALK_TO", "npcId": "bulma" }
],
"rewards": [
{ "type": "ATTRIBUTES", "amount": 25 }
]
}
Un encargo repetible, que se entrega a un NPC:
{
"id": "my_market_run",
"title": "dmz.sidequest.my_market_run.name",
"description": "dmz.sidequest.my_market_run.desc",
"type": "SIDEQUEST",
"category": "collection",
"quest_giver": "bulma",
"turn_in": "bulma",
"repeatable": true,
"repeat_cooldown_seconds": 3600,
"objectives": [
{ "type": "DELIVER", "item": "minecraft:emerald", "count": 12, "npcId": "bulma" },
{ "type": "TALK_TO", "npcId": "bulma" }
],
"rewards": [
{ "type": "ITEM", "item": "dragonminez:senzu_bean", "count": 2 }
]
}
NPCs que dan y reciben misiones
quest_giver y turn_in hacen referencia a un NPC por id: el mismo id que usan las entidades de NPCs de misiones y los NPCs maestros y entrenadores (los objetivos TALK_TO y DELIVER usan los mismos ids). DragonMineZ indexa las misiones por ambos campos, así que un NPC puede mostrar marcadores de "misión disponible" y aceptar entregas sin que tengas que conectar nada más. Ambos campos son opcionales: omítelos o ponlos en null si la misión no está ligada a un NPC (por ejemplo, una misión de saga que solo consiste en explorar o eliminar enemigos).
Hablar con quien da la misión abre su diálogo, donde la opción Misiones lista las misiones que ofrece, las que están en curso y las que están listas para entregar, además de sus misiones bloqueadas: al pasar el cursor sobre una se ve qué falta (por ejemplo, la misión de saga o la misión secundaria que hay que completar antes), y una misión repeatable completada muestra una cuenta atrás hasta que se pueda volver a tomar. Las misiones secret bloqueadas no aparecen. La lista se ordena según cuándo se abre cada misión en la historia (orden de saga, luego orden de misión, luego requisito de nivel), así que las primeras misiones de un NPC salen primero.
Si quien da la misión es un maestro con requisito de alineamiento, sus misiones solo se pueden iniciar mientras el alineamiento del jugador cumpla, desde cualquier pantalla; las misiones ya en curso se pueden seguir entregando. Goku, Gohan, Kaiosama, Kaioshin Anciano, Roshi y Krilin necesitan un alineamiento de 61 o más, y Cell y Freezer de 40 o menos. Consulta Maestros.
Claves desconocidas o mal escritas
Cada misión, saga, objetivo, recompensa, condición de prerrequisito o requisito y pista de estructura se compara con una lista explícita de campos permitidos (QuestParser.validate y validateSaga). Cualquier clave que no se reconozca (una errata, mayúsculas incorrectas, un campo sobrante de un esquema antiguo) no se descarta sin avisar: se registra en el log y se muestra a los jugadores en el informe de carga del JSON del juego al conectarse (controlado por developer.reportJsonProblemsInChat, activado por defecto), además de en la consola del servidor. La entrada se sigue cargando con el resto de sus campos válidos; solo se señala la clave no reconocida. Úsalo para detectar erratas (por ejemplo CanTransfrom en lugar de canTransform) en lugar de tener un campo que no hace nada sin que te enteres. Un archivo con sintaxis JSON rota se omite y se reporta de la misma forma.
Las claves que empiezan por _, $ o // se tratan como comentarios y nunca se señalan, así que puedes dejarte notas directamente en el JSON.
Tipos de objetivos y recompensas personalizados
Los addons en Java pueden registrar sus propios type de objetivos y recompensas mediante QuestObjectiveRegistry y QuestRewardRegistry. Una vez registrados, se escriben en el JSON de las misiones igual que los tipos incluidos. Consulta Implementación y eventos y Crear un addon de DMZ.
Actualización de los archivos por defecto
gameplay.autoUpdateQuestsCada archivo de misión, saga y misión secundaria generado lleva un campo defaultsVersion (un texto semver, actualmente "2.2.0"). QuestUpgrader lo gestiona automáticamente y lo usa para hacer una combinación a tres bandas de tus cambios con los valores por defecto incluidos en DragonMineZ cada vez que cambia el contenido incluido:
- Un campo que nunca cambiaste toma el nuevo valor por defecto.
- Un campo que cambiaste conserva tu valor. Si DragonMineZ también lo cambió, se registra como conflicto, y tu valor sigue ganando.
- Las claves que añadiste se conservan.
- Cuando la combinación cambia algo, antes se copia el archivo anterior a
<world>/dragonminez/oldBackup/.
Se escribe un resumen en <world>/dragonminez/quest_update_report.txt y se muestra en el informe de carga del JSON. Desactiva todo el sistema con autoUpdateQuests: false. No necesitas poner defaultsVersion en tu propio contenido personalizado. Consulta Recargar y actualizar cambios para ver cómo se reportan las actualizaciones.
Claves de traducción
Sigue la convención de nombres existente para que tu contenido encaje con el resto de la historia:
- Nombre de la saga:
dmz.saga.<saga_id> - Título y descripción de una misión de saga:
dmz.quest.<key>.name/dmz.quest.<key>.desc - Título y descripción de una misión secundaria:
dmz.sidequest.<key>.name/dmz.sidequest.<key>.desc
Añade estas claves a tu en_us.json o a tu propio archivo de idioma. Las traducciones propias se combinan con las de Crowdin igual que en las razas personalizadas.
Recarga y validación
- Guarda el JSON de tu saga, misión o misión secundaria en la carpeta
dragonminez/del mundo. - Valida la sintaxis JSON (consulta Cómo usar JSON).
- Ejecuta
/dmzreload story(o/dmzreload all); consulta Recargar y actualizar cambios. - Abre el registro de misiones en el juego y comprueba que tu saga, misión o misión secundaria aparece con los requisitos, objetivos y recompensas correctos.