diff --git a/osx/boe.specials.cpp b/osx/boe.specials.cpp index 90cae2d5..514db953 100644 --- a/osx/boe.specials.cpp +++ b/osx/boe.specials.cpp @@ -434,13 +434,6 @@ bool check_special_terrain(location where_check,eSpecCtx mode,short which_pc,sho } } //print_nums(1,which_pc,current_pc); -// if (mode == 2) { -// if (get_ran(1,1,100) <= ter_flag2){ -// if (ter_special == 5) -// poison_pc(which_pc,ter_flag1); -// else disease_pc(which_pc,ter_flag1); -// } -// } break; case eTerSpec::CALL_SPECIAL: { @@ -458,13 +451,6 @@ bool check_special_terrain(location where_check,eSpecCtx mode,short which_pc,sho can_enter = false; break; } -// case 13: // global special -// run_special(mode,0,ter_flag1,where_check,&s1,&s2,&s3); -// if (s1 > 0) -// can_enter = false; -// break; - - // Locked doors case eTerSpec::UNLOCKABLE: if (is_combat()) { // No lockpicking in combat @@ -3296,10 +3282,19 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, if(which_mode == eSpecCtx::SEE_MONST) *next_spec = spec.ex1c; break; + // Past here are special values that don't have an equivalent in eSpecCtx. case 100: // Look (town or out) if(which_mode == eSpecCtx::OUT_LOOK || which_mode == eSpecCtx::TOWN_LOOK) *next_spec = spec.ex1c; break; + case 101: // In boat + if(univ.party.in_boat >= 0) + *next_spec = spec.ex1c; + break; + case 102: // On horse + if(univ.party.in_horse >= 0) + *next_spec = spec.ex1c; + break; } if(j >= 0) *a = j; break; diff --git a/osx/classes/outdoors.cpp b/osx/classes/outdoors.cpp index 61f31371..644d72ce 100644 --- a/osx/classes/outdoors.cpp +++ b/osx/classes/outdoors.cpp @@ -11,6 +11,7 @@ #include #include +#include "dlogutil.h" #include "classes.h" #include "oldstructs.h" @@ -18,6 +19,18 @@ extern cScenario scenario; cOutdoors& cOutdoors::operator = (legacy::outdoor_record_type& old){ int i,j; + // Collect a list of unused special nodes, to be used for fixing specials that could be triggered in a boat. + std::vector unused_special_slots; + for(i = 0; i < 60; i++) { + if(specials[i].type == eSpecType::NONE && specials[i].jumpto == -1) { + // Also make sure no specials jump to it + bool is_free = true; + for(j = 0; j < 60; j++) { + if(specials[j].jumpto == i) is_free = false; + } + if(is_free) unused_special_slots.push_back(i); + } + } for(i = 0; i < 48; i++) for(j = 0; j < 48; j++){ terrain[i][j] = old.terrain[i][j]; @@ -51,6 +64,34 @@ cOutdoors& cOutdoors::operator = (legacy::outdoor_record_type& old){ terrain[i][j] = 38; } } + if(scenario.ter_types[terrain[i][j]].boat_over) { + // 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; i < 18; k++) { + if(i == special_locs[k].x && j == special_locs[k].y) { + found_spec = k; + break; + } + } + if(found_spec >= 0) { + if(!unused_special_slots.empty()) { + int found_spec_id = special_id[found_spec], use_slot = unused_special_slots.back(); + unused_special_slots.pop_back(); + cSpecial& node = specials[use_slot]; + node.type = eSpecType::IF_CONTEXT; + node.ex1a = 101; // if in boat + node.ex1c = -1; // do nothing + node.jumpto = found_spec_id; // else jump here + special_id[found_spec] = use_slot; + } else { + std::stringstream sout; + sout << "In outdoor section (" << x << ',' << y << ") at (" << i << ',' << j << "); special node ID "; + sout << special_id[found_spec]; + giveError("Warning: A special node was found that could be triggered from in a boat, which is probably not what the designer intended. An attempt to fix this has failed because there were not enough unused special nodes.", sout.str()); + } + } + } } for(i = 0; i < 18; i++){ special_locs[i].x = old.special_locs[i].x; diff --git a/osx/classes/outdoors.h b/osx/classes/outdoors.h index 83d7b6c9..86cd942e 100644 --- a/osx/classes/outdoors.h +++ b/osx/classes/outdoors.h @@ -47,6 +47,7 @@ public: cCreature& operator = (legacy::outdoor_creature_type old); }; + short x,y; // Used while loading legacy scenarios. ter_num_t terrain[48][48]; location special_locs[18]; unsigned short special_id[18]; diff --git a/osx/classes/regtown.cpp b/osx/classes/regtown.cpp index eca9d293..7a6735ed 100644 --- a/osx/classes/regtown.cpp +++ b/osx/classes/regtown.cpp @@ -11,16 +11,29 @@ #include #include +#include "dlogutil.h" #include "classes.h" #include "oldstructs.h" #include "fileio.h" extern cScenario scenario; -void cTinyTown::append(legacy::tiny_tr_type& old){ +void cTinyTown::append(legacy::tiny_tr_type& old, int town_num){ int i,j; cField the_field; the_field.type = 2; + // Collect a list of unused special nodes, to be used for fixing specials that could be triggered in a boat. + std::vector unused_special_slots; + for(i = 0; i < 100; i++) { + if(specials[i].type == eSpecType::NONE && specials[i].jumpto == -1) { + // Also make sure no specials jump to it + bool is_free = true; + for(j = 0; j < 100; j++) { + if(specials[j].jumpto == i) is_free = false; + } + if(is_free) unused_special_slots.push_back(i); + } + } for (i = 0; i < 32; i++) for (j = 0; j < 32; j++) { _terrain[i][j] = old.terrain[i][j]; @@ -30,6 +43,33 @@ void cTinyTown::append(legacy::tiny_tr_type& old){ the_field.loc.y = j; preset_fields.push_back(the_field); } + if(scenario.ter_types[_terrain[i][j]].boat_over) { + // 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; i < 50; k++) { + if(i == special_locs[k].x && j == special_locs[k].y) { + found_spec = k; + break; + } + } + if(found_spec >= 0) { + if(!unused_special_slots.empty()) { + int found_spec_id = spec_id[found_spec], use_slot = unused_special_slots.back(); + unused_special_slots.pop_back(); + cSpecial& node = specials[use_slot]; + node.type = eSpecType::IF_CONTEXT; + node.ex1a = 101; // if in boat + node.ex1c = -1; // do nothing + node.jumpto = found_spec_id; // else jump here + spec_id[found_spec] = use_slot; + } else { + std::stringstream sout; + sout << "In town \"" << town_num << "\" at (" << i << ',' << j << "); special node ID " << spec_id[found_spec]; + giveError("Warning: A special node was found that could be triggered from in a boat, which is probably not what the designer intended. An attempt to fix this has failed because there were not enough unused special nodes.", sout.str()); + } + } + } } for (i = 0; i < 16; i++) { _room_rect[i].top = old.room_rect[i].top; @@ -58,10 +98,22 @@ void cTinyTown::append(legacy::tiny_tr_type& old){ } } -void cMedTown::append(legacy::ave_tr_type& old){ +void cMedTown::append(legacy::ave_tr_type& old, int town_num){ int i,j; cField the_field; the_field.type = 2; + // Collect a list of unused special nodes, to be used for fixing specials that could be triggered in a boat. + std::vector unused_special_slots; + for(i = 0; i < 100; i++) { + if(specials[i].type == eSpecType::NONE && specials[i].jumpto == -1) { + // Also make sure no specials jump to it + bool is_free = true; + for(j = 0; j < 100; j++) { + if(specials[j].jumpto == i) is_free = false; + } + if(is_free) unused_special_slots.push_back(i); + } + } for (i = 0; i < 48; i++) for (j = 0; j < 48; j++) { _terrain[i][j] = old.terrain[i][j]; @@ -71,6 +123,33 @@ void cMedTown::append(legacy::ave_tr_type& old){ the_field.loc.y = j; preset_fields.push_back(the_field); } + if(scenario.ter_types[_terrain[i][j]].boat_over) { + // 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; i < 50; k++) { + if(i == special_locs[k].x && j == special_locs[k].y) { + found_spec = k; + break; + } + } + if(found_spec >= 0) { + if(!unused_special_slots.empty()) { + int found_spec_id = spec_id[found_spec], use_slot = unused_special_slots.back(); + unused_special_slots.pop_back(); + cSpecial& node = specials[use_slot]; + node.type = eSpecType::IF_CONTEXT; + node.ex1a = 101; // if in boat + node.ex1c = -1; // do nothing + node.jumpto = found_spec_id; // else jump here + spec_id[found_spec] = use_slot; + } else { + std::stringstream sout; + sout << "In town " << town_num << " at (" << i << ',' << j << "); special node ID " << spec_id[found_spec]; + giveError("Warning: A special node was found that could be triggered from in a boat, which is probably not what the designer intended. An attempt to fix this has failed because there were not enough unused special nodes.", sout.str()); + } + } + } } for (i = 0; i < 16; i++) { _room_rect[i].top = old.room_rect[i].top; @@ -99,10 +178,22 @@ void cMedTown::append(legacy::ave_tr_type& old){ } } -void cBigTown::append(legacy::big_tr_type& old){ +void cBigTown::append(legacy::big_tr_type& old, int town_num){ int i,j; cField the_field; the_field.type = 2; + // Collect a list of unused special nodes, to be used for fixing specials that could be triggered in a boat. + std::vector unused_special_slots; + for(i = 0; i < 100; i++) { + if(specials[i].type == eSpecType::NONE && specials[i].jumpto == -1) { + // Also make sure no specials jump to it + bool is_free = true; + for(j = 0; j < 100; j++) { + if(specials[j].jumpto == i) is_free = false; + } + if(is_free) unused_special_slots.push_back(i); + } + } for (i = 0; i < 64; i++) for (j = 0; j < 64; j++) { _terrain[i][j] = old.terrain[i][j]; @@ -112,6 +203,33 @@ void cBigTown::append(legacy::big_tr_type& old){ the_field.loc.y = j; preset_fields.push_back(the_field); } + if(scenario.ter_types[_terrain[i][j]].boat_over) { + // 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; i < 50; k++) { + if(i == special_locs[k].x && j == special_locs[k].y) { + found_spec = k; + break; + } + } + if(found_spec >= 0) { + if(!unused_special_slots.empty()) { + int found_spec_id = spec_id[found_spec], use_slot = unused_special_slots.back(); + unused_special_slots.pop_back(); + cSpecial& node = specials[use_slot]; + node.type = eSpecType::IF_CONTEXT; + node.ex1a = 101; // if in boat + node.ex1c = -1; // do nothing + node.jumpto = found_spec_id; // else jump here + spec_id[found_spec] = use_slot; + } else { + std::stringstream sout; + sout << "In town " << town_num << " at (" << i << ',' << j << "); special node ID " << spec_id[found_spec]; + giveError("Warning: A special node was found that could be triggered from in a boat, which is probably not what the designer intended. An attempt to fix this has failed because there were not enough unused special nodes.", sout.str()); + } + } + } } for (i = 0; i < 16; i++) { _room_rect[i].top = old.room_rect[i].top; diff --git a/osx/classes/regtown.h b/osx/classes/regtown.h index b1889c94..f220af25 100644 --- a/osx/classes/regtown.h +++ b/osx/classes/regtown.h @@ -29,7 +29,7 @@ protected: cCreature _creatures[60]; unsigned char _lighting[8][64]; public: - void append(legacy::big_tr_type& old); + void append(legacy::big_tr_type& old, int town_num); ter_num_t& terrain(size_t x, size_t y); rectangle& room_rect(size_t i); cCreature& creatures(size_t i); @@ -50,7 +50,7 @@ protected: cCreature _creatures[40]; unsigned char _lighting[6][48]; public: - void append(legacy::ave_tr_type& old); + void append(legacy::ave_tr_type& old, int town_num); ter_num_t& terrain(size_t x, size_t y); rectangle& room_rect(size_t i); cCreature& creatures(size_t i); @@ -71,7 +71,7 @@ protected: cCreature _creatures[30]; unsigned char _lighting[4][32]; public: - void append(legacy::tiny_tr_type& old); + void append(legacy::tiny_tr_type& old, int town_num); ter_num_t& terrain(size_t x, size_t y); rectangle& room_rect(size_t i); cCreature& creatures(size_t i); diff --git a/osx/classes/town.cpp b/osx/classes/town.cpp index a1c18047..1badcce9 100644 --- a/osx/classes/town.cpp +++ b/osx/classes/town.cpp @@ -14,9 +14,9 @@ #include "classes.h" #include "oldstructs.h" -void cTown::append(legacy::big_tr_type&){} -void cTown::append(legacy::ave_tr_type&){} -void cTown::append(legacy::tiny_tr_type&){} +void cTown::append(legacy::big_tr_type&, int town_num){} +void cTown::append(legacy::ave_tr_type&, int town_num){} +void cTown::append(legacy::tiny_tr_type&, int town_num){} cTown& cTown::operator = (legacy::town_record_type& old){ int i; diff --git a/osx/classes/town.h b/osx/classes/town.h index 2bcc4583..973e0964 100644 --- a/osx/classes/town.h +++ b/osx/classes/town.h @@ -111,9 +111,9 @@ public: cSpeech talking; virtual ~cTown(){} - virtual void append(legacy::big_tr_type& old); - virtual void append(legacy::ave_tr_type& old); - virtual void append(legacy::tiny_tr_type& old); + virtual void append(legacy::big_tr_type& old, int town_num); + virtual void append(legacy::ave_tr_type& old, int town_num); + virtual void append(legacy::tiny_tr_type& old, int town_num); virtual ter_num_t& terrain(size_t x, size_t y) = 0; virtual rectangle& room_rect(size_t i) = 0; virtual cCreature& creatures(size_t i) = 0; diff --git a/osx/tools/fileio.cpp b/osx/tools/fileio.cpp index 947abf2c..a5152ec7 100644 --- a/osx/tools/fileio.cpp +++ b/osx/tools/fileio.cpp @@ -263,7 +263,7 @@ static bool load_town_v1(short which_town, cTown*& the_town) { port_t_d(&t_d); the_town = new cBigTown; *the_town = store_town; - the_town->append(t_d); + the_town->append(t_d, which_town); break; case 1: @@ -272,7 +272,7 @@ static bool load_town_v1(short which_town, cTown*& the_town) { port_ave_t(&ave_t); the_town = new cMedTown; *the_town = store_town; - the_town->append(ave_t); + the_town->append(ave_t, which_town); break; case 2: @@ -281,7 +281,7 @@ static bool load_town_v1(short which_town, cTown*& the_town) { port_tiny_t(&tiny_t); the_town = new cTinyTown; *the_town = store_town; - the_town->append(tiny_t); + the_town->append(tiny_t, which_town); break; } @@ -606,6 +606,8 @@ static bool load_outdoors_v1(location which_out,cOutdoors& the_out){ return false; } + the_out.x = which_out.x; + the_out.y = which_out.y; port_out(&store_out); the_out = store_out; for (i = 0; i < 108; i++) {