From f4c9d98808fee4da4103b7ccb2810039cf227498 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Mon, 22 Dec 2014 23:34:28 -0500 Subject: [PATCH] Generalize the special node types dealing with fields. - IF_FIELDS (formerly IF_OBJECTS) can now deal with any kind of field (apart from special spots, which aren't technically a field but share some implementation details). - The twelve RECT_PLACE_XXX field nodes (well, one of them was RECT_CLEANSE) have been collapsed into one, allowing the placement of any kind of field (apart from special spots). In particular, antimagic fields can now be placed! (There wasn't a node for them before.) As a bonus, since it exists in the field type enum, RECT_PLACE_FIELDS can also smash fragile wall terrains (like the Move Mountains spell). --- osx/boe.specials.cpp | 176 ++++++++++++++++++++--------------- osx/classes/simpletypes.h | 26 +++--- osx/classes/special.cpp | 72 +++++++++++--- osx/tools/specials_parse.cpp | 8 +- 4 files changed, 174 insertions(+), 108 deletions(-) diff --git a/osx/boe.specials.cpp b/osx/boe.specials.cpp index f1a90c4f..ee6e80f8 100644 --- a/osx/boe.specials.cpp +++ b/osx/boe.specials.cpp @@ -2927,6 +2927,20 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, } } +static bool isValidField(int fld, bool allowSpecial) { + if(fld <= SPECIAL_EXPLORED) + return false; + if(fld == SPECIAL_SPOT) + return false; + if(fld >= WALL_FORCE && fld <= BARRIER_CAGE) + return true; + if(!allowSpecial) + return false; + if(fld == FIELD_DISPEL || fld == FIELD_SMASH) + return true; + return false; +} + // TODO: What was next_spec_type for? Is it still needed? void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, short *next_spec,short */*next_spec_type*/,short *a,short *b,short *redraw) { @@ -3052,18 +3066,49 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, if(calc_day() >= spec.ex1a) *next_spec = spec.ex1b; break; - case eSpecType::IF_OBJECTS: - if(spec.ex1a == 0) { - for(j = 0; j < univ.town->max_dim(); j++) - for(k = 0; k < univ.town->max_dim(); k++) - if(univ.town.is_barrel(j,k)) - *next_spec = spec.ex1b; - } else if(spec.ex1a == 1) { - for(j = 0; j < univ.town->max_dim(); j++) - for(k = 0; k < univ.town->max_dim(); k++) - if(univ.town.is_crate(j,k)) - *next_spec = spec.ex1b; + case eSpecType::IF_FIELDS: + if(!isValidField(spec.ex1a, false)) { + giveError("Scenario tried to check for invalid field type (1...24)"); + break; } + i = 0; + for(j = 0; j < univ.town->max_dim(); j++) + for(k = 0; k < univ.town->max_dim(); k++) { + switch(eFieldType(spec.ex1a)) { + // These values are not allowed + case SPECIAL_EXPLORED: case SPECIAL_SPOT: case FIELD_DISPEL: case FIELD_SMASH: break; + // Walls + case WALL_FIRE: i += univ.town.is_fire_wall(i,j); break; + case WALL_FORCE: i += univ.town.is_force_wall(i,j); break; + case WALL_ICE: i += univ.town.is_ice_wall(i,j); break; + case WALL_BLADES: i += univ.town.is_blade_wall(i,j); break; + // Clouds + case CLOUD_STINK: i += univ.town.is_scloud(i,j); break; + case CLOUD_SLEEP: i += univ.town.is_sleep_cloud(i,j); break; + // Advanced + case FIELD_QUICKFIRE: i += univ.town.is_quickfire(i,j); break; + case FIELD_ANTIMAGIC: i += univ.town.is_antimagic(i,j); break; + case BARRIER_FIRE: i += univ.town.is_fire_barr(i,j); break; + case BARRIER_FORCE: i += univ.town.is_force_barr(i,j); break; + case BARRIER_CAGE: i += univ.town.is_force_cage(i,j); break; + // Objects + case FIELD_WEB: i += univ.town.is_web(i,j); break; + case OBJECT_BARREL: i += univ.town.is_barrel(i,j); break; + case OBJECT_CRATE: i += univ.town.is_crate(i,j); break; + case OBJECT_BLOCK: i += univ.town.is_block(i,j); break; + // Sfx + case SFX_SMALL_BLOOD: i += univ.town.is_sm_blood(i,j); break; + case SFX_MEDIUM_BLOOD: i += univ.town.is_med_blood(i,j); break; + case SFX_LARGE_BLOOD: i += univ.town.is_lg_blood(i,j); break; + case SFX_SMALL_SLIME: i += univ.town.is_sm_slime(i,j); break; + case SFX_LARGE_SLIME: i += univ.town.is_lg_slime(i,j); break; + case SFX_ASH: i += univ.town.is_ash(i,j); break; + case SFX_BONES: i += univ.town.is_bones(i,j); break; + case SFX_RUBBLE: i += univ.town.is_rubble(i,j); break; + } + } + if(i > 0) + *next_spec = spec.ex1b; // TODO: Are there other object types to account for? // TODO: Allow restricting to a specific rect // TODO: Allow requiring a minimum and maximum number of objects @@ -3759,70 +3804,52 @@ void rect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, for(j = spec.ex1a; j <= spec.ex2a; j++) { l.x = i; l.y = j; switch(cur_node.type) { - case eSpecType::RECT_PLACE_FIRE: - if(get_ran(1,1,100) <= spec.sd1 ) - univ.town.set_fire_wall(i,j,true); - break; - case eSpecType::RECT_PLACE_FORCE: - if(get_ran(1,1,100) <= spec.sd1 ) - univ.town.set_force_wall(i,j,true); - break; - case eSpecType::RECT_PLACE_ICE: - if(get_ran(1,1,100) <= spec.sd1 ) - univ.town.set_ice_wall(i,j,true); - break; - case eSpecType::RECT_PLACE_BLADE: - if(get_ran(1,1,100) <= spec.sd1 ) - univ.town.set_blade_wall(i,j,true); - break; - case eSpecType::RECT_PLACE_SCLOUD: - if(get_ran(1,1,100) <= spec.sd1 ) - univ.town.set_scloud(i,j,true); - break; - case eSpecType::RECT_PLACE_SLEEP: - if(get_ran(1,1,100) <= spec.sd1 ) - univ.town.set_sleep_cloud(i,j,true); - break; - case eSpecType::RECT_PLACE_QUICKFIRE: - if(get_ran(1,1,100) <= spec.sd1 ) - univ.town.set_quickfire(i,j,true); - break; - case eSpecType::RECT_PLACE_FIRE_BARR: - if(get_ran(1,1,100) <= spec.sd1 ) - univ.town.set_fire_barr(i,j,true); - break; - case eSpecType::RECT_PLACE_FORCE_BARR: - if(get_ran(1,1,100) <= spec.sd1 ) - univ.town.set_force_barr(i,j,true); - break; - case eSpecType::RECT_CLEANSE: - if(spec.sd1 == 0) - dispel_fields(i,j,1); - else dispel_fields(i,j,2); - break; - case eSpecType::RECT_PLACE_SFX: - if(get_ran(1,1,100) <= spec.sd1 ) - switch(spec.sd2) { - case 0: univ.town.set_sm_blood(i,j,true); break; - case 1: univ.town.set_med_blood(i,j,true); break; - case 2: univ.town.set_lg_blood(i,j,true); break; - case 3: univ.town.set_sm_slime(i,j,true); break; - case 4: univ.town.set_lg_slime(i,j,true); break; - case 5: univ.town.set_ash(i,j,true); break; - case 6: univ.town.set_bones(i,j,true); break; - case 7: univ.town.set_rubble(i,j,true); break; - default: giveError("Invalid sfx type (0...7)"); - } - break; - case eSpecType::RECT_PLACE_OBJECT: - if(get_ran(1,1,100) <= spec.sd1 ) { - if(spec.sd2 == 0) - univ.town.set_web(i,j,true); - if(spec.sd2 == 1) - univ.town.set_barrel(i,j,true); - if(spec.sd2 == 2) - univ.town.set_crate(i,j,true); + case eSpecType::RECT_PLACE_FIELD: + if(!isValidField(spec.sd2, true)) { + giveError("Scenario tried to place an invalid field type (1...24)"); + goto END; // Break out of the switch AND both loops, but still handle messages } + if(spec.sd2 == FIELD_DISPEL || get_ran(1,1,100) <= spec.sd1) + switch(eFieldType(spec.sd2)) { + // These values are not allowed. + case SPECIAL_EXPLORED: case SPECIAL_SPOT: break; + // Walls + case WALL_FIRE: univ.town.set_fire_wall(i,j,true); break; + case WALL_FORCE: univ.town.set_force_wall(i,j,true); break; + case WALL_ICE: univ.town.set_ice_wall(i,j,true); break; + case WALL_BLADES: univ.town.set_blade_wall(i,j,true); break; + // Clouds + case CLOUD_STINK: univ.town.set_scloud(i,j,true); break; + case CLOUD_SLEEP: univ.town.set_sleep_cloud(i,j,true); break; + // Advanced + case FIELD_QUICKFIRE: univ.town.set_quickfire(i,j,true); break; + case FIELD_ANTIMAGIC: univ.town.set_antimagic(i,j,true); break; + case BARRIER_FIRE: univ.town.set_fire_barr(i,j,true); break; + case BARRIER_FORCE: univ.town.set_force_barr(i,j,true); break; + case BARRIER_CAGE: univ.town.set_force_cage(i,j,true); break; + // Cleanse + case FIELD_DISPEL: + if(spec.sd1 == 0) + dispel_fields(i,j,1); + else dispel_fields(i,j,2); + break; + // Objects + case FIELD_WEB: univ.town.set_web(i,j,true); break; + case OBJECT_BARREL: univ.town.set_barrel(i,j,true); break; + case OBJECT_CRATE: univ.town.set_crate(i,j,true); break; + case OBJECT_BLOCK: univ.town.set_block(i,j,true); break; + // Sfx + case SFX_SMALL_BLOOD: univ.town.set_sm_blood(i,j,true); break; + case SFX_MEDIUM_BLOOD: univ.town.set_med_blood(i,j,true); break; + case SFX_LARGE_BLOOD: univ.town.set_lg_blood(i,j,true); break; + case SFX_SMALL_SLIME: univ.town.set_sm_slime(i,j,true); break; + case SFX_LARGE_SLIME: univ.town.set_lg_slime(i,j,true); break; + case SFX_ASH: univ.town.set_ash(i,j,true); break; + case SFX_BONES: univ.town.set_bones(i,j,true); break; + case SFX_RUBBLE: univ.town.set_rubble(i,j,true); break; + // Special value: Move Mountains! + case FIELD_SMASH: crumble_wall(loc(i,j)); break; + } break; case eSpecType::RECT_MOVE_ITEMS: for(k = 0; k < NUM_TOWN_ITEMS; k++) @@ -3880,6 +3907,7 @@ void rect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, } } } +END: if(check_mess) { handle_message(which_mode,cur_spec_type,cur_node.m1,cur_node.m2,a,b); } diff --git a/osx/classes/simpletypes.h b/osx/classes/simpletypes.h index 19c52d34..e7e74f43 100644 --- a/osx/classes/simpletypes.h +++ b/osx/classes/simpletypes.h @@ -662,7 +662,7 @@ enum class eSpecType { IF_HAVE_ITEM_CLASS_AND_TAKE = 145, IF_EQUIP_ITEM_CLASS_AND_TAKE = 146, IF_DAY_REACHED = 147, - IF_OBJECTS = 148, + IF_FIELDS = 148, IF_PARTY_SIZE = 149, IF_EVENT_OCCURRED = 150, IF_SPECIES = 151, @@ -700,18 +700,18 @@ enum class eSpecType { TOWN_TIMER_START = 195, TOWN_CHANGE_LIGHTING = 196, TOWN_SET_ATTITUDE = 197, - RECT_PLACE_FIRE = 200, - RECT_PLACE_FORCE = 201, - RECT_PLACE_ICE = 202, - RECT_PLACE_BLADE = 203, - RECT_PLACE_SCLOUD = 204, - RECT_PLACE_SLEEP = 205, - RECT_PLACE_QUICKFIRE = 206, - RECT_PLACE_FIRE_BARR = 207, - RECT_PLACE_FORCE_BARR = 208, - RECT_CLEANSE = 209, - RECT_PLACE_SFX = 210, - RECT_PLACE_OBJECT = 211, // place barrels, etc + RECT_PLACE_FIELD = 200, + UNUSED2 = 201, + UNUSED3 = 202, + UNUSED4 = 203, + UNUSED5 = 204, + UNUSED6 = 205, + UNUSED7 = 206, + UNUSED8 = 207, + UNUSED9 = 208, + UNUSED10 = 209, + UNUSED11 = 210, + UNUSED12 = 211, RECT_MOVE_ITEMS = 212, RECT_DESTROY_ITEMS = 213, RECT_CHANGE_TER = 214, diff --git a/osx/classes/special.cpp b/osx/classes/special.cpp index 7fa24ddc..3a9f297e 100644 --- a/osx/classes/special.cpp +++ b/osx/classes/special.cpp @@ -72,8 +72,8 @@ void cSpecial::append(legacy::special_node_type& old){ ex1b = 1; // Meaning give spell, not take break; case 148: case 149: // if barrels or crates - type = eSpecType::IF_OBJECTS; - ex1a = old.type - 148; + type = eSpecType::IF_FIELDS; + ex1a = old.type == 148 ? OBJECT_BARREL : OBJECT_CRATE; break; case 151: case 152: // if has cave lore or woodsman type = eSpecType::IF_TRAIT; @@ -98,6 +98,59 @@ void cSpecial::append(legacy::special_node_type& old){ if(ex1b == 1 || ex1b == 2) ex1a += 30; break; + // Place fields (twelve individual node types were collapsed into one) + case 200: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = WALL_FIRE; + break; + case 201: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = WALL_FORCE; + break; + case 202: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = WALL_ICE; + break; + case 203: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = WALL_BLADES; + break; + case 204: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = CLOUD_STINK; + break; + case 205: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = CLOUD_SLEEP; + break; + case 206: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = FIELD_QUICKFIRE; + break; + case 207: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = BARRIER_FIRE; + break; + case 208: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = BARRIER_FORCE; + break; + case 209: + type = eSpecType::RECT_PLACE_FIELD; + sd2 = FIELD_DISPEL; + break; + case 210: + type = eSpecType::RECT_PLACE_FIELD; + sd2 += SFX_SMALL_BLOOD; + break; + case 211: + type = eSpecType::RECT_PLACE_FIELD; + switch(old.sd2) { + case 0: sd2 = FIELD_WEB; break; + case 1: sd2 = OBJECT_BARREL; break; + case 2: sd2 = OBJECT_CRATE; break; + } + break; // These are ones that were added in the Windows version but only recently added to the Mac version. case 28: type = eSpecType::DISPLAY_PICTURE; @@ -257,7 +310,7 @@ const std::map allNodeProps = { {eSpecType::IF_HAVE_ITEM_CLASS_AND_TAKE, {ex1b_ch = true,jmp_lbl = 3}}, {eSpecType::IF_EQUIP_ITEM_CLASS_AND_TAKE, {ex1b_ch = true,jmp_lbl = 3}}, {eSpecType::IF_DAY_REACHED, {ex1b_ch = true,jmp_lbl = 3}}, - {eSpecType::IF_OBJECTS, {ex1b_ch = true,jmp_lbl = 3}}, + {eSpecType::IF_FIELDS, {ex1b_ch = true,jmp_lbl = 3}}, {eSpecType::IF_EVENT_OCCURRED, {ex1b_ch = true,jmp_lbl = 3}}, {eSpecType::IF_SPECIES, {ex1b_ch = true,jmp_lbl = 3}}, {eSpecType::IF_TRAIT, {ex1b_ch = true,jmp_lbl = 3}}, @@ -291,18 +344,7 @@ const std::map allNodeProps = { {eSpecType::TOWN_SPLIT_PARTY, {msg_lbl = 1}}, {eSpecType::TOWN_REUNITE_PARTY, {msg_lbl = 1}}, {eSpecType::TOWN_TIMER_START, {ex1b_ch = true,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_FIRE, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_FORCE, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_ICE, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_BLADE, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_SCLOUD, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_SLEEP, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_QUICKFIRE, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_FIRE_BARR, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_FORCE_BARR, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_CLEANSE, {sdf_lbl = 2,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_SFX, {sdf_lbl = 7,msg_lbl = 1}}, - {eSpecType::RECT_PLACE_OBJECT, {sdf_lbl = 8,msg_lbl = 1}}, + {eSpecType::RECT_PLACE_FIELD, {sdf_lbl = 2,msg_lbl = 1}}, {eSpecType::RECT_MOVE_ITEMS, {sdf_lbl = 4,msg_lbl = 1}}, {eSpecType::RECT_DESTROY_ITEMS, {msg_lbl = 1}}, {eSpecType::RECT_CHANGE_TER, {sdf_lbl = 5,msg_lbl = 1}}, diff --git a/osx/tools/specials_parse.cpp b/osx/tools/specials_parse.cpp index 56500433..72f82757 100644 --- a/osx/tools/specials_parse.cpp +++ b/osx/tools/specials_parse.cpp @@ -127,8 +127,7 @@ struct initer { ("if-item-class", eSpecType::IF_HAVE_ITEM_CLASS_AND_TAKE) ("if-item-class-equip", eSpecType::IF_EQUIP_ITEM_CLASS_AND_TAKE) ("if-day", eSpecType::IF_DAY_REACHED) -// ("if-field", eSpecType::IF_BARRELS) - ("if-object", eSpecType::IF_OBJECTS) + ("if-field", eSpecType::IF_FIELDS) ("if-event", eSpecType::IF_EVENT_OCCURRED) ("if-trait", eSpecType::IF_TRAIT) ("if-species", eSpecType::IF_SPECIES) @@ -161,10 +160,7 @@ struct initer { ("split-party", eSpecType::TOWN_SPLIT_PARTY) ("unite-party", eSpecType::TOWN_REUNITE_PARTY) ("start-timer-town", eSpecType::TOWN_TIMER_START) - ("rect-place-field", eSpecType::RECT_PLACE_BLADE) - ("rect-cleanse", eSpecType::RECT_CLEANSE) - ("rect-place-sfx", eSpecType::RECT_PLACE_SFX) - ("rect-place-object", eSpecType::RECT_PLACE_OBJECT) + ("rect-place-field", eSpecType::RECT_PLACE_FIELD) ("rect-move-items", eSpecType::RECT_MOVE_ITEMS) ("rect-destroy-items", eSpecType::RECT_DESTROY_ITEMS) ("rect-change-ter", eSpecType::RECT_CHANGE_TER)