54 #include <fmt/format.h>
58 # include <curl/curl.h>
59 # include <curl/easy.h>
62 #if defined(_MSC_VER) && defined(GetObject) // This MS Windows macro from <wingdi.h> (Windows Kit 8.1) clashes with RapidJSON
71 static size_t CurlWriteFunc(
void *ptr,
size_t size,
size_t nmemb, std::string* data)
73 data->append((
char*)ptr, size * nmemb);
86 Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(
"waypoints.json",
RGN_SAVEGAMES);
102 std::string url =
"https://raw.githubusercontent.com/RigsOfRods-Community/ai-waypoints/main/waypoints.json";
103 std::string response_payload;
104 long response_code = 0;
106 CURL *curl = curl_easy_init();
107 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
108 curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
110 curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
112 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
CurlWriteFunc);
113 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_payload);
115 CURLcode curl_result = curl_easy_perform(curl);
116 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
118 curl_easy_cleanup(curl);
121 if (curl_result != CURLE_OK || response_code != 200)
123 Ogre::LogManager::getSingleton().stream()
124 <<
"[RoR|Repository] Failed to download AI presets;"
125 <<
" Error: '" << curl_easy_strerror(curl_result) <<
"'; HTTP status code: " << response_code;
138 #endif // defined(USE_CURL)
161 int num_playable_actors = 0;
164 if (!actor->ar_hide_in_actor_list)
166 num_playable_actors++;
170 std::string sim_title =
_LC(
"TopMenubar",
"Simulation");
171 std::string actors_title =
fmt::format(
"{} ({})",
_LC(
"TopMenubar",
"Vehicles"), num_playable_actors);
172 std::string savegames_title =
_LC(
"TopMenubar",
"Saves");
173 std::string settings_title =
_LC(
"TopMenubar",
"Settings");
174 std::string tools_title =
_LC(
"TopMenubar",
"Tools");
175 std::string ai_title =
_LC(
"TopMenubar",
"Vehicle AI");
176 std::string tuning_title =
_LC(
"TopMenubar",
"Tuning");
178 int menubar_num_buttons = 5;
179 float menubar_content_width =
180 ImGui::CalcTextSize(sim_title.c_str()).x +
181 ImGui::CalcTextSize(actors_title.c_str()).x +
182 ImGui::CalcTextSize(savegames_title.c_str()).x +
183 ImGui::CalcTextSize(settings_title.c_str()).x +
184 ImGui::CalcTextSize(tools_title.c_str()).x;
188 menubar_num_buttons += 1;
189 menubar_content_width += ImGui::CalcTextSize(ai_title.c_str()).x;
194 menubar_num_buttons += 1;
195 menubar_content_width += ImGui::CalcTextSize(tuning_title.c_str()).x;
198 menubar_content_width +=
199 (ImGui::GetStyle().ItemSpacing.x * (menubar_num_buttons - 1)) +
200 (ImGui::GetStyle().FramePadding.x * (menubar_num_buttons * 2));
202 ImVec2 window_target_pos = ImVec2((ImGui::GetIO().DisplaySize.x/2.f) - (menubar_content_width / 2.f), theme.
screen_edge_padding.y);
212 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0));
215 int flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove
216 | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize;
217 ImGui::SetNextWindowContentSize(ImVec2(menubar_content_width, 0.f));
218 ImGui::SetNextWindowPos(window_target_pos);
219 ImGui::Begin(
"Top menubar",
nullptr, flags);
221 if (ImGui::IsWindowHovered())
227 ImVec2 window_pos = ImGui::GetWindowPos();
228 ImVec2 sim_cursor = ImGui::GetCursorPos();
229 ImGui::Button(sim_title.c_str());
236 ImVec2 tuning_cursor = ImVec2(0, 0);
240 tuning_cursor = ImGui::GetCursorPos();
241 ImGui::Button(tuning_title.c_str());
249 ImVec2 ai_cursor = ImVec2(0, 0);
253 ai_cursor = ImGui::GetCursorPos();
254 ImGui::Button(ai_title.c_str());
264 ImVec2 actors_cursor = ImGui::GetCursorPos();
265 ImGui::Button(actors_title.c_str());
274 ImVec2 savegames_cursor = ImGui::GetCursorPos();
275 ImGui::Button(savegames_title.c_str());
282 for (
int i = 0; i <= 9; i++)
292 ImVec2 settings_cursor = ImGui::GetCursorPos();
293 ImGui::Button(settings_title.c_str());
306 ImVec2 tools_cursor = ImGui::GetCursorPos();
307 ImGui::Button(tools_title.c_str());
313 ImVec2 topmenu_final_size = ImGui::GetWindowSize();
325 menu_pos.x = sim_cursor.x + window_pos.x - ImGui::GetStyle().WindowPadding.x;
326 ImGui::SetNextWindowPos(menu_pos);
327 if (ImGui::Begin(
_LC(
"TopMenubar",
"Sim menu"),
nullptr,
static_cast<ImGuiWindowFlags_
>(flags)))
331 if (ImGui::Button(
_LC(
"TopMenubar",
"Get new vehicle")))
340 if (current_actor !=
nullptr)
342 if (ImGui::Button(
_LC(
"TopMenubar",
"Show vehicle description")))
349 if (ImGui::Button(
_LC(
"TopMenubar",
"Reload current vehicle")))
357 if (ImGui::Button(
_LC(
"TopMenubar",
"Remove current vehicle")))
365 if (ImGui::Button(
_LC(
"TopMenubar",
"Activate last spawned vehicle")))
373 if (ImGui::Button(
_LC(
"TopMenubar",
"Reload last spawned vehicle")))
381 if (ImGui::Button(
_LC(
"TopMenubar",
"Remove last spawned vehicle")))
390 if (ImGui::Button(
_LC(
"TopMenubar",
"Remove all vehicles")))
397 if (ImGui::Button(
_LC(
"TopMenubar",
" [!] Confirm removal")))
401 if (!actor->ar_hide_in_actor_list && !actor->isPreloadedWithTerrain() &&
409 ImGui::PopStyleColor();
412 if (ImGui::Button(
_LC(
"TopMenubar",
"Activate all vehicles")))
418 if (ImGui::Checkbox(
_LC(
"TopMenubar",
"Activated vehicles never sleep"), &force_trucks_active))
423 if (ImGui::Button(
_LC(
"TopMenubar",
"Send all vehicles to sleep")))
431 if (ImGui::Button(
_LC(
"TopMenubar",
"Reload current terrain")))
444 if (ImGui::Button(
_LC(
"TopMenubar",
"Back to menu")))
454 if (ImGui::Button(
_LC(
"TopMenubar",
"Exit")))
469 menu_pos.x = actors_cursor.x + window_pos.x - ImGui::GetStyle().WindowPadding.x;
470 ImGui::SetNextWindowPos(menu_pos);
471 if (ImGui::Begin(
_LC(
"TopMenubar",
"Actors menu"),
nullptr,
static_cast<ImGuiWindowFlags_
>(flags)))
484 for (
auto& user: remote_users)
488 #endif // USE_SOCKETW
499 menu_pos.y = window_pos.y + savegames_cursor.y +
MENU_Y_OFFSET;
500 menu_pos.x = savegames_cursor.x + window_pos.x - ImGui::GetStyle().WindowPadding.x;
501 ImGui::SetNextWindowPos(menu_pos);
502 if (ImGui::Begin(
_LC(
"TopMenubar",
"Savegames"),
nullptr,
static_cast<ImGuiWindowFlags_
>(flags)))
504 if (ImGui::Button(
_LC(
"TopMenubar",
"Quicksave")))
514 if (ImGui::Button(
_LC(
"TopMenubar",
"Quickload")))
525 ImGui::TextColored(
GRAY_HINT_TEXT,
"%s",
_LC(
"TopMenubar",
"(Save with CTRL+ALT+1..5)"));
526 for (
int i = 1; i <= 5; i++)
528 Ogre::String name =
_LC(
"TopMenubar",
"Empty Slot");
534 if (ImGui::Button(caption.c_str()))
542 ImGui::TextColored(
GRAY_HINT_TEXT,
"%s",
_LC(
"TopMenubar",
"(Load with ALT+1..5)"));
543 for (
int i = 1; i <= 5; i++)
549 if (ImGui::Button(caption.c_str()))
567 menu_pos.y = window_pos.y + settings_cursor.y +
MENU_Y_OFFSET;
568 menu_pos.x = settings_cursor.x + window_pos.x - ImGui::GetStyle().WindowPadding.x;
569 ImGui::SetNextWindowPos(menu_pos);
570 if (ImGui::Begin(
_LC(
"TopMenubar",
"Settings menu"),
nullptr,
static_cast<ImGuiWindowFlags_
>(flags)))
574 ImGui::PushItemWidth(125.f);
580 ImGui::TextColored(
GRAY_HINT_TEXT,
"%s",
_LC(
"TopMenubar",
"Frames per second:"));
590 float slowmotion = std::min(
App::GetGameContext()->GetActorManager()->GetSimulationSpeed(), 1.0f);
591 if (ImGui::SliderFloat(
_LC(
"TopMenubar",
"Slow motion"), &slowmotion, 0.01f, 1.0f))
595 float timelapse = std::max(
App::GetGameContext()->GetActorManager()->GetSimulationSpeed(), 1.0f);
596 if (ImGui::SliderFloat(
_LC(
"TopMenubar",
"Time lapse"), &timelapse, 1.0f, 10.0f))
616 if (ImGui::SliderInt(
_LC(
"TopMenubar",
"FOV"), &fov, 10, 120))
624 if (ImGui::SliderInt(
_LC(
"TopMenubar",
"FOV"), &fov, 10, 120))
660 ImGui::PushID(
"waves");
671 if (current_actor !=
nullptr)
674 ImGui::TextColored(
GRAY_HINT_TEXT,
"%s",
_LC(
"TopMenubar",
"Vehicle control options:"));
686 ImGui::PopItemWidth();
697 menu_pos.x = tools_cursor.x + window_pos.x - ImGui::GetStyle().WindowPadding.x;
698 ImGui::SetNextWindowPos(menu_pos);
699 if (ImGui::Begin(
_LC(
"TopMenubar",
"Tools menu"),
nullptr,
static_cast<ImGuiWindowFlags_
>(flags)))
701 if (ImGui::Button(
_LC(
"TopMenubar",
"Friction settings")))
707 if (ImGui::Button(
_LC(
"TopMenubar",
"Show console")))
713 if (ImGui::Button(
_LC(
"TopMenubar",
"Texture tool")))
719 if (ImGui::Button(
_LC(
"TopMenubar",
"Collisions debug")))
725 if (current_actor !=
nullptr)
727 if (ImGui::Button(
_LC(
"TopMenubar",
"Node / Beam utility")))
733 if (ImGui::Button(
_LC(
"TopMenubar",
"FlexBody debug")))
741 ImGui::TextColored(
GRAY_HINT_TEXT,
"%s",
_LC(
"TopMenubar",
"Pre-spawn diag. options:"));
744 if (ImGui::Checkbox(
_LC(
"TopMenubar",
"Node mass recalc. logging"), &diag_mass))
748 if (ImGui::IsItemHovered())
750 ImGui::BeginTooltip();
751 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Extra logging on runtime - mass recalculation"));
756 if (ImGui::Checkbox(
_LC(
"TopMenubar",
"Beam break logging"), &diag_break))
760 if (ImGui::IsItemHovered())
762 ImGui::BeginTooltip();
763 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Extra logging on runtime"));
768 if (ImGui::Checkbox(
_LC(
"TopMenubar",
"Beam deform. logging"), &diag_deform))
772 if (ImGui::IsItemHovered())
774 ImGui::BeginTooltip();
775 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Extra logging on runtime"));
780 if (ImGui::Checkbox(
_LC(
"TopMenubar",
"Trigger logging"), &diag_trig))
784 if (ImGui::IsItemHovered())
786 ImGui::BeginTooltip();
787 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Extra logging on runtime - trigger beams activity"));
792 if (ImGui::Checkbox(
_LC(
"TopMenubar",
"VideoCamera direction marker"), &diag_vcam))
796 if (ImGui::IsItemHovered())
798 ImGui::BeginTooltip();
799 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Visual marker of VideoCameras direction"));
803 ImGui::PushItemWidth(125.f);
807 if (ImGui::IsItemHovered())
809 ImGui::BeginTooltip();
810 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"1 = Solid"));
811 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"2 = Wireframe"));
812 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"3 = Points"));
826 menu_pos.x = ai_cursor.x + window_pos.x - ImGui::GetStyle().WindowPadding.x;
827 ImGui::SetNextWindowPos(menu_pos);
828 if (ImGui::Begin(
_LC(
"TopMenubar",
"AI menu"),
nullptr,
static_cast<ImGuiWindowFlags_
>(flags)))
830 if (ImGui::IsWindowHovered())
835 ImGui::PushItemWidth(125.f);
844 ImGui::PushItemFlag(ImGuiItemFlags_Disabled,
true);
845 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
848 ImGui::InputInt(
_LC(
"TopMenubar",
"Vehicle count"), &
ai_num, 1, 100);
849 if (ImGui::IsItemHovered())
851 ImGui::BeginTooltip();
852 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Number of vehicles"));
858 ImGui::PopItemFlag();
859 ImGui::PopStyleVar();
864 ImGui::PushItemFlag(ImGuiItemFlags_Disabled,
true);
865 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
870 ImGui::PushItemFlag(ImGuiItemFlags_Disabled,
true);
871 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
874 ImGui::InputInt(
_LC(
"TopMenubar",
"Distance"), &
ai_distance, 1, 100);
875 if (ImGui::IsItemHovered())
877 ImGui::BeginTooltip();
878 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Following distance in meters"));
884 ImGui::PopItemFlag();
885 ImGui::PopStyleVar();
888 std::string label1 =
"Behind";
900 ImGui::PushItemFlag(ImGuiItemFlags_Disabled,
true);
901 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
904 if (ImGui::BeginCombo(
"Position", label1.c_str()))
906 if (ImGui::Selectable(
"Behind"))
910 if (ImGui::Selectable(
"Parallel"))
916 if (ImGui::IsItemHovered())
918 ImGui::BeginTooltip();
919 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Positioning scheme"));
921 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Behind: Set vehicle behind vehicle, in line"));
922 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Parallel: Set vehicles in parallel, useful for certain scenarios like drag races"));
928 ImGui::PopItemFlag();
929 ImGui::PopStyleVar();
937 ImGui::PushItemFlag(ImGuiItemFlags_Disabled,
true);
938 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
941 ImGui::InputInt(
_LC(
"TopMenubar",
"Repeat times"), &
ai_times, 1, 100);
942 if (ImGui::IsItemHovered())
944 ImGui::BeginTooltip();
945 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"How many times to loop the path"));
951 ImGui::PopItemFlag();
952 ImGui::PopStyleVar();
957 ImGui::PopItemFlag();
958 ImGui::PopStyleVar();
964 std::string label2 =
"Normal";
971 label2 =
"Drag Race";
984 if (actor->ar_driveable ==
AI)
986 ImGui::PushItemFlag(ImGuiItemFlags_Disabled,
true);
987 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
992 if (ImGui::BeginCombo(
"Mode", label2.c_str()))
994 if (ImGui::Selectable(
"Normal"))
1007 if (ImGui::Selectable(
"Race"))
1020 if (ImGui::Selectable(
"Drag Race"))
1037 if (ImGui::Selectable(
"Crash"))
1053 if (ImGui::Selectable(
"Chase"))
1068 if (ImGui::IsItemHovered())
1070 ImGui::BeginTooltip();
1071 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Land vehicle driving mode"));
1073 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Normal: Modify speed according to turns, other vehicles and character"));
1074 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Race: Always keep defined speed"));
1075 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Drag Race: Two vehicles performing a drag race"));
1076 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Crash: Two vehicles driving in opposite direction"));
1077 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Chase: Follow character and player vehicle"));
1078 ImGui::EndTooltip();
1083 if (actor->ar_driveable ==
AI)
1085 ImGui::PopItemFlag();
1086 ImGui::PopStyleVar();
1094 ImGui::InputInt(
_LC(
"TopMenubar",
"Speed"), &
ai_speed, 1, 100);
1095 if (ImGui::IsItemHovered())
1097 ImGui::BeginTooltip();
1098 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Speed in km/h for land vehicles or knots/s for boats"));
1099 ImGui::EndTooltip();
1105 ImGui::InputInt(
_LC(
"TopMenubar",
"Altitude"), &
ai_altitude, 1, 100);
1106 if (ImGui::IsItemHovered())
1108 ImGui::BeginTooltip();
1109 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Airplane maximum altitude in feet"));
1110 ImGui::EndTooltip();
1123 if (ImGui::IsItemHovered())
1125 ImGui::BeginTooltip();
1126 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Land vehicles, boats and airplanes"));
1127 ImGui::EndTooltip();
1132 ImGui::PushID(
"vehicle2");
1141 if (ImGui::IsItemHovered())
1143 ImGui::BeginTooltip();
1144 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Land vehicles, boats and airplanes"));
1145 ImGui::EndTooltip();
1154 ImGui::PushItemFlag(ImGuiItemFlags_Disabled,
true);
1155 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
1160 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_ButtonActive]);
1163 if (ImGui::Button(
_LC(
"TopMenubar",
"Start"), ImVec2(80, 0)))
1187 fmt::format(
_LC(
"TopMenubar",
"Select a preset, record or open survey map ({}) to set waypoints."),
1199 ImGui::PopStyleColor();
1204 if (ImGui::Button(
_LC(
"TopMenubar",
"Stop"), ImVec2(80, 0)))
1213 if (actor->ar_driveable ==
AI)
1222 ImGui::PopItemFlag();
1223 ImGui::PopStyleVar();
1228 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_Button]);
1229 std::string label =
"Record";
1232 label =
"Recording";
1233 ImGui::PushStyleColor(ImGuiCol_Button,
RED_TEXT);
1236 if (ImGui::Button(label.c_str(), ImVec2(80, 0)))
1249 ImGui::PopStyleColor();
1252 if (ImGui::CollapsingHeader(
_LC(
"TopMenubar",
"Presets")))
1256 int display_count = 0;
1257 for (
size_t i = 0; i < num_rows; i++)
1259 rapidjson::Value& j_row =
ai_presets_all[
static_cast<rapidjson::SizeType
>(i)];
1264 if (ImGui::Button(j_row[
"preset"].GetString(), ImVec2(250, 0)))
1268 for (
size_t i = 0; i < j_row[
"waypoints"].Size(); i++)
1270 float x = j_row[
"waypoints"][i][0].GetFloat();
1271 float y = j_row[
"waypoints"][i][1].GetFloat();
1272 float z = j_row[
"waypoints"][i][2].GetFloat();
1278 if (j_row[
"waypoints"][i].Size() == 4)
1280 speed = j_row[
"waypoints"][i][3].GetInt();
1286 waypoint.
speed = speed;
1298 float spinner_size = 8.f;
1299 ImGui::SetCursorPosX((ImGui::GetWindowSize().
x / 2.f) - spinner_size);
1304 ImGui::TextColored(
RED_TEXT,
"%s",
_LC(
"TopMenubar",
"Failed to fetch external presets."));
1305 if (ImGui::Button(
_LC(
"TopMenubar",
"Retry")))
1319 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"No presets found for this terrain :("));
1320 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Supported terrains:"));
1323 ImGui::BeginChild(
"terrains-scrolling", ImVec2(0.f, 200),
false);
1325 for (
size_t i = 0; i < num_rows; i++)
1327 rapidjson::Value& j_row_terrains =
ai_presets_all[
static_cast<rapidjson::SizeType
>(i)];
1328 if (j_row_terrains.HasMember(
"terrains"))
1330 for (
size_t i = 0; i < j_row_terrains[
"terrains"].Size(); i++)
1332 ImGui::Text(
"%s", j_row_terrains[
"terrains"][i].GetString());
1341 if (ImGui::CollapsingHeader(
_LC(
"TopMenubar",
"Waypoints")))
1345 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"No waypoints defined."));
1349 if (ImGui::Button(
_LC(
"TopMenubar",
"Export"), ImVec2(250, 0)))
1372 std::string json =
fmt::format(
"\n {{\n \"terrain\":\"{}\",\n \"preset\":\"Preset name\",\n \"waypoints\":\n [{}\n ]\n }}",
App::sim_terrain_name->getStr(), s);
1376 fmt::format(
_LC(
"TopMenubar",
"{} waypoints exported to RoR.log"),
1380 ImGui::BeginChild(
"waypoints-scrolling", ImVec2(0.f, 200),
false);
1385 ImGui::AlignTextToFramePadding();
1386 ImGui::Text(
"%d", i);
1388 if (ImGui::Button(
"teleport", ImVec2(60, 0)))
1390 Ogre::Vector3* payload =
new Ogre::Vector3(
ai_waypoints[i].position);
1393 if (ImGui::IsItemHovered())
1395 ImGui::BeginTooltip();
1397 ImGui::Text(
w.c_str());
1398 ImGui::EndTooltip();
1401 ImGui::SetNextItemWidth(90);
1407 ImGui::InputInt(
_LC(
"TopMenubar",
"speed"), &
ai_waypoints[i].speed, 1, 100);
1408 if (ImGui::IsItemHovered())
1410 ImGui::BeginTooltip();
1411 ImGui::Text(
_LC(
"TopMenubar",
"Set waypoint speed in km/h for land vehicles"));
1413 ImGui::Text(
_LC(
"TopMenubar",
"Value -1: Ignore, vehicle will use default speed"));
1414 ImGui::Text(
_LC(
"TopMenubar",
"Value >= 5: Override default speed"));
1415 ImGui::EndTooltip();
1424 ImGui::PopItemWidth();
1434 menu_pos.y = window_pos.y + tuning_cursor.y +
MENU_Y_OFFSET;
1435 menu_pos.x = tuning_cursor.x + window_pos.x - ImGui::GetStyle().WindowPadding.x;
1436 ImGui::SetNextWindowPos(menu_pos);
1437 if (ImGui::Begin(
_LC(
"TopMenubar",
"Tuning menu"),
nullptr,
static_cast<ImGuiWindowFlags_
>(flags)))
1443 ImGui::Text(
"%s",
_LC(
"Tuning",
"You are on foot."));
1444 ImGui::Text(
"%s",
_LC(
"Tuning",
"Enter a vehicle to tune it."));
1445 ImGui::PopStyleColor();
1458 ImGui::AlignTextToFramePadding();
1479 std::string delbtn_text =
_LC(
"Tuning",
"Delete");
1480 float delbtn_w = ImGui::CalcTextSize(delbtn_text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2;
1481 float delbtn_cursorx = ImGui::GetWindowContentRegionWidth() - delbtn_w;
1484 ImGui::SetCursorPosX(delbtn_cursorx);
1487 ImGui::PopStyleColor();
1498 ImGui::AlignTextToFramePadding();
1499 ImGui::TextDisabled(
_LC(
"Tuning",
"Working tuneup"));
1504 if (ImGui::Button(
_LC(
"Tuning",
"Save")))
1520 std::string cancelbtn_text =
_LC(
"Tuning",
"Cancel");
1521 float cancelbtn_w = ImGui::CalcTextSize(cancelbtn_text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2;
1522 float cancelbtn_cursorx = ImGui::GetWindowContentRegionWidth() - cancelbtn_w;
1525 ImGui::SetCursorPosX(cancelbtn_cursorx);
1526 if (ImGui::SmallButton(
_LC(
"Tuning",
"Cancel")))
1532 else if (tuneup_def)
1535 if (ImGui::Button(
_LC(
"Tuning",
"Save as...")))
1544 ImGui::AlignTextToFramePadding();
1545 std::string resetbtn_text =
_LC(
"Tuning",
"Reset");
1546 float delbtn_w = ImGui::CalcTextSize(resetbtn_text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2;
1547 float delbtn_cursorx = ImGui::GetWindowContentRegionWidth() - delbtn_w;
1550 ImGui::SetCursorPosX(delbtn_cursorx);
1553 ImGui::PopStyleColor();
1554 if (resetbtn_pressed)
1565 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
1567 if (ImGui::CollapsingHeader(addonparts_title.c_str()))
1573 ImGui::PushID(addonpart_entry->
fname.c_str());
1578 const ImVec2 checkbox_cursor = ImGui::GetCursorScreenPos();
1579 if (ImGui::Checkbox(addonpart_entry->
dname.c_str(), &used)
1580 && !conflict_w_hovered
1595 const float square_sz = ImGui::GetFrameHeight();
1596 const ImVec2 min = checkbox_cursor + ImGui::GetStyle().FramePadding*1.4f;
1597 const ImVec2 max = checkbox_cursor + (ImVec2(square_sz, square_sz) - ImGui::GetStyle().FramePadding*1.5f);
1598 const ImColor X_COLOR(0.5f, 0.48f, 0.45f);
1599 ImGui::GetWindowDrawList()->AddLine(min, max, X_COLOR, 4.f);
1600 ImGui::GetWindowDrawList()->AddLine(ImVec2(min.x, max.y), ImVec2(max.x, min.y), X_COLOR, 4.f);
1602 if (conflict_w_hovered)
1605 const float square_sz = ImGui::GetFrameHeight();
1606 const ImVec2 min = checkbox_cursor;
1607 const ImVec2 max = checkbox_cursor + ImVec2(square_sz + 0.5f, square_sz);
1608 const ImColor SQ_COLOR(0.7f, 0.1f, 0.f);
1609 ImGui::GetWindowDrawList()->AddRect(min, max, SQ_COLOR, 0.f, ImDrawCornerFlags_None, 3.f);
1612 if (ImGui::IsItemHovered())
1624 ImGui::AlignTextToFramePadding();
1625 std::string reloadbtn_text =
_LC(
"Tuning",
"Reload");
1626 const float reloadbtn_w = ImGui::CalcTextSize(reloadbtn_text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2;
1628 ImGui::SetCursorPosX(reloadbtn_cursorx);
1629 const bool reloadbtn_pressed = ImGui::SmallButton(reloadbtn_text.c_str());
1630 if (reloadbtn_pressed)
1653 if (ImGui::Button(
_LC(
"Tuning",
"Browse all parts")))
1663 std::string props_title =
fmt::format(
_LC(
"Tuning",
"Props ({})"), total_props);
1664 if (ImGui::CollapsingHeader(props_title.c_str()))
1669 ImGui::PushID(p.pp_id);
1670 ImGui::AlignTextToFramePadding();
1683 if (p.pp_beacon_type ==
'L' || p.pp_beacon_type ==
'R' || p.pp_beacon_type ==
'w')
1686 ImGui::TextDisabled(
"(special!)");
1687 if (ImGui::IsItemHovered())
1689 ImGui::BeginTooltip();
1690 ImGui::Text(
"special prop - aerial nav light");
1691 ImGui::EndTooltip();
1694 else if (p.pp_wheel_mesh_obj)
1697 ImGui::TextDisabled(
"(special!)");
1698 if (ImGui::IsItemHovered())
1700 ImGui::BeginTooltip();
1701 ImGui::Text(
"special prop - dashboard + dirwheel");
1702 ImGui::EndTooltip();
1721 std::string flexbodies_title =
fmt::format(
_LC(
"Tuning",
"Flexbodies ({})"), total_flexbodies);
1722 if (ImGui::CollapsingHeader(flexbodies_title.c_str()))
1727 ImGui::PushID(flexbody->getID());
1728 ImGui::AlignTextToFramePadding();
1734 flexbody->getOrigMeshName(),
1752 std::string wheels_title =
fmt::format(
_LC(
"TopMenubar",
"Wheels ({})"), total_wheels);
1753 if (ImGui::CollapsingHeader(wheels_title.c_str()))
1755 for (
WheelID_t i = 0; i < total_wheels; i++)
1758 ImGui::AlignTextToFramePadding();
1766 ImGui::PushStyleColor(ImGuiCol_Border,
ORANGE_TEXT);
1767 ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.f);
1774 ImGui::TextDisabled(
"|");
1785 bool resetPressed =
false;
1791 resetPressed = ImGui::SmallButton(
_LC(
"Tuning",
"Reset"));
1792 ImGui::PopStyleColor();
1793 ImGui::PopStyleVar();
1794 ImGui::PopStyleColor();
1798 if (selected_side != active_side)
1807 else if (resetPressed)
1828 std::string flares_title =
fmt::format(
_LC(
"Tuning",
"Flares ({})"), total_flares);
1829 if (ImGui::CollapsingHeader(flares_title.c_str()))
1834 ImGui::PushID(flareid);
1835 ImGui::AlignTextToFramePadding();
1841 std::string flarename;
1845 flarename =
fmt::format(
"{} {}", (
char)flaretype, controlnumber);
1850 flarename =
fmt::format(
"{} {}", (
char)flaretype, linkname);
1877 std::string exhausts_title =
fmt::format(
_LC(
"Tuning",
"Exhausts ({})"), total_exhausts);
1878 if (ImGui::CollapsingHeader(exhausts_title.c_str()))
1881 for (
ExhaustID_t exhaustid = 0; exhaustid < (int)total_exhausts; exhaustid++)
1883 ImGui::PushID(exhaustid);
1884 ImGui::AlignTextToFramePadding();
1908 std::string materials_title =
fmt::format(
_LC(
"Tuning",
"Managed Materials ({})"), total_materials);
1909 if (ImGui::CollapsingHeader(materials_title.c_str()))
1914 const std::string& material_name = mm_pair.first;
1915 ImGui::PushID(material_name.c_str());
1916 ImGui::AlignTextToFramePadding();
1951 ImGui::PopStyleColor(2);
1961 if (ImGui::IsMouseDown(1))
1972 ImVec2 box_min(0,0);
1973 ImVec2 box_max(ImGui::GetIO().DisplaySize.x, ImGui::GetStyle().WindowPadding.y +
PANEL_HOVERBOX_HEIGHT);
1974 ImVec2 mouse_pos = ImGui::GetIO().MousePos;
1975 const bool window_hovered ((mouse_pos.x >= box_min.x) && (mouse_pos.x <= box_max.x) &&
1976 (mouse_pos.y >= box_min.y) && (mouse_pos.y <= box_max.y));
1977 bool result = window_hovered;
1979 bool menu_hovered =
false;
1985 result |= menu_hovered;
1987 bool box_hovered =
false;
1992 result |= box_hovered;
1995 if (box_hovered && !menu_hovered)
2006 unsigned int num_actors_player = 0;
2009 if (actor->ar_net_source_id == user.
uniqueid)
2011 ++num_actors_player;
2018 ImVec4 player_gui_color(player_color.r, player_color.g, player_color.b, 1.f);
2019 ImGui::PushStyleColor(ImGuiCol_Text, player_gui_color);
2020 ImGui::Text(
"%s: %u (%s, Ver: %s, Lang: %s)",
2024 ImGui::PopStyleColor();
2025 #endif // USE_SOCKETW
2028 Ogre::TexturePtr tex1 =
FetchIcon(
"control_pause.png");
2029 Ogre::TexturePtr tex2 =
FetchIcon(
"control_play.png");
2033 if ((!actor->ar_hide_in_actor_list) && (actor->ar_net_source_id == user.
uniqueid))
2036 ImGui::PushID(
id.c_str());
2039 if (ImGui::ImageButton(
reinterpret_cast<ImTextureID
>(tex1->getHandle()), ImVec2(16, 16)))
2046 if (ImGui::ImageButton(
reinterpret_cast<ImTextureID
>(tex2->getHandle()), ImVec2(16, 16)))
2053 std::string text_buf_rem =
fmt::format(
" X ##[{}]", i);
2054 ImGui::PushStyleColor(ImGuiCol_Text,
RED_TEXT);
2055 if (ImGui::Button(text_buf_rem.c_str()))
2059 ImGui::PopStyleColor();
2065 if (ImGui::Button(actortext_buf.c_str()))
2075 std::vector<ActorPtr> actor_list;
2078 if (!actor->ar_hide_in_actor_list)
2080 actor_list.emplace_back(actor);
2083 if (actor_list.empty())
2086 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"None spawned yet"));
2087 ImGui::Text(
"%s",
_LC(
"TopMenubar",
"Use [Simulation] menu"));
2088 ImGui::PopStyleColor();
2096 std::string text_buf_rem =
fmt::format(
"X ##[{}]", i);
2097 ImGui::PushStyleColor(ImGuiCol_Text,
RED_TEXT);
2098 if (ImGui::Button(text_buf_rem.c_str()))
2102 ImGui::PopStyleColor();
2106 if (actor == player_actor)
2108 ImGui::PushStyleColor(ImGuiCol_Text,
GREEN_TEXT);
2110 else if (std::find(actor->ar_linked_actors.begin(), actor->ar_linked_actors.end(), player_actor) != actor->ar_linked_actors.end())
2112 ImGui::PushStyleColor(ImGuiCol_Text,
ORANGE_TEXT);
2116 ImGui::PushStyleColor(ImGuiCol_Text,
WHITE_TEXT);
2122 if (ImGui::Button(text_buf.c_str()))
2126 ImGui::PopStyleColor();
2143 float content_width = 0.f;
2145 std::string special_text;
2146 ImVec4 special_color = ImGui::GetStyle().Colors[ImGuiCol_Text];
2147 float special_text_centering_weight = 1.f;
2149 std::string special_text_b;
2150 std::string special_text_c;
2151 std::string special_text_d;
2152 ImVec4 special_color_c = ImVec4(0,0,0,0);
2159 special_text =
fmt::format(
_LC(
"TopMenubar",
"All physics paused, press {} to resume"),
2161 content_width = ImGui::CalcTextSize(special_text.c_str()).x;
2168 special_text =
fmt::format(
_LC(
"TopMenubar",
"Vehicle physics paused, press {} to resume"),
2170 content_width = ImGui::CalcTextSize(special_text.c_str()).x;
2175 content_width = 300;
2177 special_text =
_LC(
"TopMenubar",
"Replay");
2181 special_text =
fmt::format(
_LC(
"TopMenubar",
"Live repair mode, hit '{}' to stop"),
2183 content_width = 450;
2186 special_text_centering_weight = 0.7f;
2190 special_text =
fmt::format(
_LC(
"TopMenubar",
"Quick repair ('{}' for Live repair)"),
2192 content_width = 450;
2195 special_text_centering_weight = 0.7f;
2204 float distance = 0.0f;
2218 special_text_b =
fmt::format(
"{:.1f} {}", distance,
_LC(
"DirectionArrow",
"meter"));
2219 content_width = ImGui::CalcTextSize(special_text.c_str()).x + ImGui::CalcTextSize(special_text_b.c_str()).x;
2222 special_text_c =
fmt::format(
"{:02d}.{:02d}.{:02d}", (
int)(time) / 60, (
int)(time) % 60, (
int)(time * 100.0) % 100);
2224 special_color_c = (time_diff > 0.0f)
2231 special_text_d =
fmt::format(
"{:02d}.{:02d}.{:02d}", (
int)(best_time) / 60, (
int)(best_time) % 60, (
int)(best_time * 100.0) % 100);
2240 special_text =
fmt::format(
_LC(
"TopMenubar",
"Terrain editing mode, press {} to exit"),
2242 content_width = ImGui::CalcTextSize(special_text.c_str()).x + 25.f;
2247 special_text =
fmt::format(
_LC(
"TopMenubar",
"Terrain editing mode, press {} to save and exit"),
2249 content_width = ImGui::CalcTextSize(special_text.c_str()).x;
2254 if (!special_text.empty())
2257 box_pos.y = top_offset;
2258 box_pos.x = (ImGui::GetIO().DisplaySize.x / 2) - ((content_width / 2) + ImGui::GetStyle().FramePadding.x);
2259 ImGui::SetNextWindowPos(box_pos);
2260 ImGui::SetNextWindowSize(ImVec2(0.f, 0.f));
2261 ImGui::SetNextWindowContentWidth(content_width);
2262 ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
2263 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse;
2264 ImGui::PushStyleColor(ImGuiCol_WindowBg,
App::GetGuiManager()->GetTheme().semitransparent_window_bg);
2265 if (ImGui::Begin(special_text.c_str(),
nullptr, flags))
2270 float text_w = ImGui::CalcTextSize(special_text.c_str()).x;
2271 ImGui::SetCursorPosX(((content_width / 2) - (text_w / 2)) * special_text_centering_weight);
2273 ImGui::TextColored(special_color,
"%s", special_text.c_str());
2283 float pbar_width = content_width - (ImGui::GetStyle().ItemSpacing.x + ImGui::CalcTextSize(special_text.c_str()).x);
2284 ImGui::ProgressBar(fraction, ImVec2(pbar_width, ImGui::GetTextLineHeight()), pbar_text.
ToCStr());
2292 int min = (int)time_sec / 60;
2293 str_pos = snprintf(str, 200,
"%dmin ", min);
2294 time_sec -= (float)min * 60.f;
2296 snprintf(str+str_pos, 200-str_pos,
"%.2fsec", time_sec);
2297 ImGui::TextDisabled(
"%s: %s",
_LC(
"TopMenubar",
"Time"), str);
2303 ImGui::Text(special_text_b.c_str());
2304 ImGui::SetCursorPosX((ImGui::GetWindowSize().
x / 2) - (ImGui::CalcTextSize(special_text_c.c_str()).x / 2));
2305 ImGui::TextColored(special_color_c,
"%s", special_text_c.c_str());
2308 text <<
"Best Time: " << special_text_d.c_str();
2309 ImGui::SetCursorPosX((ImGui::GetWindowSize().
x / 2) - (ImGui::CalcTextSize(text).
x / 2));
2311 if (!special_text_d.empty())
2313 ImGui::TextDisabled(text);
2320 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.f, 0.f));
2324 ImGui::ProgressBar(fraction, ImVec2(15.f, ImGui::GetTextLineHeight() / 2.f),
"");
2328 ImGui::PopStyleVar();
2330 const ImVec2 MINI_SPACING = ImVec2(2.f,0.f);
2331 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, MINI_SPACING);
2335 const float INDENT = 15.f;
2337 ImGui::TextDisabled(
"%s:",
_LC(
"LiveRepair",
"Movement"));
2339 ImGui::SetColumnWidth(0, INDENT);
2340 ImGui::NextColumn();
2343 ImGui::NextColumn();
2346 ImGui::NextColumn();
2351 ImGui::TextDisabled(
"%s:",
_LC(
"LiveRepair",
"Rotation"));
2353 ImGui::SetColumnWidth(0, INDENT);
2354 ImGui::NextColumn();
2359 ImGui::TextDisabled(
"%s:",
_LC(
"LiveRepair",
"Modifiers"));
2361 ImGui::SetColumnWidth(0, INDENT);
2362 ImGui::SetColumnWidth(1, 125);
2363 ImGui::SetColumnWidth(2, 125);
2364 ImGui::NextColumn();
2371 ImGui::TextDisabled(
"%s (%s):",
_LC(
"LiveRepair",
"Reset mode"),
ToLocalizedString(resetmode).c_str());
2372 ImGui::Dummy(ImVec2(INDENT, 1.f));
2376 ImGui::PopStyleVar();
2382 std::string lbl_readonly =
_LC(
"TopMenubar",
"This terrain is read only.");
2383 ImGui::SetCursorPosX(ImGui::GetCursorPosX()
2384 + (ImGui::GetWindowContentRegionWidth() / 2 - ImGui::CalcTextSize(lbl_readonly.c_str()).x/2));
2385 ImGui::TextDisabled(
"%s", lbl_readonly.c_str());
2387 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2, 0.2, 0.2, 1.0));
2388 std::string btn_import =
_LC(
"TopMenubar",
"Import as editable project.");
2389 ImGui::SetCursorPosX(ImGui::GetCursorPosX()
2390 + ((ImGui::GetWindowContentRegionWidth() / 2 - ImGui::CalcTextSize(btn_import.c_str()).x / 2) - ImGui::GetStyle().FramePadding.x));
2399 ImGui::PopStyleColor();
2401 const ImVec2 PAD = ImVec2(5, 5);
2409 ImGui::PopStyleColor(1);
2425 for (
const std::string& filename: terrain->
GetDef()->ai_presets_files)
2427 rapidjson::Document j_doc;
2438 if (!j_doc.IsArray())
2440 LOG(
fmt::format(
"[RoR|Terrain] AI presets file '{}' declared in '{}' has wrong format - the root element is not an array!",
2446 for (
const rapidjson::Value& j_bundled_preset: j_doc.GetArray())
2459 #if defined(USE_CURL)
2461 std::thread(std::move(task)).detach();
2463 #endif // defined(USE_CURL)
2476 rapidjson::Value preset_copy(bundled_preset,
ai_presets_all.GetAllocator());
2482 rapidjson::Value preset_copy(extern_preset,
ai_presets_all.GetAllocator());
2588 std::string protectchk_text =
_LC(
"Tuning",
"Protected");
2589 float protectchk_w = ImGui::CalcTextSize(protectchk_text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2;
2590 float protectchk_cursorx = (ImGui::GetWindowContentRegionWidth() - protectchk_w) - 20.f;
2593 ImGui::SetCursorPosX(protectchk_cursorx);
2596 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
2597 bool chk_pressed = ImGui::Checkbox(protectchk_text.c_str(), &protectchk_value);
2598 ImGui::PopStyleVar(1);
2613 request->
mpr_type = (protectchk_value) ? request_type_set : request_type_reset;
2622 ImGui::GetWindowDrawList()->AddRect(
2623 ImGui::GetCursorScreenPos(),
2624 ImGui::GetCursorScreenPos() + ImGui::CalcTextSize(
"00") + ImGui::GetStyle().FramePadding*2,
2625 ImColor(ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]),
2626 ImGui::GetStyle().FrameRounding);
2627 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().FramePadding.x);
2628 ImGui::Text(
"%02d", subject_id);
2630 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().FramePadding.x);
2639 bool isEnabled = !is_unwanted && !is_force_removed;
2640 if (is_force_removed)
2642 ImGui::PushStyleColor(ImGuiCol_Border,
ORANGE_TEXT);
2643 ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.f);
2645 bool chkPressed = ImGui::Checkbox(name.c_str(), &isEnabled);
2646 bool resetPressed =
false;
2647 if (is_force_removed)
2651 resetPressed = ImGui::SmallButton(
_LC(
"Tuning",
"Reset"));
2652 ImGui::PopStyleColor();
2653 ImGui::PopStyleVar();
2654 ImGui::PopStyleColor();
2658 if (chkPressed && !isEnabled)
2673 else if ((chkPressed && isEnabled) || resetPressed)
2676 req->
mpr_type = request_type_reset;