campaign_manager.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #include "campaign_manager.h"
  2. #include "game/map/map_definition.h"
  3. #include "game/map/mission_loader.h"
  4. #include "game/systems/save_load_service.h"
  5. #include "game/systems/save_storage.h"
  6. #include "game/systems/victory_service.h"
  7. #include <QCoreApplication>
  8. #include <QDebug>
  9. #include <QFile>
  10. #include <QStringList>
  11. #include <QVariantMap>
  12. CampaignManager::CampaignManager(QObject *parent) : QObject(parent) {}
  13. void CampaignManager::load_campaigns() { emit available_campaigns_changed(); }
  14. void CampaignManager::set_available_campaigns(const QVariantList &campaigns) {
  15. m_available_campaigns = campaigns;
  16. emit available_campaigns_changed();
  17. }
  18. void CampaignManager::start_campaign_mission(const QString &mission_path,
  19. int &selected_player_id) {
  20. const QStringList parts = mission_path.split('/');
  21. if (parts.size() != 2) {
  22. qWarning()
  23. << "Invalid mission path format. Expected: campaign_id/mission_id";
  24. return;
  25. }
  26. const QString campaign_id = parts[0];
  27. const QString mission_id = parts[1];
  28. QStringList search_paths = {
  29. QString("assets/missions/%1.json").arg(mission_id),
  30. QString("../assets/missions/%1.json").arg(mission_id),
  31. QString("../../assets/missions/%1.json").arg(mission_id),
  32. QCoreApplication::applicationDirPath() +
  33. QString("/assets/missions/%1.json").arg(mission_id),
  34. QCoreApplication::applicationDirPath() +
  35. QString("/../assets/missions/%1.json").arg(mission_id)};
  36. QString mission_file_path;
  37. bool found = false;
  38. for (const QString &path : search_paths) {
  39. if (QFile::exists(path)) {
  40. mission_file_path = path;
  41. found = true;
  42. qInfo() << "Loading mission from filesystem:" << mission_file_path;
  43. break;
  44. }
  45. }
  46. if (!found) {
  47. mission_file_path = QString(":/assets/missions/%1.json").arg(mission_id);
  48. qInfo() << "Loading mission from Qt resources:" << mission_file_path;
  49. }
  50. Game::Mission::MissionDefinition mission;
  51. QString error;
  52. if (!Game::Mission::MissionLoader::loadFromJsonFile(mission_file_path,
  53. mission, &error)) {
  54. qWarning()
  55. << QString("Failed to load mission %1: %2").arg(mission_id).arg(error);
  56. return;
  57. }
  58. m_current_campaign_id = campaign_id;
  59. m_current_mission_id = mission_id;
  60. m_current_mission_definition = mission;
  61. m_current_mission_context.mode = "campaign";
  62. m_current_mission_context.campaign_id = campaign_id;
  63. m_current_mission_context.mission_id = mission_id;
  64. m_current_mission_context.difficulty = "normal";
  65. emit current_campaign_changed();
  66. emit current_mission_changed();
  67. }
  68. void CampaignManager::mark_current_mission_completed() {
  69. if (m_current_campaign_id.isEmpty() || m_current_mission_id.isEmpty()) {
  70. qWarning() << "No active campaign mission to mark as completed";
  71. return;
  72. }
  73. qInfo() << "Campaign mission" << m_current_campaign_id << "/"
  74. << m_current_mission_id << "marked as completed";
  75. auto *save_service = Game::Systems::SaveLoadService::instance();
  76. if (save_service != nullptr) {
  77. QString error;
  78. bool saved = save_service->save_mission_result(
  79. m_current_mission_id, m_current_mission_context.mode,
  80. m_current_campaign_id, true, "victory",
  81. m_current_mission_context.difficulty, 0.0F, &error);
  82. if (!saved) {
  83. qWarning() << "Failed to save mission result:" << error;
  84. } else {
  85. if (m_current_mission_context.is_campaign()) {
  86. bool unlocked = save_service->unlock_next_campaign_mission(
  87. m_current_campaign_id, m_current_mission_id, &error);
  88. if (!unlocked) {
  89. qWarning() << "Failed to unlock next mission:" << error;
  90. } else {
  91. qInfo() << "Next mission unlocked successfully, reloading campaigns";
  92. emit available_campaigns_changed();
  93. }
  94. }
  95. }
  96. }
  97. }
  98. void CampaignManager::set_skirmish_context(const QString &map_path) {
  99. m_current_campaign_id.clear();
  100. m_current_mission_id.clear();
  101. m_current_mission_definition.reset();
  102. m_current_mission_context.mode = "skirmish";
  103. m_current_mission_context.campaign_id = "";
  104. m_current_mission_context.mission_id = map_path;
  105. m_current_mission_context.difficulty = "normal";
  106. emit current_campaign_changed();
  107. emit current_mission_changed();
  108. }
  109. void CampaignManager::configure_mission_victory_conditions(
  110. Game::Systems::VictoryService *victory_service, int local_owner_id) {
  111. if (!victory_service || !m_current_mission_context.is_campaign() ||
  112. !m_current_mission_definition.has_value()) {
  113. return;
  114. }
  115. const auto &mission = *m_current_mission_definition;
  116. Game::Map::VictoryConfig mission_victory_config;
  117. if (!mission.victory_conditions.empty()) {
  118. const auto &first_condition = mission.victory_conditions[0];
  119. if (first_condition.type == "destroy_all_enemies") {
  120. mission_victory_config.victoryType = "elimination";
  121. mission_victory_config.keyStructures = {"barracks"};
  122. } else if (first_condition.type == "survive_duration" &&
  123. first_condition.duration.has_value()) {
  124. mission_victory_config.victoryType = "survive_time";
  125. mission_victory_config.surviveTimeDuration = *first_condition.duration;
  126. } else if (first_condition.type == "control_structures" ||
  127. first_condition.type == "capture_structures") {
  128. mission_victory_config.victoryType = first_condition.type;
  129. if (!first_condition.structure_types.empty()) {
  130. mission_victory_config.keyStructures.clear();
  131. for (const auto &structure_type : first_condition.structure_types) {
  132. if (structure_type == "village") {
  133. mission_victory_config.keyStructures.push_back("barracks");
  134. } else {
  135. mission_victory_config.keyStructures.push_back(structure_type);
  136. }
  137. }
  138. } else if (first_condition.structure_type.has_value()) {
  139. if (*first_condition.structure_type == "village") {
  140. mission_victory_config.keyStructures = {"barracks"};
  141. } else {
  142. mission_victory_config.keyStructures = {
  143. *first_condition.structure_type};
  144. }
  145. } else {
  146. mission_victory_config.keyStructures = {"barracks"};
  147. }
  148. mission_victory_config.requiredKeyStructures =
  149. first_condition.min_count.value_or(1);
  150. } else {
  151. mission_victory_config.victoryType = "elimination";
  152. mission_victory_config.keyStructures = {"barracks"};
  153. }
  154. }
  155. if (!mission.defeat_conditions.empty()) {
  156. mission_victory_config.defeatConditions.clear();
  157. }
  158. for (const auto &defeat_condition : mission.defeat_conditions) {
  159. if (defeat_condition.type == "lose_structure" &&
  160. defeat_condition.structure_type.has_value()) {
  161. mission_victory_config.defeatConditions.push_back("no_key_structures");
  162. mission_victory_config.keyStructures.push_back(
  163. *defeat_condition.structure_type);
  164. } else if (defeat_condition.type == "lose_all_units") {
  165. mission_victory_config.defeatConditions.push_back("no_units");
  166. }
  167. }
  168. victory_service->configure(mission_victory_config, local_owner_id);
  169. qInfo() << "Applied mission victory conditions from" << m_current_mission_id;
  170. }