diff --git a/src/boe.graphics.cpp b/src/boe.graphics.cpp index 5316f042..7c7c075a 100644 --- a/src/boe.graphics.cpp +++ b/src/boe.graphics.cpp @@ -361,7 +361,7 @@ void draw_startup_stats() { } style.pointSize = 12; pc_rect.offset(12,16); - std::string status = "Level " + univ.party[i].level; + std::string status = "Level " + std::to_string(univ.party[i].level); switch(univ.party[i].main_status) { case eMainStatus::ALIVE: switch(univ.party[i].race) { diff --git a/src/boe.graphutil.cpp b/src/boe.graphutil.cpp index c1ae0b97..3761785f 100644 --- a/src/boe.graphutil.cpp +++ b/src/boe.graphutil.cpp @@ -270,14 +270,26 @@ void draw_pcs(location center,short mode) { (/*cartoon_happening ||*/ party_can_see(univ.party[i].combat_pos) < 6)){ where_draw.x = univ.party[i].combat_pos.x - center.x + 4; where_draw.y = univ.party[i].combat_pos.y - center.y + 4; - source_rect = calc_rect(2 * (univ.party[i].which_graphic / 8), univ.party[i].which_graphic % 8); - if(univ.party[i].dir >= 4) - source_rect.offset(28,0); - if(combat_posing_monster == i) - source_rect.offset(0,288); + sf::Texture* from_gw; + if(univ.party[i].which_graphic >= 1000) { + bool isParty = univ.party[i].which_graphic >= 10000; + pic_num_t need_pic = univ.party[i].which_graphic % 1000; + if(univ.party[i].dir >= 4) + need_pic++; + if(combat_posing_monster == i) + need_pic += 2; + graf_pos_ref(from_gw, source_rect) = spec_scen_g.find_graphic(need_pic, isParty); + } else { + source_rect = calc_rect(2 * (univ.party[i].which_graphic / 8), univ.party[i].which_graphic % 8); + if(univ.party[i].dir >= 4) + source_rect.offset(28,0); + if(combat_posing_monster == i) + source_rect.offset(0,288); + from_gw = &pc_gworld; + } if(mode == 0) { - Draw_Some_Item(pc_gworld, source_rect, terrain_screen_gworld, where_draw, 1, 0); + Draw_Some_Item(*from_gw, source_rect, terrain_screen_gworld, where_draw, 1, 0); } if((current_pc == i) && (mode == 1) && !monsters_going) { @@ -470,14 +482,24 @@ void draw_party_symbol(location center) { if((univ.party.in_boat < 0) && (univ.party.in_horse < 0)) { i = first_active_pc(); - source_rect = calc_rect(2 * (univ.party[current_pc].which_graphic / 8), univ.party[i].which_graphic % 8); - if(univ.party[current_pc].dir >= 4) - source_rect.offset(28,0); + sf::Texture* from_gw; + if(univ.party[i].which_graphic >= 1000) { + bool isParty = univ.party[i].which_graphic >= 10000; + pic_num_t need_pic = univ.party[i].which_graphic % 1000; + if(univ.party[i].dir >= 4) + need_pic++; + graf_pos_ref(from_gw, source_rect) = spec_scen_g.find_graphic(need_pic, isParty); + } else { + source_rect = calc_rect(2 * (univ.party[current_pc].which_graphic / 8), univ.party[i].which_graphic % 8); + if(univ.party[current_pc].dir >= 4) + source_rect.offset(28,0); + from_gw = &pc_gworld; + } ter_num_t ter = is_out() ? univ.out[univ.party.p_loc.x][univ.party.p_loc.y] : univ.town->terrain(univ.town.p_loc.x,univ.town.p_loc.y); // now wedge in bed graphic if(is_town() && univ.scenario.ter_types[ter].special == eTerSpec::BED) draw_one_terrain_spot((short) target.x,(short) target.y,10000 + univ.scenario.ter_types[ter].flag1.u); - else Draw_Some_Item(pc_gworld, source_rect, terrain_screen_gworld, target, 1, 0); + else Draw_Some_Item(*from_gw, source_rect, terrain_screen_gworld, target, 1, 0); } else if(univ.party.in_boat >= 0) { if(univ.party.direction == 0 || univ.party.direction > 4) i = 4; diff --git a/src/boe.specials.cpp b/src/boe.specials.cpp index 344e7308..7049b90d 100644 --- a/src/boe.specials.cpp +++ b/src/boe.specials.cpp @@ -4052,8 +4052,14 @@ void townmode_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, if(which_mode == eSpecCtx::TALK) break; i = combat_posing_monster; - if(l.y >= 0) combat_posing_monster = monst_there(l); - else combat_posing_monster = spec.ex1a; + if(l.y >= 0) { + int monst = monst_there(l); + if(monst < 90) + combat_posing_monster = 100 + monst; + else combat_posing_monster = pc_there(l); + if(combat_posing_monster == 6) + combat_posing_monster = -1; + } else combat_posing_monster = spec.ex1a; if(combat_posing_monster < 0 || combat_posing_monster >= univ.town->max_monst()) { combat_posing_monster = i; break; diff --git a/src/classes/universe.cpp b/src/classes/universe.cpp index a39db1b4..be0607ec 100644 --- a/src/classes/universe.cpp +++ b/src/classes/universe.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "classes.h" #include "oldstructs.h" @@ -856,6 +857,8 @@ cOutdoors* cCurOut::operator->() { cUniverse::cUniverse(long party_type) : party(*this, party_type), out(*this), town(*this) {} void cUniverse::check_monst(cMonster& monst) { + if(monst.see_spec == -2) return; // Avoid infinite recursion + monst.see_spec = -2; if(monst.picture_num >= 10000) { int pic = monst.picture_num - 10000; int sz = pic / 1000, base = pic % 1000; @@ -865,7 +868,34 @@ void cUniverse::check_monst(cMonster& monst) { for(int i = 0; i < numGraph; i++) used_graphics.insert(base + i); } else if(monst.picture_num >= 1000) { - update_monsters[monst.picture_num].insert(&monst); + update_monsters[monst.picture_num - 1000].insert(&monst); + } + for(auto& abil : monst.abil) { + switch(getMonstAbilCategory(abil.first)) { + case eMonstAbilCat::MISSILE: + if(abil.second.missile.pic >= 10000) { + for(int i = 0; i < 4; i++) + used_graphics.insert(abil.second.missile.pic - 10000 + i); + } else if(abil.second.missile.pic >= 1000) { + update_missiles[abil.second.missile.pic - 1000].insert(&abil.second.missile.pic); + } + break; + case eMonstAbilCat::GENERAL: + if(abil.second.gen.pic >= 10000) { + for(int i = 0; i < 4; i++) + used_graphics.insert(abil.second.gen.pic - 10000 + i); + } else if(abil.second.gen.pic >= 1000) { + update_missiles[abil.second.gen.pic - 1000].insert(&abil.second.gen.pic); + } + break; + case eMonstAbilCat::SUMMON: + check_monst(scenario.scen_monsters[abil.second.summon.type]); + break; + case eMonstAbilCat::RADIATE: + case eMonstAbilCat::SPECIAL: + case eMonstAbilCat::INVALID: + break; + } } } @@ -886,7 +916,7 @@ void cUniverse::check_item(cItem& item) { for(int i = 0; i < 4; i++) used_graphics.insert(item.missile - 10000 + i); else if(item.missile >= 1000) - update_missiles[item.missile - 1000].insert(&item); + update_missiles[item.missile - 1000].insert(&item.missile); } } @@ -970,8 +1000,8 @@ void cUniverse::exportGraphics() { update_items.clear(); for(auto pic : update_missiles) { pic_num_t pos = addGraphic(pic.first, PIC_MISSILE); - for(auto& item : pic.second) - item->missile = 10000 + pos; + for(auto& missile : pic.second) + *missile = 10000 + pos; } update_missiles.clear(); for(auto pic : update_monsters) { @@ -1030,6 +1060,21 @@ void cUniverse::exportSummons() { used_monsters.insert(party.imprisoned_monst[i] - 10000); else need_monsters.insert(party.imprisoned_monst[i]); } + std::stack last_check; + for(mon_num_t m : need_monsters) last_check.push(m); + while(!last_check.empty()) { + mon_num_t monst = last_check.top(); + last_check.pop(); + if(scenario.scen_monsters[monst].abil[eMonstAbil::SUMMON].active) { + mon_num_t summon = scenario.scen_monsters[monst].abil[eMonstAbil::SUMMON].summon.type; + if(summon >= 10000) + used_monsters.insert(summon - 10000); + else if(!need_monsters.count(summon)) { + last_check.push(summon); + need_monsters.insert(summon); + } + } + } // Now that we know which exported summon slots are still in use and which new monsters need to be exported, // we can copy the monster records from the scenario record into the exported summon slots. if(used_monsters.empty()) party.summons.clear(); diff --git a/src/classes/universe.h b/src/classes/universe.h index 87a7552f..9b36cfcd 100644 --- a/src/classes/universe.h +++ b/src/classes/universe.h @@ -154,9 +154,10 @@ enum eAmbientSound { class cUniverse{ template using update_info = std::set; - std::map> update_items, update_missiles; + std::map> update_items; std::map> update_monsters; std::map> update_pcs; + std::map> update_missiles; std::set used_graphics; pic_num_t addGraphic(pic_num_t pic, ePicType type); void check_monst(cMonster& monst);