#include "game/events/research_events.h" namespace sots::events { bool ResearchCompletedOnBudget(float progressRatio) { // The original widens the float ratio and compares it against the double nearest 0.8f. return static_cast(progressRatio) >= kResearchOnBudgetRatio; } std::string FormatEventText(std::string_view fmt, std::string_view arg, std::size_t cap) { std::string out; out.reserve(fmt.size() + arg.size()); bool substituted = false; for (std::size_t i = 0; i < fmt.size(); ++i) { if (fmt[i] == '%' && i + 1 < fmt.size()) { if (fmt[i + 1] == 's' && !substituted) { out.append(arg.begin(), arg.end()); substituted = true; ++i; continue; } if (fmt[i + 1] == '%') { out.push_back('%'); ++i; continue; } } out.push_back(fmt[i]); } if (cap != 0 && out.size() > cap) out.resize(cap); return out; } namespace { int PostPair(EventStorage& log, const EventText& text, const EventTextKeys& keys, std::string_view arg, std::size_t cap, int turn, std::string_view img, int action) { std::string summary = FormatEventText(text(keys.summaryKey), arg, cap); std::string message = FormatEventText(text(keys.messageKey), arg, cap); return log.PostGlobal(std::move(summary), std::move(message), turn, img, action); } } // namespace int PostResearchOverbudget(EventStorage& log, const EventText& text, std::string_view techName, int turn) { // Formatted into a std::string by the original, so no length cap. return PostPair(log, text, kTextResearchOverbudget, techName, 0, turn, kImgResearchOverbudget, 1); } int PostResearchCompleted(EventStorage& log, const EventText& text, std::string_view techName, float progressRatio, int turn) { const bool onBudget = ResearchCompletedOnBudget(progressRatio); const EventTextKeys& keys = onBudget ? kTextResearchComplete : kTextResearchUnderbudget; const std::string_view img = onBudget ? kImgResearchComplete : kImgResearchUnderbudget; // Only the message goes through the 256-byte buffer; the summary is taken verbatim from // its slot without formatting. std::string summary(text(keys.summaryKey)); std::string message = FormatEventText(text(keys.messageKey), techName, kCompletionMessageCap); return log.PostGlobal(std::move(summary), std::move(message), turn, img, 1); } int PostTemperance(EventStorage& log, const EventText& text, int turn) { // action 0 with no subject and no position -> EventStorage::Post stores 2. return PostPair(log, text, kTextTemperance, {}, 0, turn, kImgTemperance, 0); } int PostTechsUnlocked(EventStorage& log, const EventText& text, const std::vector& techNames, std::string_view separator, int turn) { std::string summary(text(kTextTechsUnlocked.summaryKey)); std::string message(text(kTextTechsUnlocked.messageKey)); for (const std::string& name : techNames) { message.append(separator.begin(), separator.end()); message.append(name); } return log.PostGlobal(std::move(summary), std::move(message), turn, kImgTechsUnlocked, 1); } int PostNoResearch(EventStorage& log, const EventText& text, int turn) { std::string summary(text(kTextNoResearch.summaryKey)); std::string message(text(kTextNoResearch.messageKey)); return log.PostGlobal(std::move(summary), std::move(message), turn, kImgNoResearch, 1); } } // namespace sots::events