Quest flag overrides: Difference between revisions

From ZeldaMods (Breath of the Wild)
Jump to navigation Jump to search
imported>Leoetlino
(Created page with "To ensure that quests do not become uncompletable if the player leaves an area when they have only been partially solved, some GameData flags are '''always''' manually ove...")
 
(→‎Implementation in 1.5.0: add link to decomp source)
 
(3 intermediate revisions by 2 users not shown)
Line 4: Line 4:


== Kass quests ==
== Kass quests ==
Sometime ''after'' the release of 1.0.0, completion checks for Kass' quests were added to the same GameDataMgr function. These are exactly the same as the ones that can be found in Kass' [[event flow]] but implemented in the executable instead. The reason why Nintendo has decided to duplicate the checks is unknown, but it might be a workaround for some kind of event bug: Kass not spawning in Rito Village even after all of his quests have been completed used to be a widespread issue.
Sometime ''after'' the release of 1.0.0, completion checks for Kass' quests were added to the same GameDataMgr function. These are exactly the same as the ones that can be found in the BloodyMoonRelief<Musician_Check> [[event flow]] but implemented in the executable instead. The reason why Nintendo has decided to duplicate the checks is unknown, but it might be a workaround for some kind of event bug: Kass not spawning in Rito Village even after all of his quests have been completed used to be a widespread issue.


In 1.5.0, Npc_Musician_Come (the flag that causes Kass to spawn in Rito Village) is set iff the following flags are set:
In 1.5.0, Npc_Musician_Come (the flag that causes Kass to spawn in Rito Village) is set iff the following flags are set:
Line 18: Line 18:


== Implementation in 1.5.0 ==
== Implementation in 1.5.0 ==
See https://github.com/zeldaret/botw/blob/7bda72574e1d7cf3e76de20155c1f37b74971f4e/src/KingSystem/GameData/gdtManager.cpp#L373 for a fully accurate version of this code.
<source lang="c++">
<source lang="c++">
// utility functions (inlined in the actual executable)
// utility functions (inlined in the actual executable)

Latest revision as of 17:29, 5 May 2021

To ensure that quests do not become uncompletable if the player leaves an area when they have only been partially solved, some GameData flags are always manually overwritten by the GameDataMgr when a stage is loaded.

GameDataMgr is also responsible for always resetting the "get flag" for the Bow of Light to ensure it spawns and for making Kass spawn in Rito Village (see #Kass quests).

Kass quests

Sometime after the release of 1.0.0, completion checks for Kass' quests were added to the same GameDataMgr function. These are exactly the same as the ones that can be found in the BloodyMoonRelief<Musician_Check> event flow but implemented in the executable instead. The reason why Nintendo has decided to duplicate the checks is unknown, but it might be a workaround for some kind of event bug: Kass not spawning in Rito Village even after all of his quests have been completed used to be a widespread issue.

In 1.5.0, Npc_Musician_Come (the flag that causes Kass to spawn in Rito Village) is set iff the following flags are set:

  • Animal_Forest_Finish
  • HateeluMini_Treasure_Finish
  • Thunder_Sword_Finish
  • Relief_Landing_Finish
  • TwoWheels_Finish
  • Shadow_Sign_Finish
  • MouthofDragon_Finish
  • BloodyMoonRelief_Finish
  • Rito_BrosRock_Finish

Implementation in 1.5.0

See https://github.com/zeldaret/botw/blob/7bda72574e1d7cf3e76de20155c1f37b74971f4e/src/KingSystem/GameData/gdtManager.cpp#L373 for a fully accurate version of this code.

// utility functions (inlined in the actual executable)
void GameDataMgr::setFlag(const sead::SafeString& flagName, bool value)
{
  if (this->paramB.changeOnlyOnce)
    return;
  if (!TriggerParam::setBoolByKey(*this->paramB.param1, value, flag_name, this->paramB.x, 1LL, 1))
    return;
  if (!this->paramB.propagateParam1Changes)
    return;
  TriggerParam::setBoolByKey(*this->paramB.param, value, flag_name, this->paramB.x, 1LL, 1);
}

bool GameDataMgr::flagIsSet(const sead::SafeString& flagName)
{
  bool value;
  return TriggerParam::getFlagByKey(*this->param.param1, &value, flagName, this->param.x) && value;
}

// 0x7100DD0A88
// called from GameScene
void GameDataMgr::getAndSetShrineQuestAndKassFlags()
{
  if (flagIsSet("DarkWoods_Giant_Clear") && !flagIsSet("DarkWoods_Finish"))
    setFlag("DarkWoods_Giant_Clear", false);

  if ( TriggerParam::getFlagByKey(*this->param.param1, &giant_ball1, "giant_ball1", this->param.x)
    && TriggerParam::getFlagByKey(*this->param.param1, &giant_ball2, "giant_ball2", this->param.x)
    && TriggerParam::getFlagByKey(*this->param.param1, &giant_ball3, "giant_ball3", this->param.x)
    && TriggerParam::getFlagByKey(*this->param.param1, &giant_dungeon, "giant_dungeon", this->param.x)
    && TriggerParam::getFlagByKey(*this->param.param1, &lithograph1, "MainField_DgnObj_RemainsLithogragh_A_02_789666109", this->param.x)
    && TriggerParam::getFlagByKey(*this->param.param1, &lithograph2, "MainField_DgnObj_RemainsLithogragh_A_02_2456751716", this->param.x)
    && TriggerParam::getFlagByKey(*this->param.param1, &lithograph3, "MainField_DgnObj_RemainsLithogragh_A_02_1822262999", this->param.x) )
  {
    if (giant_ball1 && !lithograph1 && !(this->flags & 0x40000))
      setFlag("MainField_DgnObj_RemainsLithogragh_A_02_789666109", true);
    if (giant_ball2 && !lithograph2 && !(this->flags & 0x40000))
      setFlag("MainField_DgnObj_RemainsLithogragh_A_02_2456751716", true);
    if (giant_ball3 && !lithograph3 && !(this->flags & 0x40000))
      setFlag("MainField_DgnObj_RemainsLithogragh_A_02_1822262999", true);
    if (!giant_dungeon && giant_ball1 && giant_ball2 && giant_ball3)
      setFlag("giant_dungeon", true);
  }

  if (flagIsSet("MainField_Weapon_Bow_071_2178255681"))
    setFlag("MainField_Weapon_Bow_071_2178255681", false);

  if (flagIsSet("BalladOfHeroes_Step02") && !flagIsSet("BalladOfHeroes_Step03"))
  {
    int defeatedCount =
      flagIsSet("Defeat_OneHitDungeon001") +
      flagIsSet("Defeat_OneHitDungeon002") +
      flagIsSet("Defeat_OneHitDungeon003") +
      flagIsSet("Defeat_OneHitDungeon004");

    bool defeatedNonLockedOneHitDungeon = !Lock_OneHitDungeon001 && Defeat_OneHitDungeon001;
    defeatedNonLockedOneHitDungeon |= !Lock_OneHitDungeon002 && Defeat_OneHitDungeon002;
    defeatedNonLockedOneHitDungeon |= !Lock_OneHitDungeon003 && Defeat_OneHitDungeon003;
    defeatedNonLockedOneHitDungeon |= !Lock_OneHitDungeon004 && Defeat_OneHitDungeon004;

    if ( defeatedNonLockedOneHitDungeon && defeatedCount >= 1 )
    {
      if (!flagIsSet("BalladOfHeroes_Step02_Dungeon01"))
        setFlag("BalladOfHeroes_Step02_Dungeon01", true);
      if ( defeatedCount >= 2 )
      {
        if (!flagIsSet("BalladOfHeroes_Step02_Dungeon02"))
          setFlag("BalladOfHeroes_Step02_Dungeon02", true);
        if ( defeatedCount >= 3 )
        {
          if (!flagIsSet("BalladOfHeroes_Step02_Dungeon03"))
            setFlag("BalladOfHeroes_Step02_Dungeon03", true);
          if (defeatedCount >= 4 && !flagIsSet("BalladOfHeroes_Step2_Dungeon4"))
            setFlag("BalladOfHeroes_Step2_Dungeon4", true);
        }
      }
    }
  }

  if (flagIsSet("IsGet_Armor_005_Head") &&
      flagIsSet("IsGet_Armor_005_Upper") &&
      flagIsSet("IsGet_Armor_005_Lower") &&
      !(this->flags & 0x40000))
  {
    setFlag("CompleteDungeon_Finish", true);
  }

  if (flagIsSet("NightStoneBreak") && !flagIsSet("NightStoneDungeonAppear"))
    setFlag("NightStoneBreak", false);

  if (flagIsSet("Animal_Forest_Finish") &&
      flagIsSet("HateeluMini_Treasure_Finish") &&
      flagIsSet("Thunder_Sword_Finish") &&
      flagIsSet("Relief_Landing_Finish") &&
      flagIsSet("TwoWheels_Finish") &&
      flagIsSet("Shadow_Sign_Finish") &&
      flagIsSet("MouthofDragon_Finish") &&
      flagIsSet("BloodyMoonRelief_Finish") &&
      flagIsSet("Rito_BrosRock_Finish"))
  {
    setFlag("Npc_Musician_Come", true);
  }
}