vector2d: try to protect the access against bad index, to be improved...

+ details rewriting
This commit is contained in:
ALONSO Laurent
2021-10-24 13:14:41 +02:00
committed by Celtic Minstrel
parent 282c640173
commit f3a96391b5
8 changed files with 133 additions and 60 deletions

View File

@@ -727,8 +727,8 @@ location find_clear_spot(location from_where,short mode) {
if(!loc_off_act_area(loc) && !is_blocked(loc)
&& can_see_light(from_where,loc,combat_obscurity) == 0
&& (!is_combat() || univ.target_there(loc,TARG_PC) == nullptr)
&& (!(is_town()) || (loc != univ.party.town_loc))
&& (!(univ.town.fields[loc.x][loc.y] & blocking_fields))) {
&& (!is_town() || loc != univ.party.town_loc)
&& (!is_town() || !(univ.town.fields[loc.x][loc.y] & blocking_fields))) {
if((mode == 0) || ((mode == 1) && (adjacent(from_where,loc))))
return loc;
else store_loc = loc;

View File

@@ -196,19 +196,19 @@ bool check_special_terrain(location where_check,eSpecCtx mode,cPlayer& which_pc,
if(mode == eSpecCtx::OUT_MOVE) {
out_where = global_to_local(where_check);
for(short i = 0; i < univ.out->special_locs.size(); i++)
if(out_where == univ.out->special_locs[i]) {
spec_num = univ.out->special_locs[i].spec;
// call special
run_special(mode, eSpecCtxType::OUTDOOR, spec_num, out_where, &s1, &s2);
if(s1 > 0)
can_enter = false;
else if(s2 > 0)
*forced = true;
erase_out_specials();
put_pc_screen();
put_item_screen(stat_window);
}
for(short i = 0; i < univ.out->special_locs.size(); i++) {
if(out_where != univ.out->special_locs[i]) continue;
spec_num = univ.out->special_locs[i].spec;
// call special
run_special(mode, eSpecCtxType::OUTDOOR, spec_num, out_where, &s1, &s2);
if(s1 > 0)
can_enter = false;
else if(s2 > 0)
*forced = true;
erase_out_specials();
put_pc_screen();
put_item_screen(stat_window);
}
}
if (is_combat()) {
@@ -240,26 +240,26 @@ bool check_special_terrain(location where_check,eSpecCtx mode,cPlayer& which_pc,
}
if((mode == eSpecCtx::TOWN_MOVE || (mode == eSpecCtx::COMBAT_MOVE && which_combat_type == 1))
&& can_enter && univ.town.is_special(where_check.x,where_check.y)) {
for(short i = 0; i < univ.town->special_locs.size(); i++)
if(where_check == univ.town->special_locs[i]) {
spec_num = univ.town->special_locs[i].spec;
bool runSpecial = false;
if(!is_blocked(where_check)) runSpecial = true;
if(ter_special == eTerSpec::CHANGE_WHEN_STEP_ON) runSpecial = true;
if(ter_special == eTerSpec::CALL_SPECIAL) runSpecial = true;
if(univ.town->specials[spec_num].type == eSpecType::CANT_ENTER)
runSpecial = true;
if(!univ.scenario.is_legacy && univ.party.in_boat >= 0 && terrain.boat_over)
runSpecial = true;
if(runSpecial) {
give_help(54,0);
run_special(mode, eSpecCtxType::TOWN, spec_num, where_check, &s1, &s2);
if(s1 > 0)
can_enter = false;
else if(s2 > 0)
*forced = true;
}
for(short i = 0; i < univ.town->special_locs.size(); i++) {
if(where_check != univ.town->special_locs[i]) continue;
spec_num = univ.town->special_locs[i].spec;
bool runSpecial = false;
if(!is_blocked(where_check)) runSpecial = true;
if(ter_special == eTerSpec::CHANGE_WHEN_STEP_ON) runSpecial = true;
if(ter_special == eTerSpec::CALL_SPECIAL) runSpecial = true;
if(univ.town->specials[spec_num].type == eSpecType::CANT_ENTER)
runSpecial = true;
if(!univ.scenario.is_legacy && univ.party.in_boat >= 0 && terrain.boat_over)
runSpecial = true;
if(runSpecial) {
give_help(54,0);
run_special(mode, eSpecCtxType::TOWN, spec_num, where_check, &s1, &s2);
if(s1 > 0)
can_enter = false;
else if(s2 > 0)
*forced = true;
}
}
put_pc_screen();
put_item_screen(stat_window);
}

View File

@@ -837,15 +837,18 @@ void create_out_combat_terrain(short ter_type,short num_walls,bool is_road) {
univ.town.fields[i][j] = 0;
if((j <= 8) || (j >= 35) || (i <= 8) || (i >= 35))
univ.town->terrain(i,j) = 90;
else univ.town->terrain(i,j) = ter_base[arena];
}
for(short i = 0; i < 48; i++)
for(short j = 0; j < 48; j++)
for(short k = 0; k < 5; k++)
if((univ.town->terrain(i,j) != 90) && (get_ran(1,1,1000) < terrain_odds[arena][k * 2 + 1]))
else
univ.town->terrain(i,j) = ter_base[arena];
if (univ.town->terrain(i,j) == 90)
continue;
for(short k = 0; k < 5; k++) {
if(get_ran(1,1,1000) < terrain_odds[arena][k * 2 + 1]) {
univ.town->terrain(i,j) = terrain_odds[arena][k * 2];
univ.town->terrain(0,0) = ter_base[arena];
break;
}
}
}
univ.town->terrain(0,0) = ter_base[arena]; // to force an exit position?
bool is_bridge = (arena == 3 || arena == 4);

View File

@@ -48,6 +48,16 @@ void cScenario::destroy_terrain() {
}
}
cOutdoors *cScenario::get_bad_outdoor()
{
static std::shared_ptr<cOutdoors> badOutdoor;
if (!badOutdoor)
badOutdoor=std::make_shared<cOutdoors>(*this);
badOutdoor->reattach(*this);
badOutdoor->name="Bad Outdoor";
return badOutdoor.get();
}
cScenario::cScenario() {
std::string temp_str;
@@ -68,6 +78,7 @@ cScenario::cScenario() {
bg_fight = 4;
bg_town = 13;
bg_dungeon = 9;
outdoors.set_get_default_function([this](){return get_bad_outdoor();});
// ASAN used but unset
is_legacy = false;
for(short i = 0; i < town_mods.size(); i++) {
@@ -143,6 +154,7 @@ cScenario::cScenario(const cScenario& other)
for(size_t i = 0; i < outdoors.width(); i++)
for(size_t j = 0; j < outdoors.height(); j++)
outdoors[i][j] = new cOutdoors(*other.outdoors[i][j]);
outdoors.set_get_default_function([this](){return get_bad_outdoor();});
}
cScenario::cScenario(cScenario&& other) {

View File

@@ -132,6 +132,9 @@ public:
void reset_version();
explicit cScenario();
~cScenario();
cOutdoors *get_bad_outdoor();
// Copy-and-swap
void swap(cScenario& other);
cScenario(const cScenario& other);

View File

@@ -85,7 +85,7 @@ void cTown::import_legacy(T const & old, int){
// Try to fix specials that could be triggered while in a boat
// (Boats never triggered specials in the old BoE, so we probably don't want them to trigger.)
int found_spec = -1;
for(int k = 0; k < 50; k++) {
for(int k = 0; k < special_locs.size(); k++) {
if(i == special_locs[k].x && j == special_locs[k].y) {
found_spec = k;
break;

View File

@@ -26,7 +26,6 @@ void set_string(std::string string,std::string string2);
bool is_special(short i,short j);
void take_special(short i,short j);
void make_special(short i,short j);
void sort_specials();
bool is_field_type(short i,short j,eFieldType field_type);
void make_field_type(short i,short j,eFieldType field_type);
void take_field_type(short i,short j,eFieldType field_type);

View File

@@ -12,6 +12,7 @@
// Tried using boost::multi_array, but it kept causing weird issues, so I decided to make my own.
// TODO: Fill out missing members (should have equivalents for most of the stuff in std::vector)
#include <functional>
#include <vector>
template<typename Type, typename Alloc = std::allocator<Type>> class vector2d {
@@ -21,6 +22,7 @@ template<typename Type, typename Alloc = std::allocator<Type>> class vector2d {
friend class const_col_ref;
std::vector<Type, Alloc> data;
size_t w, h;
std::function<Type()> get_default_value_function=nullptr;
public:
using value_type = Type;
class row_ref {
@@ -30,10 +32,14 @@ public:
row_ref(vector2d<Type, Alloc>& ref, size_t row) : ref(ref), y(row) {}
public:
Type& operator[](size_t x) {
return ref.data[ref.w * y + x];
if (x<ref.w)
return ref.data[ref.w * y + x];
return ref.get_bad_value();
}
const Type& operator[](size_t x) const {
return ref.data[ref.w * y + x];
if (x<ref.w)
return ref.data[ref.w * y + x];
return ref.get_bad_value();
}
row_ref operator=(row_ref&& other) {
row_ref& me = *this;
@@ -60,10 +66,14 @@ public:
col_ref(vector2d<Type, Alloc>& ref, size_t col) : ref(ref), x(col) {}
public:
Type& operator[](size_t y) {
return ref.data[ref.w * y + x];
if (y<ref.h)
return ref.data[ref.w * y + x];
return ref.get_bad_value();
}
const Type& operator[](size_t y) const {
return ref.data[ref.w * y + x];
if (y<ref.h)
return ref.data[ref.w * y + x];
return ref.get_bad_value();
}
col_ref operator=(col_ref&& other) {
col_ref& me = *this;
@@ -90,7 +100,9 @@ public:
const_row_ref(const vector2d<Type, Alloc>& ref, size_t row) : ref(ref), y(row) {}
public:
const Type& operator[](size_t x) const {
return ref.data[ref.w * y + x];
if (x<ref.w)
return ref.data[ref.w * y + x];
return ref.get_bad_value();
}
};
class const_col_ref {
@@ -100,32 +112,50 @@ public:
const_col_ref(const vector2d<Type, Alloc>& ref, size_t col) : ref(ref), x(col) {}
public:
const Type& operator[](size_t y) const {
return ref.data[ref.w * y + x];
if (y<ref.h)
return ref.data[ref.w * y + x];
return ref.get_bad_value();
}
};
col_ref operator[](size_t x) {
return col_ref(*this, x);
if (x<w)
return col_ref(*this, x);
return get_bad_vector()[0];
}
const_col_ref operator[](size_t x) const {
return const_col_ref(*this, x);
if (x<w)
return const_col_ref(*this, x);
return get_bad_const_vector()[0];
}
col_ref col(size_t x) {
return col_ref(*this, x);
if (x<w)
return col_ref(*this, x);
return get_bad_vector()[0];
}
const_col_ref col(size_t x) const {
return const_col_ref(*this, x);
if (x<w)
return const_col_ref(*this, x);
return get_bad_const_vector()[0];
}
row_ref row(size_t x) {
return row_ref(*this, x);
row_ref row(size_t y) {
if (y<h)
return row_ref(*this, y);
return get_bad_vector().row(0);
}
const_row_ref row(size_t x) const {
return const_row_ref(*this, x);
const_row_ref row(size_t y) const {
if (y<h)
return const_row_ref(*this, y);
return get_bad_const_vector().row(0);
}
Type& operator()(size_t x, size_t y) {
return (*this)[x][y];
if (x<w && y<h)
return (*this)[x][y];
return get_bad_value();
}
const Type& operator()(size_t x, size_t y) const {
return (*this)[x][y];
if (x<w && y<h)
return (*this)[x][y];
return get_bad_value();
}
size_t width() const {
return w;
@@ -173,6 +203,32 @@ public:
vector2d(size_t w, size_t h) : w(w), h(h) {
resize(w,h);
}
Type &get_bad_value() {
static Type badValue;
badValue=get_default_value_function ? get_default_value_function() : Type(-1);
return badValue;
}
const Type &get_bad_value() const {
static Type badValue;
badValue = get_default_value_function ? get_default_value_function() : Type(-1);
return badValue;
}
vector2d &get_bad_vector() {
static vector2d bad_vector(1,1);
bad_vector.data[0]=get_bad_value();
bad_vector.set_get_default_function(get_default_value_function);
return bad_vector;
}
vector2d const &get_bad_const_vector() const {
static vector2d bad_vector(1,1);
bad_vector.data[0]=get_bad_value();
bad_vector.set_get_default_function(get_default_value_function);
return bad_vector;
}
void set_get_default_function(std::function<Type()> const &func) {
get_default_value_function=func;
}
};
#endif