Consolidate active quest data into a single map

This commit is contained in:
2017-04-14 11:38:06 -04:00
parent 5b5b2af46f
commit e57441f6a0
11 changed files with 55 additions and 58 deletions

View File

@@ -638,9 +638,7 @@ static void show_job_bank(int which_bank, std::string title) {
int which = hit[4] - '1';
me["prompt"].setText("Job accepted.");
job_bank_t& bank = univ.party.job_banks[which_bank];
univ.party.quest_status[bank.jobs[which]] = eQuestStatus::STARTED;
univ.party.quest_source[bank.jobs[which]] = store_personality;
univ.party.quest_start[bank.jobs[which]] = univ.party.calc_day();
univ.party.active_quests[bank.jobs[which]] = cJob(univ.party.calc_day(), store_personality);
// Now, if there are spare jobs available, fill in. Otherwise, clear space.
if(bank.jobs[4] >= 0)
std::swap(bank.jobs[which], bank.jobs[4]);
@@ -977,11 +975,9 @@ void handle_talk_event(location p) {
showError("Tried to give a nonexistent quest!");
return;
}
switch(univ.party.quest_status[a]) {
switch(univ.party.active_quests[a].status) {
case eQuestStatus::AVAILABLE:
univ.party.quest_status[a] = eQuestStatus::STARTED;
univ.party.quest_source[a] = -1;
univ.party.quest_start[a] = univ.party.calc_day();
univ.party.active_quests[a] = cJob(univ.party.calc_day());
break;
case eQuestStatus::STARTED:
break;

View File

@@ -675,7 +675,7 @@ void put_quest_info(short which_i) {
cDialog quest_dlg("quest-info");
quest_dlg["name"].setText(quest.name);
quest_dlg["descr"].setText(quest.descr);
int start = univ.party.quest_start[which_i];
int start = univ.party.active_quests[which_i].start;
quest_dlg["start"].setText("Day " + std::to_string(start));
if(quest.deadline > 0)
quest_dlg["chop"].setText("Day " + std::to_string(quest.deadline + (quest.flags % 10) * start));

View File

@@ -495,9 +495,9 @@ static bool display_item_event_filter(cDialog& me, std::string id, size_t& first
univ.party.spec_items.insert(item.item_level);
set_item_flag(&item);
} else if(item.variety == eItemType::QUEST) {
univ.party.quest_status[item.item_level] = eQuestStatus::STARTED;
univ.party.quest_start[item.item_level] = univ.party.calc_day();
univ.party.quest_source[item.item_level] = -1;
univ.party.active_quests[item.item_level].status = eQuestStatus::STARTED;
univ.party.active_quests[item.item_level].start = univ.party.calc_day();
univ.party.active_quests[item.item_level].source = -1;
set_item_flag(&item);
} else {
if(!allow_overload && item.item_weight() > univ.party[current_getting_pc].free_weight()) {

View File

@@ -1806,18 +1806,18 @@ void special_increase_age(long length, bool queue) {
trigger_loc = univ.party.out_loc;
}
for(auto& p : univ.party.quest_status) {
if(p.second != eQuestStatus::STARTED)
for(auto& p : univ.party.active_quests) {
if(p.second.status != eQuestStatus::STARTED)
continue;
cQuest& quest = univ.scenario.quests[p.first];
if(quest.deadline <= 0)
continue;
bool is_relative = quest.flags % 10;
int deadline = quest.deadline + is_relative * univ.party.quest_start[p.first];
int deadline = quest.deadline + is_relative * p.second.start;
if(day_reached(deadline + 1, quest.event)) {
p.second = eQuestStatus::FAILED;
if(univ.party.quest_source[p.first] >= 0) {
int bank = univ.party.quest_source[p.first];
p.second.status = eQuestStatus::FAILED;
if(p.second.source >= 0) {
int bank = p.second.source;
// Safety valve in case it was given by a special node
if(bank >= univ.party.job_banks.size())
univ.party.job_banks.resize(bank + 1);
@@ -1829,7 +1829,7 @@ void special_increase_age(long length, bool queue) {
add_anger++;
if(quest.deadline < 5)
add_anger++;
} else if(quest.deadline - univ.party.quest_start[p.first] > 20)
} else if(quest.deadline - p.second.start > 20)
add_anger++;
univ.party.job_banks[bank].anger += add_anger;
}
@@ -2460,7 +2460,7 @@ void general_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
*next_spec = -1;
break;
}
case eSpecType::UPDATE_QUEST:
case eSpecType::UPDATE_QUEST: {
check_mess = true;
if(spec.ex1a < 0 || spec.ex1a >= univ.scenario.quests.size()) {
showError("The scenario tried to update a non-existent quest.");
@@ -2470,33 +2470,36 @@ void general_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
showError("Invalid quest status (range 0 .. 3).");
break;
}
if(spec.ex1b == int(eQuestStatus::STARTED) && univ.party.quest_status[spec.ex1a] != eQuestStatus::STARTED) {
univ.party.quest_start[spec.ex1a] = univ.party.calc_day();
univ.party.quest_source[spec.ex1a] = max(-1,spec.ex2a);
if(univ.party.quest_source[spec.ex1a] >= univ.party.job_banks.size())
univ.party.job_banks.resize(univ.party.quest_source[spec.ex1a] + 1);
auto& job = univ.party.active_quests[spec.ex1a];
auto& quest = univ.scenario.quests[spec.ex1a];
if(spec.ex1b == int(eQuestStatus::STARTED) && job.status != eQuestStatus::STARTED) {
job.start = univ.party.calc_day();
job.source = max(-1,spec.ex2a);
if(job.source >= univ.party.job_banks.size())
univ.party.job_banks.resize(job.source + 1);
}
univ.party.quest_status[spec.ex1a] = eQuestStatus(spec.ex1b);
switch(univ.party.quest_status[spec.ex1a]) {
job.status = eQuestStatus(spec.ex1b);
switch(job.status) {
case eQuestStatus::STARTED: add_string_to_buf("You have received a quest."); break;
case eQuestStatus::AVAILABLE: break; // TODO: Should this award XP/gold if the quest was previously started?
case eQuestStatus::FAILED:
add_string_to_buf("You have failed to complete a quest.");
if(univ.party.quest_source[spec.ex1a] >= 0 && univ.party.quest_source[spec.ex1a] < univ.party.job_banks.size())
univ.party.job_banks[univ.party.quest_source[spec.ex1a]].anger += spec.ex2a < 0 ? 1 : spec.ex2a;
if(job.source >= 0 && job.source < univ.party.job_banks.size())
univ.party.job_banks[job.source].anger += spec.ex2a < 0 ? 1 : spec.ex2a;
break;
case eQuestStatus::COMPLETED:
add_string_to_buf("You have completed a quest!");
if(univ.scenario.quests[spec.ex1a].gold > 0) {
int gold = univ.scenario.quests[spec.ex1a].gold;
if(quest.gold > 0) {
int gold = quest.gold;
add_string_to_buf(" Received " + std::to_string(gold) + " as a reward.");
give_gold(gold, true);
}
if(univ.scenario.quests[spec.ex1a].xp > 0)
award_party_xp(univ.scenario.quests[spec.ex1a].xp);
if(quest.xp > 0)
award_party_xp(quest.xp);
break;
}
break;
}
default:
showError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
break;
@@ -3738,7 +3741,7 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
showError("Invalid quest status (range 0 .. 3).");
break;
}
if(univ.party.quest_status[spec.ex1a] == eQuestStatus(spec.ex1b))
if(univ.party.active_quests[spec.ex1a].status == eQuestStatus(spec.ex1b))
*next_spec = spec.ex1c;
break;
case eSpecType::IF_CONTEXT:

View File

@@ -573,13 +573,13 @@ void set_stat_window(short new_stat) {
case ITEM_WIN_QUESTS:
std::fill(spec_item_array.begin(), spec_item_array.end(), -1);
for(short i = 0; i < univ.scenario.quests.size(); i++)
if(univ.party.quest_status[i] == eQuestStatus::STARTED) {
if(univ.party.active_quests[i].status == eQuestStatus::STARTED) {
spec_item_array.push_back(i);
array_pos++;
} else if(univ.party.quest_status[i] == eQuestStatus::COMPLETED) {
} else if(univ.party.active_quests[i].status == eQuestStatus::COMPLETED) {
spec_item_array.push_back(i + 10000);
array_pos++;
} else if(univ.party.quest_status[i] == eQuestStatus::FAILED) {
} else if(univ.party.active_quests[i].status == eQuestStatus::FAILED) {
spec_item_array.push_back(i + 20000);
array_pos++;
}

View File

@@ -377,7 +377,7 @@ void start_town_mode(short which_town, short entry_dir) {
continue;
}
// Don't place quest items if party already started
if(item.variety == eItemType::QUEST && univ.party.quest_status[item.item_level] != eQuestStatus::AVAILABLE) {
if(item.variety == eItemType::QUEST && univ.party.active_quests[item.item_level].status != eQuestStatus::AVAILABLE) {
univ.town.items.pop_back();
continue;
}

View File

@@ -22,6 +22,15 @@ public:
std::string descr;
};
class cJob {
public:
cJob() : status(eQuestStatus::AVAILABLE), start(0), source(-1) {}
explicit cJob(int start, int source = -1) : status(eQuestStatus::STARTED), start(start), source(source) {}
eQuestStatus status;
int start; // the day the quest was started; used for quests with relative deadlines
int source; // if gotten from a job board, this is the number of the job board; otherwise -1
};
std::istream& operator>>(std::istream& in, eQuestStatus& type);
std::ostream& operator<<(std::ostream& out, eQuestStatus type);

View File

@@ -86,9 +86,7 @@ cParty::cParty(const cParty& other)
, special_notes(other.special_notes)
, talk_save(other.talk_save)
, status(other.status)
, quest_status(other.quest_status)
, quest_start(other.quest_start)
, quest_source(other.quest_source)
, active_quests(other.active_quests)
, left_at(other.left_at)
, left_in(other.left_in)
, direction(other.direction)
@@ -158,9 +156,7 @@ void cParty::swap(cParty& other) {
std::swap(special_notes, other.special_notes);
std::swap(talk_save, other.talk_save);
std::swap(status, other.status);
std::swap(quest_status, other.quest_status);
std::swap(quest_start, other.quest_start);
std::swap(quest_source, other.quest_source);
std::swap(active_quests, other.active_quests);
std::swap(left_at, other.left_at);
std::swap(left_in, other.left_in);
std::swap(direction, other.direction);
@@ -741,8 +737,8 @@ void cParty::writeTo(std::ostream& file, const cScenario& scen) const {
file << "SCENARIO " << scen_name << '\n';
file << "WON " << scen_won << '\n';
file << "PLAYED " << scen_played << '\n';
for(auto p : quest_status)
file << "QUEST " << p.first << ' ' << p.second << ' ' << quest_start.at(p.first) << ' ' << quest_source.at(p.first) << '\n';
for(auto p : active_quests)
file << "QUEST " << p.first << ' ' << p.second.status << ' ' << p.second.start << ' ' << p.second.source << '\n';
for(auto p : store_limited_stock) {
for(auto p2 : p.second) {
file << "SHOPSTOCK " << p.first << p2.first << p2.second;
@@ -990,7 +986,7 @@ void cParty::readFrom(std::istream& file, cScenario& scen){
} else if(cur == "QUEST") {
int i;
sin >> i;
sin >> quest_status[i] >> quest_start[i] >> quest_source[i];
sin >> active_quests[i].status >> active_quests[i].start >> active_quests[i].source;
} else if(cur == "SHOPSTOCK") {
int i, j;
sin >> i >> j >> store_limited_stock[i][j];

View File

@@ -111,10 +111,7 @@ public:
std::vector<cEncNote> special_notes;
std::vector<cConvers> talk_save;
std::map<ePartyStatus,short> status;
// Quest stuff
std::map<int, eQuestStatus> quest_status;
std::map<int, int> quest_start; // the day the quest was started; used for quests with relative deadlines
std::map<int, int> quest_source; // if gotten from a job board, this is the number of the job board; otherwise -1
std::map<int, cJob> active_quests;
location left_at;
size_t left_in;
eDirection direction;

View File

@@ -465,9 +465,7 @@ bool cPlayer::give_item(cItem item, int flags) {
}
if(item.variety == eItemType::QUEST) {
if(!party) return false;
party->quest_status[item.item_level] = eQuestStatus::STARTED;
party->quest_start[item.item_level] = party->calc_day();
party->quest_source[item.item_level] = -1;
party->active_quests[item.item_level] = cJob(party->calc_day());
if(do_print && print_result)
print_result("You get a quest.");
return true;
@@ -832,7 +830,7 @@ eBuyStatus cPlayer::ok_to_buy(short cost,cItem item) const {
if(party->spec_items.count(item.item_level))
return eBuyStatus::HAVE_LOTS;
} else if(item.variety == eItemType::QUEST) {
if(party->quest_status[item.item_level] != eQuestStatus::AVAILABLE)
if(party->active_quests[item.item_level].status != eQuestStatus::AVAILABLE)
return eBuyStatus::HAVE_LOTS;
} else if(item.variety != eItemType::GOLD && item.variety != eItemType::FOOD) {
for(int i = 0; i < items.size(); i++)

View File

@@ -1369,9 +1369,7 @@ void cUniverse::enter_scenario(const std::string& name) {
}
for(short i = 0; i < scenario.quests.size(); i++) {
if(scenario.quests[i].flags >= 10) {
party.quest_status[i] = eQuestStatus::STARTED;
party.quest_start[i] = 1;
party.quest_source[i] = -1;
party.active_quests[i] = cJob(1);
}
}
@@ -1397,7 +1395,7 @@ void cUniverse::generate_job_bank(int which, job_bank_t& bank) {
for(size_t i = 0; iSlot < 4 && i < scenario.quests.size(); i++) {
if(scenario.quests[i].bank1 != which && scenario.quests[i].bank2 != which)
continue;
if(party.quest_status[i] != eQuestStatus::AVAILABLE)
if(party.active_quests[i].status != eQuestStatus::AVAILABLE)
continue;
if(get_ran(1,1,100) <= 50 - bank.anger)
bank.jobs[iSlot++] = i;