Tornando Seu Mod de Skyrim Compatível com Saves Existentes
A Importância da Compatibilidade com Saves Existentes
Jogadores de Skyrim são conhecidos por sua dedicação, muitas vezes investindo centenas, até milhares de horas em um único jogo. Exigir que esses jogadores iniciem um novo jogo para experimentar seu mod, ou mesmo para uma atualização, pode ser um grande impedimento. Da perspectiva do usuário, reiniciar significa perder incontáveis horas de progresso e potencialmente perder seu mod completamente.
Este guia foi elaborado para criadores de mods, particularmente aqueles familiarizados com o Creation Kit e os conceitos básicos de modding. Exploraremos como implementar técnicas que permitem que seu mod seja instalado ou atualizado em saves existentes, garantindo uma experiência mais suave e agradável para seus usuários.
Lidando com Atualizações e Instalações
A chave para a compatibilidade com saves existentes está em entender como gerenciar scripts, missões e referências de objetos durante uma atualização de mod ou instalação inicial. Como esses cenários compartilham os mesmos princípios, vamos abordá-los juntos.
Tempo é Tudo: Executando Sua Lógica
-
Evento OnInit: Uma abordagem direta é utilizar a função
OnInit
dentro de uma nova missão especificamente projetada para atualizações/instalações. Esta missão deve ser marcada como "Start Game Enabled" na Guia de Dados da Missão do Creation Kit. Anexe um script a esta missão através da Guia de Scripts e coloque seu código de atualização/instalação dentro da funçãoOnInit
. -
Evento OnPlayerLoadGame: Para atualizações, o evento
OnPlayerLoadGame
oferece uma alternativa. Crie um alias na Guia Alias, force-o a referenciar o jogador e anexe um script (estendendo o script ReferenceAlias) a este alias. Implemente sua lógica de atualização dentro da funçãoOnPlayerLoadGame
. Lembre-se de que este evento é acionado apenas ao carregar um save, não na inicialização de uma nova missão. No entanto,OnInit
ainda será executado para este script de alias quando a missão começar. -
Evento OnCellAttach: Algumas funções, como
GetDistance
ouFindClosestReferenceOfAnyTypeInListFromRef
, exigem ObjectReferences carregadas. Se sua lógica de atualização/instalação depender delas, use a funçãoOnCellAttach
.
Desmistificando Scripts
Os scripts são frequentemente uma fonte de ansiedade para os criadores de mods preocupados com a compatibilidade com saves existentes. No entanto, a menos que um script esteja sendo executado ativamente durante o processo de salvamento (o que é raro), seu código e estado de execução não são salvos. Os scripts normalmente são executados rapidamente, especialmente se você estiver usando RegisterForSingleUpdate
e OnUpdate
para atrasos mais longos em vez de Utility.Wait
.
A principal preocupação reside nas propriedades e variáveis de instância do script, que são salvas. Felizmente, estas são gerenciáveis:
-
Propriedades: Defina diretamente seus valores para o estado desejado usando Papyrus.
-
Variáveis de Instância: Como estas são privadas ao seu script, crie funções setter para atualizá-las:
int myInstanceVar = 5 Function SetMyInstanceVar(int newValue) myInstanceVar = newValue EndFunction
Importantemente, as propriedades adicionadas recentemente a um script já inicializado serão automaticamente padronizadas para o valor especificado em seu plugin, portanto, você só precisa ajustar as propriedades existentes.
Trabalhando com Missões
Uma vez que uma missão está em andamento (não apenas visível no diário), suas etapas, propriedades de script e aliases se tornam fixos. Veja como lidar com isso:
-
Aliases: Facilmente atualizados usando a função
ForceRefTo
. Adicione a nova referência como uma propriedade de script em sua lógica de atualização/instalação e useForceRefTo
para apontar seu alias para ela. -
Etapas da Missão:
- Evite Mudanças Desnecessárias: Idealmente, mantenha sua sequência de índice de estágio original. Projete sua missão com IDs de estágio suficientes para acomodar adições futuras.
- Considere a Substituição da Missão: Para revisões importantes, finalize a missão original usando
Stop
e introduza uma nova missão completamente. - Reconstrução da Missão: Se você precisar reconstruir uma missão existente usando o mesmo formulário, use
Stop
,Reset
eSetStage
para guiar o jogador ao estado desejado após a atualização.
Gerenciando Referências de Objetos
Mods que alteram o mundo do jogo podem causar conflitos de posicionamento de objetos, frequentemente levando os autores a exigir um novo save. Isso ocorre porque as referências persistentes têm suas posições salvas.
Lembre-se de que apenas as referências de objetos persistentes são uma preocupação. Objetos temporários serão atualizados automaticamente para suas novas posições, pois não são salvos.
-
Objetos Móveis: A maioria dos objetos persistentes como Ativadores, Contêineres, MovableStatics e Marcadores podem ser movidos usando scripts. A função
MoveToMyEditorLocation
é particularmente útil para isso. -
Objetos Imóveis: Árvores, Flora, Statics e Móveis não podem ser movidos via script. Aqui estão algumas soluções:
- Desabilitar e Substituir: Se o objeto não for usado por outros mods, desabilite o antigo e adicione um novo no local desejado. Certifique-se de que quaisquer aliases de missão ou propriedades de script que referenciem esses objetos sejam atualizados de acordo.
- Requisito do Save Unbaker: Adicione o mod Save Unbaker como um requisito. Esta ferramenta move automaticamente esses objetos para suas novas posições.
Outros Registros Persistentes
Lembre-se destes registros adicionais que persistem nos saves:
-
Ranks de Facção: Modificáveis com
SetFactionRank
,AddToFaction
eRemoveFromFaction
. -
Ranks de Relacionamento: Ajustáveis usando
SetRelationshipRank
. -
Trajes de NPCs: Alteráveis com
SetOutfit
.
Exemplo: Script de Atualização Retroativa
ScriptName RetroactiveFixAlias Extends ReferenceAlias
MyQuestScript Property myQuest Auto
ObjectReference Property myQuestProperty1Ref Auto
ObjectReference Property myQuestProperty2Ref Auto
ReferenceAlias Property myAlias1 Auto
ReferenceAlias Property myAlias2 Auto
ObjectReference Property myAlias1Ref Auto
ObjectReference Property myAlias2Ref Auto
ObjectReference Property myRef1 Auto
ObjectReference Property myRef2 Auto
ObjectReference Property myActor1 Auto
Outfit Property myActor1Outfit Auto
int currentVersion = -1
Event OnInit()
HandleInstallOrUpdates()
EndEvent
Event OnPlayerLoadGame()
HandleInstallOrUpdates()
EndEvent
Function HandleInstallOrUpdates()
If currentVersion != 2
myQuest.myQuestProperty1 = myQuestProperty1Ref
myQuest.myQuestProperty2 = myQuestProperty2Ref
myAlias1.ForceRefTo(myAlias1Ref)
myAlias2.ForceRefTo(myAlias2Ref)
myRef1.MoveToMyEditorLocation()
myRef2.MoveToMyEditorLocation()
myActor1.SetOutfit(myActor1Outfit)
currentVersion = 2
EndIf
EndFunction
Exemplo: Corrigindo uma ObjectReference Após o Carregamento da Célula
ScriptName RetroactiveFixObjectReference extends ObjectReference
int currentVersion = -1
ObjectReference Property myRef Auto
FormList Property myRefTypes Auto
Event OnInit()
; Inicializado na versão 2, nenhuma correção necessária
currentVersion = 2
EndEvent
Event OnCellAttach()
If currentVersion != 2
myRef = Game.FindClosestReferenceOfAnyTypeInListFromRef(myRefTypes, self, 100.0)
currentVersion = 2
EndIf
EndEvent
Conclusão
Embora este guia não cubra todos os cenários, ele fornece uma base sólida para tornar seu mod de Skyrim mais acessível e amigável. Lembre-se de que, embora alcançar a compatibilidade perfeita com saves existentes possa ser desafiador, mesmo pequenos passos nessa direção podem melhorar significativamente a experiência para seus usuários.