very messy support for recording 6-string dialog

This commit is contained in:
2025-08-06 15:29:01 -05:00
parent d17715f71f
commit 23106c6954
6 changed files with 89 additions and 15 deletions

View File

@@ -4,16 +4,22 @@
<dialog defbtn='done' escbtn='done'>
<button name='done' type='done' top='341' left='319'/>
<pict type='dlog' num='8' top='9' left='9'/>
<text name='str1' framed='true' top='37' left='53' width='257' height='92'/>
<text name='str2' framed='true' top='136' left='53' width='257' height='92'/>
<text name='str3' framed='true' top='235' left='53' width='257' height='92'/>
<pane name='pane1' framed='true' top='37' left='53' width='257' height='92'>
<text name='str1' framed='true' top='37' left='53' width='257'/>
</pane>
<pane name='pane2' framed='true' top='136' left='53' width='257' height='92'>
<text name='str2' framed='true' top='136' left='53' width='257'/>
</pane>
<pane name='pane3' framed='true' top='235' left='53' width='257' height='92'>
<text name='str3' framed='true' top='235' left='53' width='257'/>
</pane>
<text size='large' top='9' left='53' width='257' height='19'>Encounter Notes:</text>
<button name='left' type='left' def-key='left' top='340' left='48'/>
<button name='right' type='right' def-key='right' top='340' left='111'/>
<!--
TODO: I like the idea of assigning the delete key to this...
-->
<button name='del1' type='regular' top='109' left='319'>Delete</button>
<button name='del2' type='regular' top='208' left='319'>Delete</button>
<button name='del3' type='regular' top='307' left='319'>Delete</button>
<button name='del1' type='regular' top='109' left='329'>Delete</button>
<button name='del2' type='regular' top='208' left='329'>Delete</button>
<button name='del3' type='regular' top='307' left='329'>Delete</button>
</dialog>

View File

