//==================================================================================
// Generic macrolike helper functions.
// Function names should be descriptive enough...
// Most of these can break badly if items, heros or abilities are remade from scratch
// in the Object Editor as new Ids would be assigned
// Just modify, dont delete and create a new one
// "Or" convert these to string comparisons, what probably should have been
// done at the first time...
//==================================================================================
function d2_HeroHasBow takes unit hero returns boolean
return UnitHasItemOfTypeBJ(hero, 'I00N') or UnitHasItemOfTypeBJ(hero, 'I01P') or UnitHasItemOfTypeBJ(hero, 'I00T') or UnitHasItemOfTypeBJ(hero, 'I02M') or UnitHasItemOfTypeBJ(hero, 'I02N') or UnitHasItemOfTypeBJ(hero, 'I02O') or UnitHasItemOfTypeBJ(hero, 'I02P') or UnitHasItemOfTypeBJ(hero, 'I02Q') or UnitHasItemOfTypeBJ(hero, 'I02R') or UnitHasItemOfTypeBJ(hero, 'I02S') or UnitHasItemOfTypeBJ(hero, 'I02T') or UnitHasItemOfTypeBJ(hero, 'I02U')
endfunction
function d2_IsAmazonNonRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'H006'
endfunction
function d2_IsAmazonRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'H00M'
endfunction
function d2_IsBarbarianNonRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'O000'
endfunction
function d2_IsBarbarianRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'O003'
endfunction
function d2_IsPaladinNonRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'H005'
endfunction
function d2_IsPaladinRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'H00N'
endfunction
function d2_IsSorceressNonRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'H007'
endfunction
function d2_IsSorceressRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'H00L'
endfunction
function d2_IsNecromancerNonRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'U000'
endfunction
function d2_IsNecromancerRanged takes unit hero returns boolean
return GetUnitTypeId(hero) == 'U009'
endfunction
function d2_IsHeroRanged takes unit hero returns boolean
return d2_IsAmazonRanged(hero) or d2_IsBarbarianRanged(hero) or d2_IsPaladinRanged(hero) or d2_IsSorceressRanged(hero) or d2_IsNecromancerRanged(hero)
endfunction
function d2_DeactivateRanged takes unit hero returns nothing
if (d2_IsAmazonRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01U', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "unrobogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01U', GetOwningPlayer(hero))
elseif (d2_IsBarbarianRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01O', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "unrobogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01O', GetOwningPlayer(hero))
elseif (d2_IsPaladinRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01S', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "unrobogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01S', GetOwningPlayer(hero))
elseif (d2_IsSorceressRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01T', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "unrobogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01T', GetOwningPlayer(hero))
elseif (d2_IsNecromancerRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01V', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "unrobogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01V', GetOwningPlayer(hero))
endif
endfunction
function d2_ActivateRanged takes unit hero returns nothing
if (d2_IsAmazonNonRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01U', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "robogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01U', GetOwningPlayer(hero))
elseif (d2_IsBarbarianNonRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01O', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "robogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01O', GetOwningPlayer(hero))
elseif (d2_IsPaladinNonRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01S', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "robogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01S', GetOwningPlayer(hero))
elseif (d2_IsSorceressNonRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01T', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "robogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01T', GetOwningPlayer(hero))
elseif (d2_IsNecromancerNonRanged(hero)) then
call SetPlayerAbilityAvailableBJ(true, 'A01V', GetOwningPlayer(hero))
call IssueImmediateOrderBJ(hero, "robogoblin")
call SetPlayerAbilityAvailableBJ(false, 'A01V', GetOwningPlayer(hero))
endif
endfunction
//======================================================================================
// Robogoblin removes temporary invulnerability so fix it
//======================================================================================
function d2_FixInvulnerable takes unit hero returns nothing
if (RectContainsUnit(gg_rct_Rogues_Camp, hero) or RectContainsUnit(gg_rct_Lut_Gholein, hero) or RectContainsUnit(gg_rct_Kurast_Docks, hero) or RectContainsUnit(gg_rct_Pandemonium_Fortress, hero)) then
call SetUnitInvulnerable(hero, true)
endif
endfunction
//======================================================================================
// Reset "ranged mode" when reloading the hero, reviving or creating a new hero
//======================================================================================
function d2_FixRangedHero takes unit hero returns nothing
if (d2_HeroHasBow(hero)) then
if (d2_IsHeroRanged(hero)) then
call d2_DeactivateRanged(hero)
loop
exitwhen GetUnitCurrentOrder(hero) != String2OrderIdBJ("unrobogoblin")
call TriggerSleepAction(RMaxBJ(bj_WAIT_FOR_COND_MIN_INTERVAL, 0.10))
endloop
endif
call d2_ActivateRanged(hero)
loop
exitwhen GetUnitCurrentOrder(hero) != String2OrderIdBJ("robogoblin")
call TriggerSleepAction(RMaxBJ(bj_WAIT_FOR_COND_MIN_INTERVAL, 0.10))
endloop
call d2_FixInvulnerable(hero)
endif
endfunction
//======================================================================================
// Searches hero, stash, backpack and horadric cube inventories for an item of the
// the given itemId, and based on arguments, create a new one and/or make the item
// invulnerable
//======================================================================================
function d2_FindQuestItem takes integer itemId, boolean createIfDoesntExist, boolean makeInvulnerable returns item
// Check first hero inventory
local item questItem = GetItemOfTypeFromUnitBJ(udg_TheHeros[1], itemId)
// Check stash
if (questItem == null) then
set questItem = GetItemOfTypeFromUnitBJ(udg_PlayerStashes[1], itemId)
// Check backpack
if (questItem == null) then
set questItem = GetItemOfTypeFromUnitBJ(udg_Backpacks[1], itemId)
// Check Horadric Cube
if (questItem == null and udg_HoradricCubes[1] != null) then
set questItem = GetItemOfTypeFromUnitBJ(udg_HoradricCubes[1], itemId)
endif
endif
endif
if (questItem == null and createIfDoesntExist == true) then
call CreateItemLoc(itemId, GetRectCenter(gg_rct_Chests))
set questItem = GetLastCreatedItem()
endif
if (questItem != null and makeInvulnerable == true) then
call SetItemInvulnerableBJ(questItem, true)
endif
return questItem
endfunction
function d2_KillChamberRocks takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
//======================================================================================
// To be called after setting the quests states based on the data on the game cache,
// only once and only at game startup, and after map initialization.
// This function synchronizes the game state with the quest states information loaded
// from the game cache
//======================================================================================
function d2_FixQuests takes nothing returns nothing
local item questItem
// a1q1 - Den of Evil
if (IsQuestDiscovered(udg_Quests[0]) == true) then
// Make Corpsefire vulnerable
call SetUnitInvulnerable(gg_unit_n00I_0038, false)
if (IsQuestCompleted(udg_Quests[0]) == false) then
// Allow finishing the quest
call EnableTrigger(gg_trg_Den_of_Evil_Enter_Den_of_Evil)
else
// Flavie's intro doesn't need to be updated as it is stored in the
// game cache
// Disable first time in Blood Moor event
call DisableTrigger(gg_trg_Blood_Moor_Event)
endif
endif
// a1q2 - Sisters Burial Ground
if (IsQuestDiscovered(udg_Quests[1]) == true) then
// Make Blood Raven vulnerable
call SetUnitInvulnerable(gg_unit_n00K_0037, false)
if (IsQuestCompleted(udg_Quests[1]) == false) then
// Allow finishing the quest
call EnableTrigger(gg_trg_Sisters_Burial_Ground_Taunt)
call EnableTrigger(gg_trg_Sisters_Burial_Ground_Blood_Raven_Dies)
else
// Allow hiring Rogue Scouts
call UnitAddAbilityBJ('Aneu', gg_unit_h003_0036)
// This is the only special case so far where the gossips are enabled
// based on the quest state, other special case is the information about
// Act1 Deckard Cain gossip change
if (IsQuestCompleted(udg_Quests[5]) == true or udg_QuestsStateHint[5] != 1) then
call TriggerExecute(gg_trg_Sisters_Burial_Grounds_Enable_Kashya_Gossip)
endif
// Disable Burial Grounds event
call DisableTrigger(gg_trg_Burial_Grounds_Event)
endif
endif
/// XXX a1q3 must have been finished before allowing saving a game,
/// must talk to Cain to save the game cache, so it avoids some possible problems
/// with saving when not in town, or some quests in a "non stable" state to save
// a1q3 - Search Cain
if (IsQuestCompleted(udg_Quests[2]) == true) then
// Disable discover alternate
call QueuedTriggerRemoveBJ(gg_trg_Search_Cain_Discover_Alternate)
call DisableTrigger(gg_trg_Search_Cain_Discover_Alternate)
// Disable Stones and Tree events
call QueuedTriggerRemoveBJ(gg_trg_Cairn_Stones_Event)
call DisableTrigger(gg_trg_Cairn_Stones_Event)
call QueuedTriggerRemoveBJ(gg_trg_Tree_of_Inifuss_Event)
call DisableTrigger(gg_trg_Tree_of_Inifuss_Event)
// Create Tristram red portal
call CreateNUnitsAtLoc(1, 'n001', Player(8), PolarProjectionBJ(GetRectCenter(gg_rct_Cairn_Stones), 100.00, 120.00), bj_UNIT_FACING)
call WaygateSetDestinationLocBJ(GetLastCreatedUnit(), GetRectCenter(gg_rct_Tristram_Portal))
call WaygateSetDestinationLocBJ(gg_unit_n001_0017, GetRectCenter(gg_rct_Cairn_Stones))
call WaygateActivateBJ(true, GetLastCreatedUnit())
call WaygateActivateBJ(true, gg_unit_n001_0017)
// Make Andariel vulnerable
call SetUnitInvulnerable(gg_unit_N00R_0245, false)
endif
// a1q4 - The Forgotten Tower
if (IsQuestDiscovered(udg_Quests[3]) == true) then
// Update animation and destroy SFX
// XXX FIXME if a more apropriate unit is made, instead of
// Book of Summoning Pedestal
call SetUnitAnimation(gg_unit_nbsm_0026, "stand second")
call DestroyEffectBJ(udg_SpeechStaticSFX[0])
// Disable normal discover by "talking" to tome
call DisableTrigger(gg_trg_The_Forgotten_Tower_Discover)
// Disable alternate discover
call QueuedTriggerRemoveBJ(gg_trg_The_Forgotten_Tower_Discover_Alternate)
call DisableTrigger(gg_trg_The_Forgotten_Tower_Discover_Alternate)
if (IsQuestCompleted(udg_Quests[3]) == false) then
if (udg_QuestsStateHint[3] != 1) then
// Enable the setto NotFinished trigger
call EnableTrigger(gg_trg_The_Forgotten_Tower_Enter_Forgotten_Tower)
endif
// Allow finishing the quest
call EnableTrigger(gg_trg_The_Forgotten_Tower_Countess_Dies)
call EnableTrigger(gg_trg_The_Forgotten_Tower_Taunt)
endif
endif
// a1q5 - Tools of the Trade
if (IsQuestDiscovered(udg_Quests[4]) == true) then
// Disable alternate discover
call QueuedTriggerRemoveBJ(gg_trg_Tools_of_the_Trade_Discover_Alternate)
call DisableTrigger(gg_trg_Tools_of_the_Trade_Discover_Alternate)
call DisableTrigger(gg_trg_Monastery_Gate_Event)
if (IsQuestCompleted(udg_Quests[4]) == false) then
if (udg_QuestsStateHint[4] != 1) then
// Enable the setto NotFinished trigger
call EnableTrigger(gg_trg_Tools_of_the_Trade_Enter_Barracks)
endif
// Allow finishing the quest
call EnableTrigger(gg_trg_Tools_of_the_Trade_Taunt)
// If doesn't already have Horadric Malus in inventories
if (d2_FindQuestItem('I00A', false, true) == null) then
call EnableTrigger(gg_trg_Tools_of_the_Trade_Malus)
else
call SetUnitAnimation(gg_unit_h01L_0339, "death")
endif
else
// Play Malus stand "death" animation
call SetUnitAnimation(gg_unit_h01L_0339, "death")
// Create Imbue Dialog
call TriggerExecute(gg_trg_Tools_of_the_Trade_Build_Imbue_Dialog)
endif
endif
// a1q6 - Sisters to the Slaughter
if (IsQuestDiscovered(udg_Quests[5]) == true) then
// Disable alternate discover
call QueuedTriggerRemoveBJ(gg_trg_Sisters_to_the_Slaughter_Discover_Alternate)
call DisableTrigger(gg_trg_Sisters_to_the_Slaughter_Discover_Alternate)
call DisableTrigger(gg_trg_First_time_in_Jail)
if (IsQuestCompleted(udg_Quests[5]) == false) then
if (udg_QuestsStateHint[5] != 1) then
// Enable the setto NotFinished trigger
call EnableTrigger(gg_trg_Sisters_to_the_Slaughter_Enter_Catacombs)
else
call DisableTrigger(gg_trg_First_time_in_Catacombs)
endif
// Allow finishing the quest
call EnableTrigger(gg_trg_Sisters_to_the_Slaughter_Taunt)
call EnableTrigger(gg_trg_Sisters_to_the_Slaughter_Andariel_Dies)
endif
// Changed from if quest completed, as the game cache can be saved
// after killing Andariel, but before going East, i.e. quest is marked
// as completed when arriving in Lut Gholein
if (udg_SpeechQuestFlags[5] == 10) then
// Create the Travel Dialogs
call TriggerExecute(gg_trg_Create_Travel_Dialogs)
endif
endif
// a2q1 - Radament Lair
if (IsQuestDiscovered(udg_Quests[6]) == true) then
// Make Radament vulnerable
call SetUnitInvulnerable(gg_unit_n00T_0256, false)
call EnableTrigger( gg_trg_Radament_Lair_Mummy)
call DisableTrigger(gg_trg_Sewers_Event)
if (IsQuestCompleted(udg_Quests[6]) == false) then
if (udg_QuestsStateHint[6] != 1) then
// Enable the setto NotFinished trigger
call EnableTrigger(gg_trg_Radament_Lair_Enter_Sewers)
endif
// Allow finishing the quest
call EnableTrigger(gg_trg_Radament_Lair_Taunt)
call EnableTrigger(gg_trg_Radament_Lair_Radament_Dies)
else
// If a2q6 isn't available yet, this trigger will synch state
call ConditionalTriggerExecute(gg_trg_Talk_To_Jerhyn)
endif
endif
// a2q2 - The Horadric Staff
if (IsQuestDiscovered(udg_Quests[7]) == true) then
// If hero has scroll, remove it as it isn't required anymore
set questItem = d2_FindQuestItem('I00B', false, false)
if (questItem != null) then
call RemoveItem(questItem)
endif
// Disable alternate discover
call QueuedTriggerRemoveBJ(gg_trg_The_Horadric_Staff_Discover_Alternate)
call DisableTrigger(gg_trg_The_Horadric_Staff_Discover_Alternate)
if (IsQuestCompleted(udg_Quests[7]) == false) then
// If did not yet find Horadric Cube
// checking for the cube item directly as it is/must be loaded before this
// function is called
if (udg_HoradricCubeItems[1] == null) then
call EnableTrigger(gg_trg_The_Horadric_Staff_Acquire_Cube)
endif
// Player has a Horadric Shaft?
if (d2_FindQuestItem('I00D', false, true) == null) then
call EnableTrigger(gg_trg_The_Horadric_Staff_Shaft)
call EnableTrigger(gg_trg_The_Horadric_Staff_Acquire_Shaft)
endif
// Player has a Horadric Amulet?
if (d2_FindQuestItem('I00E', false, true) == null) then
call EnableTrigger(gg_trg_The_Horadric_Staff_Amulet)
call EnableTrigger(gg_trg_The_Horadric_Staff_Acquire_Amulet)
endif
// Enable the Deckard Cain message after transmuting the Horadric Staff
call EnableTrigger(gg_trg_The_Horadric_Staff_Acquire_Staff)
endif
// XXX Changed to not check for quest already finished, just in case somehow
// it has been destroyed, should not be possible as the object is invulnerable
// (but some bug not yet found may make it vulnerable), and also for the very
// minimal players (probably only me...) that may have played and have a saved
// BETA4 gamecache, where the boolean value wasn't stored, so it is possible to
// find a new one (in which case 2 items will exist during one game, but no
// harm, and fixed when saved/reloaded again).
if (udg_HoradricCubeItems[1] == null) then
call EnableTrigger(gg_trg_The_Horadric_Staff_Cube)
endif
endif
// If did not talk to Drogan after the Tainted Sun trigger, quest isn't marked
// as discovered
// QuestsStateHint[8] should be 3 now, if the player saved the game before
// talking to Drognan so the trigger will be still effective, otherwise, if
// talked to Drognan and actually marked quest as Discovered, fog change is
// done again below.
// a2q3 - The Tainted Sun
if (IsQuestDiscovered(udg_Quests[8]) == true) then
// Disable the fog change trigger before discover
call QueuedTriggerRemoveBJ(gg_trg_The_Tainted_Sun_Trigger)
call DisableTrigger(gg_trg_The_Tainted_Sun_Trigger)
// Make altar vulnerable
call SetUnitInvulnerable(gg_unit_n015_0476, false)
if (IsQuestCompleted(udg_Quests[8]) == true) then
// If a2q6 isn't available yet, this trigger will synch state
call ConditionalTriggerExecute(gg_trg_Talk_To_Jerhyn)
else
// Repeat the fog changes...
call TriggerExecute(gg_trg_Turn_Off_Fog_Triggers)
call SetTerrainFogExBJ(0, 500.00, 1800.00, 100.00, 0.00, 0.00, 0.00)
if (udg_QuestsStateHint[8] != 1) then
// Enable the setto NotFinished trigger
call EnableTrigger(gg_trg_The_Tainted_Sun_Enter_Claw_Viper_Temple)
endif
// Enables finishing the quest
call EnableTrigger(gg_trg_The_Tainted_Sun_Claw_Viper_Altar_Dies)
endif
endif
// a2q4 - The Arcane Sanctuary
if (IsQuestDiscovered(udg_Quests[9]) == true) then
// Just enable creating the blue portal by killing the lever
call EnableTrigger(gg_trg_The_Arcane_Sanctuary_Enable_Lever)
// Need to talk to the Tome again to open a new red portal
call EnableTrigger(gg_trg_The_Arcane_Sanctuary_Completion)
// Flag is set to 3 to know already allowed entering palace, but since the
// game is being reloaded, set it to 2, so the trigger can set it back to 3...
// but the conditions will be true; the other conditions don't need
// any update for the game reload
// Note that index 11 is The Seven Tombs quest, but The Arcane Sanctuary
// must have been discovered to allow entering the palace anyway, so check
// here; both, The Arcane Sanctuary and The Seven Tombs must have been
// discovered to enter the palace, and the flag is used only to avoid
// repeating some operations
if (udg_SpeechQuestFlags[11] == 3) then
set udg_SpeechQuestFlags[11] = 2
endif
// Check if, from already loaded data, already did the required procedures
// to enter the Palace
call ConditionalTriggerExecute(gg_trg_The_Seven_Tombs_Check_if_Can_Enter_Palace)
if (IsQuestCompleted(udg_Quests[9]) == false) then
if (udg_QuestsStateHint[9] != 1) then
call EnableTrigger(gg_trg_The_Arcane_Sanctuary_Enter_Harem)
endif
// Enable finishing the quest or special events
call EnableTrigger(gg_trg_The_Arcane_Sanctuary_Enter_Arcane_Sanctuary)
call EnableTrigger(gg_trg_The_Arcane_Sanctuary_Elevators)
endif
endif
// a2q5 - The Summoner
// This quest is a lot related with The Arcane Sanctuary quest...
if (IsQuestDiscovered(udg_Quests[10]) == false and IsQuestDiscovered(udg_Quests[9]) == true) then
call EnableTrigger(gg_trg_The_Summoner_Taunt_and_Event)
call EnableTrigger(gg_trg_The_Summoner_Quest_Discover)
elseif (IsQuestDiscovered(udg_Quests[10]) == true and IsQuestCompleted(udg_Quests[10]) == false) then
if (udg_QuestsStateHint[10] != 1) then
// If not already triggered the setto NotFinished
call EnableTrigger(gg_trg_The_Summoner_Enter_Arcane_Sanctuary)
endif
// This trigger finishes the quest when the False Summoner is killed
call EnableTrigger(gg_trg_The_Summoner_The_False_Summoner_Dies)
endif
// a2q6 - The Seven Tombs
if (IsQuestDiscovered(udg_Quests[11]) == true) then
// Quest is marked as completed once arriving in Kurast Docks, so, even if
// already killed Duriel but did not go to Kurast Docks, may need to do it
// again if loading the game cache
// Already opened Tal Rasha's Chamber, remake portal
if (udg_QuestsStateHint[11] == 4) then
// Kill rocks and update animation
call EnumDestructablesInRectAll(gg_rct_Tal_Rashas_Tomb_Rocks, function d2_KillChamberRocks)
call SetUnitAnimation(gg_unit_nfrm_0703, "death")
call CreateNUnitsAtLoc(1, 'n000', Player(8), GetRectCenter(gg_rct_Tal_Rashas_Tomb_Rocks), bj_UNIT_FACING)
// call SetUnitVertexColorBJ(GetLastCreatedUnit(), 100, 100, 100, 100.00)
call WaygateSetDestinationLocBJ(GetLastCreatedUnit(), GetRectCenter(gg_rct_Tal_Rasha_Chamber_Transport_Region))
call WaygateActivateBJ(true, GetLastCreatedUnit())
call SetUnitInvulnerable(gg_unit_U00B_0698, false)
call EnableTrigger(gg_trg_The_Seven_Tombs_Taunt)
call EnableTrigger(gg_trg_The_Seven_Tombs_Duriel_Dies)
// If Jerhyn was left in the trigger Helper state, just taking to him
// should be enough to travel to Kurast Docks, without needing to kill
// Duriel again
if (SubStringBJ(udg_SpeechNPCState[8], 12, 12) == "H") then
set udg_QuestHelperTriggers[11] = gg_trg_The_Seven_Tombs_Jerhyn
endif
elseif (IsQuestCompleted(udg_Quests[11]) == false) then
call EnableTrigger(gg_trg_The_Seven_Tombs_False_Tomb_Event)
call EnableTrigger(gg_trg_The_Seven_Tombs_True_Tomb_Event)
// Will need to use the Horadric Staff to open Chamber
call EnableTrigger(gg_trg_The_Seven_Tombs_Open_Chamber)
call EnableTrigger(gg_trg_The_Seven_Tombs_Open_Chamber_Help)
endif
endif
// a3q1 - The Golden Bird
// If quest is discovered/completed, dont create a new Jade Figurine
if (IsQuestDiscovered(udg_Quests[12]) == true) then
call QueuedTriggerRemoveBJ(gg_trg_The_Golden_Bird_Create_The_Jade_Figurine)
call DisableTrigger(gg_trg_The_Golden_Bird_Create_The_Jade_Figurine)
call DestroyEffectBJ(udg_SpeechStaticSFX[3])
// XXX Not tested, should work, just don't save the game in the interval
// if it doesn't work...
if (IsQuestCompleted(udg_Quests[12]) == false) then
if (d2_FindQuestItem('I00O', false, true) != null) then
// Hero has the Jade Figurine, so did not yet talk to proper npcs to
// trade it for The Golden Bird
if (SubStringBJ(udg_SpeechNPCState[25], 13, 13) == "H") then
set udg_QuestHelperTriggers[12] = gg_trg_The_Golden_Bird_Cain
elseif (SubStringBJ(udg_SpeechNPCState[19], 13, 13) == "H") then
set udg_QuestHelperTriggers[12] = gg_trg_The_Golden_Bird_Meshif
elseif (SubStringBJ(udg_SpeechNPCState[23], 13, 13) == "H") then
// Did everything right, but did not yet listen to Alkor intro
set udg_QuestHelperTriggers[12] = gg_trg_The_Golden_Bird_Alkor
endif
elseif (d2_FindQuestItem('I008', false, true) != null) then
// Hero has the The Golden Bird so did not yet talk to Alkor
if (SubStringBJ(udg_SpeechNPCState[23], 13, 13) == "H") then
set udg_QuestHelperTriggers[12] = gg_trg_The_Golden_Bird_Alkor_Receives_Bird
endif
endif
endif
endif
// Doesn't need to discover Golden Bird quest, just a hint that already saw
// Act 3 Wanderer once
if (udg_QuestsStateHint[12] == 5) then
call QueuedTriggerRemoveBJ(gg_trg_Act3_Wanderer)
call DisableTrigger(gg_trg_Act3_Wanderer)
call SetUnitPositionLoc(gg_unit_n01H_0864, GetRectCenter(gg_rct_HeroSelection))
call ShowUnitHide(gg_unit_n01H_0864)
endif
// a3q2 - Blade of the Old Religion
if (IsQuestDiscovered(udg_Quests[13]) == true) then
// Disable the alternate discover
call QueuedTriggerRemoveBJ(gg_trg_Blade_of_the_Old_Religion_Discover_Alternate)
call DisableTrigger(gg_trg_Blade_of_the_Old_Religion_Discover_Alternate)
// If hero doesn't have The Gidbin in inventories
if (IsQuestCompleted(udg_Quests[13]) == false) then
if (d2_FindQuestItem('I00Q', false, true) == null) then
if (udg_QuestsStateHint[13] != 1) then
// If not already triggered the setto NotFinished
call EnableTrigger(gg_trg_Blade_of_the_Old_Religion_Enter_Flayer_Jungle)
endif
call EnableTrigger(gg_trg_Blade_of_the_Old_Religion_Activate)
else
// XXX This is basically a copy of the "Blade of the Old Religion Pick Gidbin"
// trigger, but without the cinematic sequence and setting the NPC states,
// that *must* be reloaded correctly, otherwise player won't receive rewards
set udg_QuestHelperTriggers[13] = gg_trg_Blade_of_the_Old_Religion_Ormus
endif
endif
endif
// a3q3 - Khalims Will
if (IsQuestDiscovered(udg_Quests[14]) == true) then
// Disable the alternate discover
call QueuedTriggerRemoveBJ(gg_trg_Khalims_Will_Discover_Alternate)
call DisableTrigger(gg_trg_Khalims_Will_Discover_Alternate)
// make sure destructibles can be killed, but triggers that create items
// are only enabled if hero doesn't already have the corresponding item
call SetDestructableInvulnerableBJ(gg_dest_B002_11027, false)
call SetDestructableInvulnerableBJ(gg_dest_B002_11022, false)
call SetDestructableInvulnerableBJ(gg_dest_B002_11004, false)
// If quest already completed or if already found heart or if already
// transmuted Khalim's Will
if (IsQuestCompleted(udg_Quests[14]) == true or d2_FindQuestItem('I00S', false, true) != null or d2_FindQuestItem('I00Y', false, true) != null) then
call DisableTrigger(gg_trg_Sewers_Act3_Event)
endif
if (IsQuestCompleted(udg_Quests[14]) == false) then
// If doesn't already have Khalim's Will
if (d2_FindQuestItem('I00Y', false, true) == null) then
// Did not yet find Eye?
if (d2_FindQuestItem('I00P', false, true) == null) then
call EnableTrigger(gg_trg_Khalims_Will_Eye)
call EnableTrigger(gg_trg_Khalims_Will_Acquire_Eye)
endif
// Did not yet find Brain?
if (d2_FindQuestItem('I00R', false, true) == null) then
call EnableTrigger(gg_trg_Khalims_Will_Brain)
call EnableTrigger(gg_trg_Khalims_Will_Acquire_Brain)
endif
// Did not yet find Heart?
if (d2_FindQuestItem('I00S', false, true) == null) then
call EnableTrigger(gg_trg_Khalims_Will_Heart)
call EnableTrigger(gg_trg_Khalims_Will_Acquire_Heart)
endif
// Did not yet find Flail?
if (d2_FindQuestItem('I00X', false, true) == null) then
call EnableTrigger(gg_trg_Khalims_Will_Flail)
call EnableTrigger(gg_trg_Khalims_Will_Acquire_Flail)
// Enable hint message that needs Khalim's Will to enter Durance of Hate
call EnableTrigger(gg_trg_Khalims_Will_Destroy_Compelling_Orb_Help)
else
// Enable hint message that needs Khalim's Will to enter Durance of Hate
call EnableTrigger(gg_trg_Khalims_Will_Destroy_Compelling_Orb_Help)
// Has Flail, enable trigger for Khalim's Will
call EnableTrigger(gg_trg_Khalims_Will_Acquire_Khalims_Will)
endif
else
// Has Khalim's Will but quest isn't finished; allow finishing the quest
call EnableTrigger(gg_trg_Khalims_Will_Destroy_Compeling_Orb)
endif
else
// Need to allow entering Durance, as player may not have enabled
// Durance of Hate Waypoint
// XXX should use some common code, instead of duplicating...
call CreateNUnitsAtLoc(1, 'n000', Player(8), GetRectCenter(gg_rct_Durance_Gate), bj_UNIT_FACING)
call WaygateSetDestinationLocBJ(GetLastCreatedUnit(), GetUnitLoc(gg_unit_n000_1127))
call WaygateActivateBJ(true, GetLastCreatedUnit())
// call SetUnitVertexColorBJ(gg_unit_n000_1127, 100, 100, 100, 100.00)
// call SetUnitVertexColorBJ(GetLastCreatedUnit(), 100, 100, 100, 100.00)
call CreateTextTagLocBJ("Durance of Hate", GetRectCenter(GetPlayableMapRect()), 0.00, 10.00, 100, 100, 100, 0)
call SetTextTagPosBJ(GetLastCreatedTextTag(), PolarProjectionBJ(GetUnitLoc(GetLastCreatedUnit()), (I2R(StringLength("Durance of Hate")) * 8.00), 180.00), 150.00)
set udg_FloatingTextsCount = udg_FloatingTextsCount + 1
set udg_FloatingTexts[udg_FloatingTextsCount] = GetLastCreatedTextTag()
call ShowTextTagForceBJ(true, GetLastCreatedTextTag(), GetPlayersAll())
call CreateTextTagLocBJ("Travincal", GetRectCenter(GetPlayableMapRect()), 0.00, 10.00, 100, 100, 100, 0)
call SetTextTagPosBJ(GetLastCreatedTextTag(), PolarProjectionBJ(GetUnitLoc(gg_unit_n000_1127), (I2R(StringLength("Travincal")) * 8.00), 180.00), 150.00)
set udg_FloatingTextsCount = udg_FloatingTextsCount + 1
set udg_FloatingTexts[udg_FloatingTextsCount] = GetLastCreatedTextTag()
call ShowTextTagForceBJ(true, GetLastCreatedTextTag(), GetPlayersAll())
// Make Mephisto vulnerable
call SetUnitInvulnerable(gg_unit_U00G_1125, false)
// Kill the Compeling Orb
call KillUnit(gg_unit_n01S_1105)
// If did not yet discover a3q6...
if (IsQuestDiscovered(udg_Quests[17]) == true) then
call EnableTrigger(gg_trg_Durance_of_Hate_Event)
endif
endif
endif
// a3q4 - Lam Esens Tome
if (IsQuestDiscovered(udg_Quests[15]) == true) then
// This quest is only available when completing the Blade of Old Religion Quest
// so, not much special handling needs to be done...
if (IsQuestCompleted(udg_Quests[15]) == false) then
// If doesn't already have Lam Esen's Tome in inventories
if (d2_FindQuestItem('I00W', false, true) == null) then
call EnableTrigger(gg_trg_Lam_Esens_Tome_Activate)
else
// Update animation
call SetUnitAnimation( gg_unit_nbsm_1078, "stand second")
endif
if (udg_QuestsStateHint[15] != 1) then
// If not already triggered the setto NotFinished
call EnableTrigger(gg_trg_Lam_Esens_Tome_Enter_Kurast_Bazaar)
endif
else
// Update speech strings
call TriggerExecute(gg_trg_Lam_Esens_Tome_Update_Speech_Strings)
endif
endif
// a3q5 - The Blackened Temple
if (IsQuestDiscovered(udg_Quests[16]) == true) then
// Disable alternate discover
call QueuedTriggerRemoveBJ(gg_trg_The_Blackened_Temple_Discover_Alternate)
call DisableTrigger(gg_trg_The_Blackened_Temple_Discover_Alternate)
if (IsQuestCompleted(udg_Quests[16]) == false) then
// Allow finishing the quest
if (udg_QuestsStateHint[16] != 1) then
// If not already triggered the setto NotFinished
call EnableTrigger(gg_trg_The_Blackened_Temple_Enter_Travincal_Event)
endif
call EnableTrigger(gg_trg_The_Blackened_Temple_Council_Member_Dies)
endif
// XXX Otherwise, just have fun farming the Council Members...
endif
// a3q6 - The Guardian
if (IsQuestDiscovered(udg_Quests[17]) == true) then
// Disable alternate discover
call QueuedTriggerRemoveBJ(gg_trg_The_Guardian_Discover_Alternate)
call DisableTrigger(gg_trg_The_Guardian_Discover_Alternate)
if (IsQuestCompleted(udg_Quests[17]) == false) then
if (udg_QuestsStateHint[17] != 1) then
// If not already triggered the setto NotFinished
call EnableTrigger(gg_trg_The_Guardian_Seto_NotFinished)
endif
// Mephisto is already made vulnerable if Khalim's Will quest is finished
// and it must have been finished
call EnableTrigger(gg_trg_The_Guardian_Mephisto_Dies)
else
// Quest was completed in a previous game, create portal
call CreateNUnitsAtLoc(1, 'n001', Player(8), GetRectCenter(gg_rct_Durance_Red_Portal), bj_UNIT_FACING)
call WaygateSetDestinationLocBJ(GetLastCreatedUnit(), GetRectCenter(gg_rct_Act_4_Revive_Point))
call WaygateActivateBJ(true, GetLastCreatedUnit())
endif
// XXX Enable this regardless of already finished, as Mephisto is alive when
// loading a game cache...
call EnableTrigger(gg_trg_The_Guardian_Taunt)
endif
// a4q1 - The Fallen Angel
if (IsQuestDiscovered(udg_Quests[18]) == true) then
// There is not alternate discover, must talk to Tyrael
// Make Izual vulnerable
call SetUnitInvulnerable(gg_unit_E003_1200, false)
// Like the Mephisto taunt, this doesn't need quest not finished
call EnableTrigger(gg_trg_The_Fallen_Angel_Taunt)
if (IsQuestCompleted(udg_Quests[18]) == false) then
if (udg_QuestsStateHint[18] != 1) then
// If not already triggered the setto NotFinished
call EnableTrigger(gg_trg_The_Fallen_Angel_Enter_Plains_of_Despair)
endif
call EnableTrigger(gg_trg_The_Fallen_Angel_Dies)
endif
endif
// a4q2 - The Hellforge
if (IsQuestDiscovered(udg_Quests[19]) == true) then
// Make Hephasto vulnerable
call SetUnitInvulnerable(gg_unit_n023_1267, false)
call EnableTrigger(gg_trg_The_Hellforge_Taunt)
if (IsQuestCompleted(udg_Quests[19]) == false) then
// There isn't really a reason to not allow duplicated Hellforge Hammers,
// but for consistency...
if (d2_FindQuestItem('I010', false, true) == null) then
call EnableTrigger(gg_trg_The_Hellforge_Hammer)
endif
call EnableTrigger(gg_trg_The_Hellforge_Position_Soulstone)
set udg_Soulstone = d2_FindQuestItem('I00Z', true, true)
if (RectContainsItem(udg_Soulstone, gg_rct_Chests) == true) then
// Soulstone item has been created now...
// Move it to an accessible position
call SetItemPositionLoc(udg_Soulstone, GetRectCenter(gg_rct_Act_4_Revive_Point))
endif
endif
// Impossible condition, unless saving without talking to Cain...
// elseif (udg_PlayerAct[1] == 4)
// Helper to discover The Hellforge quest
// if (IsQuestDiscovered(udg_Quests[19]) == false) then
// set udg_QuestHelperTriggers[19] = gg_trg_The_Hellforge_Discover
// endif
endif
// a4q3 - Terrors End
if (IsQuestDiscovered(udg_Quests[20]) == true) then
// Disable alternate discover
call QueuedTriggerRemoveBJ(gg_trg_The_Terrors_End_Discover_Alternate)
call DisableTrigger(gg_trg_The_Terrors_End_Discover_Alternate)
// XXX Cannot save the game once this quest is finished, but it doesn't
// matter...
// Allow finishing the quest
call EnableTrigger(gg_trg_The_Terrors_End_Seals)
call EnableTrigger(gg_trg_The_Terrors_End_Taunt)
endif
// Moooo
if (IsQuestCompleted(udg_Quests[21]) == true) then
call DisableTrigger(gg_trg_MooMooFarmEnter)
endif
endfunction
//======================================================================================
// Helper function to transfer items from a loaded "item storage unit" to the already
// created stash/backpack at map initialization
//======================================================================================
function d2_SwapItems takes unit from, unit to returns nothing
local integer index = 1
loop
exitwhen index > bj_MAX_INVENTORY
// XXX The function returns false when no item is available?
// anyway it is a noop if no item exists in the inventory...
call UnitAddItemSwapped(UnitItemInSlotBJ(from, index), to)
set index = index + 1
endloop
endfunction
//======================================================================================
// Helper/callbacks for the Chaos Seals interation
//======================================================================================
function d2_filter_CheckIfIsChaosSeal takes nothing returns boolean
return (GetUnitTypeId(GetFilterUnit()) == 'u00H')
endfunction
function d2_action_SetChaosSealAnimation takes nothing returns nothing
call SetUnitAnimation(GetEnumUnit(), "stand upgrade second")
endfunction
//======================================================================================
// The main load game cache function
//======================================================================================
function d2_LoadGame takes string cacheName, boolean onlyCheckIfExists returns boolean
local integer index
local string questState
local string gossipState
// Load cache
call InitGameCacheBJ(cacheName)
set udg_GameCache = GetLastCreatedGameCacheBJ()
if (udg_GameCache == null or GetStoredBooleanBJ("Available", "Game", udg_GameCache) == false) then
if (onlyCheckIfExists == false) then
call DisplayTextToForce(GetPlayersAll(), "c|ffff0000Failed to load game cache \"" + cacheName + "\"|r")
endif
return false
elseif (onlyCheckIfExists == true) then
return true
endif
// Show Load window
call DialogClearBJ(udg_SaveLoadWindow)
call DialogSetMessageBJ(udg_SaveLoadWindow, "Loading game cache...")
call DialogDisplayBJ(true, udg_SaveLoadWindow, Player(0))
// Player act
set udg_PlayerAct[1] = GetStoredIntegerBJ("Act", "Hero", udg_GameCache)
// Hero unit
call RestoreUnitLocFacingAngleBJ("Unit", "Hero", udg_GameCache, Player(0), GetRectCenter(gg_rct_HeroSelection), bj_UNIT_FACING)
// Update variables used to handle hero events
set udg_TheHeros[1] = GetLastRestoredUnitBJ()
call GroupAddUnitSimple(udg_TheHeros[1], udg_PlayingHeros)
// Equiped items state
set udg_EquipArmor[1] = GetStoredIntegerBJ("Armor", "Hero", udg_GameCache)
set udg_EquipShield[1] = GetStoredIntegerBJ("Shield", "Hero", udg_GameCache)
set udg_EquipWeapon[1] = GetStoredIntegerBJ("Weapon", "Hero", udg_GameCache)
// Mercenary
if (GetStoredBooleanBJ("Alive", "Mercenary", udg_GameCache)) then
set udg_Mercenaries[1] = RestoreUnitLocFacingAngleBJ("Unit", "Mercenary", udg_GameCache, Player(5), GetRectCenter(gg_rct_HeroSelection), bj_UNIT_FACING)
endif
// Moving the unit to the proper act should now trigger the proper extra init code
call SetUnitPositionLoc(udg_TheHeros[1], GetRectCenter(udg_StartRegions[udg_PlayerAct[1]]))
if (udg_Mercenaries[1] != null) then
call SetUnitPositionLoc(udg_Mercenaries[1], GetRectCenter(udg_StartRegions[udg_PlayerAct[1]]))
call GroupAddUnitSimple(udg_Mercenaries[1], udg_MercenaryGroup)
call SetPlayerStateBJ(Player(0), PLAYER_STATE_RESOURCE_FOOD_USED, 5)
endif
// Time of Day
call SetTimeOfDay(GetStoredRealBJ("TimeOfDay", "Game", udg_GameCache))
// Update fog
call TriggerExecute(udg_FogUpdate)
// Act 1 Rogues Encampment fire pit, just for coherence...
if (GetTimeOfDay() > 6 and GetTimeOfDay() < 18) then
call SetDoodadAnimationRectBJ("death", 'NOfp', gg_rct_Rogues_Camp)
endif
// Restore gold
call SetPlayerStateBJ(Player(0), PLAYER_STATE_RESOURCE_GOLD, GetStoredIntegerBJ("Gold", "Hero", udg_GameCache))
// For the stash/backpack, we only want the restored items as the objects must
// already been created at this time
// Stash
call RestoreUnitLocFacingAngleBJ("Stash", "Hero", udg_GameCache, Player(0), GetRectCenter(gg_rct_Chests), bj_UNIT_FACING)
// FIX: cannot swap items and kill last restored unit or will not have the
// the Horadric Cube ability properly set, so either add the ability, or swap
// the units instead of the items, better/easier to switch units
call KillUnit(udg_PlayerStashes[1])
set udg_PlayerStashes[1] = GetLastRestoredUnitBJ()
// Backpack
call RestoreUnitLocFacingAngleBJ("Backpack", "Hero", udg_GameCache, Player(0), GetRectCenter(gg_rct_Chests), bj_UNIT_FACING)
call d2_SwapItems(GetLastRestoredUnitBJ(), udg_Backpacks[1])
call KillUnit(GetLastRestoredUnitBJ())
// Horadric Cube
if (GetStoredBooleanBJ("Available", "HoradricCube", udg_GameCache)) then
call RestoreUnitLocFacingAngleBJ("Unit", "HoradricCube", udg_GameCache, Player(0), GetRectCenter(gg_rct_Chests), bj_UNIT_FACING)
if (GetLastRestoredUnitBJ() != null) then
// Player already had found the Horadric Cube, so restore it
set udg_HoradricCubes[1] = GetLastRestoredUnitBJ()
// Find the associated item, that may be anywhere, including the Horadric Cube
// or may be left in the special area if the Horadric Cube was open at save time
set udg_HoradricCubeItems[1] = d2_FindQuestItem('I00C', true, true)
if (RectContainsItem(udg_HoradricCubeItems[1], gg_rct_Chests) == true) then
// Player saved the game with Horadric Cube open, give it back to hero
call SetItemPositionLoc(udg_HoradricCubeItems[1], GetRectCenter(udg_StartRegions[udg_PlayerAct[1]]))
call UnitAddItemSwapped(udg_HoradricCubeItems[1], udg_TheHeros[1])
endif
// Abilities "added on the fly" aren't saved, so add again the
// Horadric Cube ones to the ChestInterface
// XXX If Horadric Cube object position is modified to be saved/restored
// emulating an reopen of the cube, modify here to check for that case
// and disable the abilities for the player, and the
// udg_HoradricCubeIsOpen[] value will also need to be set accordingly
call UnitAddAbilityBJ('A05T', udg_InterfaceChests[1])
call UnitAddAbilityBJ('A05S', udg_InterfaceChests[1])
endif
endif
// If player did not use all hero stat points...
set udg_HeroAvailableStats[1] = GetStoredIntegerBJ("Stats", "Hero", udg_GameCache)
call SetPlayerStateBJ(Player(0), PLAYER_STATE_RESOURCE_LUMBER, udg_HeroAvailableStats[1])
// Horadric Malus reward state
set udg_MalusReward[1] = GetStoredIntegerBJ("HoradricMalus", "Hero", udg_GameCache)
// Waypoints
set index = 0
loop
exitwhen index > 29
set udg_WaypointAvailable[index] = GetStoredBooleanBJ(I2S(index), "Waypoint", udg_GameCache)
// These sfxs aren't stored anywhere, and the town ones have a static sfx
if (udg_WaypointAvailable[index] == true and ModuloInteger(index, 9) != 0) then
call AddSpecialEffectLocBJ(OffsetLocation(GetUnitLoc(udg_WaypointObjects[index]), -100.00, 75.00), "Doodads\\LordaeronSummer\\Props\\TorchHumanOmni\\TorchHumanOmni.mdl")
call AddSpecialEffectLocBJ(OffsetLocation(GetUnitLoc(udg_WaypointObjects[index]), 120.00, -95.00), "Doodads\\LordaeronSummer\\Props\\TorchHumanOmni\\TorchHumanOmni.mdl")
endif
set index = index + 1
endloop
// Unique items map
set index = 0
loop
exitwhen index > udg_UniqueItemsCount
set udg_UniqueItemsMap[index] = GetStoredBooleanBJ("Unique" + I2S(index), "Item", udg_GameCache)
set index = index + 1
endloop
// NPC states
set index = 0
loop
exitwhen index > udg_NPCCount
// Intro/WellcomeBack and quest state of NPCs
set udg_SpeechNPCState[index] = GetStoredStringBJ("State" + I2S(index), "NPC", udg_GameCache)
// Intro message may change based on quests state
set udg_SpeechIntro[index] = GetStoredStringBJ("Intro" + I2S(index), "NPC", udg_GameCache)
set index = index + 1
endloop
// Gossips, for more details see save code...
set index = 0
loop
exitwhen index > 48
set udg_SpeechGossips[index] = GetStoredStringBJ("Gossip" + I2S(index), "NPC", udg_GameCache)
set index = index + 8
endloop
set index = 49
loop
exitwhen index > 192
set udg_SpeechGossips[index] = GetStoredStringBJ("Gossip" + I2S(index), "NPC", udg_GameCache)
set index = index + 13
endloop
set index = 193
loop
exitwhen index > 241
set udg_SpeechGossips[index] = GetStoredStringBJ("Gossip" + I2S(index), "NPC", udg_GameCache)
set index = index + 8
endloop
// Quests state
set questState = GetStoredStringBJ("State", "Quests", udg_GameCache)
if (questState != null) then
set index = 0
loop
exitwhen index > 21
set udg_SpeechQuestFlags[index] = GetStoredIntegerBJ("Flag" + I2S(index), "Quests", udg_GameCache)
set udg_QuestsStateHint[index] = GetStoredIntegerBJ("Hint" + I2S(index), "Quests", udg_GameCache)
// + means not yet discovered
if (SubStringBJ(questState, index + 1, index + 1) != "+") then
call QuestSetDiscoveredBJ(udg_Quests[index], true)
// x means completed
if (SubStringBJ(questState, index + 1, index + 1) == "x") then
call QuestSetCompletedBJ(udg_Quests[index], true)
endif
endif
set index = index + 1
endloop
endif
call d2_FixQuests()
// Gossip states.
// Restore after "fixing" quests, so that if already listened to some gossip
// that is modified based on quest states, will properly restore the game state
// and don't require the player to listen again to that gossip in a new game
// This should not conflict with the "about self" gossips restored above, or
// at worst, will just do the noop of setting an empty string to an empty string...
set gossipState = GetStoredStringBJ("GossipMap", "NPC", udg_GameCache)
if (gossipState != null) then
set index = 0
loop
exitwhen index > 266
// x means string was empty in previous game, otherwise, it is the initial
// value, or a value set when restoring the "about self" above, or some
// value set by a change in quests state.
if (SubStringBJ(gossipState, index + 1, index + 1) == "x") then
set udg_SpeechGossips[index] = ""
endif
set index = index + 1
endloop
endif
// Deckard Cain related information
set udg_SpeechHistoryIndex = GetStoredIntegerBJ("Act", "Cain", udg_GameCache)
// Cumulative updates up to Cain's Act
// In Act 2 or later
if (udg_SpeechHistoryIndex > 6) then
// Cain is initially an Act1 npc, but is now in Act 2 or later
set udg_NPCObjects[6] = null
// Palace fountain
if (IsQuestCompleted(udg_Quests[11]) == false) then
// XXX Actually, should not need to check for quest completed, as
// hero is restaured in Cain's act.
call SetDoodadAnimationRectBJ("stand third", 'YOsw', gg_rct_Palace)
endif
// Jerhyn can walk around if not in Intro state, also move to his region
// instead of waiting for the NPC timer to do it
if (SubStringBJ(udg_SpeechNPCState[8], 22, 22) != "!") then
set udg_NPCRegions[8] = gg_rct_Jerhyn
call SetUnitPositionLoc(gg_unit_h00K_0477, GetRectCenter(gg_rct_Jerhyn))
endif
endif
// In Act 3 or later
if (udg_SpeechHistoryIndex > 18) then
// Hratli can walk around if not in Intro state, also move to his region
// instead of waiting for the NPC timer to do it
if (SubStringBJ(udg_SpeechNPCState[20], 22, 22) != "!") then
set udg_NPCRegions[20] = gg_rct_Hratli
call SetUnitPositionLoc(gg_unit_h00Y_0874, GetRectCenter(gg_rct_Hratli))
endif
// Tyrael no longer in Tal Rasha's chamber
call SetUnitPositionLoc(gg_unit_E002_0699, GetRectCenter(gg_rct_Tyrael))
call DestroyEffectBJ(udg_SpeechStaticSFX[2])
endif
// Specific updates to Cain's Act
if (udg_SpeechHistoryIndex < 18) then
// Must only be able to save by talking to Cain
call SetUnitPositionLoc(udg_DeckardCain, GetRectCenter(gg_rct_Deckard_Cain_1))
elseif (udg_SpeechHistoryIndex < 25) then
set udg_NPCObjects[18] = gg_unit_h001_0035
call SetUnitPositionLoc(udg_DeckardCain, GetRectCenter(gg_rct_Deckard_Cain_2))
elseif (udg_SpeechHistoryIndex < 30) then
set udg_NPCObjects[25] = gg_unit_h001_0035
call SetUnitPositionLoc(udg_DeckardCain, GetRectCenter(gg_rct_Deckard_Cain_3))
else
set udg_NPCObjects[30] = gg_unit_h001_0035
call SetUnitPositionLoc(udg_DeckardCain, GetRectCenter(gg_rct_Deckard_Cain_4))
// Almost a duplication of the "First Time In Pandemonium Fortress" trigger
call DisableTrigger(gg_trg_First_Time_In_Pandemonium_Fortress)
// One could save in the countdown timer, so add this feature
if (IsQuestCompleted(udg_Quests[20]) == false) then
call SetWaterBaseColorBJ(100, 0.00, 0.00, 0)
call ForGroupBJ(GetUnitsInRectMatching(gg_rct_Chaos_Sanctuary, Condition(function d2_filter_CheckIfIsChaosSeal)), function d2_action_SetChaosSealAnimation)
endif
// Tyrael
set udg_NPCObjects[28] = gg_unit_E002_0699
call GroupAddUnitSimple(gg_unit_E002_0699, udg_NPCGroup)
// Natalya
call SetUnitPositionLoc(gg_unit_h01J_0272, GetRectCenter(gg_rct_HeroSelection))
call ShowUnitHide(gg_unit_h01J_0272)
endif
// Should only be possible to save game after saving Cain, so enable finding
// Wirt's leg if don't already have one in inventories
if (d2_FindQuestItem('wtlg', false, true) == null) then
call EnableTrigger(gg_trg_Find_Wirts_Leg)
endif
// Kill Deckard Cain's cage
call KillDestructable(gg_dest_LOcg_0922)
// Hide Load window
call DialogDisplayBJ(false, udg_SaveLoadWindow, Player(0))
return true
endfunction
//===========================================================================
// Just make sure the Battle Orders and Zeal pseudo buffs are not active, or
// they may be saved in the hero unit, and when reloading a game cache, would
// reload the hero unit with those life/mana/attack modifications
//===========================================================================
function d2_SaveGameCheckHero takes unit hero returns nothing
local integer index
if (hero == udg_Paladin) then
set index = 1
loop
exitwhen index > 5
call UnitRemoveAbilityBJ(udg_ZealGroup[index], udg_Paladin)
set index = index + 1
endloop
elseif (hero == udg_Barbarian) then
set index = 1
loop
exitwhen index > 5
call UnitRemoveAbilityBJ(udg_BOLifeGroup[index], udg_Barbarian)
call UnitRemoveAbilityBJ(udg_BOManaGroup[index], udg_Barbarian)
if (udg_Mercenaries[1] != null) then
call UnitRemoveAbilityBJ(udg_BOLifeGroup[index], udg_Mercenaries[1])
call UnitRemoveAbilityBJ(udg_BOManaGroup[index], udg_Mercenaries[1])
endif
set index = index + 1
endloop
endif
// Remove any other buff, doesn't matter if positive or negative...
call UnitRemoveBuffsBJ(bj_REMOVEBUFFS_ALL, hero)
if (udg_Mercenaries[1] != null) then
call UnitRemoveBuffsBJ(bj_REMOVEBUFFS_ALL, udg_Mercenaries[1])
endif
endfunction
//======================================================================================
// The main SaveGame function
//======================================================================================
function d2_SaveGame takes string cacheName returns boolean
local integer index
local string questState
local string gossipState
// Load game cache
call InitGameCacheBJ(cacheName)
set udg_GameCache = GetLastCreatedGameCacheBJ()
if (udg_GameCache == null) then
call DisplayTextToForce(GetPlayersAll(), "c|ffff0000Failed to save game cache \"" + cacheName + "\"|r")
return false
endif
// This must be done before showing the Save window as the dialog
// will actually pause the game
if (d2_IsHeroRanged(udg_TheHeros[1])) then
call d2_DeactivateRanged(udg_TheHeros[1])
loop
exitwhen GetUnitCurrentOrder(udg_TheHeros[1]) != String2OrderIdBJ("unrobogoblin")
call TriggerSleepAction(RMaxBJ(bj_WAIT_FOR_COND_MIN_INTERVAL, 0.10))
endloop
endif
// Disable any available gossips, as they have a 30 seconds timer anyway
// not really important, but for consistency
call TriggerExecute(gg_trg_Speech_Disable_Gossip)
// Show Save window
call DialogClearBJ(udg_SaveLoadWindow)
call DialogSetMessageBJ(udg_SaveLoadWindow, "Saving game cache...")
call DialogDisplayBJ(true, udg_SaveLoadWindow, Player(0))
// Time of Day
call StoreRealBJ(GetTimeOfDay(), "TimeOfDay", "Game", udg_GameCache)
// Save hero state/items
call d2_SaveGameCheckHero(udg_TheHeros[1])
call StoreUnitBJ(udg_TheHeros[1], "Unit", "Hero", udg_GameCache)
call StoreUnitBJ(udg_PlayerStashes[1], "Stash", "Hero", udg_GameCache)
call StoreUnitBJ(udg_Backpacks[1], "Backpack", "Hero", udg_GameCache)
// Horadric Cube must store a boolean also, or if creating again a game with
// a hero that already has one, will load the horadric cube from the previous
// character
if (udg_HoradricCubes[1] != null) then
call StoreUnitBJ(udg_HoradricCubes[1], "Unit", "HoradricCube", udg_GameCache)
endif
call StoreBooleanBJ(udg_HoradricCubes[1] != null, "Available", "HoradricCube", udg_GameCache)
// Skeletons and Valkyrie not saved
if (udg_Mercenaries[1] != null) then
call StoreUnitBJ(udg_Mercenaries[1], "Unit", "Mercenary", udg_GameCache)
endif
// The game cache doesn't allow saving a null unit, that is what I was
// expecting, so save this as a state that probably will be used when/if
// mercenaries are modified to LoD behaviour, and converted to heros
call StoreBooleanBJ(udg_Mercenaries[1] != null, "Alive", "Mercenary", udg_GameCache)
// Player's current gold
call StoreIntegerBJ(GetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD), "Gold", "Hero", udg_GameCache)
// Player current act town
// XXX This doesn't really need to be saved, as can be translated from Cain
// current Act, but will keep it in case the code is adapted to not depend
// on Decard Cain to save a game
call StoreIntegerBJ(udg_PlayerAct[1], "Act", "Hero", udg_GameCache)
// States controled by equiped item
call StoreIntegerBJ(udg_EquipArmor[1], "Armor", "Hero", udg_GameCache)
call StoreIntegerBJ(udg_EquipShield[1], "Shield", "Hero", udg_GameCache)
call StoreIntegerBJ(udg_EquipWeapon[1], "Weapon", "Hero", udg_GameCache)
// In case player did not use all the available stat points
call StoreIntegerBJ(udg_HeroAvailableStats[1], "Stats", "Hero", udg_GameCache)
// Horadric Malus reward state
call StoreIntegerBJ(udg_MalusReward[1], "HoradricMalus", "Hero", udg_GameCache)
// XXX Camera and fog, at least for the first version will be restored to default
// values, i.e. "smart camera" and fog enabled.
// Waypoints
set index = 0
loop
exitwhen index > 29
// Actually it is [33 * <player-number-with-0-being-player-1> + index]
call StoreBooleanBJ(udg_WaypointAvailable[index], I2S(index), "Waypoint", udg_GameCache)
set index = index + 1
endloop
// Unique items map
// Unlike normal Diablo II, will not allow dropping unique items again in a new game
set index = 0
loop
exitwhen index > udg_UniqueItemsCount
call StoreBooleanBJ(udg_UniqueItemsMap[index], "Unique" + I2S(index), "Item", udg_GameCache)
set index = index + 1
endloop
// Save NPC states
set index = 0
loop
exitwhen index > udg_NPCCount
call StoreStringBJ(udg_SpeechNPCState[index], "State" + I2S(index), "NPC", udg_GameCache)
// Intro message and state are used by some quests, so store related information
call StoreStringBJ(udg_SpeechIntro[index], "Intro" + I2S(index), "NPC", udg_GameCache)
set index = index + 1
endloop
// Only gossip about self is saved, as it may contain quest related information
// Act1 has 7 ncps
// Warriv about self is offset 0, Akara about self is offset 8 and so on
set index = 0
loop
exitwhen index > 48
call StoreStringBJ(udg_SpeechGossips[index], "Gossip" + I2S(index), "NPC", udg_GameCache)
set index = index + 8
endloop
// Act2 has 12 ncps
set index = 49
loop
exitwhen index > 192
call StoreStringBJ(udg_SpeechGossips[index], "Gossip" + I2S(index), "NPC", udg_GameCache)
set index = index + 13
endloop
// Act3 has 7 ncps
set index = 193
loop
exitwhen index > 241
call StoreStringBJ(udg_SpeechGossips[index], "Gossip" + I2S(index), "NPC", udg_GameCache)
set index = index + 8
endloop
// Act4 ncps don't have gossips about themselves, and probably will never have
// gossips that change state based on quest states either, so don't save
// anything
// Gossip states stored as a pseudo boolean, one character per gossip string
// stored as a string to allow possible extensions about states, and to make
// life easier, the states are only 267 bytes anyway, no need to create a bit
// field or such
// Values are:
// x Gossip string is empty, either NPC doesn't have that gossip, or player
// already listened to that gossip
// + Gossip is available
set index = 0
set gossipState = ""
loop
exitwhen index > 266
if (udg_SpeechGossips[index] == "") then
set gossipState = gossipState + "x"
else
set gossipState = gossipState + "+"
endif
set index = index + 1
endloop
call StoreStringBJ(gossipState, "GossipMap", "NPC", udg_GameCache)
// Quest states saved in a string format with character values:
// + quest is not discovered
// ! quest is not finished
// x quest is finished
// using a string to make life easier, and to allow extensions to store more states
set index = 0
set questState = ""
loop
exitwhen index > 21
call StoreIntegerBJ(udg_SpeechQuestFlags[index], "Flag" + I2S(index), "Quests", udg_GameCache)
call StoreIntegerBJ(udg_QuestsStateHint[index], "Hint" + I2S(index), "Quests", udg_GameCache)
if (IsQuestCompleted(udg_Quests[index]) == true) then
set questState = questState + "x"
elseif (IsQuestDiscovered(udg_Quests[index]) == true) then
set questState = questState + "!"
else
set questState = questState + "+"
endif
set index = index + 1
endloop
call StoreStringBJ(questState, "State", "Quests", udg_GameCache)
// Deckard Cain state is associated with "map history" state
call StoreIntegerBJ(udg_SpeechHistoryIndex, "Act", "Cain", udg_GameCache)
// If something weird happened earlier, should not get here, by weird I mean
// this function not completing, like by trying to deference an invalid pointer,
// and the game halting this function, or the game crashing, etc
// Just to know data is available, and it seems to be working...
call StoreBooleanBJ(true, "Available", "Game", udg_GameCache)
call SaveGameCacheBJ(udg_GameCache)
// Hide Save window
call DialogDisplayBJ(false, udg_SaveLoadWindow, Player(0))
// This must be done after hiding the Save window, as the dialog will
// actually pause the game
if (d2_HeroHasBow(udg_TheHeros[1])) then
call d2_ActivateRanged(udg_TheHeros[1])
loop
exitwhen GetUnitCurrentOrder(udg_TheHeros[1]) != String2OrderIdBJ("robogoblin")
call TriggerSleepAction(RMaxBJ(bj_WAIT_FOR_COND_MIN_INTERVAL, 0.10))
endloop
call d2_FixInvulnerable(udg_TheHeros[1])
endif
return true
endfunction
//======================================================================================
// Check game caches and build selection dialog
//======================================================================================
function d2_LoadGameDialog takes nothing returns nothing
local integer index = 0
local integer numCaches = 0
local string cacheName
local string dialogTitle = "|cffff0000Game Cache|r"
call DialogClearBJ(udg_GameCacheLoadDialog)
loop
exitwhen index > 4
set cacheName = udg_GameCachePrefix + udg_HeroClassNames[index] + ".w3v"
if (d2_LoadGame(cacheName, true) == true) then
set numCaches = numCaches + 1
call DialogAddButtonBJ(udg_GameCacheLoadDialog, udg_HeroClassNames[index])
set udg_GameCacheLoadButtons[index] = GetLastCreatedButtonBJ()
else
set udg_GameCacheLoadButtons[index] = null
set dialogTitle = dialogTitle + "|n" + udg_HeroClassNames[index]
endif
set index = index + 1
endloop
call DialogSetMessageBJ(udg_GameCacheLoadDialog, dialogTitle)
call DialogAddButtonBJ(udg_GameCacheLoadDialog, "Cancel")
if (numCaches > 0) then
call CameraSetupApplyForPlayer(true, gg_cam_HeroSelectionCamera, Player(0), 0.00)
set udg_GameCacheWaitingSelection = true
call DialogDisplayBJ(true, udg_GameCacheLoadDialog, Player(0))
endif
endfunction
Name | Type | is_array | initial_value |
Amazon | unit | No | |
ArcaneGhosts | group | No | |
AttributesData | string | Yes | |
Backpacks | unit | Yes | |
Barbarian | unit | No | |
BattleOrdersGroup | group | No | |
BOLifeGroup | abilcode | Yes | |
BOManaGroup | abilcode | Yes | |
BurrowedSandMaggots | group | No | |
CairnStones | group | No | |
CameraAngleIncrement | real | No | |
CameraAngleMax | real | No | |
CameraAngleMin | real | No | |
CameraAngleOfAttack | real | Yes | |
CameraAngleState | integer | Yes | |
CameraAngleVariation | real | No | |
CameraDistance | real | Yes | |
CameraDistanceMax | real | No | |
CameraDistanceMin | real | No | |
CameraDistancingFactor | real | No | |
CameraFlags | string | Yes | |
CameraHeroDistance | real | Yes | |
CameraHeroFacing | real | Yes | |
CameraHeroFacingChangeToRotate | real | No | |
CameraHeroPosition | location | Yes | |
CameraHeroRotation | real | Yes | |
CameraHeroRotationFactor | real | No | |
CameraHint | integer | Yes | |
CameraIdle | boolean | Yes | |
CameraIsAngled | boolean | Yes | |
CameraIsDistant | boolean | Yes | |
CameraIsRolled | boolean | Yes | |
CameraLock | boolean | Yes | |
CameraOffsetPosition | location | Yes | |
CameraPanFactor | real | No | |
CameraPanTriggers | trigger | Yes | |
CameraPlayers | force | No | |
CameraRoll | real | Yes | |
CameraRotateCicle | integer | No | |
CameraTimer | timer | Yes | |
CameraTriggers | trigger | Yes | |
CameraWaitTime | real | Yes | |
CameraYOffset | real | No | |
CEAoE | integer | No | |
CECorpse | unit | No | |
CEDamage | real | No | |
CEGroup | group | No | |
ChargeCount | integer | No | |
ChargeGroup | group | No | |
CinematicBandits | group | No | |
CinematicDJVisibility | boolean | No | |
CinematicLoop | integer | Yes | |
CinematicMode | boolean | No | |
CinematicPart | boolean | No | |
CinematicPlayers | force | No | |
CinematicSkeletons | group | No | |
CinematicSkip | boolean | No | |
CinematicSound | sound | No | |
CinematicSoundName | string | No | |
CinematicSoundNames | string | Yes | |
CinematicSounds | sound | Yes | |
CinematicStrings | string | Yes | |
CinematicTime | real | No | |
CinematicUnits | unit | Yes | |
CinematicVisibility | fogmodifier | Yes | |
CinematicVisibilityModifiers | fogmodifier | Yes | |
CouncilMembers | integer | No | 5 |
CountdownTimer | timer | No | |
CountdownTimerWindow | timerdialog | No | |
CubeItemCount | integer | No | |
CubeItems | item | Yes | |
CubeItemsLock | boolean | No | |
DEBUG | boolean | No | true |
DEBUG_CurrentTime | real | No | |
DEBUG_FOGindex | integer | No | |
DeckardCain | unit | No | |
DecrepifyAoE | integer | No | |
DecrepifyGroup | group | No | |
DiabloCountdown | integer | No | 6 |
DungeonNames | string | Yes | |
DungeonObjects | unit | Yes | |
EquipArmor | integer | Yes | |
EquipDropFlag | boolean | Yes | |
EquipDropText | string | Yes | |
EquipRequirementsFlag | integer | Yes | |
EquipShield | integer | Yes | |
EquipWeapon | integer | Yes | |
FetishSounds | sound | Yes | |
FloatingTexts | texttag | Yes | |
FloatingTextsCount | integer | No | |
Fog1Blue | real | Yes | |
Fog1Density | real | Yes | |
Fog1Green | real | Yes | |
Fog1Red | real | Yes | |
Fog1ZEnd | real | Yes | |
Fog1ZStart | real | Yes | |
Fog2Blue | real | Yes | |
Fog2Density | real | Yes | |
Fog2Green | real | Yes | |
Fog2Red | real | Yes | |
Fog2ZEnd | real | Yes | |
Fog2ZStart | real | Yes | |
Fog3Blue | real | Yes | |
Fog3Density | real | Yes | |
Fog3Green | real | Yes | |
Fog3Red | real | Yes | |
Fog3ZEnd | real | Yes | |
Fog3ZStart | real | Yes | |
Fog4Blue | real | Yes | |
Fog4Density | real | Yes | |
Fog4Green | real | Yes | |
Fog4Red | real | Yes | |
Fog4ZEnd | real | Yes | |
Fog4ZStart | real | Yes | |
FogAct | integer | No | |
FogActTriggers | trigger | Yes | |
FogBlue | real | Yes | |
FogDensity | real | Yes | |
FogDisabled | boolean | No | |
FogGreen | real | Yes | |
FogRed | real | Yes | |
FogSampleTime | integer | No | |
FogState | integer | No | |
FogUpdate | trigger | No | |
FogZEnd | real | Yes | |
FogZStart | real | Yes | |
FreezingArrowTarget | unit | No | |
FreezingArrowWard | unit | No | |
GameCache | gamecache | No | |
GameCacheLoadButtons | button | Yes | |
GameCacheLoadDialog | dialog | No | |
GameCachePrefix | string | No | Diablo_II_Classic_By_Wok_Vingador_ |
GameCacheSaveDialog | dialog | No | |
GameCacheSaveYes | button | No | |
GameCacheWaitingSelection | boolean | No | |
GameCacheWasLoaded | boolean | No | false |
GargoyleTraps | group | No | |
GemActivated | boolean | No | |
GoEast | dialog | No | |
GoEastYes | button | No | |
GoWest | dialog | No | |
GoWestYes | button | No | |
HeroAttributes | dialog | Yes | |
HeroAttributesDexterity | button | Yes | |
HeroAttributesEnergy | button | Yes | |
HeroAttributesStrength | button | Yes | |
HeroAttributesTitle | string | Yes | |
HeroAttributesVitality | button | Yes | |
HeroAvailableStats | integer | Yes | |
HeroClassNames | string | Yes | |
HeroRegion | rect | Yes | |
HolyFreezeGroup | group | No | |
HoradricCubeIsOpen | boolean | Yes | |
HoradricCubeItems | item | Yes | ItemNull |
HoradricCubes | unit | Yes | UnitNull |
HoradricScroll | item | No | ItemNull |
InfernoCaster1 | unit | No | |
InfernoCaster2 | unit | No | |
InfernoCaster3 | unit | No | |
InfernoCaster4 | unit | No | |
InfernoCounter | integer | No | |
InfernoLock | boolean | No | |
InfernoPoint | location | No | |
InfernoRealCaster | unit | No | |
InterfaceChests | unit | Yes | |
ItemArmor | itemcode | Yes | |
ItemEndArmor | integer | No | |
ItemEndAxe | integer | No | |
ItemEndBow | integer | No | |
ItemEndPolearm | integer | No | |
ItemEndShield | integer | No | |
ItemEndSpear | integer | No | |
ItemEndStaff | integer | No | |
ItemEndSword | integer | No | |
ItemEndWand | integer | No | |
ItemGambleEnd | integer | No | |
ItemGambleStart | integer | No | |
ItemGambleType | integer | No | |
ItemNumArmor | integer | No | |
ItemNumShield | integer | No | |
ItemNumWeapon1 | integer | No | |
ItemNumWeapon2 | integer | No | |
ItemShield | itemcode | Yes | |
ItemStartArmor | integer | No | |
ItemStartAxe | integer | No | |
ItemStartBow | integer | No | |
ItemStartPolearm | integer | No | |
ItemStartShield | integer | No | |
ItemStartSpear | integer | No | |
ItemStartStaff | integer | No | |
ItemStartSword | integer | No | |
ItemStartWand | integer | No | |
ItemsTypeBase | itemcode | Yes | |
ItemWeapon1 | itemcode | Yes | |
ItemWeapon2 | itemcode | Yes | |
JabCounter | integer | No | |
LeapAttackCount | integer | No | 0 |
LeapAttackGroup | group | No | |
LightFireBoltsFlag | boolean | No | |
LightningFuryBase | integer | No | |
LightningFuryCounter | integer | No | |
LightningFuryTargets | unit | Yes | |
LightningFuryWards | unit | Yes | |
MagicItems | itemcode | Yes | |
MalusDialog | dialog | No | |
MalusDialogOk | button | No | |
MalusReward | integer | Yes | |
Mercenaries | unit | Yes | |
MercenaryGroup | group | No | |
MooMooRegions | rect | Yes | |
MovePortalTimer | timer | Yes | |
Necromancer | unit | No | |
NPCCount | integer | No | |
NPCGroup | group | No | |
NPCObjects | unit | Yes | UnitNull |
NPCRegions | rect | Yes | RectNull |
Paladin | unit | No | |
PlayerAct | integer | Yes | |
PlayerStashes | unit | Yes | UnitNull |
PlayingHeros | group | No | |
QuestCompletionTriggers | trigger | Yes | |
QuestDiscoverTriggers | trigger | Yes | |
QuestHelperTriggers | trigger | Yes | |
Quests | quest | Yes | |
QuestsStateHint | integer | Yes | |
RegionEnterFlag | boolean | Yes | |
RegionNames | string | Yes | |
Regions | rect | Yes | |
RewardGroup | force | No | |
SailEast | dialog | No | |
SailEastYes | button | No | |
SailWest | dialog | No | |
SailWestYes | button | No | |
SaveLoadWindow | dialog | No | |
Skeletons | group | No | |
Soulstone | item | No | ItemNull |
SpecialEffectActive | boolean | No | |
SpecialEffectIndex | integer | No | |
SpecialEffectKeepRunning | boolean | No | |
SpecialEffectLock | boolean | No | |
SpecialEffectLoop | integer | Yes | |
SpecialEffectPoints | location | Yes | |
SpecialEffects | effect | Yes | |
SpecialEffectTarget | unit | No | |
SpecialEffectTime | integer | Yes | |
SpeechCheckIndex | integer | No | |
SpeechCheckingState | boolean | No | |
SpeechCheckString | string | No | |
SpeechCinematicCancel | boolean | No | |
SpeechCinematicMode | boolean | No | |
SpeechEventOffset | integer | Yes | |
SpeechGossipAlternate | string | Yes | |
SpeechGossipAlternateClass | integer | Yes | -1 |
SpeechGossipBase | integer | Yes | |
SpeechGossipIndex | integer | No | |
SpeechGossips | string | Yes | |
SpeechGossipTimer | timer | No | |
SpeechHistoryIndex | integer | No | |
SpeechIntro | string | Yes | |
SpeechIntroAlternate | string | Yes | |
SpeechIntroAlternateClass | integer | Yes | -1 |
SpeechNPCActIndex | integer | Yes | |
SpeechNPCBase | integer | Yes | |
SpeechNPCCount | integer | Yes | |
SpeechNPCDialog | boolean | No | |
SpeechNPCFlags | integer | Yes | |
SpeechNPCFrom | integer | Yes | |
SpeechNPCGoodMDE | boolean | Yes | true |
SpeechNPCGreetings | string | Yes | |
SpeechNPCIndex | integer | No | |
SpeechNPCState | string | Yes | |
SpeechNPCStateShadow | string | Yes | |
SpeechNPCTo | integer | Yes | |
SpeechPlayerGroup | force | No | |
SpeechQuestAfter | string | Yes | |
SpeechQuestDiscover | string | Yes | |
SpeechQuestEvents | string | Yes | |
SpeechQuestFinished | string | Yes | |
SpeechQuestFlags | integer | Yes | |
SpeechQuestIndex | integer | No | |
SpeechQuestNotFinished | string | Yes | |
SpeechQuestSpecial | string | Yes | |
SpeechSFX | effect | Yes | |
SpeechSomethingToSay | integer | Yes | |
SpeechStaticSFX | effect | Yes | |
SpeechString | string | No | |
SpeechStringCount | integer | No | |
SpeechStringIndex | integer | No | |
SpeechStringOffsets | integer | Yes | |
SpeechStringWait | real | No | |
SpeechStringWaitFactor | real | No | |
SpeechStringWords | real | No | |
SpeechSubstring | string | No | |
SpeechTalkingGroup | group | No | |
SpeechTalkTarget | unit | No | |
SpeechTaunting | boolean | No | |
SpeechTaunts | string | Yes | |
SpeechTauntString | string | No | |
SpeechTauntTransmiter | unit | No | |
SpeechTauntWait | real | No | |
SpeechTransmiter | unit | No | |
SpeechWaiting | boolean | No | |
SpeechWaitingTimer | timer | No | |
SpeechWelcomeBack | string | Yes | |
StartRegions | rect | Yes | |
StashLoopIndex | integer | No | |
StashState | integer | Yes | |
TalkToJerhyn | boolean | No | |
TempRegion | rect | Yes | |
TheHeros | unit | Yes | |
TilesetFrom | terraintype | No | |
TilesetRegion | rect | No | |
TilesetTo | terraintype | No | |
TownPortalAvailable | boolean | Yes | |
TownPortalField | unit | Yes | |
TownPortalObject | unit | No | |
TownPortalRegions | rect | Yes | |
TownPortalStringField | string | Yes | |
TownPortalStringTown | string | Yes | |
TownPortalTextField | texttag | Yes | |
TownPortalTextTown | texttag | Yes | |
TownPortalTown | unit | Yes | |
TownRegionNames | string | Yes | |
TownRegions | rect | Yes | |
TristramCountDown | integer | No | 5 |
UniqueItemIndex | integer | No | |
UniqueItems | itemcode | Yes | |
UniqueItemsCount | integer | No | |
UniqueItemsMap | boolean | Yes | |
UnitSpellOrAttack | boolean | No | |
Valkyrie | unit | No | |
Valkyries | unitcode | Yes | |
Visibility | boolean | Yes | |
WaypointAct | integer | Yes | |
WaypointAvailable | boolean | Yes | |
WaypointButtons | button | Yes | |
WaypointData | string | Yes | |
WaypointDialogs | dialog | Yes | |
WaypointEndIndex | integer | Yes | |
WaypointNames | string | Yes | |
WaypointObject | unit | No | |
WaypointObjects | unit | Yes | |
WaypointStartIndex | integer | Yes | |
WaypointTitle | string | Yes | |
WhirlwindAoE | integer | No | |
WhirlwindDamage | integer | No | |
WhirlwindGroup | group | No | |
WhirlwindTimer | timer | No | |
ZealGroup | abilcode | Yes |
function Trig_Game_Cache_Load_Dialog_Actions takes nothing returns nothing
local integer index = 0
local string cacheName
call DisableTrigger(GetTriggeringTrigger())
loop
exitwhen index > 4
if (GetClickedButtonBJ() == udg_GameCacheLoadButtons[index]) then
set cacheName = udg_GameCachePrefix + udg_HeroClassNames[index] + ".w3v"
set udg_GameCacheWasLoaded = d2_LoadGame(cacheName, false)
exitwhen true
endif
set index = index + 1
endloop
set udg_GameCacheWaitingSelection = false
call EnableTrigger(GetTriggeringTrigger())
endfunction
//===========================================================================
function InitTrig_Game_Cache_Load_Dialog takes nothing returns nothing
set gg_trg_Game_Cache_Load_Dialog = CreateTrigger( )
call TriggerRegisterDialogEventBJ( gg_trg_Game_Cache_Load_Dialog, udg_GameCacheLoadDialog )
call TriggerAddAction( gg_trg_Game_Cache_Load_Dialog, function Trig_Game_Cache_Load_Dialog_Actions )
endfunction