diff --git a/data/mp/multiplay/skirmish/nb_generic.json b/data/mp/multiplay/skirmish/nb_generic.json index dcd5b20af5d..36f2b437eed 100644 --- a/data/mp/multiplay/skirmish/nb_generic.json +++ b/data/mp/multiplay/skirmish/nb_generic.json @@ -2,6 +2,8 @@ "AI": { "js": "nb_generic.js", "name": "NullBot", - "tip": "Adaptive AI with multiple personalities" + "tip": "Adaptive AI with multiple personalities", + "easy_tip": "Gets ~ 25% less power from each oil derrick\nResearch is not focused on a specific weapon branch", + "insane_tip": "Gets ~ 100% more power from each oil derrick\nStarts with defensive structures and oil derricks" } } diff --git a/data/mp/multiplay/skirmish/nb_hover.json b/data/mp/multiplay/skirmish/nb_hover.json index a99a7725672..286240a6784 100644 --- a/data/mp/multiplay/skirmish/nb_hover.json +++ b/data/mp/multiplay/skirmish/nb_hover.json @@ -2,6 +2,8 @@ "AI": { "js": "nb_hover.js", "name": "Hover AI", - "tip": "Sea map AI, based on NullBot" + "tip": "Sea map AI, based on NullBot", + "easy_tip": "Gets ~ 25% less power from each oil derrick", + "insane_tip": "Gets ~ 100% more power from each oil derrick\nStarts with defensive structures and oil derricks" } } diff --git a/data/mp/multiplay/skirmish/nb_turtle.json b/data/mp/multiplay/skirmish/nb_turtle.json index 7a49a801e23..f5d567de61e 100644 --- a/data/mp/multiplay/skirmish/nb_turtle.json +++ b/data/mp/multiplay/skirmish/nb_turtle.json @@ -2,6 +2,8 @@ "AI": { "js": "nb_turtle.js", "name": "Turtle AI", - "tip": "Tower wars AI, based on NullBot" + "tip": "Tower wars AI, based on NullBot", + "easy_tip": "Gets ~ 25% less power from each oil derrick\nResearch is not focused on a specific weapon branch", + "insane_tip": "Gets ~ 100% more power from each oil derrick\nStarts with defensive structures and oil derricks" } } diff --git a/data/mp/multiplay/skirmish/nexus.json b/data/mp/multiplay/skirmish/nexus.json index 500e7cbad17..ae8ba2418a6 100644 --- a/data/mp/multiplay/skirmish/nexus.json +++ b/data/mp/multiplay/skirmish/nexus.json @@ -1,8 +1,12 @@ { "AI": { - "name": "Nexus", "slo": "nexus.slo", + "vlo": "nexus.vlo", + "name": "Nexus", "tip": "Initial AI, now supplanted by NullBot", - "vlo": "nexus.vlo" + "easy_tip": "Gets ~ 25% less power from each oil derrick", + "medium_tip": "Research speed +40% (per minute)", + "hard_tip": "Research speed +60% (per minute)", + "insane_tip": "Gets ~ 100% more power from each oil derrick\nResearch speed +80% (per minute)\nStarts with defensive structures and oil derricks" } } diff --git a/data/mp/multiplay/skirmish/semperfi-js.json b/data/mp/multiplay/skirmish/semperfi-js.json index b10951c0cc0..37128533de7 100644 --- a/data/mp/multiplay/skirmish/semperfi-js.json +++ b/data/mp/multiplay/skirmish/semperfi-js.json @@ -2,6 +2,8 @@ "AI": { "js": "semperfi.js", "name": "SemperFi JavaScript", - "tip": "Prototypical JavaScript AI focusing on rockets/missiles" + "tip": "Prototypical JavaScript AI focusing on rockets/missiles", + "easy_tip": "Gets ~ 25% less power from each oil derrick", + "insane_tip": "Gets ~ 100% more power from each oil derrick\nStarts with defensive structures and oil derricks" } } diff --git a/data/mp/multiplay/skirmish/semperfi.json b/data/mp/multiplay/skirmish/semperfi.json index 30e25fee147..3cef9e47943 100644 --- a/data/mp/multiplay/skirmish/semperfi.json +++ b/data/mp/multiplay/skirmish/semperfi.json @@ -1,8 +1,11 @@ { "AI": { - "name": "SemperFi", "slo": "semperfi.slo", + "vlo": "semperfi.vlo", + "name": "SemperFi", "tip": "Enhanced Nexus AI", - "vlo": "semperfi.vlo" + "easy_tip": "Gets ~ 25% less power from each oil derrick\nDoes not build defenses next to enemy oil derricks\nNever tries a truck rush", + "medium_tip": "Never tries a truck rush", + "insane_tip": "Gets ~ 100% more power from each oil derrick\nStarts with defensive structures and oil derricks" } } diff --git a/po/custom/fromJson.txt b/po/custom/fromJson.txt index 49944d64aab..a34d5bf0bf7 100644 --- a/po/custom/fromJson.txt +++ b/po/custom/fromJson.txt @@ -509,6 +509,11 @@ _("Gauss Cannon Hardpoint") _("Gauss Cannon Python Tracks") _("Gauss Cannon Wyvern Tracks") _("Generates and concentrates bursts of laser energy") +_("Gets ~ 100% more power from each oil derrick\nResearch speed +80% (per minute)\nStarts with defensive structures and oil derricks") +_("Gets ~ 100% more power from each oil derrick\nStarts with defensive structures and oil derricks") +_("Gets ~ 25% less power from each oil derrick") +_("Gets ~ 25% less power from each oil derrick\nDoes not build defenses next to enemy oil derricks\nNever tries a truck rush") +_("Gets ~ 25% less power from each oil derrick\nResearch is not focused on a specific weapon branch") _("Gives Cyborg limited flight abilities") _("Good main battle tank and heavy artillery platform") _("Good medium tank and support vehicle") @@ -937,6 +942,7 @@ _("Needle Gun Vengeance Tracks") _("Neural Synapse Research Brain") _("Neural Synapse Research Brain Mk2") _("Neural Synapse Research Brain Mk3") +_("Never tries a truck rush") _("New AA Turret Available") _("New Advanced Weapon Available") _("New armored construction") @@ -1138,6 +1144,8 @@ _("Research Module") _("Research Module Available") _("Research module expands research facilities") _("Research speed +30%") +_("Research speed +40% (per minute)") +_("Research speed +60% (per minute)") _("Research speed +85%") _("Retaliation") _("Retribution") diff --git a/po/parseJson.py b/po/parseJson.py index 535320c6152..54d9ee54498 100644 --- a/po/parseJson.py +++ b/po/parseJson.py @@ -8,7 +8,7 @@ def parse(obj): if isinstance(obj, dict): for k, v in obj.items(): parse(v) - if k in ['name', 'tip'] and isinstance(v, str): + if k in ['name', 'tip', 'easy_tip', 'medium_tip', 'hard_tip', 'insane_tip'] and isinstance(v, str): printString(v, '_(', '\n') elif k in ['text', 'ranks'] and isinstance(v, list): for s in v: diff --git a/src/multiint.cpp b/src/multiint.cpp index 115741e21d6..869020a748e 100644 --- a/src/multiint.cpp +++ b/src/multiint.cpp @@ -276,6 +276,7 @@ struct AIDATA char vlo[MAX_LEN_AI_NAME]; char js[MAX_LEN_AI_NAME]; char tip[255]; + char difficultyTips[4][255]; // optional difficulty level info int assigned; ///< How many AIs have we assigned of this type }; static std::vector aidata; @@ -787,6 +788,20 @@ void readAIs() sstrcpy(ai.vlo, aiconf.value("vlo", "").toWzString().toUtf8().c_str()); sstrcpy(ai.js, aiconf.value("js", "").toWzString().toUtf8().c_str()); + const char *difficultyKeys[] = { "easy_tip", "medium_tip", "hard_tip", "insane_tip" }; + for (int i = 0; i < ARRAY_SIZE(difficultyKeys); i++) + { + if (aiconf.contains(difficultyKeys[i])) + { + sstrcpy(ai.difficultyTips[i], _(aiconf.value(difficultyKeys[i], "").toWzString().toUtf8().c_str())); + } + else + { + // note that the empty string "" must never be translated + sstrcpy(ai.difficultyTips[i], ""); + } + } + if (aiconf.contains("tip")) { sstrcpy(ai.tip, _(aiconf.value("tip", "").toWzString().toUtf8().c_str())); @@ -1932,6 +1947,12 @@ static void addDifficultyChooser(int player) case 2: sButInit.pTip = _("No holds barred"); break; case 3: sButInit.pTip = _("Starts with advantages"); break; } + const char *difficultyTip = aidata[NetPlay.players[player].ai].difficultyTips[i]; + if (strcmp(difficultyTip, "") != 0) + { + sButInit.pTip += "\n"; + sButInit.pTip += difficultyTip; + } sButInit.pDisplay = displayDifficulty; sButInit.UserData = i; sButInit.pUserData = new DisplayDifficultyCache(); @@ -2519,8 +2540,17 @@ static void drawReadyButton(UDWORD player) if (!NetPlay.players[player].allocated && NetPlay.players[player].ai >= 0) { int icon = difficultyIcon(NetPlay.players[player].difficulty); + int playerDifficulty = NetPlay.players[player].difficulty; + char tooltip[128 + 255]; + sstrcpy(tooltip, _(difficultyList[playerDifficulty])); + const char *difficultyTip = aidata[NetPlay.players[player].ai].difficultyTips[playerDifficulty]; + if (strcmp(difficultyTip, "") != 0) + { + sstrcat(tooltip, "\n"); + sstrcat(tooltip, difficultyTip); + } addMultiBut(psWScreen, MULTIOP_READY_FORM_ID + player, MULTIOP_DIFFICULTY_INIT_START + player, 6, 4, MULTIOP_READY_WIDTH, MULTIOP_READY_HEIGHT, - (NetPlay.isHost && !locked.difficulty) ? _("Click to change difficulty") : _(difficultyList[NetPlay.players[player].difficulty]), icon, icon, icon); + (NetPlay.isHost && !locked.difficulty) ? _("Click to change difficulty") : tooltip, icon, icon, icon); return; } else if (!NetPlay.players[player].allocated)