@@ -155,6 +155,13 @@ void cThreeChoice::init_buttons(cBasicButtonType btn1, cBasicButtonType btn2, cB
me->add(btn, cur_btn_rect, sout.str());
cur_btn_rect.right = cur_btn_rect.left - 4;
}
// Add a record button and hide it
cButton* record = new cButton(*me);
record->setText("Record");
record->attachClickHandler(std::bind(&cThreeChoice::onRecord, this, _2));
cur_btn_rect = {buttons_top,10,buttons_top + 23,buttons_right};
me->add(record, cur_btn_rect, "record");
record->hide();
}
void cThreeChoice::init_pict(pic_num_t pic){
@@ -174,7 +181,7 @@ std::string cThreeChoice::show(){
return "**ERROR**"; // shouldn't be reached
}
short custom_choice_dialog(std::array<std::string, 6>& strs,short pic_num,ePicType pic_type,std::array<short, 3>& buttons,bool anim_pict,short anim_loops, int anim_fps, cDialog* parent) {
short custom_choice_dialog(std::array<std::string, 6>& strs,short pic_num,ePicType pic_type,std::array<short, 3>& buttons,bool anim_pict,short anim_loops, int anim_fps, cUniverse* univ, cDialog* parent) {
set_cursor(sword_curs);
std::vector<std::string> vec(strs.begin(), strs.end());
@@ -185,6 +192,28 @@ short custom_choice_dialog(std::array<std::string, 6>& strs,short pic_num,ePicTy
if(anim_pict)
setup_dialog_pict_anim(*(customDialog.operator->()), "pict", anim_loops, anim_fps);
if(univ != nullptr){
customDialog.setRecordHandler([vec, univ](cDialog& dlg) -> void {
std::string combined;
for(std::string msg : vec){
if(!msg.empty()){
if(!combined.empty()){
combined += " ||";
}
combined += msg;
}
}
// It's not necessarily a NOTE_SCEN and location shouldn't be empty,
// but these things aren't actually shown to the party in the encounter notes dialog.
if(univ->party.record(NOTE_SCEN, combined, "")){
give_help(58,0,dlg);
// TODO ASB is only in game source, but this function is in common source so the scenario editor can preview dialogs :(
/*
add_string_to_buf("Added to encounter notes.");
*/
}
});
}
std::string item_hit = customDialog.show();
for(int i = 0; i < 3; i++) {
@@ -220,5 +249,23 @@ short once_dialog(cUniverse& univ, cSpecial& spec, eSpecCtxType cur_type, cDialo
showError("Dialog box ended up with no buttons.");
return -1;
}
return custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons, true, spec.ex1c, spec.ex2c, parent);
return custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons, true, spec.ex1c, spec.ex2c, &univ, parent);
}
cThreeChoice& cThreeChoice::setRecordHandler(record_callback_t rec){
if(rec == nullptr){
hasRecord = false;
dlg["record"].hide();
}else{
hasRecord = true;
rec_f = rec;
dlg["record"].show();
}
return *this;
}
bool cThreeChoice::onRecord(std::string id){
if(hasRecord) rec_f(dlg);
else dlg[id].hide();
return hasRecord;
}

View File

@@ -37,6 +37,9 @@ namespace {cBasicButtonType null_btn = boost::none;}
extern bbtt basic_buttons[71];
#endif
/// The signature of a record handler for cThreeChoice.
typedef std::function<void(cDialog&)> record_callback_t;
/// A choice dialog with several strings and up to three buttons.
/// This is the class used for dialogs generated by special nodes.
/// It generates the dialog dynamically from the given input.
@@ -48,6 +51,9 @@ class cThreeChoice : public cChoiceDlog {
void init_buttons(cBasicButtonType btn1, cBasicButtonType btn2, cBasicButtonType btn3);
void init_pict(pic_num_t pic);
const ePicType type;
record_callback_t rec_f;
bool hasRecord;
bool onRecord(std::string id);
public:
/// Create a dialog with just one button.
/// @param strings A list of the strings to place in the dialog.
@@ -70,12 +76,21 @@ public:
/// @param t The type of the icon.
/// @param parent Optionally, a parent dialog.
cThreeChoice(std::vector<std::string>& strings, std::array<short, 3>& buttons, pic_num_t pic, ePicType t, cDialog* parent = nullptr);
/// Set a record handler.
/// @param rec The handler.
/// @return This object, for method-call chaining.
/// @note Only one record handler can be set at a time. To remove it, set it to null.
/// @note The presence of the Record button is determined entirely by the presence of a record handler.
///
/// A record handler should take one parameter, which is a reference to the dialog.
/// (That's the cDialog, not the cThreeChoice.) It should return void.
cThreeChoice& setRecordHandler(record_callback_t rec);
/// @copydoc cChoiceDlog::show()
/// @note The unique key in this case is the label specified in the button specification.
std::string show();
};
short custom_choice_dialog(std::array<std::string, 6>& strs,short pic_num,ePicType pic_type,std::array<short, 3>& buttons, bool anim_pict = false, short anim_loops = -1, int anim_fps = -1, cDialog* parent = nullptr);
short custom_choice_dialog(std::array<std::string, 6>& strs,short pic_num,ePicType pic_type,std::array<short, 3>& buttons, bool anim_pict = false, short anim_loops = -1, int anim_fps = -1, cUniverse* univ = nullptr, cDialog* parent = nullptr);
short once_dialog(cUniverse& univ, cSpecial& spec, eSpecCtxType cur_type, cDialog* parent = nullptr);
#endif

View File

@@ -17,8 +17,8 @@
/// This class loads a definition from a file, so there can be any amount of other stuff in the dialog,
/// and the buttons could be arranged in any fashion you want.
class cChoiceDlog {
cDialog dlg;
protected:
cDialog dlg;
/// The click handler for the dialog's buttons.
/// @param me A reference to the current dialog.
/// @param id The unique key of the clicked control.

View File

@@ -512,10 +512,14 @@ static bool adventure_notes_event_filter(cDialog& me, std::string item_hit, eKey
std::string n = boost::lexical_cast<std::string>(i + 1);
if(univ.party.special_notes.size() > store_page_on * 3+i) {
me["str" + n].setText(univ.party.special_notes[store_page_on * 3+i].the_str);
me["str" + n].recalcRect();
me["pane" + n].recalcRect();
me["del" + n].show();
}
else {
me["str" + n].setText("");
me["str" + n].recalcRect();
me["pane" + n].recalcRect();
me["del" + n].hide();
}
}
@@ -544,6 +548,8 @@ void adventure_notes() {
std::string n = boost::lexical_cast<std::string>(i + 1);
if(univ.party.special_notes.size() > i) {
encNotes["str" + n].setText(univ.party.special_notes[i].the_str);
encNotes["str" + n].recalcRect();
encNotes["pane" + n].recalcRect();
encNotes["del" + n].show();
}
else encNotes["del" + n].hide();

View File

@@ -2637,7 +2637,7 @@ void oneshot_spec(const runtime_state& ctx) {
univ.get_strs(strs, ctx.cur_spec_type, spec.m1);
// Leave / Take
buttons[0] = 9; buttons[1] = 19;
dlg_res = custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons, true, spec.ex1c, spec.ex2c);
dlg_res = custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons, true, spec.ex1c, spec.ex2c, &univ);
if(dlg_res == 1) {set_sd = false; ctx.next_spec = -1;}
else {
store_i = univ.scenario.get_stored_item(spec.ex1a);
@@ -2677,7 +2677,7 @@ void oneshot_spec(const runtime_state& ctx) {
if((spec.m1 >= 0) || (spec.m2 >= 0)) {
univ.get_strs(strs[0],strs[1], ctx.cur_spec_type, spec.m1, spec.m2);
buttons[0] = 3; buttons[1] = 2;
dlg_res = custom_choice_dialog(strs,spec.pic,ePicType(spec.pictype),buttons, true, spec.ex1c, spec.ex2c);
dlg_res = custom_choice_dialog(strs,spec.pic,ePicType(spec.pictype),buttons, true, spec.ex1c, spec.ex2c, &univ);
// TODO: Make custom_choice_dialog return string?
}
else dlg_res = cChoiceDlog("basic-trap",{"yes","no"}).show() == "no";
@@ -4006,7 +4006,7 @@ void townmode_spec(const runtime_state& ctx) {
else {
univ.get_strs(strs,ctx.cur_spec_type, spec.m1);
buttons[0] = 9; buttons[1] = 35;
if(custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons, true, spec.ex1c, spec.ex2c) == 1)
if(custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons, true, spec.ex1c, spec.ex2c, &univ) == 1)
ctx.next_spec = -1;
else {
int x = univ.party.get_ptr(10), y = univ.party.get_ptr(11);
@@ -4037,7 +4037,7 @@ void townmode_spec(const runtime_state& ctx) {
else {
univ.get_strs(strs, ctx.cur_spec_type,spec.m1);
buttons[0] = 9; buttons[1] = 8;
if(custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons, true, spec.ex1c, spec.ex2c) == 1) {
if(custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons, true, spec.ex1c, spec.ex2c, &univ) == 1) {
ctx.next_spec = -1;
if(ctx.which_mode == eSpecCtx::OUT_MOVE || ctx.which_mode == eSpecCtx::TOWN_MOVE || ctx.which_mode == eSpecCtx::COMBAT_MOVE)
*ctx.ret_a = 1;
@@ -4069,7 +4069,7 @@ void townmode_spec(const runtime_state& ctx) {
else {
univ.get_strs(strs,ctx.cur_spec_type, spec.m1);
buttons[0] = 20; buttons[1] = 24;
int i = spec.ex2b == 1 ? 2 : custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons);
int i = spec.ex2b == 1 ? 2 : custom_choice_dialog(strs, spec.pic, ePicType(spec.pictype), buttons, false, -1, -1, &univ);
*ctx.ret_a = 1;
if(i == 1) {
ctx.next_spec = -1;