From c5044967aa1ba4f1c31401b708e3974756cc72d4 Mon Sep 17 00:00:00 2001 From: ALONSO Laurent Date: Sat, 13 Nov 2021 12:43:59 +0100 Subject: [PATCH] save_creatures: delete them when we exist a scenario all: begin to check index access for scen_monsters, to be continued... --- src/fileio/fileio_scen.cpp | 4 ++-- src/game/boe.actions.cpp | 3 +++ src/game/boe.combat.cpp | 2 +- src/game/boe.dlgutil.cpp | 6 +++--- src/game/boe.fileio.cpp | 25 +++++++++++++++++-------- src/game/boe.graphutil.cpp | 4 ++-- src/game/boe.infodlg.cpp | 2 +- src/game/boe.items.cpp | 4 ++-- src/game/boe.menus.mac.mm | 4 ++-- src/game/boe.monster.cpp | 15 +++++++-------- src/game/boe.newgraph.cpp | 2 +- src/game/boe.party.cpp | 2 +- src/game/boe.specials.cpp | 2 +- src/game/boe.text.cpp | 2 +- src/game/boe.town.cpp | 2 +- src/pcedit/pc.editors.cpp | 4 ++-- src/pcedit/pc.fileio.cpp | 2 ++ src/scenario/monster.hpp | 6 ++++++ src/scenario/scenario.cpp | 30 ++++++++++++++++++++++++------ src/scenario/scenario.hpp | 2 ++ src/scenario/special.cpp | 4 ++-- src/scenedit/scen.actions.cpp | 14 +++++++------- src/universe/population.cpp | 8 ++++++++ src/universe/population.hpp | 3 ++- src/universe/universe.cpp | 18 ++++++++++-------- src/utility.cpp | 2 +- src/view_dialogs.cpp | 4 ++-- 27 files changed, 113 insertions(+), 63 deletions(-) diff --git a/src/fileio/fileio_scen.cpp b/src/fileio/fileio_scen.cpp index eb43fe70..2466222f 100644 --- a/src/fileio/fileio_scen.cpp +++ b/src/fileio/fileio_scen.cpp @@ -1429,9 +1429,9 @@ void readMonstersFromXml(ticpp::Document&& data, cScenario& scenario) { elem->GetAttribute("id", &which_monst); if(which_monst == 0) throw xBadVal(type, "id", "0", elem->Row(), elem->Column(), fname); - if(which_monst >= scenario.scen_monsters.size()) + if(which_monst >= scenario.scen_monsters.size() && which_monst<5000) scenario.scen_monsters.resize(which_monst + 1); - cMonster& the_mon = scenario.scen_monsters[which_monst]; + cMonster& the_mon = scenario.get_monster(which_monst); the_mon = cMonster(); std::set reqs = { "name", "level", "armor", "skill", "hp", "speed", diff --git a/src/game/boe.actions.cpp b/src/game/boe.actions.cpp index 44e3c2e2..a5529255 100644 --- a/src/game/boe.actions.cpp +++ b/src/game/boe.actions.cpp @@ -995,7 +995,10 @@ static void handle_victory() { overall_mode = MODE_STARTUP; draw_startup(0); menu_activate(); + // clean a little the party univ.party.scen_name = ""; // should be harmless... + for (auto &pop : univ.party.creature_save) + pop.clear(); if(cChoiceDlog("congrats-save",{"cancel","save"}).show() == "save"){ // TODO: Wait, this shouldn't be a "save as" action, should it? It should save without asking for a location. fs::path file = nav_put_party(); diff --git a/src/game/boe.combat.cpp b/src/game/boe.combat.cpp index 5f748812..55ce1c70 100644 --- a/src/game/boe.combat.cpp +++ b/src/game/boe.combat.cpp @@ -4726,7 +4726,7 @@ bool combat_cast_mage_spell() { store_sum_monst = pick_trapped_monst(); if(store_sum_monst == 0) return false; - get_monst = univ.scenario.scen_monsters[store_sum_monst]; + get_monst = univ.scenario.get_monster(store_sum_monst); if(store_sp < get_monst.level) { add_string_to_buf("Cast: Not enough spell points."); return false; diff --git a/src/game/boe.dlgutil.cpp b/src/game/boe.dlgutil.cpp index 070788a3..2911d319 100644 --- a/src/game/boe.dlgutil.cpp +++ b/src/game/boe.dlgutil.cpp @@ -760,7 +760,7 @@ void handle_talk_event(location p) { return; if (which_talk_entry==TALK_BACK) { if (talk_history_pos<2 || talk_history_pos>=talk_history_nodes.size()+2) { - beep(); + play_sound(37); // checkme return; } talk_history_pos-=2; @@ -768,7 +768,7 @@ void handle_talk_event(location p) { } else if (which_talk_entry==TALK_FRONT) { if (talk_history_pos>=talk_history_nodes.size()) { - beep(); + play_sound(37); // checkme return; } which_talk_entry=talk_history_nodes[talk_history_pos]; @@ -821,7 +821,7 @@ void handle_talk_event(location p) { break; case TALK_RECORD: if(!can_save_talk) { - beep(); + play_sound(37); // checkme return; } if(univ.party.save_talk(univ.town->talking.people[store_personality%10].title, univ.town->name, save_talk_str1, save_talk_str2)) { diff --git a/src/game/boe.fileio.cpp b/src/game/boe.fileio.cpp index 0e6e69a3..f67c0029 100644 --- a/src/game/boe.fileio.cpp +++ b/src/game/boe.fileio.cpp @@ -71,22 +71,31 @@ void finish_load_party(){ return; } - // Saved creatures may not have had their monster attributes saved + // Saved creatures and town.monst may not have had their monster attributes saved // Make sure that they know what they are! // Cast to cMonster base class and assign, to avoid clobbering other attributes - for(auto& pop : univ.party.creature_save) { + bool found_some_bad_monster=false; + for (size_t j=0; j<=univ.party.creature_save.size(); ++j) { + auto &pop = j bad_monster; for(size_t i = 0; i < pop.size(); i++) { int number = pop[i].number; + if (number<0 || number>=univ.scenario.scen_monsters.size()) { + bad_monster.push_back(i); + continue; + } cMonster& monst = pop[i]; monst = univ.scenario.scen_monsters[number]; } + if (bad_monster.empty()) continue; + // now remove the creatures that clearly are not from this scenario + found_some_bad_monster=true; + for (auto it=bad_monster.rbegin(); it!=bad_monster.rend(); ++it) + pop.removeCreature(*it); } - for(size_t j = 0; j < univ.town.monst.size(); j++) { - int number = univ.town.monst[j].number; - cMonster& monst = univ.town.monst[j]; - monst = univ.scenario.scen_monsters[number]; - } - + if (found_some_bad_monster) + showWarning("Found some unexistent monsters in the saved game, try to repair it."); + // if at this point, startup must be over, so make this call to make sure we're ready, // graphics wise end_startup(); diff --git a/src/game/boe.graphutil.cpp b/src/game/boe.graphutil.cpp index 89218641..1a800e9b 100644 --- a/src/game/boe.graphutil.cpp +++ b/src/game/boe.graphutil.cpp @@ -180,7 +180,7 @@ void draw_monsters() { } void play_see_monster_str(unsigned short m, location monst_loc) { - short spec = univ.scenario.scen_monsters[m].see_spec; + short spec = univ.scenario.get_monster(m).see_spec; // Then run the special, if any if(spec > -1){ queue_special(eSpecCtx::SEE_MONST, eSpecCtxType::SCEN, spec, monst_loc); @@ -601,7 +601,7 @@ void check_if_monst_seen(unsigned short m_num, location at) { snd_num_t sound = -1; if(m_num >= 10000) sound = univ.party.summons[m_num - 10000].ambient_sound; - else sound = univ.scenario.scen_monsters[m_num].ambient_sound; + else sound = univ.scenario.get_monster(m_num).ambient_sound; if(sound > 0 && get_ran(1,1,100) < 10) play_sound(-sound); } diff --git a/src/game/boe.infodlg.cpp b/src/game/boe.infodlg.cpp index 9be4f07d..662e7f70 100644 --- a/src/game/boe.infodlg.cpp +++ b/src/game/boe.infodlg.cpp @@ -246,7 +246,7 @@ static bool display_monst_event_filter(cDialog& me, std::string item_hit, cCreat return true; // Means an immunity LED was hit if(roster[position % 60].number != on_monst_menu[position]) { - cMonster& monst = univ.scenario.scen_monsters[on_monst_menu[position]]; + cMonster& monst = univ.scenario.get_monster(on_monst_menu[position]); roster.assign(position % 60, cCreature(on_monst_menu[position]), monst, univ.party.easy_mode, univ.difficulty_adjust()); } store_m = roster[position % 60]; diff --git a/src/game/boe.items.cpp b/src/game/boe.items.cpp index 5c2d4dcf..fef77460 100644 --- a/src/game/boe.items.cpp +++ b/src/game/boe.items.cpp @@ -335,7 +335,7 @@ void set_town_attitude(short lo,short hi,eAttitude att) { univ.town.monst.hostile = true; univ.town.monst[i].mobility = 1; // If a "guard", give a power boost - if(univ.scenario.scen_monsters[num].guard) { + if(univ.scenario.get_monster(num).guard) { univ.town.monst[i].active = 2; univ.town.monst[i].health *= 3; univ.town.monst[i].status[eStatus::HASTE_SLOW] = 8; @@ -682,7 +682,7 @@ void place_glands(location where,mon_num_t m_type) { if(m_type >= 10000) monst = univ.party.summons[m_type - 10000]; - else monst = univ.scenario.scen_monsters[m_type]; + else monst = univ.scenario.get_monster(m_type); if(monst.corpse_item >= 0 && monst.corpse_item < univ.scenario.scen_items.size() && get_ran(1,1,100) < monst.corpse_item_chance) place_item(univ.get_item(monst.corpse_item),where); diff --git a/src/game/boe.menus.mac.mm b/src/game/boe.menus.mac.mm index f1b77a7e..9b2d1547 100644 --- a/src/game/boe.menus.mac.mm +++ b/src/game/boe.menus.mac.mm @@ -83,11 +83,11 @@ void adjust_monst_menu() { } for(short i = 0; i < 256; i++) { if(on_monst_menu[i] >= 0) { - std::string monst_name = univ.scenario.scen_monsters[on_monst_menu[i]].m_name; + std::string monst_name = univ.scenario.get_monster(on_monst_menu[i]).m_name; NSString* str = [NSString stringWithUTF8String: monst_name.c_str()]; NSMenuItem* newItem = [monst_menu addItemWithTitle: str action: @selector(monstMenu:) keyEquivalent: @""]; [newItem setTarget: targ]; - [newItem setRepresentedObject: [MonsterWrapper withMonster: univ.scenario.scen_monsters[on_monst_menu[i]]]]; + [newItem setRepresentedObject: [MonsterWrapper withMonster: univ.scenario.get_monster(on_monst_menu[i])]]; } } } diff --git a/src/game/boe.monster.cpp b/src/game/boe.monster.cpp index ecd88b0d..415d6da2 100644 --- a/src/game/boe.monster.cpp +++ b/src/game/boe.monster.cpp @@ -36,7 +36,7 @@ short out_enc_lev_tot(short which) { for(short i = 0; i < 7; i++) if(univ.party.out_c[which].what_monst.monst[i] != 0) - count += univ.scenario.scen_monsters[univ.party.out_c[which].what_monst.monst[i]].level * num[i]; + count += univ.scenario.get_monster(univ.party.out_c[which].what_monst.monst[i]).level * num[i]; return count; } @@ -126,7 +126,7 @@ location get_monst_head(short m_num) { short get_monst_picnum(mon_num_t monst) { if(monst >= 10000) return univ.party.summons[monst - 10000].picture_num; - return univ.scenario.scen_monsters[monst].picture_num; + return univ.scenario.get_monster(monst).picture_num; } ePicType get_monst_pictype(mon_num_t monst) { @@ -134,7 +134,7 @@ ePicType get_monst_pictype(mon_num_t monst) { short n; if(monst >= 10000) n = univ.party.summons[monst - 10000].picture_num; - else n = univ.scenario.scen_monsters[monst].picture_num; + else n = univ.scenario.get_monster(monst).picture_num; if(n >= 1000){ type += PIC_CUSTOM; switch(n / 1000){ @@ -157,7 +157,7 @@ ePicType get_monst_pictype(mon_num_t monst) { } std::pair get_monst_dims(mon_num_t monst) { - cMonster& the_monst = monst >= 10000 ? univ.party.summons[monst - 10000] : univ.scenario.scen_monsters[monst]; + cMonster& the_monst = monst >= 10000 ? univ.party.summons[monst - 10000] : univ.scenario.get_monster(monst); return std::make_pair(the_monst.x_width, the_monst.y_width); } @@ -165,7 +165,7 @@ std::pair get_monst_dims(mon_num_t monst) { void set_up_monst(eAttitude mode,mon_num_t m_num) { short which = univ.town.monst.size(); - cMonster& monst = m_num >= 10000 ? univ.party.summons[m_num - 10000] : univ.scenario.scen_monsters[m_num]; + cMonster& monst = m_num >= 10000 ? univ.party.summons[m_num - 10000] : univ.scenario.get_monster(m_num); univ.town.monst.assign(which, cCreature(m_num), monst, univ.party.easy_mode, univ.difficulty_adjust()); univ.town.monst[which].active = 2; univ.town.monst[which].summon_time = 0; @@ -1101,7 +1101,7 @@ short place_monster(mon_num_t which,location where,bool forced) { } // 10000 or more means an exported summon saved with the party - cMonster& monst = which >= 10000 ? univ.party.summons[which - 10000] : univ.scenario.scen_monsters[which]; + cMonster& monst = which >= 10000 ? univ.party.summons[which - 10000] : univ.scenario.get_monster(which); univ.town.monst.assign(i, cCreature(which), monst, univ.party.easy_mode, univ.difficulty_adjust()); // TODO: Should this static_cast assignment be happening? // One effect is resetting max health to ignore difficulty_adjust() @@ -1172,7 +1172,7 @@ void activate_monsters(short code,short /*attitude*/) { for(short i = 0; i < univ.town->creatures.size(); i++) if(univ.town->creatures[i].spec_enc_code == code) { cTownperson& monst = univ.town->creatures[i]; - univ.town.monst.assign(i, monst, univ.scenario.scen_monsters[monst.number], univ.party.easy_mode, univ.difficulty_adjust()); + univ.town.monst.assign(i, monst, univ.scenario.get_monster(monst.number), univ.party.easy_mode, univ.difficulty_adjust()); univ.town.monst[i].spec_enc_code = 0; univ.town.monst[i].active = 2; @@ -1186,7 +1186,6 @@ void activate_monsters(short code,short /*attitude*/) { mon_num_t get_summon_monster(short summon_class) { for(short i = 0; i < 200; i++) { - // ASAN univ.scenario.scen_monsters.size() can be less than 255 short j = get_ran(1,0,univ.scenario.scen_monsters.size()-1); if(univ.scenario.scen_monsters[j].summon_type == summon_class) { return j; diff --git a/src/game/boe.newgraph.cpp b/src/game/boe.newgraph.cpp index 849e1c2f..840e5bd2 100644 --- a/src/game/boe.newgraph.cpp +++ b/src/game/boe.newgraph.cpp @@ -811,7 +811,7 @@ static void place_talk_face() { rectangle face_rect = {6,6,38,38}; face_rect.offset(talk_area_rect.topLeft()); mainPtr.setActive(); - short face_to_draw = univ.scenario.scen_monsters[store_monst_type].default_facial_pic; + short face_to_draw = univ.scenario.get_monster(store_monst_type).default_facial_pic; if(store_talk_face_pic >= 0) face_to_draw = store_talk_face_pic; if(store_talk_face_pic >= 1000) diff --git a/src/game/boe.party.cpp b/src/game/boe.party.cpp index 3ae3acf5..0be464b3 100644 --- a/src/game/boe.party.cpp +++ b/src/game/boe.party.cpp @@ -2234,7 +2234,7 @@ mon_num_t pick_trapped_monst() { else { sp = get_m_name(which); soulCrystal->getControl("slot" + n).setText(sp); - get_monst = which >= 10000 ? univ.party.summons[which - 10000] : univ.scenario.scen_monsters[which]; + get_monst = which >= 10000 ? univ.party.summons[which - 10000] : univ.scenario.get_monster(which); soulCrystal->getControl("lvl" + n).setTextToNum(get_monst.level); } } diff --git a/src/game/boe.specials.cpp b/src/game/boe.specials.cpp index f1cf2f68..1ca4986b 100644 --- a/src/game/boe.specials.cpp +++ b/src/game/boe.specials.cpp @@ -2401,7 +2401,7 @@ void general_spec(const runtime_state& ctx) { univ.get_buf() += univ.party[pc].name; else if(!is_out()) univ.get_buf() += univ.town.monst[pc - 100].m_name; - } else univ.get_buf() += univ.scenario.scen_monsters[spec.ex1a].m_name; + } else univ.get_buf() += univ.scenario.get_monster(spec.ex1a).m_name; break; case eSpecType::APPEND_ITEM: if(spec.pic) univ.get_buf() += ' '; diff --git a/src/game/boe.text.cpp b/src/game/boe.text.cpp index 6981b8f0..ff30e0ca 100644 --- a/src/game/boe.text.cpp +++ b/src/game/boe.text.cpp @@ -874,7 +874,7 @@ void notify_out_combat_began(cOutdoors::cWandering encounter,short *nums) { std::string get_m_name(mon_num_t num) { if(num >= 10000) return univ.party.summons[num - 10000].m_name; - return univ.scenario.scen_monsters[num].m_name; + return univ.scenario.get_monster(num).m_name; } std::string get_ter_name(ter_num_t num) { if(num == 90 && (is_out() || is_town() || (is_combat() && which_combat_type == 1))) diff --git a/src/game/boe.town.cpp b/src/game/boe.town.cpp index e8b1d71d..0ac6a29d 100644 --- a/src/game/boe.town.cpp +++ b/src/game/boe.town.cpp @@ -169,7 +169,7 @@ void start_town_mode(short which_town, short entry_dir) { if(univ.town->creatures[i].number > 0) { // recreate the lists. const cTownperson& preset = univ.town->creatures[i]; - univ.town.monst.assign(i, preset, univ.scenario.scen_monsters[preset.number], univ.party.easy_mode, univ.difficulty_adjust()); + univ.town.monst.assign(i, preset, univ.scenario.get_monster(preset.number), univ.party.easy_mode, univ.difficulty_adjust()); } } } diff --git a/src/pcedit/pc.editors.cpp b/src/pcedit/pc.editors.cpp index e895e73b..fbfb4ec5 100644 --- a/src/pcedit/pc.editors.cpp +++ b/src/pcedit/pc.editors.cpp @@ -505,7 +505,7 @@ static bool spend_xp_event_filter(cDialog& me, std::string item_hit, eKeyMod mod give_help(25,0,me); else if(save.mode == 1 && save.g < 10) give_help(24,0,me); - else beep(); + else beep();// TODO: This is a game event, so it should have a game sound, not a system alert. } } @@ -540,7 +540,7 @@ static bool spend_xp_event_filter(cDialog& me, std::string item_hit, eKeyMod mod give_help(25,0,me); else if(save.mode == 1 && save.g < 15) give_help(24,0,me); - else beep(); + else beep(); // TODO: This is a game event, so it should have a game sound, not a system alert. } } diff --git a/src/pcedit/pc.fileio.cpp b/src/pcedit/pc.fileio.cpp index 4f048a22..62cd792f 100644 --- a/src/pcedit/pc.fileio.cpp +++ b/src/pcedit/pc.fileio.cpp @@ -25,6 +25,8 @@ void remove_party_from_scen() { univ.exportGraphics(); univ.exportSummons(); univ.party.scen_name = ""; + for (auto &pop : univ.party.creature_save) + pop.clear(); party_in_scen = false; load_base_item_defs(); } diff --git a/src/scenario/monster.hpp b/src/scenario/monster.hpp index 1a492e5e..4d1f7e71 100644 --- a/src/scenario/monster.hpp +++ b/src/scenario/monster.hpp @@ -77,6 +77,12 @@ public: cMonster(); void writeTo(std::ostream& file) const; void readFrom(std::istream& file); + + static cMonster bad() { + cMonster monster; + monster.m_name="BAD Monster"; + return monster; + } }; class cTownperson { diff --git a/src/scenario/scenario.cpp b/src/scenario/scenario.cpp index fcaecc41..b40a53a0 100644 --- a/src/scenario/scenario.cpp +++ b/src/scenario/scenario.cpp @@ -451,12 +451,13 @@ void cScenario::import_legacy(legacy::scen_item_data_type const &old){ else scen_items[i].desc=descIt->second; } - for(short i = 0; i < 256; i++) { - scen_monsters[i].m_name = old.monst_names[i]; - if(scen_monsters[i].m_type == eRace::UNDEAD && scen_monsters[i].m_name.find("Skeleton") != std::string::npos) - scen_monsters[i].m_type = eRace::SKELETAL; - if(scen_monsters[i].m_type == eRace::HUMANOID && scen_monsters[i].m_name.find("Goblin") != std::string::npos) - scen_monsters[i].m_type = eRace::GOBLIN; + for(short i = 0; i < std::min(256,scen_monsters.size()); i++) { + auto &monster=scen_monsters[i]; + monster.m_name = old.monst_names[i]; + if(monster.m_type == eRace::UNDEAD && monster.m_name.find("Skeleton") != std::string::npos) + monster.m_type = eRace::SKELETAL; + if(monster.m_type == eRace::HUMANOID && monster.m_name.find("Goblin") != std::string::npos) + monster.m_type = eRace::GOBLIN; } for(short i = 0; i < std::min(256, ter_types.size()); i++) ter_types[i].name = old.ter_names[i]; @@ -698,6 +699,23 @@ cOutdoors& cScenario::get_sector(int x, int y) { return *outdoors[x][y]; } +cMonster &cScenario::get_monster(mon_num_t monst) +{ + if (monst= 0 && loc.spec < towns.size(); } diff --git a/src/scenario/scenario.hpp b/src/scenario/scenario.hpp index a3d28239..e77b8527 100644 --- a/src/scenario/scenario.hpp +++ b/src/scenario/scenario.hpp @@ -122,6 +122,8 @@ public: ter_num_t get_trim_terrain(unsigned short ground, unsigned short trim_g, eTrimType trim); cOutdoors& get_sector(int x, int y); bool is_town_entrance_valid(spec_loc_t loc) const; + cMonster &get_monster(mon_num_t monst); + cMonster const &get_monster(mon_num_t monst) const; bool is_ter_used(ter_num_t ter); bool is_monst_used(mon_num_t monst); diff --git a/src/scenario/special.cpp b/src/scenario/special.cpp index aa9a673f..ddfa2144 100644 --- a/src/scenario/special.cpp +++ b/src/scenario/special.cpp @@ -90,7 +90,7 @@ static cPictNum port_graphic_num(int pic) { if (pic<900) return cPictNum(pic-700, PIC_DLOG); if (pic<1000)// ARGH: normally bwpats, force an error picture - return cPictNum(900, PIC_TER); + return cPictNum(800, PIC_TER); if (pic < 1100) return cPictNum(pic-1000, PIC_TALK); if (pic < 1200) @@ -98,7 +98,7 @@ static cPictNum port_graphic_num(int pic) { if (pic < 1300) return cPictNum(pic-1200, PIC_PC); // ARGH: not implemented, force an error picture - return cPictNum(900, PIC_TER); + return cPictNum(800, PIC_TER); } void cSpecial::import_legacy(legacy::special_node_type const &old){ diff --git a/src/scenedit/scen.actions.cpp b/src/scenedit/scen.actions.cpp index e8d130f0..9f8664f5 100644 --- a/src/scenedit/scen.actions.cpp +++ b/src/scenedit/scen.actions.cpp @@ -285,8 +285,8 @@ static bool handle_rb_action(location the_point, bool option_hit) { for(; j < scenario.scen_monsters.size(); j++) scenario.scen_monsters[j].m_name = "New Monster"; } else { - scenario.scen_monsters[j] = cMonster(); - scenario.scen_monsters[j].m_name = "Unused Monster"; + scenario.get_monster(j) = cMonster(); + scenario.get_monster(j).m_name = "Unused Monster"; } } else { if(j == size_before) { @@ -814,10 +814,10 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) { return who.number == 0; }); if(iter != town->creatures.end()) { - *iter = {spot_hit, static_cast(mode_count), scenario.scen_monsters[mode_count]}; + *iter = {spot_hit, static_cast(mode_count), scenario.get_monster(mode_count)}; last_placed_monst = *iter; } else { // Placement failed - town->creatures.push_back({spot_hit, static_cast(mode_count), scenario.scen_monsters[mode_count]}); + town->creatures.push_back({spot_hit, static_cast(mode_count), scenario.get_monster(mode_count)}); last_placed_monst = town->creatures.back(); } } @@ -1150,7 +1150,7 @@ static bool handle_terpal_action(location cur_point, bool option_hit) { break; overall_mode = MODE_PLACE_CREATURE; mode_count = k + 1; - set_string("Place the monster:",scenario.scen_monsters[mode_count].m_name); + set_string("Place the monster:",scenario.get_monster(mode_count).m_name); break; } } @@ -2575,9 +2575,9 @@ bool monst_on_space(location loc,short m_num) { if(town->creatures[m_num].number == 0) return false; if((loc.x - town->creatures[m_num].start_loc.x >= 0) && - (loc.x - town->creatures[m_num].start_loc.x <= scenario.scen_monsters[town->creatures[m_num].number].x_width - 1) && + (loc.x - town->creatures[m_num].start_loc.x <= scenario.get_monster(town->creatures[m_num].number).x_width - 1) && (loc.y - town->creatures[m_num].start_loc.y >= 0) && - (loc.y - town->creatures[m_num].start_loc.y <= scenario.scen_monsters[town->creatures[m_num].number].y_width - 1)) + (loc.y - town->creatures[m_num].start_loc.y <= scenario.get_monster(town->creatures[m_num].number).y_width - 1)) return true; return false; diff --git a/src/universe/population.cpp b/src/universe/population.cpp index ffefc692..d1b8b479 100644 --- a/src/universe/population.cpp +++ b/src/universe/population.cpp @@ -54,6 +54,14 @@ void cPopulation::init(size_t n) { dudes[n]->active = 1; } +void cPopulation::removeCreature(size_t n) +{ + if (n>=dudes.size()) + return; + std::swap(dudes[n],dudes.back()); + dudes.pop_back(); +} + // This function combines a cTownperson from a scenario town record with a cMonster from the scenario record // into a cCreature, and prepares it for use in-game according to the user's preferences and party strength // replaces return_monster_template() from boe.monsters.cpp diff --git a/src/universe/population.hpp b/src/universe/population.hpp index 12a34c4a..8f21e5aa 100644 --- a/src/universe/population.hpp +++ b/src/universe/population.hpp @@ -35,7 +35,8 @@ public: void clear() {dudes.clear();} cCreature& operator[](size_t n); const cCreature& operator[](size_t n) const; - // ASAN hostile copied but unset + // remove the n^th creature from the list by swapping it with the last dude and then pop_back it + void removeCreature(size_t n); cPopulation() : which_town(200), hostile(false) {} iterator begin() {return iterator(dudes.begin());} iterator end() {return iterator(dudes.end());} diff --git a/src/universe/universe.cpp b/src/universe/universe.cpp index ffc8381a..e0f97ca4 100644 --- a/src/universe/universe.cpp +++ b/src/universe/universe.cpp @@ -1133,7 +1133,7 @@ void cCustomUpdateState::check_monst(cUniverse &univers, cMonster & monst) { break; case eMonstAbilCat::SUMMON: if(abil.second.summon.type == eMonstSummon::TYPE) - check_monst(univers, univers.scenario.scen_monsters[abil.second.summon.what]); + check_monst(univers, univers.scenario.get_monster(abil.second.summon.what)); break; case eMonstAbilCat::RADIATE: case eMonstAbilCat::SPECIAL: @@ -1155,7 +1155,7 @@ void cCustomUpdateState::check_item(cUniverse &universe, cItem& item) { mon_num_t monst = item.abil_data[1]; if(monst >= 10000) check_monst(universe, universe.party.summons[monst - 10000]); - else check_monst(universe, universe.scenario.scen_monsters[monst]); + else check_monst(universe, universe.scenario.get_monster(monst)); } if(item.variety == eItemType::ARROW || item.variety == eItemType::BOLTS || item.variety == eItemType::MISSILE_NO_AMMO || item.variety == eItemType::THROWN_MISSILE) insert_missile_pict(item.missile); @@ -1266,7 +1266,7 @@ void cUniverse::exportSummons() { while(!last_check.empty()) { mon_num_t monst = last_check.top(); last_check.pop(); - cMonster& what = scenario.scen_monsters[monst]; + cMonster& what = scenario.get_monster(monst); if(what.abil[eMonstAbil::SUMMON].active && what.abil[eMonstAbil::SUMMON].summon.type == eMonstSummon::TYPE) { mon_num_t summon = what.abil[eMonstAbil::SUMMON].summon.what; if(summon >= 10000) @@ -1289,8 +1289,8 @@ void cUniverse::exportSummons() { while(used_monsters.count(++dest)); used_monsters.insert(dest); if(dest < party.summons.size()) - party.summons[dest] = scenario.scen_monsters[monst]; - else party.summons.push_back(scenario.scen_monsters[monst]); + party.summons[dest] = scenario.get_monster(monst); + else party.summons.push_back(scenario.get_monster(monst)); for(auto& item : update_items[monst]) item->abil_data[1] = 10000 + dest; for(mon_num_t& sc : party.imprisoned_monst) @@ -1360,14 +1360,16 @@ void cUniverse::enter_scenario(const std::string& name) { } party.in_boat = -1; party.in_horse = -1; - for(auto& pop : party.creature_save) + for(auto& pop : party.creature_save) { + pop.clear(); pop.which_town = 200; + } for(short i = 0; i < 10; i++) party.out_c[i].exists = false; party.store_limited_stock.clear(); party.magic_store_items.clear(); - // TODO: Now uncertain if the journal should really persist -// univ.party.journal.clear(); + + party.journal.clear(); party.special_notes.clear(); party.talk_save.clear(); // reset the scried monster diff --git a/src/utility.cpp b/src/utility.cpp index 96d146f4..93453765 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -13,7 +13,7 @@ std::string get_str(std::string list, short j){ if(j == 0) return list; const StringList& strings = *ResMgr::strings.get(list); - return strings[j - 1]; + return (j<0 || j>strings.size()) ? "BAD String" : strings[j - 1]; } short can_see(location p1,location p2,std::function get_obscurity) { diff --git a/src/view_dialogs.cpp b/src/view_dialogs.cpp index 9e08462d..1cb54576 100644 --- a/src/view_dialogs.cpp +++ b/src/view_dialogs.cpp @@ -63,7 +63,7 @@ void put_item_info(cDialog& me, const cItem& s_i, const cScenario& scen) { } else { std::string abil = s_i.getAbilName(); if(s_i.ability == eItemAbil::SUMMONING || s_i.ability == eItemAbil::MASS_SUMMONING) - abil.replace(abil.find("%s"), 2, scen.scen_monsters[s_i.abil_data[1]].m_name); + abil.replace(abil.find("%s"), 2, scen.get_monster(s_i.abil_data[1]).m_name); me["abil"].setText(abil); } } @@ -153,7 +153,7 @@ void put_monst_info(cDialog& me, const cMonster& store_m, const cScenario& scen) std::string id = "abil" + std::to_string(i); std::string name = abil.second.to_string(abil.first); if(abil.first == eMonstAbil::SUMMON && abil.second.summon.type == eMonstSummon::TYPE) - name.replace(name.find("%s"), 2, scen.scen_monsters[abil.second.summon.what].m_name); + name.replace(name.find("%s"), 2, scen.get_monster(abil.second.summon.what).m_name); me[id].setText(name); i++; }