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.
develop
Alexander Gavrilov 2014-04-14 19:41:01 +04:00
parent b56c3a95a6
commit 7844907204
5 changed files with 216 additions and 28 deletions

@ -1160,6 +1160,26 @@ the container itself.</p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedBuilding([silent])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedBuilding([silent])</span></tt></p>
<p>Returns the building selected via <em>'q'</em>, <em>'t'</em>, <em>'k'</em> or <em>'i'</em>.</p> <p>Returns the building selected via <em>'q'</em>, <em>'t'</em>, <em>'k'</em> or <em>'i'</em>.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.writeToGamelog(text)</tt></p>
<p>Writes a string to gamelog.txt without doing an announcement.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.makeAnnouncement(type,flags,pos,text,color[,is_bright])</span></tt></p>
<p>Adds an announcement with given announcement_type, text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.</p>
<p>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.</p>
<p>Returns the index of the new announcement in <tt class="docutils literal">df.global.world.status.reports</tt>, or -1.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.addCombatReport(unit,slot,report_index)</tt></p>
<p>Adds the report with the given index (returned by makeAnnouncement)
to the specified group of the given unit. Returns <em>true</em> on success.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.addCombatReportAuto(unit,flags,report_index)</tt></p>
<p>Adds the report with the given index to the appropriate group(s)
of the given unit, as requested by the flags.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAnnouncement(text,color[,is_bright])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAnnouncement(text,color[,is_bright])</span></tt></p>
<p>Adds a regular announcement with given text, color, and brightness. <p>Adds a regular announcement with given text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.</p> The is_bright boolean actually seems to invert the brightness.</p>
@ -1170,9 +1190,9 @@ The is_bright boolean actually seems to invert the brightness.</p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showPopupAnnouncement(text,color[,is_bright])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showPopupAnnouncement(text,color[,is_bright])</span></tt></p>
<p>Pops up a titan-style modal announcement window.</p> <p>Pops up a titan-style modal announcement window.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright,unit1,unit2])</span></tt></p>
<p>Uses the type to look up options from announcements.txt, and calls the <p>Uses the type to look up options from announcements.txt, and calls the above
above operations accordingly. If enabled, pauses and zooms to position.</p> operations accordingly. The units are used to call <tt class="docutils literal">addCombatReportAuto</tt>.</p>
</li> </li>
</ul> </ul>
</div> </div>

@ -862,6 +862,32 @@ Gui module
Returns the building selected via *'q'*, *'t'*, *'k'* or *'i'*. 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])`` * ``dfhack.gui.showAnnouncement(text,color[,is_bright])``
Adds a regular announcement with given text, color, and brightness. Adds a regular announcement with given text, color, and brightness.
@ -875,10 +901,10 @@ Gui module
Pops up a titan-style modal announcement window. 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 Uses the type to look up options from announcements.txt, and calls the above
above operations accordingly. If enabled, pauses and zooms to position. operations accordingly. The units are used to call ``addCombatReportAuto``.
Job module Job module

@ -1307,6 +1307,10 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
WRAPM(Gui, getSelectedUnit), WRAPM(Gui, getSelectedUnit),
WRAPM(Gui, getSelectedItem), WRAPM(Gui, getSelectedItem),
WRAPM(Gui, getSelectedBuilding), WRAPM(Gui, getSelectedBuilding),
WRAPM(Gui, writeToGamelog),
WRAPM(Gui, makeAnnouncement),
WRAPM(Gui, addCombatReport),
WRAPM(Gui, addCombatReportAuto),
WRAPM(Gui, showAnnouncement), WRAPM(Gui, showAnnouncement),
WRAPM(Gui, showZoomAnnouncement), WRAPM(Gui, showZoomAnnouncement),
WRAPM(Gui, showPopupAnnouncement), WRAPM(Gui, showPopupAnnouncement),

@ -35,6 +35,8 @@ distribution.
#include "df/init.h" #include "df/init.h"
#include "df/ui.h" #include "df/ui.h"
#include "df/announcement_type.h" #include "df/announcement_type.h"
#include "df/announcement_flags.h"
#include "df/unit_report_type.h"
namespace df { namespace df {
struct viewscreen; struct viewscreen;
@ -97,13 +99,20 @@ namespace DFHack
DFHACK_EXPORT bool any_building_hotkey(df::viewscreen *top); DFHACK_EXPORT bool any_building_hotkey(df::viewscreen *top);
DFHACK_EXPORT df::building *getSelectedBuilding(color_ostream &out, bool quiet = false); 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 // 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 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 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); DFHACK_EXPORT void showPopupAnnouncement(std::string message, int color = 7, bool bright = true);
// Show an announcement with effects determined by announcements.txt // 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 * Cursor and window coords

@ -87,6 +87,8 @@ using namespace DFHack;
#include "df/announcements.h" #include "df/announcements.h"
#include "df/stop_depart_condition.h" #include "df/stop_depart_condition.h"
#include "df/route_stockpile_link.h" #include "df/route_stockpile_link.h"
#include "df/game_mode.h"
#include "df/unit.h"
using namespace df::enums; using namespace df::enums;
using df::global::gview; using df::global::gview;
@ -97,6 +99,7 @@ using df::global::world;
using df::global::selection_rect; using df::global::selection_rect;
using df::global::ui_menu_width; using df::global::ui_menu_width;
using df::global::ui_area_map_width; using df::global::ui_area_map_width;
using df::global::gamemode;
static df::layer_object_listst *getLayerList(df::viewscreen_layer *layer, int idx) 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( DFHACK_EXPORT void Gui::writeToGamelog(std::string message)
df::announcement_type type, df::coord pos, std::string message, int color, bool bright {
) { 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::world;
using df::global::cur_year; using df::global::cur_year;
using df::global::cur_year_tick; using df::global::cur_year_tick;
if (message.empty())
return -1;
int year = 0, year_time = 0; int year = 0, year_time = 0;
if (cur_year && cur_year_tick) if (cur_year && cur_year_tick)
@ -1102,6 +1118,31 @@ static void doShowAnnouncement(
year_time = last->time; 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; bool continued = false;
while (!message.empty()) while (!message.empty())
@ -1117,7 +1158,6 @@ static void doShowAnnouncement(
new_rep->time = year_time; new_rep->time = year_time;
new_rep->flags.bits.continuation = continued; new_rep->flags.bits.continuation = continued;
new_rep->flags.bits.announcement = true;
int size = std::min(message.size(), (size_t)73); int size = std::min(message.size(), (size_t)73);
new_rep->text = message.substr(0, size); new_rep->text = message.substr(0, size);
@ -1129,20 +1169,114 @@ static void doShowAnnouncement(
new_rep->id = world->status.next_report_id++; new_rep->id = world->status.next_report_id++;
world->status.reports.push_back(new_rep); 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) 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( void Gui::showZoomAnnouncement(
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
) { ) {
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) 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( 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; 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) if (is_valid_enum_item(type) && announcements)
flags = announcements->flags[type]; flags = announcements->flags[type];
doShowAnnouncement(type, pos, message, color, bright); int id = makeAnnouncement(type, flags, 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);
}
if (flags.bits.DO_MEGA) addCombatReportAuto(unit1, flags, id);
showPopupAnnouncement(message, color, bright); addCombatReportAuto(unit2, flags, id);
} }
df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed) df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed)