1 /***************************************************************************
2  *   Free Heroes of Might and Magic II: https://github.com/ihhub/fheroes2  *
3  *   Copyright (C) 2021                                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 
21 #include "campaign_data.h"
22 #include "artifact.h"
23 #include "heroes.h"
24 #include "monster.h"
25 #include "resource.h"
26 #include "spell.h"
27 #include "translations.h"
28 #include <cassert>
29 
30 namespace
31 {
32     const std::vector<Campaign::ScenarioIntroVideoInfo> emptyPlayback;
33 
getRolandCampaignAwardData(const int scenarioID)34     std::vector<Campaign::CampaignAwardData> getRolandCampaignAwardData( const int scenarioID )
35     {
36         std::vector<Campaign::CampaignAwardData> obtainableAwards;
37 
38         switch ( scenarioID ) {
39         case 2:
40             obtainableAwards.emplace_back( 0, Campaign::CampaignAwardData::TYPE_CREATURE_ALLIANCE, Monster::DWARF, _( "Dwarven Alliance" ) );
41             break;
42         case 5:
43             obtainableAwards.emplace_back( 1, Campaign::CampaignAwardData::TYPE_HIREABLE_HERO, Heroes::ELIZA, 0, 0, _( "Sorceress Guild" ) );
44             break;
45         case 6:
46             obtainableAwards.emplace_back( 2, Campaign::CampaignAwardData::TYPE_CARRY_OVER_FORCES, 0, 0, 9 );
47             break;
48         case 7:
49             obtainableAwards.emplace_back( 3, Campaign::CampaignAwardData::TYPE_GET_ARTIFACT, Artifact::ULTIMATE_CROWN, 1, 9 );
50             break;
51         case 8:
52             obtainableAwards.emplace_back( 4, Campaign::CampaignAwardData::TYPE_DEFEAT_ENEMY_HERO, Heroes::CORLAGON, 0, 9 );
53             break;
54         }
55 
56         return obtainableAwards;
57     }
58 
getArchibaldCampaignAwardData(const int scenarioID)59     std::vector<Campaign::CampaignAwardData> getArchibaldCampaignAwardData( const int scenarioID )
60     {
61         std::vector<Campaign::CampaignAwardData> obtainableAwards;
62 
63         switch ( scenarioID ) {
64         case 2:
65             obtainableAwards.emplace_back( 1, Campaign::CampaignAwardData::TYPE_HIREABLE_HERO, Heroes::BAX, 0, 0, _( "Necromancer Guild" ) );
66             break;
67         case 3:
68             obtainableAwards.emplace_back( 2, Campaign::CampaignAwardData::TYPE_CREATURE_ALLIANCE, Monster::OGRE );
69             obtainableAwards.emplace_back( 3, Campaign::CampaignAwardData::TYPE_CREATURE_CURSE, Monster::DWARF );
70             break;
71         case 6:
72             obtainableAwards.emplace_back( 4, Campaign::CampaignAwardData::TYPE_CREATURE_ALLIANCE, Monster::GREEN_DRAGON, _( "Dragon Alliance" ) );
73             break;
74         case 8:
75             obtainableAwards.emplace_back( 5, Campaign::CampaignAwardData::TYPE_GET_ARTIFACT, Artifact::ULTIMATE_CROWN );
76             break;
77         case 9:
78             obtainableAwards.emplace_back( 6, Campaign::CampaignAwardData::TYPE_CARRY_OVER_FORCES, 0 );
79             break;
80         }
81 
82         return obtainableAwards;
83     }
84 
getPriceOfLoyaltyCampaignAwardData(const int scenarioID)85     std::vector<Campaign::CampaignAwardData> getPriceOfLoyaltyCampaignAwardData( const int scenarioID )
86     {
87         std::vector<Campaign::CampaignAwardData> obtainableAwards;
88 
89         switch ( scenarioID ) {
90         case 1:
91             obtainableAwards.emplace_back( 0, Campaign::CampaignAwardData::TYPE_GET_ARTIFACT, Artifact::BREASTPLATE_ANDURAN );
92             break;
93         case 2:
94             obtainableAwards.emplace_back( 1, Campaign::CampaignAwardData::TYPE_CREATURE_ALLIANCE, Monster::ELF, _( "Elven Alliance" ) );
95             obtainableAwards.emplace_back( 2, Campaign::CampaignAwardData::TYPE_RESOURCE_BONUS, Resource::WOOD, 2 );
96             break;
97         case 5:
98             obtainableAwards.emplace_back( 3, Campaign::CampaignAwardData::TYPE_GET_ARTIFACT, Artifact::HELMET_ANDURAN );
99             break;
100         case 6:
101             // Will assemble Battle Garb of Anduran along with the previous anduran set pieces
102             // If we get all the parts, we'll obtain the Battle Garb award while removing the awards for the individual parts
103             obtainableAwards.emplace_back( 4, Campaign::CampaignAwardData::TYPE_GET_ARTIFACT, Artifact::SWORD_ANDURAN );
104 
105             // seems that Kraeger is a custom name for Dainwin in this case
106             obtainableAwards.emplace_back( 5, Campaign::CampaignAwardData::TYPE_DEFEAT_ENEMY_HERO, Heroes::DAINWIN, _( "Kraeger defeated" ) );
107             break;
108         }
109 
110         return obtainableAwards;
111     }
112 
getWizardsIsleCampaignAwardData(const int scenarioID)113     std::vector<Campaign::CampaignAwardData> getWizardsIsleCampaignAwardData( const int scenarioID )
114     {
115         std::vector<Campaign::CampaignAwardData> obtainableAwards;
116 
117         switch ( scenarioID ) {
118         case 1:
119             obtainableAwards.emplace_back( 0, Campaign::CampaignAwardData::TYPE_GET_SPELL, Spell::SETEGUARDIAN );
120             break;
121         case 2:
122             obtainableAwards.emplace_back( 1, Campaign::CampaignAwardData::TYPE_GET_ARTIFACT, Artifact::SPHERE_NEGATION );
123             break;
124         }
125 
126         return obtainableAwards;
127     }
128 
getDescendantsCampaignAwardData(const int scenarioID)129     std::vector<Campaign::CampaignAwardData> getDescendantsCampaignAwardData( const int scenarioID )
130     {
131         std::vector<Campaign::CampaignAwardData> obtainableAwards;
132 
133         switch ( scenarioID ) {
134         case 2:
135             obtainableAwards.emplace_back( 0, Campaign::CampaignAwardData::TYPE_HIREABLE_HERO, Heroes::JOSEPH, 0, 0, _( "Wayward Son" ) );
136             break;
137         case 3:
138             obtainableAwards.emplace_back( 1, Campaign::CampaignAwardData::TYPE_HIREABLE_HERO, Heroes::UNCLEIVAN, 0, 0, _( "Uncle Ivan" ) );
139             break;
140         case 5:
141             obtainableAwards.emplace_back( 2, Campaign::CampaignAwardData::TYPE_GET_ARTIFACT, Artifact::LEGENDARY_SCEPTER );
142             break;
143         case 6:
144             obtainableAwards.emplace_back( 3, Campaign::CampaignAwardData::TYPE_CREATURE_ALLIANCE, Monster::ELF, _( "Elven Alliance" ) );
145             break;
146         }
147 
148         return obtainableAwards;
149     }
150 
getRolandCampaignData()151     Campaign::CampaignData getRolandCampaignData()
152     {
153         const std::string rolandCampaignScenarioNames[10]
154             = { _( "Force of Arms" ), _( "Annexation" ),   _( "Save the Dwarves" ), _( "Carator Mines" ),      _( "Turning Point" ),
155                 _( "Defender" ),      _( "The Gauntlet" ), _( "The Crown" ),        _( "Corlagon's Defense" ), _( "Final Justice" ) };
156         const std::string rolandCampaignDescription[10] = {
157             _( "Roland needs you to defeat the lords near his castle to begin his war of rebellion against his brother.  They are not allied with each other, so they will spend"
158                " most of their time fighting with one another.  Victory is yours when you have defeated all of their castles and heroes." ),
159             _( "The local lords refuse to swear allegiance to Roland, and must be subdued. They are wealthy and powerful, so be prepared for a tough fight. Capture all enemy castles to win." ),
160             _( "Your task is to defend the Dwarves against Archibald's forces. Capture all of the enemy towns and castles to win, and be sure not to lose all of the dwarf towns at once, or the enemy will have won." ),
161             _( "You will face four allied enemies in a straightforward fight for resource and treasure. Capture all of the enemy castles for victory." ),
162             _( "Your enemies are allied against you and start close by, so be ready to come out fighting. You will need to own all four castles in this small valley to win." ),
163             _( "The Sorceress' guild of Noraston has requested Roland's aid against an attack from Archibald's allies. Capture all of the enemy castles to win, and don't lose Noraston, or you'll lose the scenario. (Hint: There is an enemy castle on an island in the ocean.)" ),
164             _( "Gather as large an army as possible and capture the enemy castle within 8 weeks. You are opposed by only one enemy, but must travel a long way to get to the enemy castle. Any troops you have in your army at the end of this scenario will be with you in the final battle." ),
165             _( "Find the Crown before Archibald's heroes find it. Roland will need the Crown for the final battle against Archibald." ),
166             _( "Three allied enemies stand before you and victory, including Lord Corlagon. Roland is in a castle to the northwest, and you will lose if he falls to the enemy. Remember that capturing Lord Corlagon will ensure that he will not fight against you in the final scenario." ),
167             _( "This is the final battle. Both you and your enemy are armed to the teeth, and all are allied against you. Capture Archibald to end the war!" ) };
168         std::vector<Campaign::ScenarioData> scenarioDatas;
169         scenarioDatas.reserve( 10 );
170 
171         scenarioDatas.emplace_back( 0, std::vector<int>{ 1 }, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 0 ), "CAMPG01.H2C", rolandCampaignScenarioNames[0],
172                                     rolandCampaignDescription[0],
173                                     Campaign::VideoSequence{ { "GOOD01V.SMK", Video::VideoAction::IGNORE_VIDEO },
174                                                              { "GOOD01.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
175                                     emptyPlayback );
176         scenarioDatas.emplace_back( 1, std::vector<int>{ 2, 3 }, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 1 ), "CAMPG02.H2C", rolandCampaignScenarioNames[1],
177                                     rolandCampaignDescription[1],
178                                     Campaign::VideoSequence{ { "GOOD02W.SMK", Video::VideoAction::IGNORE_VIDEO },
179                                                              { "GOOD02.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
180                                     Campaign::VideoSequence{ { "GOOD03QW.SMK", Video::VideoAction::IGNORE_VIDEO },
181                                                              { "GOOD03.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
182         scenarioDatas.emplace_back( 2, std::vector<int>{ 3 }, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 2 ), "CAMPG03.H2C", rolandCampaignScenarioNames[2],
183                                     rolandCampaignDescription[2], emptyPlayback,
184                                     Campaign::VideoSequence{ { "GOOD04W.SMK", Video::VideoAction::IGNORE_VIDEO },
185                                                              { "GOOD04.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
186                                     Campaign::ScenarioVictoryCondition::STANDARD, Campaign::ScenarioLossCondition::LOSE_ALL_SORCERESS_VILLAGES );
187         scenarioDatas.emplace_back( 3, std::vector<int>{ 4 }, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 3 ), "CAMPG04.H2C", rolandCampaignScenarioNames[3],
188                                     rolandCampaignDescription[3], emptyPlayback,
189                                     Campaign::VideoSequence{ { "GOOD05V.SMK", Video::VideoAction::IGNORE_VIDEO },
190                                                              { "GOOD05.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
191         scenarioDatas.emplace_back( 4, std::vector<int>{ 5 }, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 4 ), "CAMPG05.H2C", rolandCampaignScenarioNames[4],
192                                     rolandCampaignDescription[4], emptyPlayback, emptyPlayback );
193         scenarioDatas.emplace_back( 5, std::vector<int>{ 6, 7 }, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 5 ), "CAMPG06.H2C", rolandCampaignScenarioNames[5],
194                                     rolandCampaignDescription[5],
195                                     Campaign::VideoSequence{ { "GOOD06AV.SMK", Video::VideoAction::IGNORE_VIDEO },
196                                                              { "GOOD06.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
197                                     Campaign::VideoSequence{ { "GOOD07QW.SMK", Video::VideoAction::IGNORE_VIDEO },
198                                                              { "GOOD07.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
199         scenarioDatas.emplace_back( 6, std::vector<int>{ 8 }, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 6 ), "CAMPG07.H2C", rolandCampaignScenarioNames[6],
200                                     rolandCampaignDescription[6], emptyPlayback, emptyPlayback );
201         scenarioDatas.emplace_back( 7, std::vector<int>{ 8 }, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 7 ), "CAMPG08.H2C", rolandCampaignScenarioNames[7],
202                                     rolandCampaignDescription[7], emptyPlayback, emptyPlayback, Campaign::ScenarioVictoryCondition::OBTAIN_ULTIMATE_CROWN );
203         scenarioDatas.emplace_back( 8, std::vector<int>{ 9 }, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 8 ), "CAMPG09.H2C", rolandCampaignScenarioNames[8],
204                                     rolandCampaignDescription[8],
205                                     Campaign::VideoSequence{ { "GOOD09W.SMK", Video::VideoAction::IGNORE_VIDEO },
206                                                              { "GOOD09.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
207                                     emptyPlayback );
208         scenarioDatas.emplace_back( 9, std::vector<int>{}, Campaign::ScenarioBonusData::getCampaignBonusData( 0, 9 ), "CAMPG10.H2C", rolandCampaignScenarioNames[9],
209                                     rolandCampaignDescription[9],
210                                     Campaign::VideoSequence{ { "GOOD10W.SMK", Video::VideoAction::IGNORE_VIDEO },
211                                                              { "GOOD10.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
212                                     Campaign::VideoSequence{ { "LIBRARYW.SMK", Video::VideoAction::IGNORE_VIDEO },
213                                                              { "LIBRARY.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
214 
215         Campaign::CampaignData campaignData;
216         campaignData.setCampaignID( Campaign::ROLAND_CAMPAIGN );
217         campaignData.setCampaignDescription( "Roland Campaign" );
218         campaignData.setCampaignScenarios( scenarioDatas );
219 
220         return campaignData;
221     }
222 
getArchibaldCampaignData()223     Campaign::CampaignData getArchibaldCampaignData()
224     {
225         const std::string archibaldCampaignScenarioNames[11]
226             = { _( "First Blood" ),   _( "Barbarian Wars" ), _( "Necromancers" ), _( "Slay the Dwarves" ), _( "Turning Point" ), _( "Rebellion" ),
227                 _( "Dragon Master" ), _( "Country Lords" ),  _( "The Crown" ),    _( "Greater Glory" ),    _( "Apocalypse" ) };
228         const std::string archibaldCampaignDescription[11] = {
229             _( "King Archibald requires you to defeat the three enemies in this region.  They are not allied with one another, so they will spend most of their energy fighting"
230                " amongst themselves.  You will win when you own all of the enemy castles and there are no more heroes left to fight." ),
231             _( "You must unify the barbarian tribes of the north by conquering them. As in the previous mission, the enemy is not allied against you, but they have more resources at their disposal. You will win when you own all of the enemy castles and there are no more heroes left to fight." ),
232             _( "Do-gooder wizards have taken the Necromancers' castle. You must retake it to achieve victory. Remember that while you start with a powerful army, you have no castle and must take one within 7 days, or lose this battle. (Hint: The nearest castle is to the southeast.)" ),
233             _( "The dwarves need conquering before they can interfere in King Archibald's plans. Roland's forces have more than one hero and many towns to start with, so be ready for attack from multiple directions. You must capture all of the enemy towns and castles to claim victory." ),
234             _( "Your enemies are allied against you and start close by, so be ready to come out fighting. You will need to own all four castles in this small valley to win." ),
235             _( "You must put down a peasant revolt led by Roland's forces. All are allied against you, but you have Lord Corlagon, an experienced hero, to help you. Capture all enemy castles to win." ),
236             _( "There are two enemies allied against you in this mission. Both are well armed and seek to evict you from their island. Avoid them and capture Dragon City to win." ),
237             _( "Your orders are to conquer the country lords that have sworn to serve Roland. All of the enemy castles are unified against you. Since you start without a castle, you must hurry to capture one before the end of the week. Capture all enemy castles for victory." ),
238             _( "Find the Crown before Roland's heroes find it. Archibald will need the Crown for the final battle against Roland." ),
239             _( "Gather as large an army as possible and capture the enemy castle within 8 weeks. You are opposed by only one enemy, but must travel a long way to get to the enemy castle. Any troops you have in your army at the end of this scenario will be with you in the final battle." ),
240             _( "This is the final battle. Both you and your enemy are armed to the teeth, and all are allied against you. Capture Roland to win the war, and be sure not to lose Archibald in the fight!" ) };
241         std::vector<Campaign::ScenarioData> scenarioDatas;
242         scenarioDatas.reserve( 11 );
243 
244         scenarioDatas.emplace_back( 0, std::vector<int>{ 1 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 0 ), "CAMPE01.H2C", archibaldCampaignScenarioNames[0],
245                                     archibaldCampaignDescription[0],
246                                     Campaign::VideoSequence{ { "EVIL01V.SMK", Video::VideoAction::IGNORE_VIDEO },
247                                                              { "EVIL01.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
248                                     emptyPlayback );
249         scenarioDatas.emplace_back( 1, std::vector<int>{ 2, 3 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 1 ), "CAMPE02.H2C",
250                                     archibaldCampaignScenarioNames[1], archibaldCampaignDescription[1],
251                                     Campaign::VideoSequence{ { "EVIL02W.SMK", Video::VideoAction::IGNORE_VIDEO },
252                                                              { "EVIL02.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
253                                     Campaign::VideoSequence{ { "EVIL03QW.SMK", Video::VideoAction::IGNORE_VIDEO },
254                                                              { "EVIL03.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
255         scenarioDatas.emplace_back( 2, std::vector<int>{ 4 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 2 ), "CAMPE03.H2C", archibaldCampaignScenarioNames[2],
256                                     archibaldCampaignDescription[2], emptyPlayback,
257                                     Campaign::VideoSequence{ { "EVIL05AV.SMK", Video::VideoAction::IGNORE_VIDEO },
258                                                              { "EVIL05.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
259         scenarioDatas.emplace_back( 3, std::vector<int>{ 4 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 3 ), "CAMPE04.H2C", archibaldCampaignScenarioNames[3],
260                                     archibaldCampaignDescription[3], emptyPlayback,
261                                     Campaign::VideoSequence{ { "EVIL05AV.SMK", Video::VideoAction::IGNORE_VIDEO },
262                                                              { "EVIL05.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
263         scenarioDatas.emplace_back( 4, std::vector<int>{ 5 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 4 ), "CAMPE05.H2C", archibaldCampaignScenarioNames[4],
264                                     archibaldCampaignDescription[4], emptyPlayback, emptyPlayback );
265         scenarioDatas.emplace_back( 5, std::vector<int>{ 6, 7 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 5 ), "CAMPE06.H2C",
266                                     archibaldCampaignScenarioNames[5], archibaldCampaignDescription[5],
267                                     Campaign::VideoSequence{ { "EVIL06AW.SMK", Video::VideoAction::IGNORE_VIDEO },
268                                                              { "EVIL06.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
269                                     Campaign::VideoSequence{ { "EVIL07W.SMK", Video::VideoAction::IGNORE_VIDEO },
270                                                              { "EVIL07.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
271         scenarioDatas.emplace_back( 6, std::vector<int>{ 7 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 6 ), "CAMPE07.H2C", archibaldCampaignScenarioNames[6],
272                                     archibaldCampaignDescription[6], emptyPlayback, Campaign::VideoSequence{ { "EVIL08.SMK", Video::VideoAction::PLAY_TILL_VIDEO_END } },
273                                     Campaign::ScenarioVictoryCondition::CAPTURE_DRAGON_CITY );
274         scenarioDatas.emplace_back( 7, std::vector<int>{ 8, 9 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 7 ), "CAMPE08.H2C",
275                                     archibaldCampaignScenarioNames[7], archibaldCampaignDescription[7], emptyPlayback,
276                                     Campaign::VideoSequence{ { "EVIL09W.SMK", Video::VideoAction::IGNORE_VIDEO },
277                                                              { "EVIL09.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
278         scenarioDatas.emplace_back( 8, std::vector<int>{ 10 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 8 ), "CAMPE09.H2C",
279                                     archibaldCampaignScenarioNames[8], archibaldCampaignDescription[8], emptyPlayback, emptyPlayback,
280                                     Campaign::ScenarioVictoryCondition::OBTAIN_ULTIMATE_CROWN );
281         scenarioDatas.emplace_back( 9, std::vector<int>{ 10 }, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 9 ), "CAMPE10.H2C",
282                                     archibaldCampaignScenarioNames[9], archibaldCampaignDescription[9], emptyPlayback, emptyPlayback );
283         scenarioDatas.emplace_back( 10, std::vector<int>{}, Campaign::ScenarioBonusData::getCampaignBonusData( 1, 10 ), "CAMPE11.H2C", archibaldCampaignScenarioNames[10],
284                                     archibaldCampaignDescription[10],
285                                     Campaign::VideoSequence{ { "EVIL11W.SMK", Video::VideoAction::IGNORE_VIDEO },
286                                                              { "EVIL10.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
287                                     Campaign::VideoSequence{ { "PRISON.SMK", Video::VideoAction::PLAY_TILL_VIDEO_END } } );
288 
289         Campaign::CampaignData campaignData;
290         campaignData.setCampaignID( Campaign::ARCHIBALD_CAMPAIGN );
291         campaignData.setCampaignDescription( "Archibald Campaign" );
292         campaignData.setCampaignScenarios( scenarioDatas );
293 
294         return campaignData;
295     }
296 
getPriceOfLoyaltyCampaignData()297     Campaign::CampaignData getPriceOfLoyaltyCampaignData()
298     {
299         const std::string priceOfLoyaltyCampaignScenarioNames[8] = { _( "Uprising" ),         _( "Island of Chaos" ), _( "Arrow's Flight" ), _( "The Abyss" ),
300                                                                      _( "The Giant's Pass" ), _( "Aurora Borealis" ), _( "Betrayal's End" ), _( "Corruption's Heart" ) };
301         const std::string priceOfLoyaltyCampaignDescription[8] = {
302             _( "Subdue the unruly local lords in order to provide the Empire with facilities to operate in this region." ),
303             _( "Eliminate all oposition in this area. Then the first piece of the artifact will be yours." ),
304             _( "The sorceresses to the northeast are rebelling! For the good of the empire you must quash their feeble uprising on your way to the mountains." ),
305             _( "Having prepared for your arrival, Kraeger has arranged for a force of necromancers to thwart your quest. You must capture the castle of Scabsdale before the first day of the third week, or the Necromancers will be too strong for you." ),
306             _( "The barbarian despot in this area is, as yet, ignorant of your presence. Quickly, build up your forces before you are discovered and attacked! Secure the region by subduing all enemy forces." ),
307             _( "The Empire is weak in this region. You will be unable to completely subdue all forces in this area, so take what you can before reprisal strikes. Remember, your true goal is to claim the Helmet of Anduran." ),
308             _( "For the good of the Empire, eliminate Kraeger." ),
309             _( "At last, you have the opportunity and the facilities to rid the Empire of the necromancer's evil. Eradicate them completely, and you will be sung as a hero for all time." ) };
310         std::vector<Campaign::ScenarioData> scenarioDatas;
311         scenarioDatas.reserve( 8 );
312 
313         const int campaignID = Campaign::PRICE_OF_LOYALTY_CAMPAIGN;
314         scenarioDatas.emplace_back( 0, std::vector<int>{ 1 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 0 ), "CAMP1_01.HXC",
315                                     priceOfLoyaltyCampaignScenarioNames[0], priceOfLoyaltyCampaignDescription[0],
316                                     Campaign::VideoSequence{ { "MIXPOL1.SMK", Video::VideoAction::IGNORE_VIDEO },
317                                                              { "POL1.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
318                                     emptyPlayback );
319         scenarioDatas.emplace_back( 1, std::vector<int>{ 2, 3 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 1 ), "CAMP1_02.HXC",
320                                     priceOfLoyaltyCampaignScenarioNames[1], priceOfLoyaltyCampaignDescription[1],
321                                     Campaign::VideoSequence{ { "MIXPOL2.SMK", Video::VideoAction::IGNORE_VIDEO },
322                                                              { "POL2.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
323                                     Campaign::VideoSequence{ { "MIXPOL3.SMK", Video::VideoAction::IGNORE_VIDEO },
324                                                              { "POL3.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
325         scenarioDatas.emplace_back( 2, std::vector<int>{ 4 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 2 ), "CAMP1_03.HXC",
326                                     priceOfLoyaltyCampaignScenarioNames[2], priceOfLoyaltyCampaignDescription[2], emptyPlayback, emptyPlayback );
327         scenarioDatas.emplace_back( 3, std::vector<int>{ 5 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 3 ), "CAMP1_04.HXC",
328                                     priceOfLoyaltyCampaignScenarioNames[3], priceOfLoyaltyCampaignDescription[3], emptyPlayback, emptyPlayback );
329         scenarioDatas.emplace_back( 4, std::vector<int>{ 5 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 4 ), "CAMP1_05.HXC",
330                                     priceOfLoyaltyCampaignScenarioNames[4], priceOfLoyaltyCampaignDescription[4],
331                                     Campaign::VideoSequence{ { "MIXPOL4.SMK", Video::VideoAction::IGNORE_VIDEO },
332                                                              { "POL4.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
333                                     emptyPlayback );
334         scenarioDatas.emplace_back( 5, std::vector<int>{ 6, 7 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 5 ), "CAMP1_06.HXC",
335                                     priceOfLoyaltyCampaignScenarioNames[5], priceOfLoyaltyCampaignDescription[5],
336                                     Campaign::VideoSequence{ { "MIXPOL5.SMK", Video::VideoAction::IGNORE_VIDEO },
337                                                              { "POL5.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
338                                     Campaign::VideoSequence{ { "MIXPOL6.SMK", Video::VideoAction::IGNORE_VIDEO },
339                                                              { "POL6.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
340         scenarioDatas.emplace_back( 6, std::vector<int>{ 7 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 6 ), "CAMP1_07.HXC",
341                                     priceOfLoyaltyCampaignScenarioNames[6], priceOfLoyaltyCampaignDescription[6], emptyPlayback,
342                                     Campaign::VideoSequence{ { "MIXPOL7.SMK", Video::VideoAction::IGNORE_VIDEO },
343                                                              { "POL7.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
344         scenarioDatas.emplace_back( 7, std::vector<int>{}, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 7 ), "CAMP1_08.HXC",
345                                     priceOfLoyaltyCampaignScenarioNames[7], priceOfLoyaltyCampaignDescription[7], emptyPlayback,
346                                     Campaign::VideoSequence{ { "MIXPOL8.SMK", Video::VideoAction::IGNORE_VIDEO },
347                                                              { "POL8.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
348 
349         Campaign::CampaignData campaignData;
350         campaignData.setCampaignID( campaignID );
351         campaignData.setCampaignScenarios( scenarioDatas );
352 
353         return campaignData;
354     }
355 
getDescendantsCampaignData()356     Campaign::CampaignData getDescendantsCampaignData()
357     {
358         const std::string descendantsCampaignScenarioNames[8] = { _( "Conquer and Unify" ), _( "Border Towns" ), _( "The Wayward Son" ), _( "Crazy Uncle Ivan" ),
359                                                                   _( "The Southern War" ),  _( "Ivory Gates" ),  _( "The Elven Lands" ), _( "The Epic Battle" ) };
360         const std::string descendantsCampaignDescription[8] = {
361             _( "Conquer and unite all the enemy tribes. Don't lose the hero Jarkonas, the forefather of all descendants." ),
362             _( "Your rival, the Kingdom of Harondale, is attacking weak towns on your border! Recover from their first strike and crush them completely!" ),
363             _( "Find your wayward son Joseph who is rumored to be living in the desolate lands. Do it before the first day of the third month or it will be of no help to your family." ),
364             _( "Rescue your crazy uncle Ivan. Find him before the first day of the fourth month or it will be no help to your kingdom." ),
365             _( "Destroy the barbarians who are attacking the southern border of your kingdom! Recover your fallen towns, and then invade the jungle kingdom. Leave no enemy standing." ),
366             _( "Retake the castle of Ivory Gates, which has fallen due to treachery." ),
367             _( "Gain the favor of the elves. They will not allow trees to be chopped down, so they will send you wood every 2 weeks. You must complete your mission before the first day of the seventh month, or the kingdom will surely fall." ),
368             _( "This is the final battle against your rival kingdom of Harondale. Eliminate everyone, and don't lose the hero Jarkonas VI." ) };
369         std::vector<Campaign::ScenarioData> scenarioDatas;
370         scenarioDatas.reserve( 8 );
371 
372         const int campaignID = Campaign::DESCENDANTS_CAMPAIGN;
373         scenarioDatas.emplace_back( 0, std::vector<int>{ 1 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 0 ), "CAMP2_01.HXC",
374                                     descendantsCampaignScenarioNames[0], descendantsCampaignDescription[0],
375                                     Campaign::VideoSequence{ { "MIXDES9.SMK", Video::VideoAction::IGNORE_VIDEO },
376                                                              { "DES9.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
377                                     emptyPlayback );
378         scenarioDatas.emplace_back( 1, std::vector<int>{ 2, 3 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 1 ), "CAMP2_02.HXC",
379                                     descendantsCampaignScenarioNames[1], descendantsCampaignDescription[1],
380                                     Campaign::VideoSequence{ { "MIXDES10.SMK", Video::VideoAction::IGNORE_VIDEO },
381                                                              { "DES10.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
382                                     Campaign::VideoSequence{ { "MIXDES11.SMK", Video::VideoAction::IGNORE_VIDEO },
383                                                              { "DES11.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
384         scenarioDatas.emplace_back( 2, std::vector<int>{ 4 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 2 ), "CAMP2_03.HXC",
385                                     descendantsCampaignScenarioNames[2], descendantsCampaignDescription[2], emptyPlayback, emptyPlayback );
386         scenarioDatas.emplace_back( 3, std::vector<int>{ 4 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 3 ), "CAMP2_04.HXC",
387                                     descendantsCampaignScenarioNames[3], descendantsCampaignDescription[3], emptyPlayback, emptyPlayback );
388         scenarioDatas.emplace_back( 4, std::vector<int>{ 5, 6 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 4 ), "CAMP2_05.HXC",
389                                     descendantsCampaignScenarioNames[4], descendantsCampaignDescription[4],
390                                     Campaign::VideoSequence{ { "MIXDES12.SMK", Video::VideoAction::IGNORE_VIDEO },
391                                                              { "DES12.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
392                                     emptyPlayback );
393         scenarioDatas.emplace_back( 5, std::vector<int>{ 7 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 5 ), "CAMP2_06.HXC",
394                                     descendantsCampaignScenarioNames[5], descendantsCampaignDescription[5],
395                                     Campaign::VideoSequence{ { "MIXDES13.SMK", Video::VideoAction::IGNORE_VIDEO },
396                                                              { "DES13.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
397                                     emptyPlayback );
398         scenarioDatas.emplace_back( 6, std::vector<int>{ 7 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 6 ), "CAMP2_07.HXC",
399                                     descendantsCampaignScenarioNames[6], descendantsCampaignDescription[6], emptyPlayback, emptyPlayback );
400         scenarioDatas.emplace_back( 7, std::vector<int>{}, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 7 ), "CAMP2_08.HXC",
401                                     descendantsCampaignScenarioNames[7], descendantsCampaignDescription[7],
402                                     Campaign::VideoSequence{ { "MIXDES14.SMK", Video::VideoAction::IGNORE_VIDEO },
403                                                              { "DES14.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
404                                     Campaign::VideoSequence{ { "MIXDES15.SMK", Video::VideoAction::IGNORE_VIDEO },
405                                                              { "DES15.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
406 
407         Campaign::CampaignData campaignData;
408         campaignData.setCampaignID( campaignID );
409         campaignData.setCampaignScenarios( scenarioDatas );
410 
411         return campaignData;
412     }
413 
getWizardsIsleCampaignData()414     Campaign::CampaignData getWizardsIsleCampaignData()
415     {
416         const std::string wizardsIsleCampaignScenarioNames[4] = { _( "The Shrouded Isles" ), _( "The Eternal Scrolls" ), _( "Power's End" ), _( "Fount of Wizardry" ) };
417         const std::string wizardsIsleCampaignDescription[4] = {
418             _( "Your mission is to vanquish the warring mages in the magical Shrouded Isles. The completion of this task will give you a fighting chance against your rivals." ),
419             _( "The location of the great library has been discovered! You must make your way to it, and reclaim the city of Chronos in which it lies." ),
420             _( "Find the Orb of negation, which is said to be buried in this land. There are clues inscribed on stone obelisks which will help lead you to your price. Find the orb before the first day of the sixth month, or your rivals will surely have gotten to the fount before you." ),
421             _( "You must take control of the castle of Magic, where the fount of wizardry lies. Do this and your victory will be supreme." ) };
422         std::vector<Campaign::ScenarioData> scenarioDatas;
423         scenarioDatas.reserve( 4 );
424 
425         const int campaignID = Campaign::WIZARDS_ISLE_CAMPAIGN;
426         scenarioDatas.emplace_back( 0, std::vector<int>{ 1 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 0 ), "CAMP3_01.HXC",
427                                     wizardsIsleCampaignScenarioNames[0], wizardsIsleCampaignDescription[0],
428                                     Campaign::VideoSequence{ { "MIXWIZ16.SMK", Video::VideoAction::IGNORE_VIDEO },
429                                                              { "WIZ16.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
430                                     emptyPlayback );
431         scenarioDatas.emplace_back( 1, std::vector<int>{ 2, 3 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 1 ), "CAMP3_02.HXC",
432                                     wizardsIsleCampaignScenarioNames[1], wizardsIsleCampaignDescription[1],
433                                     Campaign::VideoSequence{ { "MIXWIZ17.SMK", Video::VideoAction::IGNORE_VIDEO },
434                                                              { "WIZ17.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
435                                     Campaign::VideoSequence{ { "MIXWIZ18.SMK", Video::VideoAction::IGNORE_VIDEO },
436                                                              { "WIZ18.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
437         scenarioDatas.emplace_back( 2, std::vector<int>{ 3 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 2 ), "CAMP3_03.HXC",
438                                     wizardsIsleCampaignScenarioNames[2], wizardsIsleCampaignDescription[2], emptyPlayback,
439                                     Campaign::VideoSequence{ { "MIXWIZ19.SMK", Video::VideoAction::IGNORE_VIDEO },
440                                                              { "WIZ19.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
441                                     Campaign::ScenarioVictoryCondition::OBTAIN_SPHERE_NEGATION );
442         scenarioDatas.emplace_back( 3, std::vector<int>{}, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 3 ), "CAMP3_04.HXC",
443                                     wizardsIsleCampaignScenarioNames[3], wizardsIsleCampaignDescription[3], emptyPlayback,
444                                     Campaign::VideoSequence{ { "MIXWIZ20.SMK", Video::VideoAction::IGNORE_VIDEO },
445                                                              { "WIZ20.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
446 
447         Campaign::CampaignData campaignData;
448         campaignData.setCampaignID( campaignID );
449         campaignData.setCampaignScenarios( scenarioDatas );
450 
451         return campaignData;
452     }
453 
getVoyageHomeCampaignData()454     Campaign::CampaignData getVoyageHomeCampaignData()
455     {
456         const std::string voyageHomeCampaignScenarioNames[4] = { _( "Stranded" ), _( "Pirate Isles" ), _( "King and Country" ), _( "Blood is Thicker" ) };
457         const std::string voyageHomeCampaignDescription[4] = {
458             _( "Capture the town on the island off the southeast shore in order to construct a boat and travel back towards the mainland. Do not lose the hero Gallavant." ),
459             _( "Find and defeat Martine, the pirate leader, who resides in Pirates Cove. Do not lose Gallavant or your quest will be over." ),
460             _( "Eliminate all the other forces who oppose the rule of Lord Alberon. Gallavant must not die." ),
461             _( "Overthrow the entrenched monarchy of Lord Alberon, and claim all the land in your name. Gallavant must not die." ) };
462         std::vector<Campaign::ScenarioData> scenarioDatas;
463         scenarioDatas.reserve( 4 );
464 
465         const int campaignID = Campaign::VOYAGE_HOME_CAMPAIGN;
466         scenarioDatas.emplace_back( 0, std::vector<int>{ 1 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 0 ), "CAMP4_01.HXC",
467                                     voyageHomeCampaignScenarioNames[0], voyageHomeCampaignDescription[0],
468                                     Campaign::VideoSequence{ { "MIXVOY21.SMK", Video::VideoAction::IGNORE_VIDEO },
469                                                              { "VOY21.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
470                                     emptyPlayback );
471         scenarioDatas.emplace_back( 1, std::vector<int>{ 2, 3 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 1 ), "CAMP4_02.HXC",
472                                     voyageHomeCampaignScenarioNames[1], voyageHomeCampaignDescription[1],
473                                     Campaign::VideoSequence{ { "MIXVOY22.SMK", Video::VideoAction::IGNORE_VIDEO },
474                                                              { "VOY22.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } },
475                                     Campaign::VideoSequence{ { "MIXVOY23.SMK", Video::VideoAction::IGNORE_VIDEO },
476                                                              { "VOY23.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
477         scenarioDatas.emplace_back( 2, std::vector<int>{ 3 }, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 2 ), "CAMP4_03.HXC",
478                                     voyageHomeCampaignScenarioNames[2], voyageHomeCampaignDescription[2], emptyPlayback,
479                                     Campaign::VideoSequence{ { "MIXVOY24.SMK", Video::VideoAction::IGNORE_VIDEO },
480                                                              { "VOY24.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
481         scenarioDatas.emplace_back( 3, std::vector<int>{}, Campaign::ScenarioBonusData::getCampaignBonusData( campaignID, 3 ), "CAMP4_04.HXC",
482                                     voyageHomeCampaignScenarioNames[3], voyageHomeCampaignDescription[3], emptyPlayback,
483                                     Campaign::VideoSequence{ { "MIXVOY25.SMK", Video::VideoAction::IGNORE_VIDEO },
484                                                              { "VOY25.SMK", Video::VideoAction::PLAY_TILL_AUDIO_END } } );
485 
486         Campaign::CampaignData campaignData;
487         campaignData.setCampaignID( campaignID );
488         campaignData.setCampaignScenarios( scenarioDatas );
489 
490         return campaignData;
491     }
492 }
493 
494 namespace Campaign
495 {
CampaignData()496     CampaignData::CampaignData()
497         : _campaignID( 0 )
498     {}
499 
500     // this is used to get awards that are not directly obtainable via scenario clear, such as assembling artifacts
getExtraCampaignAwardData(const int campaignID)501     std::vector<Campaign::CampaignAwardData> CampaignAwardData::getExtraCampaignAwardData( const int campaignID )
502     {
503         assert( campaignID >= 0 );
504 
505         switch ( campaignID ) {
506         case PRICE_OF_LOYALTY_CAMPAIGN: {
507             std::vector<Campaign::CampaignAwardData> extraAwards;
508             extraAwards.emplace_back( 10, Campaign::CampaignAwardData::TYPE_GET_ARTIFACT, Artifact::BATTLE_GARB );
509             return extraAwards;
510         }
511         case ROLAND_CAMPAIGN:
512         case ARCHIBALD_CAMPAIGN:
513         case DESCENDANTS_CAMPAIGN:
514         case WIZARDS_ISLE_CAMPAIGN:
515         case VOYAGE_HOME_CAMPAIGN:
516         default:
517             break;
518         }
519 
520         return std::vector<Campaign::CampaignAwardData>();
521     }
522 
getScenariosAfter(const int scenarioID) const523     const std::vector<int> & CampaignData::getScenariosAfter( const int scenarioID ) const
524     {
525         for ( size_t i = 0; i < _scenarios.size(); ++i ) {
526             if ( _scenarios[i].getScenarioID() == scenarioID )
527                 return _scenarios[i].getNextMaps();
528         }
529 
530         return _scenarios[scenarioID].getNextMaps();
531     }
532 
getStartingScenarios() const533     std::vector<int> CampaignData::getStartingScenarios() const
534     {
535         std::vector<int> startingScenarios;
536 
537         for ( size_t i = 0; i < _scenarios.size(); ++i ) {
538             const int scenarioID = _scenarios[i].getScenarioID();
539             if ( isStartingScenario( scenarioID ) )
540                 startingScenarios.emplace_back( scenarioID );
541         }
542 
543         return startingScenarios;
544     }
545 
isStartingScenario(const int scenarioID) const546     bool CampaignData::isStartingScenario( const int scenarioID ) const
547     {
548         // starting scenario = a scenario that is never included as a nextMap
549         for ( size_t i = 0; i < _scenarios.size(); ++i ) {
550             const std::vector<int> & nextMaps = _scenarios[i].getNextMaps();
551 
552             if ( std::find( nextMaps.begin(), nextMaps.end(), scenarioID ) != nextMaps.end() )
553                 return false;
554         }
555 
556         return true;
557     }
558 
isAllCampaignMapsPresent() const559     bool CampaignData::isAllCampaignMapsPresent() const
560     {
561         for ( size_t i = 0; i < _scenarios.size(); ++i ) {
562             if ( !_scenarios[i].isMapFilePresent() )
563                 return false;
564         }
565 
566         return true;
567     }
568 
isLastScenario(const int scenarioID) const569     bool CampaignData::isLastScenario( const int scenarioID ) const
570     {
571         assert( !_scenarios.empty() );
572         return scenarioID == _scenarios.back().getScenarioID();
573     }
574 
setCampaignID(const int campaignID)575     void CampaignData::setCampaignID( const int campaignID )
576     {
577         _campaignID = campaignID;
578     }
579 
setCampaignScenarios(const std::vector<ScenarioData> & scenarios)580     void CampaignData::setCampaignScenarios( const std::vector<ScenarioData> & scenarios )
581     {
582         _scenarios = scenarios;
583     }
584 
setCampaignDescription(const std::string & campaignDescription)585     void CampaignData::setCampaignDescription( const std::string & campaignDescription )
586     {
587         _campaignDescription = campaignDescription;
588     }
589 
getCampaignData(const int campaignID)590     const CampaignData & CampaignData::getCampaignData( const int campaignID )
591     {
592         switch ( campaignID ) {
593         case ROLAND_CAMPAIGN: {
594             static const Campaign::CampaignData campaign( getRolandCampaignData() );
595             return campaign;
596         }
597         case ARCHIBALD_CAMPAIGN: {
598             static const Campaign::CampaignData campaign( getArchibaldCampaignData() );
599             return campaign;
600         }
601         case PRICE_OF_LOYALTY_CAMPAIGN: {
602             static const Campaign::CampaignData campaign( getPriceOfLoyaltyCampaignData() );
603             return campaign;
604         }
605         case DESCENDANTS_CAMPAIGN: {
606             static const Campaign::CampaignData campaign( getDescendantsCampaignData() );
607             return campaign;
608         }
609         case VOYAGE_HOME_CAMPAIGN: {
610             static const Campaign::CampaignData campaign( getVoyageHomeCampaignData() );
611             return campaign;
612         }
613         case WIZARDS_ISLE_CAMPAIGN: {
614             static const Campaign::CampaignData campaign( getWizardsIsleCampaignData() );
615             return campaign;
616         }
617         default: {
618             // Did you add a new campaign? Add the corresponding case above.
619             assert( 0 );
620             static const Campaign::CampaignData noCampaign;
621             return noCampaign;
622         }
623         }
624     }
625 
626     // default amount to 1 for initialized campaign award data
CampaignAwardData(int id,uint32_t type,uint32_t subType)627     CampaignAwardData::CampaignAwardData( int id, uint32_t type, uint32_t subType )
628         : CampaignAwardData( id, type, subType, 1, 0 )
629     {}
630 
CampaignAwardData(int id,uint32_t type,uint32_t subType,uint32_t amount)631     CampaignAwardData::CampaignAwardData( int id, uint32_t type, uint32_t subType, uint32_t amount )
632         : CampaignAwardData( id, type, subType, amount, 0 )
633     {}
634 
CampaignAwardData(int id,uint32_t type,uint32_t subType,const std::string & customName)635     CampaignAwardData::CampaignAwardData( int id, uint32_t type, uint32_t subType, const std::string & customName )
636         : CampaignAwardData( id, type, subType, 1, 0, customName )
637     {}
638 
CampaignAwardData(int id,uint32_t type,uint32_t subType,uint32_t amount,int startScenarioID,const std::string & customName)639     CampaignAwardData::CampaignAwardData( int id, uint32_t type, uint32_t subType, uint32_t amount, int startScenarioID, const std::string & customName )
640         : _id( id )
641         , _type( type )
642         , _subType( subType )
643         , _amount( amount )
644         , _startScenarioID( startScenarioID )
645         , _customName( customName )
646     {}
647 
ToString() const648     std::string CampaignAwardData::ToString() const
649     {
650         if ( !_customName.empty() )
651             return _customName;
652 
653         switch ( _type ) {
654         case CampaignAwardData::TYPE_CREATURE_CURSE:
655             return Monster( _subType ).GetName() + std::string( _( " bane" ) );
656         case CampaignAwardData::TYPE_CREATURE_ALLIANCE:
657             return Monster( _subType ).GetName() + std::string( _( " alliance" ) );
658         case CampaignAwardData::TYPE_GET_ARTIFACT:
659             return Artifact( _subType ).GetName();
660         case CampaignAwardData::TYPE_CARRY_OVER_FORCES:
661             return _( "Carry-over forces" );
662         case CampaignAwardData::TYPE_RESOURCE_BONUS:
663             return Resource::String( _subType ) + std::string( _( " bonus" ) );
664         case CampaignAwardData::TYPE_GET_SPELL:
665             return Spell( _subType ).GetName();
666         case CampaignAwardData::TYPE_HIREABLE_HERO:
667             return Heroes( _subType, 0 ).GetName();
668         case CampaignAwardData::TYPE_DEFEAT_ENEMY_HERO:
669             return Heroes( _subType, 0 ).GetName() + std::string( _( " defeated" ) );
670         default:
671             assert( 0 ); // some new/unhandled award
672             return "";
673         }
674     }
675 
getCampaignAwardData(const int campaignID,const int scenarioID)676     std::vector<Campaign::CampaignAwardData> CampaignAwardData::getCampaignAwardData( const int campaignID, const int scenarioID )
677     {
678         assert( campaignID >= 0 && scenarioID >= 0 );
679 
680         switch ( campaignID ) {
681         case ROLAND_CAMPAIGN:
682             return getRolandCampaignAwardData( scenarioID );
683         case ARCHIBALD_CAMPAIGN:
684             return getArchibaldCampaignAwardData( scenarioID );
685         case PRICE_OF_LOYALTY_CAMPAIGN:
686             return getPriceOfLoyaltyCampaignAwardData( scenarioID );
687         case DESCENDANTS_CAMPAIGN:
688             return getDescendantsCampaignAwardData( scenarioID );
689         case WIZARDS_ISLE_CAMPAIGN:
690             return getWizardsIsleCampaignAwardData( scenarioID );
691         case VOYAGE_HOME_CAMPAIGN:
692             // No campaign award for voyage home!
693             return {};
694         default:
695             // Did you add a new campaign? Add the corresponding case above.
696             assert( 0 );
697             break;
698         }
699 
700         return {};
701     }
702 
getAllianceJoiningMessage(const int monsterId)703     const char * CampaignAwardData::getAllianceJoiningMessage( const int monsterId )
704     {
705         switch ( monsterId ) {
706         case Monster::DWARF:
707         case Monster::BATTLE_DWARF:
708             return _( "The dwarves recognize their allies and gladly join your forces." );
709         case Monster::OGRE:
710         case Monster::OGRE_LORD:
711             return _( "The ogres recognize you as the Dwarfbane and lumber over to join you." );
712         case Monster::GREEN_DRAGON:
713         case Monster::RED_DRAGON:
714         case Monster::BLACK_DRAGON:
715             return _( "The dragons, snarling and growling, agree to join forces with you, their 'Ally'." );
716         case Monster::ELF:
717         case Monster::GRAND_ELF:
718             return _(
719                 "As you approach the group of elves, their leader calls them all to attention.  He shouts to them, \"Who of you is brave enough to join this fearless ally of ours?\"  The group explodes with cheers as they run to join your ranks." );
720         default:
721             break;
722         }
723 
724         assert( 0 ); // Did you forget to add a new alliance type?
725         return nullptr;
726     }
727 
getAllianceFleeingMessage(const int monsterId)728     const char * CampaignAwardData::getAllianceFleeingMessage( const int monsterId )
729     {
730         switch ( monsterId ) {
731         case Monster::DWARF:
732         case Monster::BATTLE_DWARF:
733             return _( "The dwarves hail you, \"Any friend of Roland is a friend of ours.  You may pass.\"" );
734         case Monster::OGRE:
735         case Monster::OGRE_LORD:
736             return _( "The ogres give you a grunt of recognition, \"Archibald's allies may pass.\"" );
737         case Monster::GREEN_DRAGON:
738         case Monster::RED_DRAGON:
739         case Monster::BLACK_DRAGON:
740             return _(
741                 "The dragons see you and call out.  \"Our alliance with Archibald compels us to join you.  Unfortunately you have no room.  A pity!\"  They quickly scatter." );
742         case Monster::ELF:
743         case Monster::GRAND_ELF:
744             return _(
745                 "The elves stand at attention as you approach.  Their leader calls to you and says, \"Let us not impede your progress, ally!  Move on, and may victory be yours.\"" );
746         default:
747             break;
748         }
749 
750         assert( 0 ); // Did you forget to add a new alliance type?
751         return nullptr;
752     }
753 
getBaneFleeingMessage(const int monsterId)754     const char * CampaignAwardData::getBaneFleeingMessage( const int monsterId )
755     {
756         switch ( monsterId ) {
757         case Monster::DWARF:
758         case Monster::BATTLE_DWARF:
759             return _( "\"The Dwarfbane!!!!, run for your lives.\"" );
760         default:
761             break;
762         }
763 
764         assert( 0 ); // Did you forget to add a new bane type?
765         return nullptr;
766     }
767 }
768