Introduce enum for monster attitudes

- Fix some issues with Hostile B monsters (their presence didn't prevent taking nearby items, and they became Hostile A after a mindduel)
- Fix the town a saved creature was in not being saved in the saved game file
- Fix town not going hostile when you damage a friendly monster
This commit is contained in:
2015-07-07 13:44:18 -04:00
parent a5ea3174c8
commit a2d7a1a233
30 changed files with 225 additions and 178 deletions

View File

@@ -20,7 +20,7 @@ void cPopulation::append(legacy::creature_list_type old){
for(int i = 0; i < 60; i++)
dudes[i].append(old.dudes[i]);
which_town = old.which_town;
friendly = old.friendly;
hostile = old.hostile;
}
const cCreature& cPopulation::operator[](size_t n) const {

View File

@@ -34,7 +34,7 @@ class cPopulation { // formerly creature_list_type
std::vector<cCreature> dudes;
public:
short which_town;
short friendly;
bool hostile;
void append(legacy::creature_list_type old);
void init(size_t n);

View File

@@ -18,7 +18,8 @@
const short cCreature::charm_odds[21] = {90,90,85,80,78, 75,73,60,40,30, 20,10,4,1,0, 0,0,0,0,0, 0};
cCreature::cCreature(){
number = active = attitude = start_attitude = 0;
number = active = 0;
attitude = start_attitude = eAttitude::DOCILE;
start_loc.x = start_loc.y = cur_loc.x = cur_loc.y = targ_loc.x = targ_loc.y = 80;
mobility = 1;
summon_time = 0;
@@ -34,7 +35,7 @@ cCreature::cCreature(int num) : cCreature() {
void cCreature::append(legacy::creature_data_type old){
active = old.active;
attitude = old.attitude;
attitude = eAttitude(old.attitude);
number = old.number;
cur_loc.x = old.m_loc.x;
cur_loc.y = old.m_loc.y;
@@ -46,7 +47,7 @@ void cCreature::append(legacy::creature_data_type old){
summon_time -= 100;
} else party_summoned = true;
number = old.monst_start.number;
start_attitude = old.monst_start.start_attitude;
start_attitude = eAttitude(old.monst_start.start_attitude);
start_loc.x = old.monst_start.start_loc.x;
start_loc.y = old.monst_start.start_loc.y;
mobility = old.monst_start.mobile;
@@ -245,8 +246,8 @@ void cCreature::sleep(eStatus which_status,int amount,int penalty) {
}
else {
if(which_status == eStatus::CHARM) {
if(amount == 0 || amount > 3) amount = 2;
attitude = amount;
if(amount <= 0 || amount > 3) amount = 2;
attitude = eAttitude(amount);
spell_note(23);
} else if(which_status == eStatus::FORCECAGE) {
status[eStatus::FORCECAGE] = amount;
@@ -269,7 +270,18 @@ bool cCreature::is_alive() const {
}
bool cCreature::is_friendly() const {
return attitude % 2 == 0;
return attitude == eAttitude::DOCILE || attitude == eAttitude::FRIENDLY;
}
bool cCreature::is_friendly(const iLiving& other) const {
if(is_friendly() != other.is_friendly())
return false;
if(const cCreature* monst = dynamic_cast<const cCreature*>(&other)) {
if(!is_friendly()) return attitude == monst->attitude;
}
// If we get this far, both monsters are friendly to the player.
// (Or, maybe the other is a player rather than a monster.)
return true;
}
location cCreature::get_loc() const {
@@ -366,9 +378,7 @@ void cCreature::readFrom(std::istream& file) {
else if(cur == "ATTITUDE")
line >> attitude;
else if(cur == "STARTATT") {
unsigned int i;
line >> i;
start_attitude = i;
line >> start_attitude;
} else if(cur == "STARTLOC")
line >> start_loc.x >> start_loc.y;
else if(cur == "LOCATION")

View File

@@ -18,7 +18,8 @@
class cCreature : public cMonster, public cTownperson, public iLiving {
public:
static const short charm_odds[21];
short active, attitude;
short active;
eAttitude attitude;
location cur_loc;
short summon_time;
bool party_summoned;
@@ -53,6 +54,7 @@ public:
bool is_alive() const;
bool is_friendly() const;
bool is_friendly(const iLiving& other) const;
bool is_shielded() const;
int get_shared_dmg(int base_dmg) const;
location get_loc() const;

View File

@@ -616,3 +616,18 @@ std::istream& operator>> (std::istream& in, eTalkNode& node) {
in.setstate(std::ios::failbit);
return in;
}
// MARK: eAttitude
cEnumLookup attitude_strs = {"docile", "hostile-a", "friendly", "hostile-b"};
std::ostream& operator<< (std::ostream& out, eAttitude att) {
writeEnum(out, att, attitude_strs, "docile");
return out;
}
std::istream& operator>> (std::istream& in, eAttitude& att) {
if(!readEnum(in, att, attitude_strs, eAttitude::DOCILE))
in.setstate(std::ios::failbit);
return in;
}

View File

@@ -24,7 +24,8 @@ public:
short marked_damage = 0; // for use during animations
virtual bool is_alive() const = 0;
virtual bool is_friendly() const = 0;
virtual bool is_friendly() const = 0; // Return true if friendly to the party.
virtual bool is_friendly(const iLiving& other) const = 0; // Return true if friendly to living entity
virtual bool is_shielded() const = 0; // Checks for martyr's shield in any form - status, monster abil, item abil
virtual int get_shared_dmg(int base_dmg) const = 0; // And this goes with the above.

View File

@@ -126,7 +126,7 @@ void cMonster::append(legacy::monster_record_type& old){
else poison_res = 100;
x_width = old.x_width;
y_width = old.y_width;
default_attitude = old.default_attitude;
default_attitude = eAttitude(old.default_attitude);
summon_type = old.summon_type;
default_facial_pic = old.default_facial_pic;
if(default_facial_pic == 0)
@@ -384,7 +384,8 @@ cMonster::cMonster(){
mindless = invuln = guard = invisible = false;
level = m_health = armor = skill = 0;
speed = 4;
default_facial_pic = default_attitude = 0;
default_facial_pic = 0;
default_attitude = eAttitude::DOCILE;
ambient_sound = 0;
corpse_item = corpse_item_chance = treasure = 0;
mu = cl = 0;
@@ -419,7 +420,7 @@ cTownperson::cTownperson(location loc, mon_num_t num, const cMonster& monst) : c
void cTownperson::append(legacy::creature_start_type old){
number = old.number;
start_attitude = old.start_attitude;
start_attitude = eAttitude(old.start_attitude);
start_loc.x = old.start_loc.x;
start_loc.y = old.start_loc.y;
mobility = old.mobile;
@@ -851,6 +852,8 @@ void cMonster::readFrom(std::istream& file) {
line >> picture_num;
else if(cur == "SOUND")
line >> ambient_sound;
else if(cur == "ATTITUDE")
line >> default_attitude;
else {
line >> temp1;
if(cur == "LEVEL")
@@ -869,8 +872,6 @@ void cMonster::readFrom(std::istream& file) {
cl = temp1;
else if(cur == "TREASURE")
treasure = temp1;
else if(cur == "ATTITUDE")
default_attitude = temp1;
else if(cur == "SUMMON")
summon_type = temp1;
}

View File

@@ -115,7 +115,7 @@ public:
unsigned int poison_res;
bool mindless, invuln, invisible, guard;
unsigned int x_width,y_width;
unsigned int default_attitude;
eAttitude default_attitude;
unsigned int summon_type;
pic_num_t default_facial_pic;
pic_num_t picture_num;
@@ -133,7 +133,7 @@ public:
class cTownperson {
public:
mon_num_t number;
unsigned int start_attitude;
eAttitude start_attitude;
location start_loc;
unsigned short mobility;
eMonstTime time_flag;
@@ -170,5 +170,7 @@ std::ostream& operator << (std::ostream& out, eFieldType e);
std::istream& operator >> (std::istream& in, eFieldType& e);
std::ostream& operator << (std::ostream& out, eMonstTime e);
std::istream& operator >> (std::istream& in, eMonstTime& e);
std::ostream& operator<< (std::ostream& out, eAttitude node);
std::istream& operator>> (std::istream& in, eAttitude& node);
std::ostream& operator<<(std::ostream& out, const cMonster::cAttack& att);
#endif

View File

@@ -320,6 +320,10 @@ bool cParty::is_friendly() const {
return true;
}
bool cParty::is_friendly(const iLiving& other) const {
return other.is_friendly();
}
bool cParty::is_shielded() const {
return false;
}
@@ -582,6 +586,11 @@ void cParty::writeTo(std::ostream& file) const {
file << "SOULCRYSTAL " << i << ' ' << imprisoned_monst[i] << '\n';
file << "DIRECTION " << direction << '\n';
file << "WHICHSLOT " << at_which_save_slot << '\n';
for(int i = 0; i < 4; i++) {
file << "TOWNSAVE " << i << ' ' << creature_save[i].which_town;
if(creature_save[i].hostile) file << " HOSTILE";
file << '\n';
}
for(int i = 0; i < 20; i++)
if(alchemy[i])
file << "ALCHEMY " << i << '\n';
@@ -809,6 +818,11 @@ void cParty::readFrom(std::istream& file){
int i;
sin >> i;
alchemy[i] = true;
} else if(cur == "TOWNSAVE") {
int i;
std::string str;
bin >> i >> creature_save[i].which_town >> str;
creature_save[i].hostile = str == "HOSTILE";
} else if(cur == "TOWNVISIBLE") {
int i;
sin >> i;

View File

@@ -142,6 +142,7 @@ public:
bool is_alive() const;
bool is_friendly() const;
bool is_friendly(const iLiving& other) const;
bool is_shielded() const;
int get_shared_dmg(int base_dmg) const;
location get_loc() const;

View File

@@ -357,6 +357,18 @@ bool cPlayer::is_friendly() const {
return true;
}
bool cPlayer::is_friendly(const iLiving& other) const {
if(status[eStatus::CHARM] > 0) {
if(other.is_friendly()) return false;
// TODO: If charmed players becomes a thing, they should match the attitude (A or B) of whoever charmed them
if(const cCreature* monst = dynamic_cast<const cCreature*>(&other))
return monst->attitude == eAttitude::HOSTILE_A;
// If we get here, the other is also a charmed player.
return true;
}
return other.is_friendly();
}
bool cPlayer::is_shielded() const {
if(status[eStatus::MARTYRS_SHIELD] > 0)
return true;

View File

@@ -66,6 +66,7 @@ public:
iLiving* last_attacked = nullptr; // Note: Currently this is assigned but never read
bool is_alive() const;
bool is_friendly(const iLiving& other) const;
bool is_friendly() const;
bool is_shielded() const;
int get_shared_dmg(int base_dmg) const;

View File

@@ -171,6 +171,10 @@ enum class ePartyStatus {
FIREWALK,
};
enum class eAttitude {
DOCILE, HOSTILE_A, FRIENDLY, HOSTILE_B
};
enum class eMonstAbil {
NO_ABIL,
MISSILE,

View File

@@ -32,7 +32,6 @@ void cCurTown::append(legacy::current_town_type& old){
for(int i = 0; i < 64; i++)
for(int j = 0; j < 64; j++)
fields[i][j] = old.explored[i][j];
hostile = old.hostile;
monst.append(old.monst);
in_boat = old.in_boat;
p_loc.x = old.p_loc.x;
@@ -775,7 +774,7 @@ void cCurOut::readFrom(std::istream& file) {
void cCurTown::writeTo(std::ostream& file) const {
file << "TOWN " << num << '\n';
file << "DIFFICULTY " << difficulty << '\n';
if(hostile) file << "HOSTILE" << '\n';
if(monst.hostile) file << "HOSTILE" << '\n';
file << "INBOAT " << in_boat << '\n';
file << "AT " << p_loc.x << ' ' << p_loc.y << '\n';
file << '\f';
@@ -817,7 +816,7 @@ void cCurTown::readFrom(std::istream& file){
else if(cur == "DIFFICULTY")
sin >> difficulty;
else if(cur == "HOSTILE")
hostile = true;
monst.hostile = true;
else if(cur == "INBOAT")
sin >> in_boat;
else if(cur == "AT")

View File

@@ -45,7 +45,6 @@ public:
// formerly current_town_type
size_t num; // 200 if outdoors (my addition)
short difficulty;
bool hostile;
cPopulation monst;
bool in_boat; // is this really needed?
location p_loc;