|
|
|
@@ -83,6 +83,22 @@ short store_talk_face_pic;
|
|
|
|
|
int current_talk_node;
|
|
|
|
|
extern std::vector<word_rect_t> talk_words;
|
|
|
|
|
|
|
|
|
|
// "Go Back" stack: When pressing the "Go Back" button, we don't just want to reverse through
|
|
|
|
|
// the nodes the player has seen, because they might change game state the first time, causing
|
|
|
|
|
// you to go backwards to a node that would behave differently than it did before.
|
|
|
|
|
// The "Go Back" stack allows you to reverse through exactly what the dialog engine has showed you,
|
|
|
|
|
// in a read-only fashion as long as you only go backwards.
|
|
|
|
|
struct dialog_history_t {
|
|
|
|
|
bool can_record;
|
|
|
|
|
|
|
|
|
|
bool special_node;
|
|
|
|
|
// Store node numbers for shop nodes.
|
|
|
|
|
int node;
|
|
|
|
|
// Store text for normal dialog nodes.
|
|
|
|
|
std::pair<std::string, std::string> text;
|
|
|
|
|
};
|
|
|
|
|
std::vector<dialog_history_t> dialog_history;
|
|
|
|
|
|
|
|
|
|
// Shopping vars
|
|
|
|
|
|
|
|
|
|
// 1 - 499 ... regular items
|
|
|
|
@@ -193,7 +209,9 @@ bool start_shop_mode(short which,short cost_adj,std::string store_name, bool can
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is for the legacy "Go Back" button behavior, and for some reason doesn't always work:
|
|
|
|
|
static void update_last_talk(int new_node) {
|
|
|
|
|
if(has_feature_flag("talk-go-back", "StackV1")) return;
|
|
|
|
|
// Store last node in the Go Back button
|
|
|
|
|
for(word_rect_t& word : talk_words) {
|
|
|
|
|
if(word.word != "Go Back") continue;
|
|
|
|
@@ -222,6 +240,7 @@ void end_shop_mode() {
|
|
|
|
|
if(store_pre_shop_mode == MODE_TALKING) {
|
|
|
|
|
save_talk_str1 = "You conclude your business.";
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
can_save_talk = false;
|
|
|
|
|
place_talk_str(save_talk_str1, save_talk_str2, 0, dummy_rect);
|
|
|
|
|
update_last_talk(TALK_BUSINESS);
|
|
|
|
|
}else{
|
|
|
|
@@ -633,6 +652,13 @@ void set_up_shop_array() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> preset_words = {
|
|
|
|
|
"Look", "Name", "Job",
|
|
|
|
|
"Buy", "Sell", "Record",
|
|
|
|
|
"Done", "Go Back",
|
|
|
|
|
"Ask About...",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void reset_talk_words() {
|
|
|
|
|
// first initialise talk_words here
|
|
|
|
|
talk_words.clear();
|
|
|
|
@@ -642,12 +668,6 @@ static void reset_talk_words() {
|
|
|
|
|
{210, 389}, {190, 366},
|
|
|
|
|
{4, 343}
|
|
|
|
|
};
|
|
|
|
|
static const std::vector<std::string> preset_words = {
|
|
|
|
|
"Look", "Name", "Job",
|
|
|
|
|
"Buy", "Sell", "Record",
|
|
|
|
|
"Done", "Go Back",
|
|
|
|
|
"Ask About...",
|
|
|
|
|
};
|
|
|
|
|
TextStyle style;
|
|
|
|
|
style.font = FONT_DUNGEON;
|
|
|
|
|
style.pointSize = TALK_WORD_SIZE;
|
|
|
|
@@ -655,6 +675,8 @@ static void reset_talk_words() {
|
|
|
|
|
// Place buttons at bottom.
|
|
|
|
|
for(short i = 0; i < preset_words.size(); i++) {
|
|
|
|
|
if(talk_end_forced && i != 6 && i != 5) continue;
|
|
|
|
|
if(!can_save_talk && i == 5) continue;
|
|
|
|
|
if(has_feature_flag("talk-go-back", "StackV1") && dialog_history.size() < 2 && i == 7) continue;
|
|
|
|
|
|
|
|
|
|
std::string word = preset_words[i];
|
|
|
|
|
location tl = preset_word_locs[i];
|
|
|
|
@@ -682,6 +704,7 @@ static void reset_talk_words() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void start_talk_mode(short m_num,short personality,mon_num_t monst_type,short store_face_pic) {
|
|
|
|
|
dialog_history.clear();
|
|
|
|
|
rectangle area_rect;
|
|
|
|
|
|
|
|
|
|
store_personality = personality;
|
|
|
|
@@ -705,6 +728,7 @@ void start_talk_mode(short m_num,short personality,mon_num_t monst_type,short st
|
|
|
|
|
overall_mode = MODE_TALKING;
|
|
|
|
|
talk_end_forced = false;
|
|
|
|
|
|
|
|
|
|
can_save_talk = true;
|
|
|
|
|
reset_talk_words();
|
|
|
|
|
|
|
|
|
|
stat_screen_mode = MODE_SHOP;
|
|
|
|
@@ -713,9 +737,9 @@ void start_talk_mode(short m_num,short personality,mon_num_t monst_type,short st
|
|
|
|
|
// Bring up and place first strings.
|
|
|
|
|
save_talk_str1 = univ.town.cur_talk().people[personality % 10].look;
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
can_save_talk = true;
|
|
|
|
|
|
|
|
|
|
place_talk_str(save_talk_str1, "", 0, dummy_rect);
|
|
|
|
|
dialog_history.push_back({true, false, -1, {save_talk_str1, save_talk_str2}});
|
|
|
|
|
|
|
|
|
|
put_item_screen(stat_window);
|
|
|
|
|
give_help(5,6);
|
|
|
|
@@ -799,12 +823,10 @@ static void show_job_bank(int which_bank, std::string title) {
|
|
|
|
|
job_dlg.run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
void handle_talk_node(int which_talk_entry, bool is_redo) {
|
|
|
|
|
if(which_talk_entry == TALK_DUNNO)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
reset_talk_words();
|
|
|
|
|
|
|
|
|
|
short get_pc,s1 = -1,s2 = -1;
|
|
|
|
|
char asked[4];
|
|
|
|
|
|
|
|
|
@@ -817,35 +839,32 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
save_talk_str1 = univ.town.cur_talk().people[store_personality % 10].dunno;
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
if(save_talk_str1.length() < 2) save_talk_str1 = "You get no response.";
|
|
|
|
|
place_talk_str(save_talk_str1, "", 0, dummy_rect);
|
|
|
|
|
update_last_talk(TALK_DUNNO);
|
|
|
|
|
return;
|
|
|
|
|
goto FINISH_TALK_NODE;
|
|
|
|
|
case TALK_BUSINESS: // This one only reachable via "go back".
|
|
|
|
|
place_talk_str("You conclude your business.", "", 0, dummy_rect);
|
|
|
|
|
can_save_talk = false;
|
|
|
|
|
save_talk_str1 = "You conclude your business.";
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
update_last_talk(TALK_BUSINESS);
|
|
|
|
|
return;
|
|
|
|
|
goto FINISH_TALK_NODE;
|
|
|
|
|
case TALK_LOOK:
|
|
|
|
|
SPECIAL_LOOK:
|
|
|
|
|
save_talk_str1 = univ.town.cur_talk().people[store_personality % 10].look;
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
place_talk_str(save_talk_str1, "", 0, dummy_rect);
|
|
|
|
|
update_last_talk(TALK_LOOK);
|
|
|
|
|
return;
|
|
|
|
|
goto FINISH_TALK_NODE;
|
|
|
|
|
case TALK_NAME:
|
|
|
|
|
SPECIAL_NAME:
|
|
|
|
|
save_talk_str1 = univ.town.cur_talk().people[store_personality % 10].name;
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
place_talk_str(save_talk_str1, "", 0, dummy_rect);
|
|
|
|
|
update_last_talk(TALK_NAME);
|
|
|
|
|
return;
|
|
|
|
|
goto FINISH_TALK_NODE;
|
|
|
|
|
case TALK_JOB:
|
|
|
|
|
SPECIAL_JOB:
|
|
|
|
|
save_talk_str1 = univ.town.cur_talk().people[store_personality % 10].job;
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
place_talk_str(save_talk_str1, "", 0, dummy_rect);
|
|
|
|
|
update_last_talk(TALK_JOB);
|
|
|
|
|
return;
|
|
|
|
|
goto FINISH_TALK_NODE;
|
|
|
|
|
case TALK_BUY:
|
|
|
|
|
SPECIAL_BUY:
|
|
|
|
|
which_talk_entry = scan_for_response("purc");
|
|
|
|
@@ -862,11 +881,6 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
if(which_talk_entry == -1) goto SPECIAL_DUNNO;
|
|
|
|
|
break;
|
|
|
|
|
case TALK_RECORD:
|
|
|
|
|
if(!can_save_talk) {
|
|
|
|
|
// TODO the button shouldn't be shown if it won't work, no?
|
|
|
|
|
play_sound(1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(univ.party.save_talk(univ.town->talking.people[store_personality%10].title, univ.town->name, save_talk_str1, save_talk_str2)) {
|
|
|
|
|
give_help(57,0);
|
|
|
|
|
play_sound(0);
|
|
|
|
@@ -878,8 +892,27 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
SPECIAL_DONE:
|
|
|
|
|
end_talk_mode();
|
|
|
|
|
return;
|
|
|
|
|
case TALK_BACK: // only if there's nothing to go back to
|
|
|
|
|
return; // so, there's nothing to do here
|
|
|
|
|
case TALK_BACK:
|
|
|
|
|
// In legacy behavior, this should only happen if there's nothing to go back to. In that case, do nothing.
|
|
|
|
|
if(has_feature_flag("talk-go-back", "StackV1")){
|
|
|
|
|
if(!dialog_history.empty()){
|
|
|
|
|
dialog_history_t last_state;
|
|
|
|
|
do{
|
|
|
|
|
last_state = dialog_history.back();
|
|
|
|
|
dialog_history.pop_back();
|
|
|
|
|
if(last_state.special_node){
|
|
|
|
|
handle_talk_node(last_state.node, true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// If they ended up in the same node, don't treat it as a step back until we get to different text.
|
|
|
|
|
}while(!dialog_history.empty() && save_talk_str1 == last_state.text.first && save_talk_str2 == last_state.text.second);
|
|
|
|
|
can_save_talk = last_state.can_record;
|
|
|
|
|
save_talk_str1 = last_state.text.first;
|
|
|
|
|
save_talk_str2 = last_state.text.second;
|
|
|
|
|
goto FINISH_TALK_NODE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
case TALK_ASK: // ask about
|
|
|
|
|
save_talk_str1 = get_text_response("Ask about what?", 8);
|
|
|
|
|
strncpy(asked, save_talk_str1.c_str(), 4);
|
|
|
|
@@ -953,13 +986,13 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
break;
|
|
|
|
|
case eTalkNode::TRAINING:
|
|
|
|
|
save_talk_str1 = "You conclude your training.";
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
can_save_talk = false;
|
|
|
|
|
if((get_pc = select_pc(eSelectPC::ONLY_LIVING,"Train who?")) < 6) {
|
|
|
|
|
can_save_talk = false;
|
|
|
|
|
spend_xp(get_pc,1, nullptr);
|
|
|
|
|
}
|
|
|
|
|
save_talk_str1 = "You conclude your training.";
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
goto RECORD_WHICH_NODE;
|
|
|
|
|
case eTalkNode::SHOP:
|
|
|
|
|
if(!start_shop_mode(b,a,save_talk_str1,true)){
|
|
|
|
|
if(!start_shop_mode_other_pc()){
|
|
|
|
@@ -976,7 +1009,7 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
}else{
|
|
|
|
|
can_save_talk = false;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
goto RECORD_WHICH_NODE;
|
|
|
|
|
case eTalkNode::JOB_BANK:
|
|
|
|
|
if(a < univ.party.job_banks.size() && univ.party.job_banks[a].anger >= 50) {
|
|
|
|
|
save_talk_str1 = save_talk_str2;
|
|
|
|
@@ -984,26 +1017,26 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
show_job_bank(a, save_talk_str1.c_str());
|
|
|
|
|
return;
|
|
|
|
|
goto RECORD_WHICH_NODE;
|
|
|
|
|
}
|
|
|
|
|
case eTalkNode::SELL_WEAPONS:
|
|
|
|
|
can_save_talk = false;
|
|
|
|
|
stat_screen_mode = MODE_SELL_WEAP;
|
|
|
|
|
put_item_screen(stat_window);
|
|
|
|
|
give_help(42,43);
|
|
|
|
|
break;
|
|
|
|
|
goto RECORD_WHICH_NODE;
|
|
|
|
|
case eTalkNode::SELL_ARMOR:
|
|
|
|
|
can_save_talk = false;
|
|
|
|
|
stat_screen_mode = MODE_SELL_ARMOR;
|
|
|
|
|
put_item_screen(stat_window);
|
|
|
|
|
give_help(42,43);
|
|
|
|
|
break;
|
|
|
|
|
goto RECORD_WHICH_NODE;
|
|
|
|
|
case eTalkNode::SELL_ITEMS:
|
|
|
|
|
can_save_talk = false;
|
|
|
|
|
stat_screen_mode = MODE_SELL_ANY;
|
|
|
|
|
put_item_screen(stat_window);
|
|
|
|
|
give_help(42,43);
|
|
|
|
|
break;
|
|
|
|
|
goto RECORD_WHICH_NODE;
|
|
|
|
|
case eTalkNode::IDENTIFY:
|
|
|
|
|
stat_screen_mode = MODE_IDENTIFY,
|
|
|
|
|
give_help(44, 0);
|
|
|
|
@@ -1020,7 +1053,7 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
shop_recharge_limit = b;
|
|
|
|
|
shop_recharge_amount = c;
|
|
|
|
|
put_item_screen(stat_window);
|
|
|
|
|
break;
|
|
|
|
|
goto RECORD_WHICH_NODE;
|
|
|
|
|
case eTalkNode::BUY_INFO:
|
|
|
|
|
if(univ.party.gold < a) {
|
|
|
|
|
save_talk_str1 = save_talk_str2;
|
|
|
|
@@ -1087,12 +1120,11 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
univ.party.gold -= a;
|
|
|
|
|
put_pc_screen();
|
|
|
|
|
iter->property = false;
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
} else {
|
|
|
|
|
save_talk_str1 = "There are no horses left.";
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
can_save_talk = false;
|
|
|
|
|
}
|
|
|
|
|
save_talk_str2 = "";
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case eTalkNode::BUY_SPEC_ITEM:
|
|
|
|
@@ -1132,7 +1164,7 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
break;
|
|
|
|
|
case eTalkNode::BUY_TOWN_LOC:
|
|
|
|
|
if(univ.scenario.towns[b]->can_find) {
|
|
|
|
|
// TODO: Uh, is something supposed to happen here?
|
|
|
|
|
save_talk_str1 = "You've already learned that.";
|
|
|
|
|
}
|
|
|
|
|
else if(univ.party.gold < a) {
|
|
|
|
|
save_talk_str1 = save_talk_str2;
|
|
|
|
@@ -1192,9 +1224,20 @@ void handle_talk_node(int which_talk_entry) {
|
|
|
|
|
put_item_screen(stat_window);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(false){
|
|
|
|
|
RECORD_WHICH_NODE:
|
|
|
|
|
if(!is_redo) dialog_history.push_back({false, true, which_talk_entry, {"", ""}});
|
|
|
|
|
place_talk_str(save_talk_str1,save_talk_str2,0,dummy_rect);
|
|
|
|
|
reset_talk_words();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FINISH_TALK_NODE:
|
|
|
|
|
dialog_history.push_back({can_save_talk, false, -1, {save_talk_str1, save_talk_str2}});
|
|
|
|
|
place_talk_str(save_talk_str1,save_talk_str2,0,dummy_rect);
|
|
|
|
|
reset_talk_words();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool handle_talk_event(location p, cFramerateLimiter& fps_limiter) {
|
|
|
|
|