From 784490720462afd0c10904fae1f39d453ea3d919 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 14 Apr 2014 19:41:01 +0400 Subject: [PATCH] Add new API functions for creating announcements and combat reports. Allow specifying the announcement flags directly, and adding unit combat reports. Also, make announcement functions write the message to the game log. --- Lua API.html | 26 +++++- Lua API.rst | 32 ++++++- library/LuaApi.cpp | 4 + library/include/modules/Gui.h | 11 ++- library/modules/Gui.cpp | 171 +++++++++++++++++++++++++++++----- 5 files changed, 216 insertions(+), 28 deletions(-) diff --git a/Lua API.html b/Lua API.html index 3d019f986..f0af74012 100644 --- a/Lua API.html +++ b/Lua API.html @@ -1160,6 +1160,26 @@ the container itself.

  • dfhack.gui.getSelectedBuilding([silent])

    Returns the building selected via 'q', 't', 'k' or 'i'.

  • +
  • dfhack.gui.writeToGamelog(text)

    +

    Writes a string to gamelog.txt without doing an announcement.

    +
  • +
  • dfhack.gui.makeAnnouncement(type,flags,pos,text,color[,is_bright])

    +

    Adds an announcement with given announcement_type, text, color, and brightness. +The is_bright boolean actually seems to invert the brightness.

    +

    The announcement is written to gamelog.txt. The announcement_flags +argument provides a custom set of announcements.txt options, +which specify if the message should actually be displayed in the +announcement list, and whether to recenter or show a popup.

    +

    Returns the index of the new announcement in df.global.world.status.reports, or -1.

    +
  • +
  • dfhack.gui.addCombatReport(unit,slot,report_index)

    +

    Adds the report with the given index (returned by makeAnnouncement) +to the specified group of the given unit. Returns true on success.

    +
  • +
  • dfhack.gui.addCombatReportAuto(unit,flags,report_index)

    +

    Adds the report with the given index to the appropriate group(s) +of the given unit, as requested by the flags.

    +
  • dfhack.gui.showAnnouncement(text,color[,is_bright])

    Adds a regular announcement with given text, color, and brightness. The is_bright boolean actually seems to invert the brightness.

    @@ -1170,9 +1190,9 @@ The is_bright boolean actually seems to invert the brightness.

  • dfhack.gui.showPopupAnnouncement(text,color[,is_bright])

    Pops up a titan-style modal announcement window.

  • -
  • dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright])

    -

    Uses the type to look up options from announcements.txt, and calls the -above operations accordingly. If enabled, pauses and zooms to position.

    +
  • dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright,unit1,unit2])

    +

    Uses the type to look up options from announcements.txt, and calls the above +operations accordingly. The units are used to call addCombatReportAuto.

  • diff --git a/Lua API.rst b/Lua API.rst index 27445be45..90e36213f 100644 --- a/Lua API.rst +++ b/Lua API.rst @@ -862,6 +862,32 @@ Gui module Returns the building selected via *'q'*, *'t'*, *'k'* or *'i'*. +* ``dfhack.gui.writeToGamelog(text)`` + + Writes a string to gamelog.txt without doing an announcement. + +* ``dfhack.gui.makeAnnouncement(type,flags,pos,text,color[,is_bright])`` + + Adds an announcement with given announcement_type, text, color, and brightness. + The is_bright boolean actually seems to invert the brightness. + + The announcement is written to gamelog.txt. The announcement_flags + argument provides a custom set of announcements.txt options, + which specify if the message should actually be displayed in the + announcement list, and whether to recenter or show a popup. + + Returns the index of the new announcement in ``df.global.world.status.reports``, or -1. + +* ``dfhack.gui.addCombatReport(unit,slot,report_index)`` + + Adds the report with the given index (returned by makeAnnouncement) + to the specified group of the given unit. Returns *true* on success. + +* ``dfhack.gui.addCombatReportAuto(unit,flags,report_index)`` + + Adds the report with the given index to the appropriate group(s) + of the given unit, as requested by the flags. + * ``dfhack.gui.showAnnouncement(text,color[,is_bright])`` Adds a regular announcement with given text, color, and brightness. @@ -875,10 +901,10 @@ Gui module Pops up a titan-style modal announcement window. -* ``dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright])`` +* ``dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright,unit1,unit2])`` - Uses the type to look up options from announcements.txt, and calls the - above operations accordingly. If enabled, pauses and zooms to position. + Uses the type to look up options from announcements.txt, and calls the above + operations accordingly. The units are used to call ``addCombatReportAuto``. Job module diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index b63e58dbf..622b3f286 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1307,6 +1307,10 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = { WRAPM(Gui, getSelectedUnit), WRAPM(Gui, getSelectedItem), WRAPM(Gui, getSelectedBuilding), + WRAPM(Gui, writeToGamelog), + WRAPM(Gui, makeAnnouncement), + WRAPM(Gui, addCombatReport), + WRAPM(Gui, addCombatReportAuto), WRAPM(Gui, showAnnouncement), WRAPM(Gui, showZoomAnnouncement), WRAPM(Gui, showPopupAnnouncement), diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h index 794cb89ff..6acb0ce08 100644 --- a/library/include/modules/Gui.h +++ b/library/include/modules/Gui.h @@ -35,6 +35,8 @@ distribution. #include "df/init.h" #include "df/ui.h" #include "df/announcement_type.h" +#include "df/announcement_flags.h" +#include "df/unit_report_type.h" namespace df { struct viewscreen; @@ -97,13 +99,20 @@ namespace DFHack DFHACK_EXPORT bool any_building_hotkey(df::viewscreen *top); DFHACK_EXPORT df::building *getSelectedBuilding(color_ostream &out, bool quiet = false); + // Low-level API that gives full control over announcements and reports + DFHACK_EXPORT void writeToGamelog(std::string message); + + DFHACK_EXPORT int makeAnnouncement(df::announcement_type type, df::announcement_flags mode, df::coord pos, std::string message, int color = 7, bool bright = true); + DFHACK_EXPORT bool addCombatReport(df::unit *unit, df::unit_report_type slot, int report_index); + DFHACK_EXPORT bool addCombatReportAuto(df::unit *unit, df::announcement_flags mode, int report_index); + // Show a plain announcement, or a titan-style popup message DFHACK_EXPORT void showAnnouncement(std::string message, int color = 7, bool bright = true); DFHACK_EXPORT void showZoomAnnouncement(df::announcement_type type, df::coord pos, std::string message, int color = 7, bool bright = true); DFHACK_EXPORT void showPopupAnnouncement(std::string message, int color = 7, bool bright = true); // Show an announcement with effects determined by announcements.txt - DFHACK_EXPORT void showAutoAnnouncement(df::announcement_type type, df::coord pos, std::string message, int color = 7, bool bright = true); + DFHACK_EXPORT void showAutoAnnouncement(df::announcement_type type, df::coord pos, std::string message, int color = 7, bool bright = true, df::unit *unit1 = NULL, df::unit *unit2 = NULL); /* * Cursor and window coords diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 04a453c06..bb9ce6676 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -87,6 +87,8 @@ using namespace DFHack; #include "df/announcements.h" #include "df/stop_depart_condition.h" #include "df/route_stockpile_link.h" +#include "df/game_mode.h" +#include "df/unit.h" using namespace df::enums; using df::global::gview; @@ -97,6 +99,7 @@ using df::global::world; using df::global::selection_rect; using df::global::ui_menu_width; using df::global::ui_area_map_width; +using df::global::gamemode; static df::layer_object_listst *getLayerList(df::viewscreen_layer *layer, int idx) { @@ -1080,13 +1083,26 @@ df::building *Gui::getSelectedBuilding(color_ostream &out, bool quiet) // -static void doShowAnnouncement( - df::announcement_type type, df::coord pos, std::string message, int color, bool bright -) { +DFHACK_EXPORT void Gui::writeToGamelog(std::string message) +{ + if (message.empty()) + return; + + std::ofstream fseed("gamelog.txt", std::ios::out | std::ios::app); + if(fseed.is_open()) + fseed << message << std::endl; + fseed.close(); +} + +DFHACK_EXPORT int Gui::makeAnnouncement(df::announcement_type type, df::announcement_flags flags, df::coord pos, std::string message, int color, bool bright) +{ using df::global::world; using df::global::cur_year; using df::global::cur_year_tick; + if (message.empty()) + return -1; + int year = 0, year_time = 0; if (cur_year && cur_year_tick) @@ -1102,6 +1118,31 @@ static void doShowAnnouncement( year_time = last->time; } + // Apply the requested effects + writeToGamelog(message); + + if (flags.bits.DO_MEGA || flags.bits.PAUSE || flags.bits.RECENTER) + { + resetDwarfmodeView(flags.bits.DO_MEGA || flags.bits.PAUSE); + + if (flags.bits.RECENTER && pos.isValid()) + revealInDwarfmodeMap(pos, true); + + if (flags.bits.DO_MEGA) + showPopupAnnouncement(message, color, bright); + } + + bool display = false; + + if (gamemode == NULL) + display = flags.bits.A_DISPLAY || flags.bits.D_DISPLAY; + else if (*gamemode == game_mode::ADVENTURE) + display = flags.bits.A_DISPLAY; + else + display = flags.bits.D_DISPLAY; + + // Generate the report objects + int report_idx = world->status.reports.size(); bool continued = false; while (!message.empty()) @@ -1117,7 +1158,6 @@ static void doShowAnnouncement( new_rep->time = year_time; new_rep->flags.bits.continuation = continued; - new_rep->flags.bits.announcement = true; int size = std::min(message.size(), (size_t)73); new_rep->text = message.substr(0, size); @@ -1129,20 +1169,114 @@ static void doShowAnnouncement( new_rep->id = world->status.next_report_id++; world->status.reports.push_back(new_rep); - world->status.announcements.push_back(new_rep); - world->status.display_timer = 2000; + + if (display) + { + new_rep->flags.bits.announcement = true; + world->status.announcements.push_back(new_rep); + world->status.display_timer = 2000; + } } + + return report_idx; +} + + +bool Gui::addCombatReport(df::unit *unit, df::unit_report_type slot, int report_index) +{ + using df::global::world; + + CHECK_INVALID_ARGUMENT(is_valid_enum_item(slot)); + + auto &vec = world->status.reports; + auto report = vector_get(vec, report_index); + + if (!unit || !report) + return false; + + // Check that it is a new report + auto &rvec = unit->reports.log[slot]; + if (!rvec.empty() && rvec.back() >= report->id) + return false; + + // Add the report + rvec.push_back(report->id); + + unit->reports.last_year[slot] = report->year; + unit->reports.last_year_tick[slot] = report->time; + + switch (slot) { + case unit_report_type::Combat: + world->status.flags.bits.combat = true; + break; + case unit_report_type::Hunting: + world->status.flags.bits.hunting = true; + break; + case unit_report_type::Sparring: + world->status.flags.bits.sparring = true; + break; + } + + // And all the continuation lines + for (size_t i = report_index+1; i < vec.size() && vec[i]->flags.bits.continuation; i++) + rvec.push_back(vec[i]->id); + + return true; +} + +bool Gui::addCombatReportAuto(df::unit *unit, df::announcement_flags mode, int report_index) +{ + using df::global::world; + + auto &vec = world->status.reports; + auto report = vector_get(vec, report_index); + + if (!unit || !report) + return false; + + bool ok = false; + + if (mode.bits.UNIT_COMBAT_REPORT) + { + if (unit->flags2.bits.sparring) + ok |= addCombatReport(unit, unit_report_type::Sparring, report_index); + else if (unit->job.current_job && unit->job.current_job->job_type == job_type::Hunt) + ok |= addCombatReport(unit, unit_report_type::Hunting, report_index); + else + ok |= addCombatReport(unit, unit_report_type::Combat, report_index); + } + + if (mode.bits.UNIT_COMBAT_REPORT_ALL_ACTIVE) + { + FOR_ENUM_ITEMS(unit_report_type, slot) + { + if (!unit->reports.log[slot].empty() && + unit->reports.last_year[slot] == report->year && + (report->time - unit->reports.last_year_tick[slot]) <= 500) + { + ok |= addCombatReport(unit, slot, report_index); + } + } + } + + return ok; } void Gui::showAnnouncement(std::string message, int color, bool bright) { - doShowAnnouncement(df::announcement_type(0), df::coord(), message, color, bright); + df::announcement_flags mode(0); + mode.bits.D_DISPLAY = mode.bits.A_DISPLAY = true; + + makeAnnouncement(df::announcement_type(0), mode, df::coord(), message, color, bright); } void Gui::showZoomAnnouncement( df::announcement_type type, df::coord pos, std::string message, int color, bool bright ) { - doShowAnnouncement(type, pos, message, color, bright); + df::announcement_flags mode(0); + mode.bits.D_DISPLAY = mode.bits.A_DISPLAY = true; + + makeAnnouncement(type, mode, pos, message, color, bright); } void Gui::showPopupAnnouncement(std::string message, int color, bool bright) @@ -1157,26 +1291,21 @@ void Gui::showPopupAnnouncement(std::string message, int color, bool bright) } void Gui::showAutoAnnouncement( - df::announcement_type type, df::coord pos, std::string message, int color, bool bright + df::announcement_type type, df::coord pos, std::string message, int color, bool bright, + df::unit *unit1, df::unit *unit2 ) { using df::global::announcements; - df::announcement_flags flags; + df::announcement_flags flags(0); + flags.bits.D_DISPLAY = flags.bits.A_DISPLAY = true; + if (is_valid_enum_item(type) && announcements) flags = announcements->flags[type]; - doShowAnnouncement(type, pos, message, color, bright); - - if (flags.bits.DO_MEGA || flags.bits.PAUSE || flags.bits.RECENTER) - { - resetDwarfmodeView(flags.bits.DO_MEGA || flags.bits.PAUSE); - - if (flags.bits.RECENTER && pos.isValid()) - revealInDwarfmodeMap(pos, true); - } + int id = makeAnnouncement(type, flags, pos, message, color, bright); - if (flags.bits.DO_MEGA) - showPopupAnnouncement(message, color, bright); + addCombatReportAuto(unit1, flags, id); + addCombatReportAuto(unit2, flags, id); } df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed)