Changes to split party implementation

- Supports playing arbitrary sound along with the split (rather than just teleport sound or no sound)
- Correctly imported from older save files
- Support for splitting off an arbitrary subgroup of the party rather than just a single PC (though the special node doesn't yet allow this)
- Support for leaving town while split - if you leave town, the absent PC's items are not dropped on the ground when later entering a town
- Option to not change location when reuniting
- If you reunite in a different town than you started, you are returned to the town you split from
This commit is contained in:
2015-01-16 01:26:46 -05:00
parent 5d9fd3cb5d
commit 71ce8946a0
9 changed files with 74 additions and 60 deletions

View File

@@ -896,7 +896,12 @@ static void handle_party_death() {for(int i = 0; i < 6; i++)
}
}
if(univ.party.is_split()) {
ASB(univ.party.end_split(0));
univ.party.end_split(0);
if(univ.party.left_in == size_t(-1) || univ.town.num == univ.party.left_in) {
univ.town.p_loc = univ.party.left_at;
update_explored(univ.town.p_loc);
center = univ.town.p_loc;
} else change_level(univ.party.left_in, univ.party.left_at.x, univ.party.left_at.y);
update_explored(univ.town.p_loc);
center = univ.town.p_loc;
if(is_combat()) overall_mode = MODE_TOWN;

View File

@@ -25,11 +25,6 @@
/* 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
//#define SDF_IS_PARTY_SPLIT 304][0
//#define SDF_PARTY_SPLIT_X 304][1
//#define SDF_PARTY_SPLIT_Y 304][2
//#define SDF_PARTY_SPLIT_PC 304][3
//#define SDF_PARTY_SPLIT_TOWN 304][4 // for future use, hopefully
#define SDF_SKIP_STARTUP 305][4 // preferably deprecated
#define SDF_LESS_SOUND 305][5
#define SDF_NO_TARGET_LINE 305][6

View File

@@ -3713,7 +3713,8 @@ void townmode_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
if(r1 != 6) {
current_pc = r1;
*next_spec = -1;
ASB(univ.party.start_split(spec.ex1a,spec.ex1b,spec.ex2a,r1));
if(!univ.party.start_split(spec.ex1a,spec.ex1b,spec.ex2a,r1))
ASB("Party already split!");
update_explored(univ.town.p_loc);
center = univ.town.p_loc;
}
@@ -3728,9 +3729,15 @@ void townmode_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
*a = 1;
*next_spec = -1;
check_mess = false;
ASB(univ.party.end_split(spec.ex1a));
update_explored(univ.town.p_loc);
center = univ.town.p_loc;
if(univ.party.end_split(spec.ex1a))
ASB("Party already together!");
else ASB("You are reunited.");
if(spec.ex2a); // This means reunite the party by bringing the others to the current location rather than the reverse.
else if(univ.party.left_in == size_t(-1) || univ.town.num == univ.party.left_in) {
univ.town.p_loc = univ.party.left_at;
update_explored(univ.town.p_loc);
center = univ.town.p_loc;
} else change_level(univ.party.left_in, univ.party.left_at.x, univ.party.left_at.y);
break;
case eSpecType::TOWN_TIMER_START:
univ.party.start_timer(spec.ex1a, spec.ex1b, 1);

View File

@@ -481,12 +481,15 @@ void start_town_mode(short which_town, short entry_dir) {
update_explored(univ.town.p_loc);
// If a PC dead, drop his items
for(m = 0; m < 6; m++)
for(m = 0; m < 6; m++) {
if(univ.party[m].main_status == eMainStatus::ALIVE || isSplit(univ.party[m].main_status))
continue;
for(n = 0; n < 24; n++)
if(univ.party[m].main_status != eMainStatus::ALIVE && univ.party[m].items[n].variety != eItemType::NO_ITEM) {
if(univ.party[m].items[n].variety != eItemType::NO_ITEM) {
place_item(univ.party[m].items[n],univ.town.p_loc,true);
univ.party[m].items[n].variety = eItemType::NO_ITEM;
}
}
for(i = 0; i < univ.town->max_monst(); i++) {
univ.town.monst[i].targ_loc.x = 0;

View File

@@ -70,6 +70,10 @@ void cParty::append(legacy::party_record_type& old){
p_loc.y = old.p_loc.y;
loc_in_sec.x = old.loc_in_sec.x;
loc_in_sec.y = old.loc_in_sec.y;
if(stuff_done[304][0]) {
left_at = loc(stuff_done[304][1], stuff_done[304][2]);
left_in = -1;
}
party_event_timers.reserve(30);
for(i = 0; i < 30; i++){
boats[i].append(old.boats[i]);
@@ -283,6 +287,10 @@ void cParty::writeTo(std::ostream& file) const {
if(kv.second > 0)
file << "STATUS " << kv.first << ' ' << kv.second << '\n';
}
if(is_split()) {
file << "SPLIT_LEFT_IN " << left_in << '\n';
file << "SPLIT_LEFT_AT " << left_at.x << ' ' << left_at.y << '\n';
}
for(int i = 0; i < 256; i++)
if(m_noted[i])
file << "ROSTER " << i << '\n';
@@ -477,6 +485,10 @@ void cParty::readFrom(std::istream& file){
sin >> p_loc.x >> p_loc.y;
else if(cur == "LOCINSECTOR")
sin >> loc_in_sec.x >> loc_in_sec.y;
else if(cur == "SPLIT_LEFT_IN")
sin >> left_in;
else if(cur == "SPLIT_LEFT_AT")
sin >> left_at.x >> left_at.y;
else if(cur == "IN")
sin >> in_boat >> in_horse;
else if(cur == "ROSTER"){
@@ -685,72 +697,57 @@ unsigned char& cParty::cpn_flag(unsigned int x, unsigned int y, std::string id)
return campaign_flags[id].idx[x][y];
}
bool cParty::is_split(){
bool cParty::is_split() const {
bool ret = false;
for(int i = 0; i < 6; i++)
if(!stuff_done[304][i])
if(!pc_present(i))
ret = true;
return ret;
}
bool cParty::pc_present(short i){
bool cParty::pc_present(short i) const {
if(i >= 6 || i < 0) return false;
return stuff_done[304][i];
return !isSplit(univ.party[i].main_status);
}
location cParty::left_at(){
return loc(stuff_done[304][6],stuff_done[304][7]);
}
size_t cParty::left_in(){
return stuff_done[304][8];
}
extern cUniverse univ;
std::string cParty::start_split(short a,short b,snd_num_t noise,short who) {
bool cParty::start_split(short x,short y,snd_num_t noise,short who) {
short i;
if(who >= 6 || who < 0) return "";
if(who >= 6 || who < 0) return false;
if(is_split())
return "Party already split!";
stuff_done[304][who] = 0;
stuff_done[304][6] = univ.town.p_loc.x;
stuff_done[304][7] = univ.town.p_loc.y;
stuff_done[304][8] = univ.town.num;
univ.town.p_loc.x = a;
univ.town.p_loc.y = b;
// TODO: This looks like it won't work.
return false;
// TODO: Allow splitting an arbitrary subgroup of the party
left_at = univ.town.p_loc;
left_in = univ.town.num;
univ.town.p_loc.x = x;
univ.town.p_loc.y = y;
for(i = 0; i < 6; i++)
if(!stuff_done[304][who])
if(i != who)
adven[i].main_status += eMainStatus::SPLIT;
// TODO: Uh, why play sound 10 instead of the one passed in?
if(noise > 0)
play_sound(10);
return "";
play_sound(noise);
return true;
}
std::string cParty::end_split(snd_num_t noise) {
bool cParty::end_split(snd_num_t noise) {
short i;
if(!is_split())
return "Party already together!";
univ.town.p_loc = left_at();
univ.town.num = left_in();
return false;
for(i = 0; i < 6; i++){
if(isSplit(univ.party[i].main_status))
univ.party[i].main_status -= eMainStatus::SPLIT;
stuff_done[304][i] = true;
}
if(noise > 0)
play_sound(10);
return "You are reunited.";
play_sound(noise);
return true;
}
short cParty::pc_present(){
short cParty::pc_present() const {
short ret = 7;
for(int i = 0; i < 6; i++){
if(stuff_done[304][i] && ret == 7)
if(pc_present(i) && ret == 7)
ret = i;
else if(stuff_done[304][i] && ret < 6)
else if(pc_present(i) && ret < 6)
ret = 6;
}
if(ret == 7) ret = 6;

View File

@@ -91,6 +91,8 @@ public:
std::vector<cEncNote> special_notes;
std::vector<cConvers> talk_save;
std::map<ePartyStatus,short> status;
location left_at;
size_t left_in;
short direction;
short at_which_save_slot;
char alchemy[20];
@@ -142,13 +144,11 @@ public:
void writeTo(std::ostream& file) const;
void readFrom(std::istream& file);
std::string start_split(short a, short b, snd_num_t noise, short who);
std::string end_split(snd_num_t noise);
bool is_split();
bool pc_present(short n);
short pc_present(); // If only one pc is present, returns the number of that pc. Otherwise returns 6.
location left_at(); // The location that the left-behind character in a split were left at.
size_t left_in(); // The town they were left in.
bool start_split(short x, short y, snd_num_t noise, short who);
bool end_split(snd_num_t noise);
bool is_split() const;
bool pc_present(short n) const;
short pc_present() const; // If only one pc is present, returns the number of that pc. Otherwise returns 6.
typedef std::vector<cEncNote>::iterator encIter;
typedef std::vector<cJournal>::iterator journalIter;

View File

@@ -178,6 +178,13 @@ void cSpecial::append(legacy::special_node_type& old){
type = eSpecType::IF_EQUIP_ITEM_CLASS;
ex2a = (old.type - 131) / 5;
break;
case 193: // Split party
if(ex2a > 0) ex2a = 10;
break;
case 194: // Reunite party
if(ex1a > 0) ex1a = 10;
ex2a = 0;
break;
// Place fields (twelve individual node types were collapsed into one)
case 200:
type = eSpecType::RECT_PLACE_FIELD;

View File

@@ -43,7 +43,7 @@ class cCurTown {
public:
bool quickfire_present = false, belt_present = false;
// formerly current_town_type
short num; // 200 if outdoors (my addition)
size_t num; // 200 if outdoors (my addition)
short difficulty;
bool hostile;
cPopulation monst;