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).
This commit is contained in:
2014-12-22 23:34:28 -05:00
parent fb1f97e2f1
commit f4c9d98808
4 changed files with 174 additions and 108 deletions

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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<eSpecType, node_properties_t> 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<eSpecType, node_properties_t> 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}},

View File

@@ -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)