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:
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -171,6 +171,10 @@ enum class ePartyStatus {
|
||||
FIREWALK,
|
||||
};
|
||||
|
||||
enum class eAttitude {
|
||||
DOCILE, HOSTILE_A, FRIENDLY, HOSTILE_B
|
||||
};
|
||||
|
||||
enum class eMonstAbil {
|
||||
NO_ABIL,
|
||||
MISSILE,
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user