Sistema de Misiones
El sistema de misiones proporciona un ciclo de vida completo de misiones: creación, seguimiento, progreso, finalización, fracaso, recompensas, requisitos previos, límites de tiempo y misiones repetibles. Todos los datos de misiones se definen mediante ScriptableObjects y están integrados con el sistema de guardado y CommandGraph.
Descripción General de la Arquitectura
| Clase | Propósito |
|---|---|
Quest | ScriptableObject que define los objetivos, recompensas, requisitos previos y metadatos de una misión |
Objective | Clase serializable que representa una única tarea rastreable dentro de una misión |
QuestReward | Clase serializable que representa una recompensa otorgada al completar |
QuestStatus | Estado en tiempo de ejecución de una misión: contadores de progreso, marcas de tiempo, banderas de finalización/fracaso |
QuestManager | SavableObject que rastrea todos los estados de misiones, maneja el ciclo de vida y dispara eventos |
Quest
Crea una misión mediante MCE > Quests > Quest en el menú de activos. Cada Quest ScriptableObject tiene las siguientes secciones:
Clasificación
| Campo | Tipo | Descripción |
|---|---|---|
IsMainQuest | bool | Las misiones principales son críticas para la progresión de la historia |
Category | QuestCategory | Organiza la misión en el registro de misiones (ver más abajo) |
Difficulty | QuestDifficulty | Easy, Normal, Hard, Expert — mostrado en la UI |
Categorías de Misiones:
MainStory— progresión de la historia principalSideQuest— misiones opcionales de NPCDailyTask— se reinicia cada 24 horasWeeklyChallenge— se reinicia cada 7 díasEvent— misiones de evento por tiempo limitadoCollection— llenar el MonsterDex, encontrar todos los objetos, etc.
Otorgante de la Misión
| Campo | Tipo | Descripción |
|---|---|---|
QuestGiver | CharacterData | El NPC que asigna esta misión |
Requisitos
| Campo | Tipo | Descripción |
|---|---|---|
PrerequisiteQuests | List<Quest> | Misiones que deben completarse primero |
MinBadges | int | Número mínimo de medallas para aceptar (0 = ninguna) |
RecommendedLevel | int | Mostrado en la UI, no es obligatorio |
Tiempo y Repetición
| Campo | Tipo | Descripción |
|---|---|---|
TimeLimitSeconds | int | Límite de tiempo en segundos (0 = sin límite). La misión falla automáticamente al expirar |
IsRepeatable | bool | Si la misión puede reiniciarse después de completarse |
RepeatCooldownSeconds | int | Tiempo de espera antes de reaceptar (86400 = diario, 604800 = semanal) |
Objective
Cada misión contiene una List<Objective> que define las tareas que el jugador debe completar. Los objetivos están ordenados y pueden avanzarse automáticamente.
Tipos de Objetivo (11)
| Tipo | Descripción | Campos Clave |
|---|---|---|
Talk | Hablar con un NPC específico | TargetNPC |
Deliver | Entregar un objeto a un NPC | TargetNPC, TargetItem |
Defeat | Derrotar entrenadores o monstruos salvajes | TargetMonster (null = cualquiera), TargetCount |
Catch | Capturar una especie específica | TargetMonster, TargetCount |
Collect | Recolectar una cantidad de un objeto | TargetItem, TargetCount |
GoTo | Viajar a un mapa específico | MapLocation |
Escort | Escoltar a un NPC a un destino | TargetNPC, MapLocation |
Evolve | Evolucionar un monstruo de una especie | TargetMonster |
HatchEgg | Incubar un huevo de monstruo | TargetMonster (null = cualquiera) |
WinAtFacility | Ganar una batalla en una instalación específica | MapLocation |
Custom | Rastreado mediante una variable del juego | CustomVariableKey, TargetCount |
Campos del Objetivo
[Serializable]
public class Objective
{
public string LocalizationKey; // Texto descriptivo localizado
public ObjectiveType Type; // Qué debe hacer el jugador
public SceneInfoAsset MapLocation; // Dónde (para GoTo, marcador en minimapa)
public CharacterData TargetNPC; // Quién (para Talk/Deliver/Escort)
public MonsterEntry TargetMonster; // Qué especie (null = cualquiera)
public ScriptableObject TargetItem; // Qué objeto (Collect/Deliver)
public int TargetCount = 1; // Cuántos se necesitan
public bool IsOptional; // Objetivo bonus, no requerido
public bool HiddenUntilPrevious; // Oculto hasta que se complete el objetivo anterior
public string CustomVariableKey; // Para seguimiento de tipo Custom
}
Los objetivos opcionales no bloquean la finalización de la misión. Los objetivos ocultos crean una sensación de descubrimiento a medida que la misión progresa.
QuestReward
Cada misión tiene una List<QuestReward> otorgada automáticamente al completar.
Tipos de Recompensa (6)
| Tipo | Campos | Ejemplo |
|---|---|---|
Item | ItemReward, ItemQuantity | 5x Super Potion |
Money | MoneyAmount | $5.000 |
Experience | ExpAmount | 2.000 EXP distribuidos al equipo |
Monster | MonsterReward, MonsterLevel | Lv.20 Thundermane |
GameVariable | GameVariableKey, GameVariableValue | Establecer HAS_BIKE = 1 |
Unlock | CustomUnlockId | "safari_zone_access" |
// Cada recompensa tiene una descripción legible para la UI
reward.GetDescription(); // "Super Potion x5", "$5.000", "2.000 EXP", etc.
QuestManager
QuestManager es un SavableObject (ScriptableObject con soporte de guardado/carga) que posee todo el estado runtime de las misiones. Crear mediante MCE > Quests > Manager.
Ciclo de Vida de las Misiones
No Iniciada --> StartQuest() --> Activa (rastreando objetivos)
|
+---------+-----+-----+---------+
| |
CompleteQuest() FailQuest()
| |
Completada Fallida
|
(si IsRepeatable)
|
StartQuest() (después de enfriamiento)
Iniciar una Misión
questManager.StartQuest(quest, startingObjective: 0);
Esto crea una entrada QuestStatus, registra la marca de tiempo de inicio, muestra una notificación y establece el objetivo inicial. Si la misión es repetible y está en enfriamiento, la llamada se ignora con una advertencia.
Progresar Objetivos
// Incrementar el contador de progreso para el objetivo #0 en 1
questManager.UpdateObjectiveProgress(quest, objectiveIndex: 0, delta: 1);
Cuando el progreso alcanza el TargetCount del objetivo, el sistema muestra una notificación y avanza automáticamente al siguiente objetivo no opcional. Si todos los objetivos requeridos están completos, la misión se completa automáticamente.
También puedes establecer el objetivo actual directamente:
questManager.SetQuestObjective(quest, objective: 2);
Completar y Fallar
questManager.CompleteQuest(quest); // Marca completada, otorga recompensas, dispara evento
questManager.FailQuest(quest); // Marca fallida, dispara evento
Misiones con Límite de Tiempo
Llama a questManager.CheckTimeExpiry() periódicamente (ej. desde el Update de un MonoBehaviour) para fallar automáticamente las misiones cuyo tiempo ha expirado:
long remaining = questManager.GetRemainingTime(quest); // segundos, o -1
Consultar Misiones
// Todas las misiones con las que el jugador ha interactuado
Dictionary<Quest, QuestStatus> all = questManager.GetAllQuests();
// Consultas filtradas
List<Quest> active = questManager.GetActiveQuests();
List<Quest> completed = questManager.GetCompletedQuests();
List<Quest> failed = questManager.GetFailedQuests();
// Filtrar por categoría, estado de finalización y/o estado de fracaso
// Firma: GetQuestsFiltered(QuestCategory? category = null, bool? completed = null, bool? failed = null)
List<Quest> dailies = questManager.GetQuestsFiltered(
category: QuestCategory.DailyTask,
completed: false,
failed: null
);
// Verificar requisitos previos
bool canStart = questManager.ArePrerequisitesMet(quest);
// Obtener todas las misiones disponibles para iniciar (requisitos cumplidos, no iniciadas aún)
List<Quest> available = questManager.GetAvailableQuests();
// Verificar si el jugador tiene una misión específica
bool has = questManager.HasQuest(quest);
Porcentaje de Finalización del Juego
El QuestManager rastrea un porcentaje de finalización del juego basado en las misiones completadas. Puede calcularse automáticamente (completadas / total de misiones en la base de datos del mundo) o contra un denominador fijo (QuestsForHundo). El porcentaje se vuelve visible para el jugador cuando VisibleGamePercentage está establecido en true.
float pct = questManager.GameCompletionPercentage; // 0.0 - 1.0
Eventos
questManager.OnQuestStarted += (Quest q) => { ... };
questManager.OnObjectiveProgressed += (Quest q, int objIdx, int newVal) => { ... };
questManager.OnObjectiveChanged += (Quest q, int newObjIdx) => { ... };
questManager.OnQuestCompleted += (Quest q) => { ... };
questManager.OnQuestFailed += (Quest q) => { ... };
questManager.OnRewardsGranted += (Quest q, List<QuestReward> rewards) => { ... };
Guardar / Cargar
QuestManager extiende SavableObject y serializa todos los estados de las misiones a JSON mediante SavableQuestManager. Las referencias a misiones se almacenan por nombre y se resuelven contra WorldDatabase al cargar.
Nodos de CommandGraph (10)
El sistema de misiones proporciona 10 nodos de CommandGraph para usar en scripts de NPC y disparadores de eventos:
Nodos de Acción
| Nodo | Descripción |
|---|---|
StartQuest | Iniciar una misión con un índice de objetivo inicial opcional |
CompleteQuest | Marcar una misión como completada (otorga recompensas) |
FailQuest | Marcar una misión como fallida |
UpdateQuestObjective | Establecer el objetivo actual en un índice específico |
ProgressQuestObjective | Incrementar el contador de progreso de un objetivo en un delta |
UnlockGameCompletionPercentage | Hacer visible el porcentaje de finalización para el jugador |
Nodos de Condición
| Nodo | Descripción |
|---|---|
IfPlayerHasQuest | Ramificar si el jugador ha iniciado (o completado) una misión |
IfCompletedQuest | Ramificar si una misión ha sido completada |
IfQuestFailed | Ramificar si una misión ha sido fallida |
IfCurrentQuestObjective | Ramificar si el objetivo actual de la misión coincide con un índice específico |
Ejemplo: Flujo de Misión de NPC
[IfPlayerHasQuest] -- No --> [Dialog: "¡Necesito ayuda!"] --> [StartQuest]
-- Sí --> [IfCompletedQuest] -- Sí --> [Dialog: "¡Gracias!"]
-- No --> [IfCurrentQuestObjective(1)]
-- Sí --> [Dialog: "¿Lo encontraste?"]
-- No --> [Dialog: "¡Sigue buscando!"]
Crear una Misión: Paso a Paso
- Crear el activo Quest: Haz clic derecho en la ventana Proyecto, selecciona MCE > Quests > Quest
- Establecer clasificación: Elige categoría, dificultad y si es una misión principal
- Asignar el otorgante: Arrastra el
CharacterDatadel NPC al campo Quest Giver - Definir objetivos: Agrega entradas a la lista de Objetivos. Establece el tipo, objetivo y cantidad para cada uno
- Definir recompensas: Agrega entradas a la lista de Recompensas. Elige el tipo de recompensa y completa los campos relevantes
- Establecer requisitos previos (opcional): Arrastra otros activos Quest a PrerequisiteQuests
- Configurar tiempo/repetición (opcional): Establece
TimeLimitSecondsy/oIsRepeatablecon un tiempo de enfriamiento - Registrar en WorldDatabase: Agrega la misión a
WorldDatabase.Questspara que aparezca en las consultas de disponibilidad - Conectar CommandGraph: Usa los nodos de misión en el CommandGraph de tu NPC para iniciar, rastrear y completar la misión