Stuff about force cages, stone blocks, move mountains
- Add all objects, fields, and sfx to place_spell_pattern - Add move mountains effect to place_spell_pattern - Most of the implementation for force cages and stone blocks is now done (still untested) - Properly implement MOVE_MOUNTAINS_MASS spell
This commit is contained in:
@@ -2946,6 +2946,11 @@ bool town_move_party(location destination,short forced)////
|
||||
ter_num_t ter;
|
||||
bool check_f = false;
|
||||
|
||||
if(univ.town.is_force_cage(univ.town.p_loc.x, univ.town.p_loc.y)) {
|
||||
add_string_to_buf("Move: Can't escape.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (in_scen_debug && ghost_mode)
|
||||
forced = true;
|
||||
|
||||
|
@@ -420,7 +420,14 @@ bool pc_combat_move(location destination) ////
|
||||
location monst_loc,store_loc;
|
||||
short spec_num;
|
||||
|
||||
if (monst_there(destination) > univ.town->max_monst())
|
||||
monst_hit = monst_there(destination);
|
||||
|
||||
if(monst_hit > univ.town->max_monst() && univ.party[current_pc].status[eStatus::FORCECAGE] > 0) {
|
||||
add_string_to_buf("Move: Can't escape.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(monst_hit > univ.town->max_monst())
|
||||
keep_going = check_special_terrain(destination,eSpecCtx::COMBAT_MOVE,current_pc,&spec_num,&check_f);
|
||||
if (check_f == true)
|
||||
forced = true;
|
||||
@@ -451,7 +458,7 @@ bool pc_combat_move(location destination) ////
|
||||
add_string_to_buf(create_line);
|
||||
return true;
|
||||
}
|
||||
else if ((monst_hit = monst_there(destination)) <= univ.town->max_monst()) {
|
||||
else if(monst_hit <= univ.town->max_monst()) {
|
||||
// s2 = 2 here appears to mean "go ahead and attack", while s2 = 1 means "cancel attack".
|
||||
// Then s1 % 2 == 1 means the monster is hostile to the party.
|
||||
s1 = univ.town.monst[monst_hit].attitude;
|
||||
@@ -3734,6 +3741,45 @@ static void place_spell_pattern(effect_pat_type pat,location center,unsigned sho
|
||||
case CLOUD_SLEEP:
|
||||
sleep_cloud_space(i,j);
|
||||
break;
|
||||
case FIELD_SMASH:
|
||||
crumble_wall(loc(i,j));
|
||||
break;
|
||||
case OBJECT_CRATE:
|
||||
univ.town.set_crate(i,j,true);
|
||||
break;
|
||||
case OBJECT_BARREL:
|
||||
univ.town.set_barrel(i,j,true);
|
||||
break;
|
||||
case OBJECT_BLOCK:
|
||||
univ.town.set_block(i,j,true);
|
||||
break;
|
||||
case BARRIER_CAGE:
|
||||
univ.town.set_force_cage(i, j, true);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
draw_terrain(0);
|
||||
@@ -3767,6 +3813,13 @@ static void place_spell_pattern(effect_pat_type pat,location center,unsigned sho
|
||||
r1 = get_ran(4,1,8);
|
||||
damage_pc(k,r1,DAMAGE_WEAPON,eRace::UNKNOWN,0);
|
||||
break;
|
||||
case OBJECT_BLOCK:
|
||||
r1 = get_ran(6,1,8);
|
||||
damage_pc(k,r1,DAMAGE_WEAPON,eRace::UNKNOWN,0);
|
||||
break;
|
||||
case BARRIER_CAGE:
|
||||
univ.party[k].status[eStatus::FORCECAGE] = 8;
|
||||
break;
|
||||
default:
|
||||
eDamageType type = DAMAGE_MARKED;
|
||||
unsigned short dice;
|
||||
@@ -3856,6 +3909,13 @@ static void place_spell_pattern(effect_pat_type pat,location center,unsigned sho
|
||||
which_m = &univ.town.monst[k];
|
||||
charm_monst(which_m,0,eStatus::ASLEEP,3);
|
||||
break;
|
||||
case OBJECT_BLOCK:
|
||||
r1 = get_ran(6,1,8);
|
||||
damage_monst(k,who_hit,r1,0,DAMAGE_WEAPON,0);
|
||||
break;
|
||||
case BARRIER_CAGE:
|
||||
univ.town.monst[k].status[eStatus::FORCECAGE] = 8;
|
||||
break;
|
||||
default:
|
||||
eDamageType type = DAMAGE_MARKED;
|
||||
unsigned short dice;
|
||||
@@ -4188,8 +4248,12 @@ bool hit_end_c_button()
|
||||
if (which_combat_type == 0) {
|
||||
end_ok = out_monst_all_dead();
|
||||
}
|
||||
// if (univ.party[0].extra[7] > 0)
|
||||
// end_ok = true;
|
||||
for(int i = 0; i < 6; i++) {
|
||||
if(univ.party[i].status[eStatus::FORCECAGE] > 0) {
|
||||
add_string_to_buf(" Someone trapped.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (end_ok == true)
|
||||
end_combat();
|
||||
@@ -4695,6 +4759,33 @@ void spell_cast_hit_return()
|
||||
}
|
||||
}
|
||||
|
||||
static void process_force_cage(location loc, short i) {
|
||||
if(i >= 100) {
|
||||
short m = i - 100;
|
||||
cCreature& which_m = univ.town.monst[m];
|
||||
if(which_m.attitude % 2 == 1 && get_ran(1,1,100) < which_m.mu * 10 + which_m.cl * 4 + 5) {
|
||||
play_sound(60);
|
||||
monst_spell_note(m, 50);
|
||||
univ.town.set_force_cage(loc.x,loc.y,false);
|
||||
which_m.status[eStatus::FORCECAGE] = 0;
|
||||
} else which_m.status[eStatus::FORCECAGE] = 8;
|
||||
} else if(i < 0) {
|
||||
if(get_ran(1,1,100) < 35)
|
||||
univ.town.set_force_cage(loc.x,loc.y,false);
|
||||
} else if(i < 6) {
|
||||
cPlayer& who = univ.party[i];
|
||||
// We want to make sure everyone has a chance of eventually breaking a cage, because it never ends on its own,
|
||||
// and because being trapped unconditionally prevents you from ending combat mode.
|
||||
short bonus = 5 + who.skills[eSkill::MAGE_LORE];
|
||||
if(get_ran(1,1,100) < who.skills[eSkill::MAGE_SPELLS]*10 + who.skills[eSkill::PRIEST_SPELLS]*4 + bonus) {
|
||||
play_sound(60);
|
||||
add_string_to_buf(" " + who.name + " breaks force cage.");
|
||||
univ.town.set_force_cage(loc.x,loc.y,false);
|
||||
who.status[eStatus::FORCECAGE] = 0;
|
||||
} else who.status[eStatus::FORCECAGE] = 8;
|
||||
}
|
||||
}
|
||||
|
||||
void process_fields()
|
||||
{
|
||||
short i,j,k,r1;
|
||||
@@ -4791,6 +4882,15 @@ void process_fields()
|
||||
if (r1 == 1)
|
||||
univ.town.set_blade_wall(i,j,false);
|
||||
}
|
||||
if(univ.town.is_force_cage(i,j)) {
|
||||
loc.x = i; loc.y = j;
|
||||
short m = monst_there(loc);
|
||||
if(m == 90) {
|
||||
short pc = pc_there(loc);
|
||||
if(pc == 6) process_force_cage(loc, -1);
|
||||
else process_force_cage(loc, pc);
|
||||
} else process_force_cage(loc, 100 + m);
|
||||
}
|
||||
}
|
||||
|
||||
processing_fields = false;
|
||||
|
@@ -22,15 +22,6 @@
|
||||
#define NUM_OF_BOATS 30
|
||||
#define NUM_OF_HORSES 30
|
||||
|
||||
#define SFX_SMALL_BLOOD 1
|
||||
#define SFX_MEDIUM_BLOOD 2
|
||||
#define SFX_LARGE_BLOOD 4
|
||||
#define SFX_SMALL_SLIME 8
|
||||
#define SFX_BIG_SLIME 16
|
||||
#define SFX_ASH 32
|
||||
#define SFX_BONES 64
|
||||
#define SFX_RUBBLE 128
|
||||
|
||||
/* stuff done flags */
|
||||
#define SDF_SPEC_LOC_X 301][0 // For special nodes to access the trigger location
|
||||
#define SDF_SPEC_LOC_Y 301][1
|
||||
|
@@ -346,6 +346,9 @@ bool is_blocked(location to_check)
|
||||
if (univ.town.is_force_barr(to_check.x,to_check.y))
|
||||
return true;
|
||||
|
||||
if(univ.town.is_force_cage(to_check.x,to_check.y))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@@ -724,6 +724,8 @@ bool try_move(short i,location start,short x,short y)
|
||||
dest.x = dest.x + x;
|
||||
dest.y = dest.y + y;
|
||||
|
||||
if((overall_mode == MODE_TOWN || overall_mode == MODE_COMBAT) && univ.town.is_force_cage(start.x,start.y))
|
||||
return false;
|
||||
|
||||
if (overall_mode == MODE_TOWN)
|
||||
return town_move_monster(i,dest);
|
||||
@@ -909,6 +911,9 @@ void monst_inflict_fields(short which_monst)
|
||||
damage_monst(which_monst,7,r1,0,DAMAGE_FIRE,0);
|
||||
break;
|
||||
}
|
||||
if(univ.town.is_force_cage(where_check.x,where_check.y))
|
||||
univ.town.monst[which_monst].status[eStatus::FORCECAGE] = 8;
|
||||
else univ.town.monst[which_monst].status[eStatus::FORCECAGE] = 0;
|
||||
}
|
||||
if (univ.town.monst[which_monst].active > 0)
|
||||
for (i = 0; i < univ.town.monst[which_monst].x_width; i++)
|
||||
@@ -1011,7 +1016,7 @@ bool monst_check_special_terrain(location where_check,short mode,short which_mon
|
||||
if (univ.town.is_fire_barr(where_check.x,where_check.y)) {
|
||||
if ((which_m->attitude % 2 == 1) && (get_ran(1,1,100) < (which_m->mu * 10 + which_m->cl * 4))) {
|
||||
play_sound(60);
|
||||
add_string_to_buf("Monster breaks barrier.");
|
||||
monst_spell_note(which_monst, 49);
|
||||
univ.town.set_fire_barr(where_check.x,where_check.y,false);
|
||||
}
|
||||
else {
|
||||
@@ -1025,11 +1030,12 @@ bool monst_check_special_terrain(location where_check,short mode,short which_mon
|
||||
if ((which_m->attitude % 2 == 1) && (get_ran(1,1,100) < (which_m->mu * 10 + which_m->cl * 4))
|
||||
&& (!univ.town->strong_barriers)) {
|
||||
play_sound(60);
|
||||
add_string_to_buf("Monster breaks barrier.");
|
||||
monst_spell_note(which_monst, 49);
|
||||
univ.town.set_force_barr(where_check.x,where_check.y,false);
|
||||
}
|
||||
else can_enter = false;
|
||||
}
|
||||
if(univ.town.is_force_cage(where_check.x,where_check.y)) can_enter = false;
|
||||
if (univ.town.is_crate(where_check.x,where_check.y)) {
|
||||
if (monster_placid(which_monst))
|
||||
can_enter = false;
|
||||
@@ -1364,7 +1370,7 @@ bool summon_monster(m_num_t which,location where,short duration,short given_atti
|
||||
if (where.x == 0)
|
||||
return false;
|
||||
}
|
||||
if ((univ.town.is_barrel(where.x,where.y)) || (univ.town.is_crate(where.x,where.y)))
|
||||
if(univ.town.is_barrel(where.x,where.y) || univ.town.is_crate(where.x,where.y) || univ.town.is_block(where.x,where.y))
|
||||
return false;
|
||||
loc = where;
|
||||
}
|
||||
|
@@ -1732,8 +1732,9 @@ void cast_town_spell(location where) ////
|
||||
place_spell_pattern(current_pat,where,FIELD_DISPEL,7);
|
||||
break;
|
||||
case eSpell::MOVE_MOUNTAINS:
|
||||
case eSpell::MOVE_MOUNTAINS_MASS:
|
||||
add_string_to_buf(" You blast the area. ");
|
||||
crumble_wall(where);
|
||||
place_spell_pattern(current_pat, where, FIELD_SMASH, 7);
|
||||
update_explored(univ.town.p_loc);
|
||||
break;
|
||||
case eSpell::BARRIER_FIRE:
|
||||
@@ -1816,6 +1817,9 @@ void cast_town_spell(location where) ////
|
||||
play_sound(41);
|
||||
add_string_to_buf(" Didn't work. ");
|
||||
}
|
||||
} else if(univ.town.is_force_cage(where.x,where.y)) {
|
||||
add_string_to_buf(" Cage broken.");
|
||||
univ.town.set_force_cage(where.x,where.y,false);
|
||||
}
|
||||
|
||||
else add_string_to_buf(" No barrier there.");
|
||||
@@ -1950,6 +1954,9 @@ void dispel_fields(short i,short j,short mode)
|
||||
r1 = get_ran(1,1,7) + mode;
|
||||
if (r1 < 5)
|
||||
univ.town.set_blade_wall(i,j,false);
|
||||
r1 = get_ran(1,1,12) + mode;
|
||||
if(r1 < 3)
|
||||
univ.town.set_force_cage(i,j,false);
|
||||
}
|
||||
|
||||
bool pc_can_cast_spell(short pc_num,eSkill type) {
|
||||
|
@@ -220,6 +220,10 @@ bool check_special_terrain(location where_check,eSpecCtx mode,short which_pc,sho
|
||||
add_string_to_buf(" Magic barrier! ");
|
||||
return false;
|
||||
}
|
||||
if(univ.town.is_force_cage(where_check.x,where_check.y)) {
|
||||
add_string_to_buf(" Force cage!");
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < 50; i++)
|
||||
if (where_check == univ.town->special_locs[i]) {
|
||||
if(univ.town->specials[univ.town->spec_id[i]].type == eSpecType::SECRET_PASSAGE) {
|
||||
@@ -273,6 +277,10 @@ bool check_special_terrain(location where_check,eSpecCtx mode,short which_pc,sho
|
||||
add_string_to_buf(" Magic barrier! ");
|
||||
can_enter = false;
|
||||
}
|
||||
if (univ.town.is_force_cage(where_check.x,where_check.y)) {
|
||||
add_string_to_buf(" Force cage! ");
|
||||
can_enter = false;
|
||||
}
|
||||
if (univ.town.is_crate(where_check.x,where_check.y)) {
|
||||
add_string_to_buf(" You push the crate.");
|
||||
to_loc = push_loc(from_loc,where_check);
|
||||
@@ -295,6 +303,13 @@ bool check_special_terrain(location where_check,eSpecCtx mode,short which_pc,sho
|
||||
&& (univ.town.items[i].contained))
|
||||
univ.town.items[i].item_loc = to_loc;
|
||||
}
|
||||
if(univ.town.is_block(where_check.x,where_check.y)) {
|
||||
add_string_to_buf(" You push the stone block.");
|
||||
to_loc = push_loc(from_loc,where_check);
|
||||
univ.town.set_block(where_check.x,where_check.y,false);
|
||||
if(to_loc.x > 0)
|
||||
univ.town.set_block(to_loc.x,to_loc.y,false);
|
||||
}
|
||||
}
|
||||
|
||||
switch (ter_special) {
|
||||
@@ -575,6 +590,11 @@ void check_fields(location where_check,eSpecCtx mode,short which_pc)
|
||||
if (overall_mode < MODE_COMBAT)
|
||||
boom_space(univ.party.p_loc,overall_mode,1,r1,12);
|
||||
}
|
||||
if(univ.town.is_force_cage(where_check.x,where_check.y)) {
|
||||
if(univ.party[which_pc].status[eStatus::FORCECAGE] == 0)
|
||||
add_string_to_buf(" Trapped in force cage!");
|
||||
univ.party[which_pc].status[eStatus::FORCECAGE] = 8;
|
||||
} else univ.party[which_pc].status[eStatus::FORCECAGE] = 0;
|
||||
fast_bang = 0;
|
||||
}
|
||||
|
||||
@@ -1776,7 +1796,7 @@ void push_things()////
|
||||
}
|
||||
if (univ.town.is_block(univ.town.p_loc.x,univ.town.p_loc.y)) {
|
||||
ASB("You crash into the block.");
|
||||
hit_party(get_ran(1, 1, 6), DAMAGE_UNBLOCKABLE);
|
||||
hit_party(get_ran(1, 1, 6), DAMAGE_WEAPON);
|
||||
}
|
||||
for (k = 0; k < NUM_TOWN_ITEMS; k++)
|
||||
if(univ.town.items[k].variety != eItemType::NO_ITEM && univ.town.items[k].contained
|
||||
@@ -1814,7 +1834,7 @@ void push_things()////
|
||||
}
|
||||
if (univ.town.is_block(univ.town.p_loc.x,univ.town.p_loc.y)) {
|
||||
ASB("You crash into the block.");
|
||||
damage_pc(i,get_ran(1, 1, 6), DAMAGE_UNBLOCKABLE,eRace::UNKNOWN,0);
|
||||
damage_pc(i,get_ran(1, 1, 6), DAMAGE_WEAPON,eRace::UNKNOWN,0);
|
||||
}
|
||||
for (k = 0; k < NUM_TOWN_ITEMS; k++)
|
||||
if(univ.town.items[k].variety != eItemType::NO_ITEM && univ.town.items[k].contained
|
||||
@@ -3035,6 +3055,7 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
|
||||
}
|
||||
// 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
|
||||
break;
|
||||
case eSpecType::IF_PARTY_SIZE:
|
||||
if (spec.ex2a < 1) {
|
||||
|
@@ -1191,6 +1191,12 @@ void monst_spell_note(m_num_t number,short which_mess)
|
||||
case 48:
|
||||
msg = " " + msg + " cleans off acid.";
|
||||
break;
|
||||
case 49:
|
||||
msg = " " + msg + " breaks barrier.";
|
||||
break;
|
||||
case 50:
|
||||
msg = " " + msg + " breaks force cage.";
|
||||
break;
|
||||
}
|
||||
|
||||
if (which_mess > 0)
|
||||
|
@@ -791,6 +791,7 @@ enum eEncNoteType {
|
||||
NOTE_MONST,
|
||||
};
|
||||
|
||||
// This is a slight misnomer, as a couple of these are not true fields.
|
||||
enum eFieldType {
|
||||
FIELD_NONE = 0,
|
||||
FIELD_WEB = 1,
|
||||
@@ -803,9 +804,22 @@ enum eFieldType {
|
||||
WALL_ICE = 8,
|
||||
WALL_BLADES = 9,
|
||||
FIELD_QUICKFIRE = 10,
|
||||
FIELD_DISPEL = 11,
|
||||
FIELD_DISPEL = 11, // Dispel field
|
||||
CLOUD_SLEEP = 12,
|
||||
// TODO: Sfx fields, objects
|
||||
OBJECT_CRATE = 13,
|
||||
OBJECT_BARREL = 14,
|
||||
BARRIER_CAGE = 15,
|
||||
OBJECT_BLOCK = 16,
|
||||
FIELD_SMASH = 17, // Move Mountains
|
||||
SFX_SMALL_BLOOD = 18,
|
||||
SFX_MEDIUM_BLOOD = 19,
|
||||
SFX_LARGE_BLOOD = 20,
|
||||
SFX_SMALL_SLIME = 21,
|
||||
SFX_LARGE_SLIME = 22,
|
||||
SFX_ASH = 23,
|
||||
SFX_BONES = 24,
|
||||
SFX_RUBBLE = 25,
|
||||
SFX_SPECIAL = 26, // Special spot
|
||||
};
|
||||
|
||||
enum class eSpell {
|
||||
|
Reference in New Issue
Block a user