Misiones personalizadas

From DragonMineZ Wiki
This page is a translated version of the page Custom Quests and the translation is 100% complete.

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

Se configura en: Configuración del servidorgameplay

Estas 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

  • AITier es opcional: 1 Novato, 2 Inteligente, 3 Élite, 4 Experto. Si se omite (o se pone en 0 o en un valor negativo), el nivel sale de la dificultad con la que se inició la misión: EASY da 1, NORMAL da 2, HARD da 3, y HARD contra el jefe final de una saga da 4. Define AITier de forma explícita para forzar un nivel concreto sin importar la dificultad.
  • TextureVariant elige una de las texturas de las entidades que tienen varias.
  • canTransform (booleano, por defecto true) controla si el enemigo puede transformarse durante la pelea. Ponlo en false para impedir por completo que el enemigo se transforme; esto se aplica en el servidor, no es solo estético. SURVIVE_WAVES lo lee como CanTransform.
  • Cuando canTransform es true, los siete campos Transform* ajustan las estadísticas del enemigo transformado sin tocar los valores por defecto de la configuración global. Todos son opcionales (null usa los valores por defecto globales de transformación de entities.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_WAVES o ESCORT.
  • Murió el escoltado: el objetivo de ESCORT murió.
  • Se acabó el tiempo: pasó time_limit_seconds desde 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"] }
Archivos antiguos Los archivos de misiones antiguos escribían la dificultad como prefijo del tipo ("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_giver y turn_in se usan mucho más, ya que las misiones secundarias suelen depender de NPCs.
  • prerequisites suele usar condiciones SAGA_QUEST o QUEST para 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

Se configura en: Configuración del servidorgameplay.autoUpdateQuests

Cada 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

  1. Guarda el JSON de tu saga, misión o misión secundaria en la carpeta dragonminez/ del mundo.
  2. Valida la sintaxis JSON (consulta Cómo usar JSON).
  3. Ejecuta /dmzreload story (o /dmzreload all); consulta Recargar y actualizar cambios.
  4. 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.