mirror of
https://github.com/vcmi/vcmi.git
synced 2025-09-16 09:26:28 +02:00
Minimize hardcoded logic for campaigns. Support for hota h3c's
This commit is contained in:
@@ -781,7 +781,7 @@ void AIGateway::showGarrisonDialog(const CArmedInstance * up, const CGHeroInstan
|
||||
//you can't request action from action-response thread
|
||||
executeActionAsync("showGarrisonDialog", [this, up, down, removableUnits, queryID]()
|
||||
{
|
||||
if(removableUnits && up->tempOwner == down->tempOwner && nullkiller->settings->isGarrisonTroopsUsageAllowed() && !cb->getStartInfo()->isRestorationOfErathiaCampaign())
|
||||
if(removableUnits && up->tempOwner == down->tempOwner && nullkiller->settings->isGarrisonTroopsUsageAllowed() && !cb->getStartInfo()->restrictedGarrisonsForAI())
|
||||
{
|
||||
pickBestCreatures(down, up);
|
||||
}
|
||||
|
@@ -762,7 +762,7 @@ void VCAI::showGarrisonDialog(const CArmedInstance * up, const CGHeroInstance *
|
||||
//you can't request action from action-response thread
|
||||
executeActionAsync("showGarrisonDialog", [this, down, up, removableUnits, queryID]()
|
||||
{
|
||||
if(removableUnits && !cb->getStartInfo()->isRestorationOfErathiaCampaign())
|
||||
if(removableUnits && !cb->getStartInfo()->restrictedGarrisonsForAI())
|
||||
pickBestCreatures(down, up);
|
||||
|
||||
answerQuery(queryID, 0);
|
||||
|
@@ -1,239 +0,0 @@
|
||||
{
|
||||
"videos": [
|
||||
//Restoration of Erathia
|
||||
//Long live the Queen
|
||||
"GOOD1A.SMK", //Good1_a
|
||||
"GOOD1B.SMK", //Good1_b
|
||||
"GOOD1C.SMK", //Good1_c
|
||||
//Dungeons and devils
|
||||
"EVIL1A.SMK", //Evil1_a
|
||||
"EVIL1B.SMK", //Evil1_b
|
||||
"EVIL1C.SMK", //Evil1_c
|
||||
//Spoils of War
|
||||
"NEUTRALA.SMK", //Neutral1_a
|
||||
"NEUTRALB.SMK", //Neutral1_b
|
||||
"NEUTRALC.SMK", //Neutral1_c
|
||||
//Liberation
|
||||
"GOOD2A.SMK", //Good2_a
|
||||
"GOOD2B.SMK", //Good2_b
|
||||
"GOOD2C.SMK", //Good2_c
|
||||
"GOOD2D.SMK", //Good2_d
|
||||
//Long Live the King
|
||||
"EVIL2A.SMK", //Evil2_a
|
||||
"EVIL2AP1.SMK", //Evil2ap1
|
||||
"EVIL2B.SMK", //Evil2_b
|
||||
"EVIL2C.SMK", //Evil2_c
|
||||
"EVIL2D.SMK", //Evil2_d
|
||||
//Song for the Father
|
||||
"GOOD3A.SMK", //Good3_a
|
||||
"GOOD3B.SMK", //Good3_b
|
||||
"GOOD3C.SMK", //Good3_c
|
||||
//Seeds Of Discontent
|
||||
"SECRETA.SMK", //Secret_a
|
||||
"SECRETB.SMK", //Secret_b
|
||||
"SECRETC.SMK", //Secret_c
|
||||
//Armageddon's Blade
|
||||
//Armageddon's Blade
|
||||
"H3ABab1.smk", //ArmageddonsBlade_a
|
||||
"H3ABab2.smk", //ArmageddonsBlade_b
|
||||
"H3ABab3.smk", //ArmageddonsBlade_c
|
||||
"H3ABab4.smk", //ArmageddonsBlade_d
|
||||
"H3ABab5.smk", //ArmageddonsBlade_e
|
||||
"H3ABab6.smk", //ArmageddonsBlade_f
|
||||
"H3ABab7.smk", //ArmageddonsBlade_g
|
||||
"H3ABab8.smk", //ArmageddonsBlade_h
|
||||
"H3ABab9.smk", //ArmageddonsBlade_end
|
||||
//Dragon's Blood
|
||||
"H3ABdb1.smk", //DragonsBlood_a
|
||||
"H3ABdb2.smk", //DragonsBlood_b
|
||||
"H3ABdb3.smk", //DragonsBlood_c
|
||||
"H3ABdb4.smk", //DragonsBlood_d
|
||||
"H3ABdb5.smk", //DragonsBlood_end
|
||||
//Dragon Slayer
|
||||
"H3ABds1.smk", //DragonSlayer_a
|
||||
"H3ABds2.smk", //DragonSlayer_b
|
||||
"H3ABds3.smk", //DragonSlayer_c
|
||||
"H3ABds4.smk", //DragonSlayer_d
|
||||
"H3ABds5.smk", //DragonSlayer_end
|
||||
//Festival of Life
|
||||
"H3ABfl1.smk", //FestivalOfLife_a
|
||||
"H3ABfl2.smk", //FestivalOfLife_b
|
||||
"H3ABfl3.smk", //FestivalOfLife_c
|
||||
"H3ABfl4.smk", //FestivalOfLife_d
|
||||
"H3ABfl5.smk", //FestivalOfLife_end
|
||||
//Foolhardy Waywardness
|
||||
"H3ABfw1.smk", //FoolhardyWaywardness_a
|
||||
"H3ABfw2.smk", //FoolhardyWaywardness_b
|
||||
"H3ABfw3.smk", //FoolhardyWaywardness_c
|
||||
"H3ABfw4.smk", //FoolhardyWaywardness_d
|
||||
"H3ABfw5.smk", //FoolhardyWaywardness_end
|
||||
//Playing with Fire
|
||||
"H3ABpf1.smk", //PlayingWithFire_a
|
||||
"H3ABpf2.smk", //PlayingWithFire_b
|
||||
"H3ABpf3.smk", //PlayingWithFire_c
|
||||
"H3ABpf4.smk", //PlayingWithFire_end
|
||||
//Shadow of Death Campaigns
|
||||
//Birth of a Barbarian
|
||||
"H3x2_BBa.smk", //BirthOfABarbarian_a
|
||||
"H3x2_BBb.smk", //BirthOfABarbarian_b
|
||||
"H3x2_BBc.smk", //BirthOfABarbarian_c
|
||||
"H3x2_BBd.smk", //BirthOfABarbarian_d
|
||||
"H3x2_BBe.smk", //BirthOfABarbarian_e
|
||||
"H3x2_BBf.smk", //BirthOfABarbarian_end
|
||||
//Elixir of Life
|
||||
"H3x2_Ela.smk", //ElixirOfLife_a
|
||||
"H3x2_Elb.smk", //ElixirOfLife_b
|
||||
"H3x2_Elc.smk", //ElixirOfLife_c
|
||||
"H3x2_Eld.smk", //ElixirOfLife_d
|
||||
"H3x2_Ele.smk", //ElixirOfLife_end
|
||||
//Hack and Slash
|
||||
"H3x2_HSa.smk", //HackAndSlash_a
|
||||
"EVIL2C.SMK", //HackAndSlash_b
|
||||
"H3x2_HSc.smk", //HackAndSlash_c
|
||||
"H3x2_HSd.smk", //HackAndSlash_d
|
||||
"H3x2_HSe.smk", //HackAndSlash_end
|
||||
//New Beginning
|
||||
"H3x2_NBa.smk", //NewBeginning_a
|
||||
"H3x2_NBb.smk", //NewBeginning_b
|
||||
"H3x2_Nbc.smk", //NewBeginning_c
|
||||
"H3x2_Nbd.smk", //NewBeginning_d
|
||||
"H3x2_Nbe.smk", //NewBeginning_end
|
||||
//Rise of the Necromancer
|
||||
"H3x2_RNa.smk", //RiseOfTheNecromancer_a
|
||||
"H3x2_RNb.smk", //RiseOfTheNecromancer_b
|
||||
"H3x2_RNc.smk", //RiseOfTheNecromancer_c
|
||||
"H3x2_RNd.smk", //RiseOfTheNecromancer_d
|
||||
"H3x2_RNe1.smk", //RiseOfTheNecromancer_end
|
||||
//Spectre of Power
|
||||
"H3x2_SPa.smk", //SpectreOfPower_a
|
||||
"H3x2_SPb.smk", //SpectreOfPower_b
|
||||
"H3x2_SPc.smk", //SpectreOfPower_c
|
||||
"H3x2_SPd.smk", //SpectreOfPower_d
|
||||
"H3x2_SPe.smk", //SpectreOfPower_end
|
||||
//Unholy Alliance
|
||||
"H3x2_UAa.smk", //UnholyAlliance_a
|
||||
"H3x2_UAb.smk", //UnholyAlliance_b
|
||||
"H3x2_UAc.smk", //UnholyAlliance_c
|
||||
"H3x2_UAd.smk", //UnholyAlliance_d
|
||||
"H3x2_UAe.smk", //UnholyAlliance_e
|
||||
"H3x2_UAf.smk", //UnholyAlliance_f
|
||||
"H3x2_UAg.smk", //UnholyAlliance_g
|
||||
"H3x2_UAh.smk", //UnholyAlliance_h
|
||||
"H3x2_UAi.smk", //UnholyAlliance_i
|
||||
"H3x2_UAj.smk", //UnholyAlliance_j
|
||||
"H3x2_UAk.smk", //UnholyAlliance_k
|
||||
"H3x2_UAl.smk", //UnholyAlliance_l
|
||||
"H3x2_UAm.smk", //UnholyAlliance_end //H3x2_UAm.bik?
|
||||
],
|
||||
|
||||
"music" : [
|
||||
// Use CmpMusic.txt from H3 instead
|
||||
],
|
||||
|
||||
"voice" : [
|
||||
//Restoration of Erathia
|
||||
"G1A", //Long live the Queen 1
|
||||
"G1B", //Long live the Queen 2
|
||||
"G1C", //Long live the Queen 3
|
||||
"E1A.wav", //Dungeons and Devils 1
|
||||
"E1B.wav", //Dungeons and Devils 2
|
||||
"E1C.wav", //Dungeons and Devils 3
|
||||
"N1A", //Spoils of War 1
|
||||
"N1B", //Spoils of War 2
|
||||
"N1C_D", //Spoils of War 3
|
||||
"G2A", //Liberation 1
|
||||
"G2B", //Liberation 2
|
||||
"G2C", //Liberation 3
|
||||
"G2D", //Liberation 4
|
||||
"E2A.wav", //Long live the King 1
|
||||
"E2AE.wav", //Long live the King 1end
|
||||
"E2B.wav", //Long live the King 2
|
||||
"E2C.wav", //Long live the King 3
|
||||
"E2D.wav", //Long live the King 4
|
||||
"G3A", //Song for the Father 1
|
||||
"G3B", //Song for the Father 2
|
||||
"G3C", //Song for the Father 3
|
||||
"S1A", //Seeds of discontent 1
|
||||
"S1B", //Seeds of discontent 2
|
||||
"S1C", //Seeds of discontent 3
|
||||
//Armageddon's Blade
|
||||
"ABvoAB1.wav", //Armageddon's Blade 1
|
||||
"ABvoAB2.wav", //Armageddon's Blade 2
|
||||
"ABvoAB3.wav", //Armageddon's blade 3
|
||||
"ABvoAB4.wav", //Armageddon's blade 4
|
||||
"ABvoAB5.wav", //Armageddon's blade 5
|
||||
"ABvoAB6.wav", //Armageddon's blade 6
|
||||
"ABvoAB7.wav", //Armageddon's blade 7
|
||||
"ABvoAB8.wav", //Armageddon's blade 8
|
||||
"ABvoAB9.wav", //Armageddon's blade 8end
|
||||
"ABvoDB1.wav", //Dragon's Blood 1
|
||||
"ABvoDB2.wav", //Dragon's Blood 2
|
||||
"ABvoDB3.wav", //Dragon's Blood 3
|
||||
"ABvoDB4.wav", //Dragon's Blood 4
|
||||
"ABvoDB5.wav", //Dragon's Blood 4end
|
||||
"ABvoDS1.wav", //Dragon Slayer 1
|
||||
"ABvoDS2.wav", //Dragon Slayer 2
|
||||
"ABvoDS3.wav", //Dragon Slayer 3
|
||||
"ABvoDS4.wav", //Dragon Slayer 4
|
||||
"ABvoDS5.wav", //Dragon Slayer 4end
|
||||
"ABvoFL1.wav", //Festival of Life 1
|
||||
"ABvoFL2.wav", //Festival of Life 2
|
||||
"ABvoFL3.wav", //Festival of Life 3
|
||||
"ABvoFL4.wav", //Festival of Life 4
|
||||
"ABvoFL5.wav", //Festival of Life 4end
|
||||
"ABvoFW1.wav", //Foolhardy Waywardness 1
|
||||
"ABvoFW2.wav", //Foolhardy Waywardness 2
|
||||
"ABvoFW3.wav", //Foolhardy Waywardness 3
|
||||
"ABvoFW4.wav", //Foolhardy Waywardness 4
|
||||
"ABvoFW5.wav", //Foolhardy Waywardness 4end
|
||||
"ABvoPF1.wav", //Playing with Fire 1
|
||||
"ABvoPF2.wav", //Playing with Fire 2
|
||||
"ABvoPF3.wav", //Playing with Fire 3
|
||||
"ABvoPF4.wav", //Playing with Fire 3end
|
||||
//Shadow of Death Campaigns
|
||||
"H3x2BBa", //Birth of a Barbarian 1
|
||||
"H3x2BBb", //Birth of a Barbarian 2
|
||||
"H3x2BBc", //Birth of a Barbarian 3
|
||||
"H3x2BBd", //Birth of a Barbarian 4
|
||||
"H3x2BBe", //Birth of a Barbarian 5
|
||||
"H3x2BBf", //Birth of a Barbarian 5end
|
||||
"H3x2ELa", //Elixir of life 1
|
||||
"H3x2ELb", //Elixir of life 2
|
||||
"H3x2ELc", //Elixir of life 3
|
||||
"H3x2ELd", //Elixir of life 4
|
||||
"H3x2ELe", //Elixir of life 4end
|
||||
"H3x2HSa", //Hack and Slash 1
|
||||
"H3x2HSb", //Hack and Slash 2
|
||||
"H3x2HSc", //Hack and Slash 3
|
||||
"H3x2HSd", //Hack and Slash 4
|
||||
"H3x2HSe", //Hack and Slash 4end
|
||||
"H3x2NBa", //New Beginning 1
|
||||
"H3x2NBb", //New Beginning 2
|
||||
"H3x2NBc", //New Beginning 3
|
||||
"H3x2NBd", //New Beginning 4
|
||||
"H3x2NBe", //New Beginning 4end
|
||||
"H3x2RNa", //Rise of the Necromancer 1
|
||||
"H3x2RNb", //Rise of the Necromancer 2
|
||||
"H3x2RNc", //Rise of the Necromancer 3
|
||||
"H3x2RNd", //Rise of the Necromancer 4
|
||||
"H3x2RNe", //Rise of the Necromancer 4end
|
||||
"H3x2SPa", //Spectre of Power 1
|
||||
"H3x2Spb", //Spectre of Power 2
|
||||
"H3x2Spc", //Spectre of Power 3
|
||||
"H3x2Spd", //Spectre of Power 4
|
||||
"H3x2Spe", //Spectre of Power 4end
|
||||
"H3x2UAa", //Unholy alliance 1
|
||||
"H3x2UAb", //Unholy alliance 2
|
||||
"H3x2UAc", //Unholy alliance 3
|
||||
"H3x2UAd", //Unholy alliance 4
|
||||
"H3x2UAe", //Unholy alliance 5
|
||||
"H3x2UAf", //Unholy alliance 6
|
||||
"H3x2UAg", //Unholy alliance 7
|
||||
"H3x2UAh", //Unholy alliance 8
|
||||
"H3x2UAi", //Unholy alliance 9
|
||||
"H3x2UAj", //Unholy alliance 10
|
||||
"H3x2UAk", //Unholy alliance 11
|
||||
"H3x2UAl", //Unholy alliance 12
|
||||
"H3x2UAm" //Unholy alliance 12end
|
||||
]
|
||||
}
|
@@ -1,11 +1,196 @@
|
||||
{
|
||||
"DATA/GOOD3" : { // RoE - "Song for the Father"
|
||||
"outroVideo": "Endgame"
|
||||
/// RoE CAMPAIGNS
|
||||
|
||||
"DATA/GOOD1" : { //Long live the Queen
|
||||
"restrictedGarrisonsForAI" : true,
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "G1A" },
|
||||
{ "voiceProlog": "G1B" },
|
||||
{ "voiceProlog": "G1C" }
|
||||
]
|
||||
},
|
||||
"DATA/AB" : { // AB Intro
|
||||
"DATA/EVIL1" : { // Dungeons and Devils
|
||||
"restrictedGarrisonsForAI" : true,
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "E1A" },
|
||||
{ "voiceProlog": "E1B" },
|
||||
{ "voiceProlog": "E1C" }
|
||||
]
|
||||
},
|
||||
"DATA/GOOD2" : { // Liberation
|
||||
"restrictedGarrisonsForAI" : true,
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "G2A" },
|
||||
{ "voiceProlog": "G2B" },
|
||||
{ "voiceProlog": "G2C" },
|
||||
{ "voiceProlog": "G2D" }
|
||||
]
|
||||
},
|
||||
"DATA/NEUTRAL1" : { // Spoils of War
|
||||
"restrictedGarrisonsForAI" : true,
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "N1A" },
|
||||
{ "voiceProlog": "N1B" },
|
||||
{ "voiceProlog": "N1C_D" }
|
||||
]
|
||||
},
|
||||
"DATA/EVIL2" : { // Long live the King
|
||||
"restrictedGarrisonsForAI" : true,
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "E2A", "voiceEpilog": "E2AE" },
|
||||
{ "voiceProlog": "E2B" },
|
||||
{ "voiceProlog": "E2C" },
|
||||
{ "voiceProlog": "E2D" }
|
||||
]
|
||||
},
|
||||
|
||||
"DATA/GOOD3" : { // Song for the Father
|
||||
"outroVideo": "Endgame",
|
||||
"restrictedGarrisonsForAI" : true,
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "G3A" },
|
||||
{ "voiceProlog": "G3B" },
|
||||
{ "voiceProlog": "G3C" }
|
||||
]
|
||||
},
|
||||
"DATA/SECRET1" : { // Seeds of discontent
|
||||
"restrictedGarrisonsForAI" : true,
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "S1A" },
|
||||
{ "voiceProlog": "S1B" },
|
||||
{ "voiceProlog": "S1C" }
|
||||
]
|
||||
},
|
||||
|
||||
/// AB CAMPAIGNS
|
||||
|
||||
"DATA/AB" : { // Armageddon's Blade
|
||||
"introVideo": "H3X1intr",
|
||||
"videoRim": "IntroRm2"
|
||||
"videoRim": "IntroRm2",
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "ABvoAB1" },
|
||||
{ "voiceProlog": "ABvoAB2" },
|
||||
{ "voiceProlog": "ABvoAB3" },
|
||||
{ "voiceProlog": "ABvoAB4" },
|
||||
{ "voiceProlog": "ABvoAB5" },
|
||||
{ "voiceProlog": "ABvoAB6" },
|
||||
{ "voiceProlog": "ABvoAB7" },
|
||||
{ "voiceProlog": "ABvoAB8", "voiceEpilog": "ABvoAB9" }
|
||||
]
|
||||
},
|
||||
"DATA/BLOOD" : { // Dragon's Blood
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "ABvoDB1" },
|
||||
{ "voiceProlog": "ABvoDB2" },
|
||||
{ "voiceProlog": "ABvoDB3" },
|
||||
{ "voiceProlog": "ABvoDB4", "voiceEpilog": "ABvoDB5" }
|
||||
]
|
||||
},
|
||||
"DATA/SLAYER" : { // Dragon Slayer
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "ABvoDS1" },
|
||||
{ "voiceProlog": "ABvoDS2" },
|
||||
{ "voiceProlog": "ABvoDS3" },
|
||||
{ "voiceProlog": "ABvoDS4", "voiceEpilog": "ABvoDS5" }
|
||||
]
|
||||
},
|
||||
"DATA/FESTIVAL" : { // Festival of Life
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "ABvoFL1" },
|
||||
{ "voiceProlog": "ABvoFL2" },
|
||||
{ "voiceProlog": "ABvoFL3" },
|
||||
{ "voiceProlog": "ABvoFL4", "voiceEpilog": "ABvoFL5" }
|
||||
]
|
||||
},
|
||||
"DATA/FIRE" : { // Playing with Fire
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "ABvoPF1" },
|
||||
{ "voiceProlog": "ABvoPF2" },
|
||||
{ "voiceProlog": "ABvoPF3", "voiceEpilog": "ABvoPF4" }
|
||||
]
|
||||
},
|
||||
"DATA/FOOL" : { // Foolhardy Waywardness
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "ABvoFW1" },
|
||||
{ "voiceProlog": "ABvoFW2" },
|
||||
{ "voiceProlog": "ABvoFW3" },
|
||||
{ "voiceProlog": "ABvoFW4", "voiceEpilog": "ABvoFW5" }
|
||||
]
|
||||
},
|
||||
|
||||
/// SoD CAMPAIGNS
|
||||
|
||||
"DATA/GELU" : { // Elixir of life
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "H3x2ELa" },
|
||||
{ "voiceProlog": "H3x2ELb" },
|
||||
{ "voiceProlog": "H3x2ELc" },
|
||||
{ "voiceProlog": "H3x2ELd", "voiceEpilog": "H3x2ELe" }
|
||||
]
|
||||
},
|
||||
"DATA/CRAG" : { // Hack and Slash
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "H3x2HSa" },
|
||||
{ "voiceProlog": "H3x2HSb" },
|
||||
{ "voiceProlog": "H3x2HSc" },
|
||||
{ "voiceProlog": "H3x2HSd", "voiceEpilog": "H3x2HSe" }
|
||||
]
|
||||
},
|
||||
"DATA/SANDRO" : { // Rise of the Necromancer
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "H3x2RNa" },
|
||||
{ "voiceProlog": "H3x2RNb" },
|
||||
{ "voiceProlog": "H3x2RNc" },
|
||||
{ "voiceProlog": "H3x2RNd", "voiceEpilog": "H3x2RNe" }
|
||||
]
|
||||
},
|
||||
"DATA/GEM" : { // New Beginning
|
||||
"heroGemSorceress" : "gem", // Gem (Sorceress class)
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "H3x2NBa" },
|
||||
{ "voiceProlog": "H3x2NBb" },
|
||||
{ "voiceProlog": "H3x2NBc" },
|
||||
{ "voiceProlog": "H3x2NBd", "voiceEpilog": "H3x2NBe" }
|
||||
]
|
||||
},
|
||||
"DATA/YOG" : { // Birth of a Barbarian
|
||||
"heroYogWizard" : "solmyr", // Yog (based on Solmyr)
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "H3x2BBa" },
|
||||
{ "voiceProlog": "H3x2BBb" },
|
||||
{ "voiceProlog": "H3x2BBc" },
|
||||
{ "voiceProlog": "H3x2BBd" },
|
||||
{ "voiceProlog": "H3x2BBe", "voiceEpilog": "H3x2BBf" }
|
||||
]
|
||||
},
|
||||
"DATA/FINAL" : { // Unholy Alliance
|
||||
"heroGemSorceress" : "gem", // Gem (Sorceress class)
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "H3x2UAa" },
|
||||
{ "voiceProlog": "H3x2UAb" },
|
||||
{ "voiceProlog": "H3x2UAc" },
|
||||
{ "voiceProlog": "H3x2UAd" },
|
||||
{ "voiceProlog": "H3x2UAe" },
|
||||
{ "voiceProlog": "H3x2UAf" },
|
||||
{ "voiceProlog": "H3x2UAg" },
|
||||
{ "voiceProlog": "H3x2UAh" },
|
||||
{ "voiceProlog": "H3x2UAi" },
|
||||
{ "voiceProlog": "H3x2UAj" },
|
||||
{ "voiceProlog": "H3x2UAk" },
|
||||
{ "voiceProlog": "H3x2UAl", "voiceEpilog": "H3x2UAm" }
|
||||
]
|
||||
},
|
||||
"DATA/SECRET" : { // Spectre of Power
|
||||
"scenarios": [
|
||||
{ "voiceProlog": "H3x2SPa" },
|
||||
{ "voiceProlog": "H3x2Spb" },
|
||||
{ "voiceProlog": "H3x2Spc" },
|
||||
{ "voiceProlog": "H3x2Spd", "voiceEpilog": "H3x2Spe" }
|
||||
]
|
||||
},
|
||||
|
||||
/// CHRONICLES CAMPAIGNS
|
||||
|
||||
"MAPS/CHRONICLES/HC1_MAIN" : { // Heroes Chronicles 1
|
||||
"regions":
|
||||
{
|
||||
|
@@ -154,7 +154,6 @@
|
||||
"restorationOfErathia" : {
|
||||
"supported" : true,
|
||||
"iconIndex" : 0,
|
||||
|
||||
"buildingsCommon": {
|
||||
"townHall" : 0,
|
||||
"cityHall" : 1,
|
||||
@@ -199,7 +198,6 @@
|
||||
"dwellingLvl7" : 39,
|
||||
"dwellingUpLvl7" : 40
|
||||
},
|
||||
|
||||
"buildings" : {
|
||||
"castle" : {
|
||||
"special1" : 18, // lighthouse
|
||||
@@ -245,7 +243,6 @@
|
||||
"special3" : 18 // glyphsOfFear
|
||||
}
|
||||
},
|
||||
|
||||
"portraits" : {
|
||||
"catherine" : 128, // In "RoE" Catherine only has portrait
|
||||
"portraitGeneralKendal" : 129
|
||||
@@ -259,6 +256,75 @@
|
||||
"evil2" : 5, // Long Live the King
|
||||
"neutral1" : 6, // Spoils of War
|
||||
"secret1" : 7 // Seeds Of Discontent
|
||||
},
|
||||
"campaignMusic" : {
|
||||
"CampainMusic01" : 0,
|
||||
"CampainMusic02" : 1,
|
||||
"CampainMusic03" : 2,
|
||||
"CampainMusic04" : 3,
|
||||
"CampainMusic05" : 4,
|
||||
"CampainMusic06" : 5,
|
||||
"CampainMusic07" : 6,
|
||||
"CampainMusic08" : 7,
|
||||
"CampainMusic09" : 8,
|
||||
"AiTheme0" : 9,
|
||||
"AiTheme1" : 10,
|
||||
"AiTheme2" : 11,
|
||||
"Combat01" : 12,
|
||||
"Combat02" : 13,
|
||||
"Combat03" : 14,
|
||||
"Combat04" : 15,
|
||||
"CstleTown" : 16,
|
||||
"TowerTown" : 17,
|
||||
"Rampart" : 18,
|
||||
"InfernoTown" : 19,
|
||||
"NecroTown" : 20,
|
||||
"Dungeon" : 21,
|
||||
"Stronghold" : 22,
|
||||
"FortressTown" : 23,
|
||||
"ElemTown" : 24,
|
||||
"Dirt" : 25,
|
||||
"Sand" : 26,
|
||||
"Grass" : 27,
|
||||
"Snow" : 28,
|
||||
"Swamp" : 29,
|
||||
"Rough" : 30,
|
||||
"Underground" : 31,
|
||||
"Lava" : 32,
|
||||
"Water" : 33,
|
||||
"GoodTheme" : 34,
|
||||
"NeutralTheme" : 35,
|
||||
"EvilTheme" : 36,
|
||||
"SecretTheme" : 37,
|
||||
"LoopLepr" : 38,
|
||||
"MainMenu" : 39,
|
||||
"Win Scenario" : 40
|
||||
},
|
||||
"campaignVideo" : {
|
||||
"GOOD1A.SMK" : 0,
|
||||
"GOOD1B.SMK" : 1,
|
||||
"GOOD1C.SMK" : 2,
|
||||
"EVIL1A.SMK" : 3,
|
||||
"EVIL1B.SMK" : 4,
|
||||
"EVIL1C.SMK" : 5,
|
||||
"NEUTRALA.SMK" : 6,
|
||||
"NEUTRALB.SMK" : 7,
|
||||
"NEUTRALC.SMK" : 8,
|
||||
"GOOD2A.SMK" : 9,
|
||||
"GOOD2B.SMK" : 10,
|
||||
"GOOD2C.SMK" : 11,
|
||||
"GOOD2D.SMK" : 12,
|
||||
"EVIL2A.SMK" : 13,
|
||||
"EVIL2AP1.SMK" : 14,
|
||||
"EVIL2B.SMK" : 15,
|
||||
"EVIL2C.SMK" : 16,
|
||||
"EVIL2D.SMK" : 17,
|
||||
"GOOD3A.SMK" : 18,
|
||||
"GOOD3B.SMK" : 19,
|
||||
"GOOD3C.SMK" : 20,
|
||||
"SECRETA.SMK" : 21,
|
||||
"SECRETB.SMK" : 22,
|
||||
"SECRETC.SMK" : 23
|
||||
}
|
||||
},
|
||||
"armageddonsBlade" : {
|
||||
@@ -270,7 +336,6 @@
|
||||
"special2" : 18 // magicUniversity
|
||||
}
|
||||
},
|
||||
|
||||
"portraits" : {
|
||||
"pasis" : 128,
|
||||
"thunar" : 129,
|
||||
@@ -285,12 +350,55 @@
|
||||
"dragonsBlood" : 11,
|
||||
"playingWithFire" : 12,
|
||||
"armageddonsBlade" : 13
|
||||
},
|
||||
"campaignMusic" : {
|
||||
"CampainMusic10" : 41,
|
||||
"BladeABCampaign" : 42,
|
||||
"BladeDBCampaign" : 43,
|
||||
"BladeDSCampaign" : 44,
|
||||
"BladeFLCampaign" : 45,
|
||||
"BladeFWCampaign" : 46,
|
||||
"BladePFCampaign" : 47
|
||||
},
|
||||
"campaignVideo" : {
|
||||
"H3ABab1.smk" : 24,
|
||||
"H3ABab2.smk" : 25,
|
||||
"H3ABab3.smk" : 26,
|
||||
"H3ABab4.smk" : 27,
|
||||
"H3ABab5.smk" : 28,
|
||||
"H3ABab6.smk" : 29,
|
||||
"H3ABab7.smk" : 30,
|
||||
"H3ABab8.smk" : 31,
|
||||
"H3ABab9.smk" : 32,
|
||||
"H3ABdb1.smk" : 33,
|
||||
"H3ABdb2.smk" : 34,
|
||||
"H3ABdb3.smk" : 35,
|
||||
"H3ABdb4.smk" : 36,
|
||||
"H3ABdb5.smk" : 37,
|
||||
"H3ABds1.smk" : 38,
|
||||
"H3ABds2.smk" : 39,
|
||||
"H3ABds3.smk" : 40,
|
||||
"H3ABds4.smk" : 41,
|
||||
"H3ABds5.smk" : 42,
|
||||
"H3ABfl1.smk" : 43,
|
||||
"H3ABfl2.smk" : 44,
|
||||
"H3ABfl3.smk" : 45,
|
||||
"H3ABfl4.smk" : 46,
|
||||
"H3ABfl5.smk" : 47,
|
||||
"H3ABfw1.smk" : 48,
|
||||
"H3ABfw2.smk" : 49,
|
||||
"H3ABfw3.smk" : 50,
|
||||
"H3ABfw4.smk" : 51,
|
||||
"H3ABfw5.smk" : 52,
|
||||
"H3ABpf1.smk" : 53,
|
||||
"H3ABpf2.smk" : 54,
|
||||
"H3ABpf3.smk" : 55,
|
||||
"H3ABpf4.smk" : 56
|
||||
}
|
||||
},
|
||||
"shadowOfDeath" : {
|
||||
"supported" : true,
|
||||
"iconIndex" : 2,
|
||||
|
||||
"portraits" : {
|
||||
"portraitGeneralKendal" : 156,
|
||||
"portraitYoungCristian" : 157,
|
||||
@@ -300,7 +408,6 @@
|
||||
"portraitYoungSandro" : 161,
|
||||
"portraitYoungYog" : 162
|
||||
},
|
||||
|
||||
"campaignRegions" : {
|
||||
"hackAndSlash" : 14,
|
||||
"birthOfBarbarian" : 15,
|
||||
@@ -309,6 +416,55 @@
|
||||
"riseOfTheNecromancer" : 18,
|
||||
"unholyAlliance" : 19,
|
||||
"spectreOfPower" : 20
|
||||
},
|
||||
"campaignMusic" : {
|
||||
"CampainMusic11" : 48
|
||||
},
|
||||
"campaignVideo" : {
|
||||
"H3x2_BBa.smk" : 57,
|
||||
"H3x2_BBb.smk" : 58,
|
||||
"H3x2_BBc.smk" : 59,
|
||||
"H3x2_BBd.smk" : 60,
|
||||
"H3x2_BBe.smk" : 61,
|
||||
"H3x2_BBf.smk" : 62,
|
||||
"H3x2_Ela.smk" : 63,
|
||||
"H3x2_Elb.smk" : 64,
|
||||
"H3x2_Elc.smk" : 65,
|
||||
"H3x2_Eld.smk" : 66,
|
||||
"H3x2_Ele.smk" : 67,
|
||||
"H3x2_HSa.smk" : 68,
|
||||
"EVIL2C.SMK" : 69,
|
||||
"H3x2_HSc.smk" : 70,
|
||||
"H3x2_HSd.smk" : 71,
|
||||
"H3x2_HSe.smk" : 72,
|
||||
"H3x2_NBa.smk" : 73,
|
||||
"H3x2_NBb.smk" : 74,
|
||||
"H3x2_Nbc.smk" : 75,
|
||||
"H3x2_Nbd.smk" : 76,
|
||||
"H3x2_Nbe.smk" : 77,
|
||||
"H3x2_RNa.smk" : 78,
|
||||
"H3x2_RNb.smk" : 79,
|
||||
"H3x2_RNc.smk" : 80,
|
||||
"H3x2_RNd.smk" : 81,
|
||||
"H3x2_RNe1.smk": 82,
|
||||
"H3x2_SPa.smk" : 83,
|
||||
"H3x2_SPb.smk" : 84,
|
||||
"H3x2_SPc.smk" : 85,
|
||||
"H3x2_SPd.smk" : 86,
|
||||
"H3x2_SPe.smk" : 87,
|
||||
"H3x2_UAa.smk" : 88,
|
||||
"H3x2_UAb.smk" : 89,
|
||||
"H3x2_UAc.smk" : 90,
|
||||
"H3x2_UAd.smk" : 91,
|
||||
"H3x2_UAe.smk" : 92,
|
||||
"H3x2_UAf.smk" : 93,
|
||||
"H3x2_UAg.smk" : 94,
|
||||
"H3x2_UAh.smk" : 95,
|
||||
"H3x2_UAi.smk" : 96,
|
||||
"H3x2_UAj.smk" : 97,
|
||||
"H3x2_UAk.smk" : 98,
|
||||
"H3x2_UAl.smk" : 99,
|
||||
"H3x2_UAm.smk" : 100 //H3x2_UAm.bik?
|
||||
}
|
||||
},
|
||||
"chronicles" : {
|
||||
|
@@ -90,22 +90,9 @@ std::string StartInfo::getCampaignName() const
|
||||
return LIBRARY->generaltexth->allTexts[508];
|
||||
}
|
||||
|
||||
bool StartInfo::isRestorationOfErathiaCampaign() const
|
||||
bool StartInfo::restrictedGarrisonsForAI() const
|
||||
{
|
||||
constexpr std::array roeCampaigns = {
|
||||
"DATA/GOOD1",
|
||||
"DATA/EVIL1",
|
||||
"DATA/GOOD2",
|
||||
"DATA/NEUTRAL1",
|
||||
"DATA/EVIL2",
|
||||
"DATA/GOOD3",
|
||||
"DATA/SECRET1",
|
||||
};
|
||||
|
||||
if (!campState)
|
||||
return false;
|
||||
|
||||
return vstd::contains(roeCampaigns, campState->getFilename());
|
||||
return campState && campState->restrictedGarrisonsForAI();
|
||||
}
|
||||
|
||||
void LobbyInfo::verifyStateBeforeStart(bool ignoreNoHuman) const
|
||||
|
@@ -153,8 +153,8 @@ struct DLL_LINKAGE StartInfo : public Serializeable
|
||||
// TODO: Must be client-side
|
||||
std::string getCampaignName() const;
|
||||
|
||||
/// Controls hardcoded check for handling of garrisons by AI in Restoration of Erathia campaigns to match H3 behavior
|
||||
bool isRestorationOfErathiaCampaign() const;
|
||||
/// Controls check for handling of garrisons by AI in Restoration of Erathia campaigns to match H3 behavior
|
||||
bool restrictedGarrisonsForAI() const;
|
||||
|
||||
template <typename Handler>
|
||||
void serialize(Handler &h)
|
||||
|
@@ -64,14 +64,14 @@ CampaignBonus::CampaignBonus(CBinaryReader & reader, const MapIdentifiersH3M & r
|
||||
{
|
||||
case CampaignBonusType::SPELL:
|
||||
{
|
||||
HeroTypeID hero(reader.readUInt16());
|
||||
HeroTypeID hero(reader.readInt16());
|
||||
SpellID spell(reader.readUInt8());
|
||||
data = CampaignBonusSpell{remapper.remap(hero), spell};
|
||||
break;
|
||||
}
|
||||
case CampaignBonusType::MONSTER:
|
||||
{
|
||||
HeroTypeID hero(reader.readUInt16());
|
||||
HeroTypeID hero(reader.readInt16());
|
||||
CreatureID creature(reader.readUInt16());
|
||||
int32_t amount = reader.readUInt16();
|
||||
data = CampaignBonusCreatures{remapper.remap(hero), remapper.remap(creature), amount};
|
||||
@@ -85,21 +85,21 @@ CampaignBonus::CampaignBonus(CBinaryReader & reader, const MapIdentifiersH3M & r
|
||||
}
|
||||
case CampaignBonusType::ARTIFACT:
|
||||
{
|
||||
HeroTypeID hero(reader.readUInt16());
|
||||
HeroTypeID hero(reader.readInt16());
|
||||
ArtifactID artifact(reader.readUInt16());
|
||||
data = CampaignBonusArtifact{remapper.remap(hero), remapper.remap(artifact)};
|
||||
break;
|
||||
}
|
||||
case CampaignBonusType::SPELL_SCROLL:
|
||||
{
|
||||
HeroTypeID hero(reader.readUInt16());
|
||||
HeroTypeID hero(reader.readInt16());
|
||||
SpellID spell(reader.readUInt8());
|
||||
data = CampaignBonusSpellScroll{remapper.remap(hero), spell};
|
||||
break;
|
||||
}
|
||||
case CampaignBonusType::PRIMARY_SKILL:
|
||||
{
|
||||
HeroTypeID hero(reader.readUInt16());
|
||||
HeroTypeID hero(reader.readInt16());
|
||||
std::array<uint8_t, 4> amounts = {};
|
||||
for(auto & value : amounts)
|
||||
value = reader.readUInt8();
|
||||
@@ -109,7 +109,7 @@ CampaignBonus::CampaignBonus(CBinaryReader & reader, const MapIdentifiersH3M & r
|
||||
}
|
||||
case CampaignBonusType::SECONDARY_SKILL:
|
||||
{
|
||||
HeroTypeID hero(reader.readUInt16());
|
||||
HeroTypeID hero(reader.readInt16());
|
||||
SecondarySkill skill(reader.readUInt8());
|
||||
int32_t skillMastery(reader.readUInt8());
|
||||
data = CampaignBonusSecondarySkill{remapper.remap(hero), remapper.remap(skill), skillMastery};
|
||||
|
@@ -188,7 +188,8 @@ public:
|
||||
{
|
||||
result = bonusValue.hero;
|
||||
}
|
||||
throw std::runtime_error("Attempt to get targeted hero on invalid type!");
|
||||
else
|
||||
throw std::runtime_error("Attempt to get targeted hero on invalid type!");
|
||||
}, data);
|
||||
|
||||
return result;
|
||||
|
@@ -370,7 +370,8 @@ void CampaignHandler::readHeaderFromMemory( CampaignHeader & ret, CBinaryReader
|
||||
else
|
||||
ret.difficultyChosenByPlayer = false;
|
||||
|
||||
ret.music = prologMusicName(reader.readInt8());
|
||||
ret.music = mapping.remapCampaignMusic(reader.readUInt8());
|
||||
logGlobal->info("Campaign %s: map %d (%d scenarios), music theme: %s", filename, campaignMapId.getNum(), ret.numberOfScenarios, ret.music.getOriginalName());
|
||||
ret.filename = filename;
|
||||
ret.modName = modName;
|
||||
ret.encoding = encoding;
|
||||
@@ -378,18 +379,17 @@ void CampaignHandler::readHeaderFromMemory( CampaignHeader & ret, CBinaryReader
|
||||
|
||||
CampaignScenario CampaignHandler::readScenarioFromMemory( CBinaryReader & reader, CampaignHeader & header)
|
||||
{
|
||||
const auto & mapping = LIBRARY->mapFormat->getMapping(header.version);
|
||||
|
||||
auto prologEpilogReader = [&](const std::string & identifier) -> CampaignScenarioPrologEpilog
|
||||
{
|
||||
CampaignScenarioPrologEpilog ret;
|
||||
ret.hasPrologEpilog = reader.readBool();
|
||||
if(ret.hasPrologEpilog)
|
||||
{
|
||||
bool isOriginalCampaign = boost::starts_with(header.getFilename(), "DATA/");
|
||||
|
||||
ui8 index = reader.readUInt8();
|
||||
ret.prologVideo = CampaignHandler::prologVideoName(index);
|
||||
ret.prologMusic = CampaignHandler::prologMusicName(reader.readUInt8());
|
||||
ret.prologVoice = isOriginalCampaign ? CampaignHandler::prologVoiceName(index) : AudioPath();
|
||||
ret.prologVideo = mapping.remapCampaignVideo(reader.readUInt8());
|
||||
ret.prologMusic = mapping.remapCampaignMusic(reader.readUInt8());
|
||||
logGlobal->info("Campaign %s, scenario %s: music theme: %s, video: %s", header.filename, identifier, ret.prologMusic.getOriginalName(), ret.prologVideo.getOriginalName());
|
||||
ret.prologText.appendTextID(readLocalizedString(header, reader, header.filename, header.modName, header.encoding, identifier));
|
||||
}
|
||||
return ret;
|
||||
@@ -544,28 +544,4 @@ std::vector< std::vector<ui8> > CampaignHandler::getFile(std::unique_ptr<CInputS
|
||||
}
|
||||
}
|
||||
|
||||
VideoPath CampaignHandler::prologVideoName(ui8 index)
|
||||
{
|
||||
JsonNode config(JsonPath::builtin("CONFIG/campaignMedia"));
|
||||
auto vids = config["videos"].Vector();
|
||||
if(index < vids.size())
|
||||
return VideoPath::fromJson(vids[index]);
|
||||
return VideoPath();
|
||||
}
|
||||
|
||||
AudioPath CampaignHandler::prologMusicName(ui8 index)
|
||||
{
|
||||
std::vector<std::string> music;
|
||||
return AudioPath::builtinTODO(LIBRARY->generaltexth->translate("core.cmpmusic." + std::to_string(static_cast<int>(index))));
|
||||
}
|
||||
|
||||
AudioPath CampaignHandler::prologVoiceName(ui8 index)
|
||||
{
|
||||
JsonNode config(JsonPath::builtin("CONFIG/campaignMedia"));
|
||||
auto audio = config["voice"].Vector();
|
||||
if(index < audio.size())
|
||||
return AudioPath::fromJson(audio[index]);
|
||||
return AudioPath();
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -37,10 +37,6 @@ class DLL_LINKAGE CampaignHandler
|
||||
/// headerOnly - only header will be decompressed, returned vector wont have any maps
|
||||
static std::vector<std::vector<ui8>> getFile(std::unique_ptr<CInputStream> file, const std::string & filename, bool headerOnly);
|
||||
|
||||
static VideoPath prologVideoName(ui8 index);
|
||||
static AudioPath prologMusicName(ui8 index);
|
||||
static AudioPath prologVoiceName(ui8 index);
|
||||
|
||||
static constexpr auto VCMP_HEADER_FILE_NAME = "header.json";
|
||||
public:
|
||||
static std::unique_ptr<Campaign> getHeader( const std::string & name); //name - name of appropriate file
|
||||
|
@@ -12,6 +12,8 @@
|
||||
|
||||
#include "../json/JsonNode.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
CampaignRegions::RegionDescription CampaignRegions::RegionDescription::fromJson(const JsonNode & node)
|
||||
{
|
||||
CampaignRegions::RegionDescription rd;
|
||||
@@ -146,3 +148,5 @@ int CampaignRegions::regionsCount() const
|
||||
{
|
||||
return regions.size();
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -12,6 +12,8 @@
|
||||
|
||||
#include "../json/JsonNode.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
std::vector<JsonNode> CampaignRegionsHandler::loadLegacyData()
|
||||
{
|
||||
return {};
|
||||
@@ -28,3 +30,5 @@ void CampaignRegionsHandler::loadObject(std::string scope, std::string name, con
|
||||
{
|
||||
throw std::runtime_error("CampaignRegionsHandler::loadObject - load by index is not supported!");
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -18,7 +18,7 @@ struct DLL_LINKAGE CampaignScenarioPrologEpilog
|
||||
{
|
||||
bool hasPrologEpilog = false;
|
||||
VideoPath prologVideo;
|
||||
AudioPath prologMusic; // from CmpMusic.txt
|
||||
AudioPath prologMusic;
|
||||
AudioPath prologVoice;
|
||||
MetaString prologText;
|
||||
|
||||
|
@@ -392,6 +392,12 @@ void Campaign::overrideCampaign()
|
||||
introVideo = VideoPath::builtin(overrides["introVideo"].String());
|
||||
if(!overrides["outroVideo"].isNull())
|
||||
outroVideo = VideoPath::builtin(overrides["outroVideo"].String());
|
||||
if(!overrides["heroGemSorceress"].isNull())
|
||||
gemSorceressID = HeroTypeID(*LIBRARY->identifiersHandler->getIdentifier("hero", overrides["heroGemSorceress"]));
|
||||
if(!overrides["heroYogWizard"].isNull())
|
||||
yogWizardID = HeroTypeID(*LIBRARY->identifiersHandler->getIdentifier("hero", overrides["heroYogWizard"]));
|
||||
|
||||
restrictGarrisonsAI = overrides["restrictedGarrisonsForAI"].Bool();
|
||||
}
|
||||
|
||||
void Campaign::overrideCampaignScenarios()
|
||||
@@ -431,4 +437,17 @@ bool CampaignState::isCampaignFinished() const
|
||||
return conqueredScenarios() == allScenarios();
|
||||
}
|
||||
|
||||
HeroTypeID CampaignHeader::getYogWizardID() const
|
||||
{
|
||||
return yogWizardID;
|
||||
}
|
||||
HeroTypeID CampaignHeader::getGemSorceressID() const
|
||||
{
|
||||
return gemSorceressID;
|
||||
}
|
||||
bool CampaignHeader::restrictedGarrisonsForAI() const
|
||||
{
|
||||
return restrictGarrisonsAI;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -57,11 +57,14 @@ class DLL_LINKAGE CampaignHeader : public boost::noncopyable
|
||||
VideoPath introVideo;
|
||||
VideoPath outroVideo;
|
||||
|
||||
HeroTypeID yogWizardID;
|
||||
HeroTypeID gemSorceressID;
|
||||
|
||||
int numberOfScenarios = 0;
|
||||
bool difficultyChosenByPlayer = false;
|
||||
bool restrictGarrisonsAI = false;
|
||||
|
||||
TextContainerRegistrable textContainer;
|
||||
|
||||
public:
|
||||
bool playerSelectedDifficulty() const;
|
||||
bool formatVCMI() const;
|
||||
@@ -81,6 +84,10 @@ public:
|
||||
VideoPath getIntroVideo() const;
|
||||
VideoPath getOutroVideo() const;
|
||||
|
||||
HeroTypeID getYogWizardID() const;
|
||||
HeroTypeID getGemSorceressID() const;
|
||||
bool restrictedGarrisonsForAI() const;
|
||||
|
||||
const CampaignRegions & getRegions() const;
|
||||
TextContainerRegistrable & getTexts();
|
||||
|
||||
@@ -96,6 +103,8 @@ public:
|
||||
h & campaignVersion;
|
||||
h & creationDateTime;
|
||||
h & difficultyChosenByPlayer;
|
||||
if (h.hasFeature(Handler::Version::CAMPAIGN_BONUSES))
|
||||
h & restrictGarrisonsAI;
|
||||
h & filename;
|
||||
h & modName;
|
||||
h & music;
|
||||
@@ -105,6 +114,11 @@ public:
|
||||
h & videoRim;
|
||||
h & introVideo;
|
||||
h & outroVideo;
|
||||
if (h.hasFeature(Handler::Version::CAMPAIGN_BONUSES))
|
||||
{
|
||||
h & yogWizardID;
|
||||
h & gemSorceressID;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -57,9 +57,9 @@ const HeroTypeID HeroTypeID::NONE(-1);
|
||||
const HeroTypeID HeroTypeID::RANDOM(-2);
|
||||
const HeroTypeID HeroTypeID::GEM(27);
|
||||
const HeroTypeID HeroTypeID::SOLMYR(45);
|
||||
const HeroTypeID HeroTypeID::CAMP_STRONGEST(0xFFFD);
|
||||
const HeroTypeID HeroTypeID::CAMP_GENERATED(0xFFFE);
|
||||
const HeroTypeID HeroTypeID::CAMP_RANDOM(0xFFFF);
|
||||
const HeroTypeID HeroTypeID::CAMP_STRONGEST(-3);
|
||||
const HeroTypeID HeroTypeID::CAMP_GENERATED(-2);
|
||||
const HeroTypeID HeroTypeID::CAMP_RANDOM(-1);
|
||||
|
||||
const ObjectInstanceID ObjectInstanceID::NONE(-1);
|
||||
|
||||
@@ -258,6 +258,8 @@ si32 HeroTypeID::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier == "random")
|
||||
return -2;
|
||||
if (identifier == "strongest")
|
||||
return -3;
|
||||
return resolveIdentifier("hero", identifier);
|
||||
}
|
||||
|
||||
@@ -267,6 +269,8 @@ std::string HeroTypeID::encode(const si32 index)
|
||||
return "";
|
||||
if (index == -2)
|
||||
return "random";
|
||||
if (index == -3)
|
||||
return "strongest";
|
||||
return LIBRARY->heroTypes()->getByIndex(index)->getJsonKey();
|
||||
}
|
||||
|
||||
|
@@ -1065,9 +1065,9 @@ public:
|
||||
MITHRIL,
|
||||
COUNT,
|
||||
|
||||
WOOD_AND_ORE = 127, // special case for town bonus resource
|
||||
COMMON = 0xFD, // campaign bonus
|
||||
RARE = 0xFE, // campaign bonus
|
||||
WOOD_AND_ORE = -4, // special case for town bonus resource
|
||||
COMMON = -3, // campaign bonus
|
||||
RARE = -2, // campaign bonus
|
||||
NONE = -1
|
||||
};
|
||||
};
|
||||
|
@@ -239,12 +239,17 @@ static void loadBonusAddInfo(CAddInfo & var, BonusType type, const JsonNode & va
|
||||
case BonusType::SPELL_BEFORE_ATTACK:
|
||||
case BonusType::SPELL_AFTER_ATTACK:
|
||||
// 3 numbers
|
||||
if (!value.isVector())
|
||||
break;
|
||||
var.resize(3);
|
||||
var[0] = value[0].Integer();
|
||||
var[1] = value[1].Integer();
|
||||
var[2] = value[2].Integer();
|
||||
if (value.isNumber())
|
||||
{
|
||||
var = getFirstValue(value).Integer();
|
||||
}
|
||||
else
|
||||
{
|
||||
var.resize(3);
|
||||
var[0] = value[0].Integer();
|
||||
var[1] = value[1].Integer();
|
||||
var[2] = value[2].Integer();
|
||||
}
|
||||
break;
|
||||
case BonusType::MULTIHEX_UNIT_ATTACK:
|
||||
case BonusType::MULTIHEX_ENEMY_ATTACK:
|
||||
|
@@ -1802,37 +1802,13 @@ void CGHeroInstance::fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &
|
||||
bool CGHeroInstance::isCampaignYog() const
|
||||
{
|
||||
const StartInfo *si = cb->getStartInfo();
|
||||
|
||||
// it would be nice to find a way to move this hack to config/mapOverrides.json
|
||||
if(!si || !si->campState)
|
||||
return false;
|
||||
|
||||
std::string campaign = si->campState->getFilename();
|
||||
if (!boost::starts_with(campaign, "DATA/YOG")) // "Birth of a Barbarian"
|
||||
return false;
|
||||
|
||||
if (getHeroTypeID() != HeroTypeID::SOLMYR) // Yog (based on Solmyr)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return si && si->campState &&si->campState->getYogWizardID() == getHeroTypeID();
|
||||
}
|
||||
|
||||
bool CGHeroInstance::isCampaignGem() const
|
||||
{
|
||||
const StartInfo *si = cb->getStartInfo();
|
||||
|
||||
// it would be nice to find a way to move this hack to config/mapOverrides.json
|
||||
if(!si || !si->campState)
|
||||
return false;
|
||||
|
||||
std::string campaign = si->campState->getFilename();
|
||||
if (!boost::starts_with(campaign, "DATA/GEM") && !boost::starts_with(campaign, "DATA/FINAL")) // "New Beginning" and "Unholy Alliance"
|
||||
return false;
|
||||
|
||||
if (getHeroTypeID() != HeroTypeID::GEM) // Yog (based on Solmyr)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return si && si->campState &&si->campState->getGemSorceressID() == getHeroTypeID();
|
||||
}
|
||||
|
||||
ResourceSet CGHeroInstance::dailyIncome() const
|
||||
|
@@ -18,6 +18,8 @@
|
||||
#include "../json/JsonUtils.h"
|
||||
#include "../modding/ModScope.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
MapIdentifiersH3M MapFormatSettings::generateMapping(EMapFormat format)
|
||||
{
|
||||
auto features = MapFormatFeaturesH3M::find(format, 0);
|
||||
@@ -87,6 +89,7 @@ MapFormatSettings::MapFormatSettings()
|
||||
for (auto & entry : mapOverridesConfig.Struct())
|
||||
JsonUtils::validate(entry.second, "vcmi:mapHeader", "patch for " + entry.first);
|
||||
|
||||
campaignOverridesConfig.setModScope(ModScope::scopeMap());
|
||||
mapOverridesConfig.setModScope(ModScope::scopeMap());
|
||||
}
|
||||
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class MapFormatSettings : boost::noncopyable
|
||||
class MapFormatSettings : boost::noncopyable
|
||||
{
|
||||
static MapIdentifiersH3M generateMapping(EMapFormat format);
|
||||
static std::map<EMapFormat, MapIdentifiersH3M> generateMappings();
|
||||
|
@@ -89,6 +89,12 @@ void MapIdentifiersH3M::loadMapping(const JsonNode & mapping)
|
||||
}
|
||||
}
|
||||
|
||||
for (auto entry : mapping["campaignVideo"].Struct())
|
||||
mappingCampaignVideo[entry.second.Integer()] = VideoPath::builtinTODO(entry.first);
|
||||
|
||||
for (auto entry : mapping["campaignMusic"].Struct())
|
||||
mappingCampaignMusic[entry.second.Integer()] = AudioPath::builtinTODO(entry.first);
|
||||
|
||||
loadMapping(mappingHeroPortrait, mapping["portraits"], "hero");
|
||||
loadMapping(mappingBuilding, mapping["buildingsCommon"], "building.core:random");
|
||||
loadMapping(mappingFaction, mapping["factions"], "faction");
|
||||
@@ -216,9 +222,26 @@ SecondarySkill MapIdentifiersH3M::remap(SecondarySkill input) const
|
||||
|
||||
CampaignRegionID MapIdentifiersH3M::remap(CampaignRegionID input) const
|
||||
{
|
||||
if (mappingCampaignRegions.count(input))
|
||||
return mappingCampaignRegions.at(input);
|
||||
return input;
|
||||
if (!mappingCampaignRegions.count(input))
|
||||
throw std::out_of_range("Campaign region with ID " + std::to_string(input.getNum()) + " is not defined");
|
||||
|
||||
return mappingCampaignRegions.at(input);
|
||||
}
|
||||
|
||||
VideoPath MapIdentifiersH3M::remapCampaignVideo(int input) const
|
||||
{
|
||||
if (!mappingCampaignVideo.count(input))
|
||||
throw std::out_of_range("Campaign video with ID " + std::to_string(input) + " is not defined");
|
||||
|
||||
return mappingCampaignVideo.at(input);
|
||||
}
|
||||
|
||||
AudioPath MapIdentifiersH3M::remapCampaignMusic(int input) const
|
||||
{
|
||||
if (!mappingCampaignMusic.count(input))
|
||||
throw std::out_of_range("Campaign music with ID " + std::to_string(input) + " is not defined");
|
||||
|
||||
return mappingCampaignMusic.at(input);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -44,6 +44,8 @@ class MapIdentifiersH3M
|
||||
std::map<ArtifactID, ArtifactID> mappingArtifact;
|
||||
std::map<SecondarySkill, SecondarySkill> mappingSecondarySkill;
|
||||
std::map<CampaignRegionID, CampaignRegionID> mappingCampaignRegions;
|
||||
std::map<int, VideoPath> mappingCampaignVideo;
|
||||
std::map<int, AudioPath> mappingCampaignMusic;
|
||||
|
||||
std::map<AnimationPath, AnimationPath> mappingObjectTemplate;
|
||||
std::map<ObjectTypeIdentifier, ObjectTypeIdentifier> mappingObjectIndex;
|
||||
@@ -55,6 +57,8 @@ public:
|
||||
|
||||
void remapTemplate(ObjectTemplate & objectTemplate);
|
||||
|
||||
AudioPath remapCampaignMusic(int index) const;
|
||||
VideoPath remapCampaignVideo(int index) const;
|
||||
BuildingID remapBuilding(std::optional<FactionID> owner, BuildingID input) const;
|
||||
HeroTypeID remapPortrait(HeroTypeID input) const;
|
||||
FactionID remap(FactionID input) const;
|
||||
|
@@ -159,7 +159,6 @@ CGeneralTextHandler::CGeneralTextHandler():
|
||||
readToVector("core.heroscrn", "DATA/HEROSCRN.TXT" );
|
||||
readToVector("core.tentcolr", "DATA/TENTCOLR.TXT" );
|
||||
readToVector("core.skilllev", "DATA/SKILLLEV.TXT" );
|
||||
readToVector("core.cmpmusic", "DATA/CMPMUSIC.TXT" );
|
||||
readToVector("core.minename", "DATA/MINENAME.TXT" );
|
||||
readToVector("core.mineevnt", "DATA/MINEEVNT.TXT" );
|
||||
readToVector("core.xtrainfo", "DATA/XTRAINFO.TXT" );
|
||||
|
Reference in New Issue
Block a user