Merge mac into windows
This commit is contained in:
655
src/universe/creature.cpp
Normal file
655
src/universe/creature.cpp
Normal file
@@ -0,0 +1,655 @@
|
||||
//
|
||||
// creature.cpp
|
||||
// BoE
|
||||
//
|
||||
// Created by Celtic Minstrel on 15-01-24.
|
||||
//
|
||||
//
|
||||
|
||||
#include "creature.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "oldstructs.hpp"
|
||||
#include "mathutil.hpp"
|
||||
#include "pc.hpp"
|
||||
#include "spell.hpp"
|
||||
|
||||
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() {
|
||||
attitude = eAttitude::DOCILE;
|
||||
cur_loc.x = cur_loc.y = targ_loc.x = targ_loc.y = 80;
|
||||
}
|
||||
|
||||
cCreature::cCreature(int num) : cCreature() {
|
||||
number = num;
|
||||
}
|
||||
|
||||
void cCreature::import_legacy(legacy::creature_data_type old){
|
||||
active = old.active;
|
||||
attitude = eAttitude(old.attitude);
|
||||
number = old.number;
|
||||
cur_loc.x = old.m_loc.x;
|
||||
cur_loc.y = old.m_loc.y;
|
||||
cMonster::import_legacy(old.m_d);
|
||||
mobility = old.mobile;
|
||||
summon_time = old.summoned;
|
||||
if(summon_time >= 100) {
|
||||
party_summoned = false;
|
||||
summon_time -= 100;
|
||||
} else party_summoned = true;
|
||||
number = old.monst_start.number;
|
||||
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;
|
||||
switch(old.monst_start.time_flag) {
|
||||
case 0: time_flag = eMonstTime::ALWAYS; break;
|
||||
case 1: time_flag = eMonstTime::APPEAR_ON_DAY; break;
|
||||
case 2: time_flag = eMonstTime::DISAPPEAR_ON_DAY; break;
|
||||
case 4: time_flag = eMonstTime::SOMETIMES_A; break;
|
||||
case 5: time_flag = eMonstTime::SOMETIMES_B; break;
|
||||
case 6: time_flag = eMonstTime::SOMETIMES_C; break;
|
||||
case 7: time_flag = eMonstTime::APPEAR_WHEN_EVENT; break;
|
||||
case 8: time_flag = eMonstTime::DISAPPEAR_WHEN_EVENT; break;
|
||||
}
|
||||
spec1 = old.monst_start.spec1;
|
||||
spec2 = old.monst_start.spec2;
|
||||
spec_enc_code = old.monst_start.spec_enc_code;
|
||||
time_code = old.monst_start.time_code;
|
||||
monster_time = old.monst_start.monster_time;
|
||||
personality = old.monst_start.personality;
|
||||
special_on_kill = old.monst_start.special_on_kill;
|
||||
facial_pic = old.monst_start.facial_pic;
|
||||
health = old.m_d.health;
|
||||
mp = old.m_d.mp;
|
||||
max_mp = old.m_d.max_mp;
|
||||
ap = old.m_d.ap;
|
||||
morale = old.m_d.morale;
|
||||
m_morale = old.m_d.m_morale;
|
||||
for(int i = 0; i < 15; i++)
|
||||
status[(eStatus) i] = old.m_d.status[i];
|
||||
direction = eDirection(old.m_d.direction);
|
||||
}
|
||||
|
||||
void cCreature::avatar() {
|
||||
health = m_health;
|
||||
status[eStatus::POISON] = 0;
|
||||
status[eStatus::BLESS_CURSE] = 8;
|
||||
status[eStatus::HASTE_SLOW] = 8;
|
||||
status[eStatus::WEBS] = 0;
|
||||
status[eStatus::DISEASE] = 0;
|
||||
if(status[eStatus::DUMB] > 0)
|
||||
status[eStatus::DUMB] = 0;
|
||||
status[eStatus::MARTYRS_SHIELD] = 8;
|
||||
}
|
||||
|
||||
void cCreature::heal(int amt) {
|
||||
if(!is_alive()) return;
|
||||
if(health >= m_health) return;
|
||||
health += amt;
|
||||
if(health > m_health)
|
||||
health = m_health;
|
||||
if(health < 0)
|
||||
health = 0;
|
||||
}
|
||||
|
||||
void cCreature::cure(int amt) {
|
||||
if(!is_alive()) return;
|
||||
if(status[eStatus::POISON] <= amt)
|
||||
status[eStatus::POISON] = 0;
|
||||
else status[eStatus::POISON] -= amt;
|
||||
}
|
||||
|
||||
void cCreature::restore_sp(int amt) {
|
||||
if(!is_alive()) return;
|
||||
if(mp >= max_mp) return;
|
||||
mp += amt;
|
||||
if(mp > max_mp)
|
||||
mp = max_mp;
|
||||
if(mp < 0) mp = 0;
|
||||
}
|
||||
|
||||
void cCreature::drain_sp(int drain) {
|
||||
drain = magic_adjust(drain);
|
||||
if(drain > 0) {
|
||||
if(mu > 0 && mp > 4)
|
||||
drain = min(mp, drain / 3);
|
||||
else if(cl > 0 && mp > 10)
|
||||
drain = min(mp, drain / 2);
|
||||
mp -= drain;
|
||||
if(mp < 0) mp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cCreature::poison(int how_much) {
|
||||
if(how_much != 0) {
|
||||
how_much *= resist[eDamageType::POISON];
|
||||
how_much /= 100;
|
||||
}
|
||||
apply_status(eStatus::POISON, how_much);
|
||||
if(how_much >= 0)
|
||||
spell_note((how_much == 0) ? 10 : 4);
|
||||
else
|
||||
spell_note(34);
|
||||
|
||||
}
|
||||
|
||||
void cCreature::acid(int how_much) {
|
||||
how_much = magic_adjust(how_much);
|
||||
apply_status(eStatus::ACID, how_much);
|
||||
if(how_much >= 0)
|
||||
spell_note(31);
|
||||
else
|
||||
spell_note(48);
|
||||
}
|
||||
|
||||
void cCreature::slow(int how_much) {
|
||||
how_much = magic_adjust(how_much);
|
||||
apply_status(eStatus::HASTE_SLOW, -how_much);
|
||||
if(how_much >= 0)
|
||||
spell_note((how_much == 0) ? 10 : 2);
|
||||
else
|
||||
spell_note(35);
|
||||
|
||||
}
|
||||
|
||||
void cCreature::curse(int how_much) {
|
||||
how_much = magic_adjust(how_much);
|
||||
apply_status(eStatus::BLESS_CURSE, -how_much);
|
||||
if(how_much >= 0)
|
||||
spell_note((how_much == 0) ? 10 : 5);
|
||||
else
|
||||
spell_note(36);
|
||||
|
||||
}
|
||||
|
||||
void cCreature::web(int how_much) {
|
||||
how_much = magic_adjust(how_much);
|
||||
apply_status(eStatus::WEBS, how_much);
|
||||
if(how_much >= 0)
|
||||
spell_note((how_much == 0) ? 10 : 19);
|
||||
else
|
||||
spell_note(37);
|
||||
|
||||
}
|
||||
|
||||
void cCreature::scare(int how_much) {
|
||||
how_much = magic_adjust(how_much);
|
||||
morale -= how_much;
|
||||
if(how_much >= 0)
|
||||
spell_note((how_much == 0) ? 10 : 1);
|
||||
else
|
||||
spell_note(47);
|
||||
|
||||
}
|
||||
|
||||
void cCreature::disease(int how_much) {
|
||||
how_much = magic_adjust(how_much);
|
||||
apply_status(eStatus::DISEASE, how_much);
|
||||
if(how_much >= 0)
|
||||
spell_note((how_much == 0) ? 10 : 25);
|
||||
else
|
||||
spell_note(38);
|
||||
|
||||
}
|
||||
|
||||
void cCreature::dumbfound(int how_much) {
|
||||
how_much = magic_adjust(how_much);
|
||||
apply_status(eStatus::DUMB, how_much);
|
||||
if(how_much >= 0)
|
||||
spell_note((how_much == 0) ? 10 : 22);
|
||||
else
|
||||
spell_note(39);
|
||||
|
||||
}
|
||||
|
||||
// For charm, amount is the resulting attitude of the charmed monster; if 0, attitude is 2.
|
||||
void cCreature::sleep(eStatus which_status,int amount,int penalty) {
|
||||
if(which_status != eStatus::CHARM && amount < 0) {
|
||||
status[which_status] -= amount;
|
||||
if(which_status != eStatus::ASLEEP)
|
||||
status[which_status] = max(0, status[which_status]);
|
||||
return;
|
||||
}
|
||||
|
||||
if((which_status == eStatus::ASLEEP) &&
|
||||
(m_type == eRace::UNDEAD || m_type == eRace::SKELETAL || m_type == eRace::SLIME ||
|
||||
m_type == eRace::STONE || m_type == eRace::PLANT))
|
||||
return;
|
||||
short r1 = get_ran(1,1,100);
|
||||
if(resist[eDamageType::MAGIC] > 0) {
|
||||
r1 *= 100;
|
||||
r1 /= resist[eDamageType::MAGIC];
|
||||
} else r1 = 200;
|
||||
r1 += penalty;
|
||||
if(which_status == eStatus::FORCECAGE && (mu > 0 || cl > 0))
|
||||
r1 += 5;
|
||||
if(which_status == eStatus::ASLEEP)
|
||||
r1 -= 25;
|
||||
if(which_status == eStatus::PARALYZED)
|
||||
r1 -= 15;
|
||||
if(which_status == eStatus::ASLEEP && abil[eMonstAbil::FIELD].active && abil[eMonstAbil::FIELD].gen.fld == eFieldType::CLOUD_SLEEP)
|
||||
return;
|
||||
|
||||
if(r1 > charm_odds[level / 2]) {
|
||||
//one_sound(68);
|
||||
spell_note(10);
|
||||
}
|
||||
else {
|
||||
if(which_status == eStatus::CHARM) {
|
||||
if(amount <= 0 || amount > 3) amount = 2;
|
||||
attitude = eAttitude(amount);
|
||||
spell_note(23);
|
||||
} else if(which_status == eStatus::FORCECAGE) {
|
||||
status[eStatus::FORCECAGE] = amount;
|
||||
spell_note(52);
|
||||
} else {
|
||||
status[which_status] = amount;
|
||||
if(which_status == eStatus::ASLEEP && (amount >= 0))
|
||||
spell_note(28);
|
||||
if(which_status == eStatus::PARALYZED && (amount >= 0))
|
||||
spell_note(30);
|
||||
if(amount < 0)
|
||||
spell_note(40);
|
||||
}
|
||||
//one_sound(53);
|
||||
}
|
||||
}
|
||||
|
||||
bool cCreature::is_alive() const {
|
||||
return active > 0;
|
||||
}
|
||||
|
||||
bool cCreature::is_friendly() const {
|
||||
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 {
|
||||
return cur_loc;
|
||||
}
|
||||
|
||||
bool cCreature::is_shielded() const {
|
||||
if(status[eStatus::MARTYRS_SHIELD] > 0)
|
||||
return true;
|
||||
if(abil[eMonstAbil::MARTYRS_SHIELD].active && get_ran(1,1,1000) <= abil[eMonstAbil::MARTYRS_SHIELD].special.extra1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int cCreature::get_shared_dmg(int base_dmg) const {
|
||||
if(abil[eMonstAbil::MARTYRS_SHIELD].active) {
|
||||
base_dmg *= abil[eMonstAbil::MARTYRS_SHIELD].special.extra2;
|
||||
base_dmg /= 100;
|
||||
}
|
||||
return base_dmg;
|
||||
}
|
||||
|
||||
int cCreature::magic_adjust(int how_much) {
|
||||
if(how_much <= 0) return how_much;
|
||||
if(abil[eMonstAbil::ABSORB_SPELLS].active && get_ran(1,1,1000) <= abil[eMonstAbil::ABSORB_SPELLS].special.extra1) {
|
||||
int gain = abil[eMonstAbil::ABSORB_SPELLS].special.extra2;
|
||||
if(32767 - health > gain)
|
||||
health = 32767;
|
||||
else health += gain;
|
||||
return 0;
|
||||
}
|
||||
// TODO: Magic resistance status effect?
|
||||
how_much *= resist[eDamageType::MAGIC];
|
||||
how_much /= 100;
|
||||
return how_much;
|
||||
}
|
||||
|
||||
int cCreature::get_health() const {
|
||||
return health;
|
||||
}
|
||||
|
||||
int cCreature::get_magic() const {
|
||||
return mp;
|
||||
}
|
||||
|
||||
int cCreature::get_level() const {
|
||||
return level;
|
||||
}
|
||||
|
||||
bool cCreature::on_space(location loc) const {
|
||||
if(loc.x - cur_loc.x >= 0 && loc.x - cur_loc.x <= x_width - 1 &&
|
||||
loc.y - cur_loc.y >= 0 && loc.y - cur_loc.y <= y_width - 1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void cCreature::writeTo(std::ostream& file) const {
|
||||
file << "MONSTER " << number << '\n';
|
||||
file << "ATTITUDE " << attitude << '\n';
|
||||
file << "STARTATT " << start_attitude << '\n';
|
||||
file << "STARTLOC " << start_loc.x << ' ' << start_loc.y << '\n';
|
||||
file << "LOCATION " << cur_loc.x << ' ' << cur_loc.y << '\n';
|
||||
file << "MOBILITY " << mobility << '\n';
|
||||
file << "TIMEFLAG " << time_flag << '\n';
|
||||
file << "SUMMONED " << summon_time << ' ' << party_summoned << '\n';
|
||||
file << "SPEC " << spec1 << ' ' << spec2 << '\n';
|
||||
file << "SPECCODE " << spec_enc_code << '\n';
|
||||
file << "TIMECODE " << time_code << '\n';
|
||||
file << "TIME " << monster_time << '\n';
|
||||
file << "TALK " << personality << '\n';
|
||||
file << "DEATH " << special_on_kill << '\n';
|
||||
file << "FACE " << facial_pic << '\n';
|
||||
file << "TARGET " << target << '\n';
|
||||
file << "TARGLOC " << targ_loc.x << ' ' << targ_loc.y << '\n';
|
||||
for(auto stat : status) {
|
||||
if(stat.second != 0)
|
||||
file << "STATUS " << stat.first << ' ' << stat.second << '\n';
|
||||
}
|
||||
file << "CURHP " << health << '\n';
|
||||
file << "CURSP " << mp << '\n';
|
||||
file << "MORALE " << morale << '\n';
|
||||
file << "DIRECTION " << direction << '\n';
|
||||
// TODO: Should we be saving "max_mp" and/or "m_morale"?
|
||||
}
|
||||
|
||||
void cCreature::readFrom(std::istream& file) {
|
||||
while(file) {
|
||||
std::string cur;
|
||||
getline(file, cur);
|
||||
std::istringstream line(cur);
|
||||
line >> cur;
|
||||
if(cur == "MONSTER")
|
||||
line >> number;
|
||||
else if(cur == "ATTITUDE")
|
||||
line >> attitude;
|
||||
else if(cur == "STARTATT") {
|
||||
line >> start_attitude;
|
||||
} else if(cur == "STARTLOC")
|
||||
line >> start_loc.x >> start_loc.y;
|
||||
else if(cur == "LOCATION")
|
||||
line >> cur_loc.x >> cur_loc.y;
|
||||
else if(cur == "MOBILITY") {
|
||||
unsigned int i;
|
||||
line >> i;
|
||||
mobility = i;
|
||||
} else if(cur == "TIMEFLAG") {
|
||||
line >> time_flag;
|
||||
} else if(cur == "SUMMONED")
|
||||
line >> summon_time >> party_summoned;
|
||||
else if(cur == "SPEC")
|
||||
line >> spec1 >> spec2;
|
||||
else if(cur == "SPECCODE") {
|
||||
int i;
|
||||
line >> i;
|
||||
spec_enc_code = i;
|
||||
} else if(cur == "TIMECODE") {
|
||||
int i;
|
||||
line >> i;
|
||||
time_code = i;
|
||||
} else if(cur == "TIME")
|
||||
line >> monster_time;
|
||||
else if(cur == "TALK")
|
||||
line >> personality;
|
||||
else if(cur == "DEATH")
|
||||
line >> special_on_kill;
|
||||
else if(cur == "FACE")
|
||||
line >> facial_pic;
|
||||
else if(cur == "TARGET")
|
||||
line >> target;
|
||||
else if(cur == "TARGLOC")
|
||||
line >> targ_loc.x >> targ_loc.y;
|
||||
else if(cur == "CURHP")
|
||||
line >> health;
|
||||
else if(cur == "CURSP")
|
||||
line >> mp;
|
||||
else if(cur == "MORALE")
|
||||
line >> morale;
|
||||
else if(cur == "DIRECTION")
|
||||
line >> direction;
|
||||
else if(cur == "STATUS") {
|
||||
eStatus i;
|
||||
line >> i >> status[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cCreature::print_attacks(iLiving* target) {
|
||||
if(!print_result) return;
|
||||
std::string msg = m_name;
|
||||
msg += " attacks ";
|
||||
if(cPlayer* who = dynamic_cast<cPlayer*>(target))
|
||||
msg += who->name;
|
||||
else if(cCreature* monst = dynamic_cast<cCreature*>(target))
|
||||
msg += monst->m_name;
|
||||
else msg += "you";
|
||||
print_result(msg);
|
||||
}
|
||||
|
||||
void cCreature::spell_note(int which_mess) {
|
||||
if(!print_result) return;
|
||||
std::string msg = m_name;
|
||||
switch(which_mess) {
|
||||
case 1:
|
||||
msg = " " + msg + " scared.";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
msg = " " + msg + " slowed.";
|
||||
break;
|
||||
|
||||
case 3:
|
||||
msg = " " + msg + " weakened.";
|
||||
break;
|
||||
|
||||
case 4:
|
||||
msg = " " + msg + " poisoned.";
|
||||
break;
|
||||
|
||||
case 5:
|
||||
msg = " " + msg + " cursed.";
|
||||
break;
|
||||
|
||||
case 6:
|
||||
msg = " " + msg + " ravaged.";
|
||||
break;
|
||||
|
||||
case 7:
|
||||
msg = " " + msg + " undamaged.";
|
||||
break;
|
||||
|
||||
case 8:
|
||||
msg = " " + msg + " is stoned.";
|
||||
break;
|
||||
case 9:
|
||||
msg = " Gazes at " + msg + '.';
|
||||
break;
|
||||
case 10:
|
||||
msg = " " + msg + " resists.";
|
||||
break;
|
||||
case 11:
|
||||
msg = " Drains " + msg + '.';
|
||||
break;
|
||||
case 12:
|
||||
msg = " Shoots at " + msg + '.';
|
||||
break;
|
||||
case 13:
|
||||
msg = " Throws spear at " + msg + '.';
|
||||
break;
|
||||
case 14:
|
||||
msg = " Throws rock at " + msg + '.';
|
||||
break;
|
||||
case 15:
|
||||
msg = " Throws razordisk at " + msg + '.';
|
||||
break;
|
||||
case 16:
|
||||
msg = " Hits " + msg + '.';
|
||||
break;
|
||||
case 17:
|
||||
msg = " " + msg + " disappears.";
|
||||
break;
|
||||
case 18:
|
||||
msg = " Misses " + msg + '.';
|
||||
break;
|
||||
case 19:
|
||||
msg = " " + msg + " is webbed.";
|
||||
break;
|
||||
case 20:
|
||||
msg = " " + msg + " chokes.";
|
||||
break;
|
||||
case 21:
|
||||
msg = " " + msg + " summoned.";
|
||||
break;
|
||||
case 22:
|
||||
msg = " " + msg + " is dumbfounded.";
|
||||
break;
|
||||
case 23:
|
||||
msg = " " + msg + " is charmed.";
|
||||
break;
|
||||
case 24:
|
||||
msg = " " + msg + " is recorded.";
|
||||
break;
|
||||
case 25:
|
||||
msg = " " + msg + " is diseased.";
|
||||
break;
|
||||
case 26:
|
||||
msg = " " + msg + " is an avatar!";
|
||||
break;
|
||||
case 27:
|
||||
msg = " " + msg + " splits!";
|
||||
break;
|
||||
case 28:
|
||||
msg = " " + msg + " falls asleep.";
|
||||
break;
|
||||
case 29:
|
||||
msg = " " + msg + " wakes up.";
|
||||
break;
|
||||
case 30:
|
||||
msg = " " + msg + " paralyzed.";
|
||||
break;
|
||||
case 31:
|
||||
msg = " " + msg + " covered with acid.";
|
||||
break;
|
||||
case 32:
|
||||
msg = " Fires spines at " + msg + '.';
|
||||
break;
|
||||
case 33:
|
||||
msg = " " + msg + " summons aid.";
|
||||
break;
|
||||
case 34:
|
||||
msg = " " + msg + " is cured.";
|
||||
break;
|
||||
case 35:
|
||||
msg = " " + msg + " is hasted.";
|
||||
break;
|
||||
case 36:
|
||||
msg = " " + msg + " is blessed.";
|
||||
break;
|
||||
case 37:
|
||||
msg = " " + msg + " cleans webs.";
|
||||
break;
|
||||
case 38:
|
||||
msg = " " + msg + " feels better.";
|
||||
break;
|
||||
case 39:
|
||||
msg = " " + msg + " mind cleared.";
|
||||
break;
|
||||
case 40:
|
||||
msg = " " + msg + " feels alert.";
|
||||
break;
|
||||
case 41:
|
||||
msg = " " + msg + " is healed.";
|
||||
break;
|
||||
case 42:
|
||||
msg = " " + msg + " drained of health.";
|
||||
break;
|
||||
case 43:
|
||||
msg = " " + msg + " magic recharged.";
|
||||
break;
|
||||
case 44:
|
||||
msg = " " + msg + " drained of magic.";
|
||||
break;
|
||||
case 45:
|
||||
msg = " " + msg + " returns to life!";
|
||||
break;
|
||||
case 46:
|
||||
msg = " " + msg + " dies.";
|
||||
break;
|
||||
case 47:
|
||||
msg = " " + msg + " rallies its courage.";
|
||||
break;
|
||||
case 48:
|
||||
msg = " " + msg + " cleans off acid.";
|
||||
break;
|
||||
case 49:
|
||||
msg = " " + msg + " breaks barrier.";
|
||||
break;
|
||||
case 50:
|
||||
msg = " " + msg + " breaks force cage.";
|
||||
break;
|
||||
case 51:
|
||||
msg = " " + msg + " is obliterated!";
|
||||
break;
|
||||
case 52:
|
||||
msg = " " + msg + " is trapped!";
|
||||
break;
|
||||
case 53:
|
||||
msg = " Throws dart at " + msg + '.';
|
||||
break;
|
||||
case 54:
|
||||
msg = " Throws knife at " + msg + '.';
|
||||
break;
|
||||
case 55:
|
||||
msg = " Fires ray at " + msg + '.';
|
||||
break;
|
||||
case 56:
|
||||
msg = " Gazes at " + msg + '.';
|
||||
break;
|
||||
case 57:
|
||||
msg = " Breathes on " + msg + '.';
|
||||
break;
|
||||
case 58:
|
||||
msg = " Throws web at " + msg + '.';
|
||||
break;
|
||||
case 59:
|
||||
msg = " Spits at " + msg + '.';
|
||||
break;
|
||||
default:
|
||||
msg += ": Unknown action " + std::to_string(which_mess);
|
||||
}
|
||||
|
||||
if(which_mess > 0)
|
||||
print_result((char *) msg.c_str());
|
||||
}
|
||||
|
||||
void cCreature::cast_spell_note(eSpell spell) {
|
||||
if(!print_result) return;
|
||||
print_result(m_name + " casts:");
|
||||
print_result(" " + (*spell).name());
|
||||
}
|
||||
|
||||
void cCreature::breathe_note() {
|
||||
if(!print_result) return;
|
||||
print_result(m_name + " breathes.");
|
||||
}
|
||||
|
||||
void cCreature::damaged_msg(int how_much,int how_much_spec) {
|
||||
if(!print_result) return;
|
||||
std::ostringstream sout;
|
||||
sout << " " << m_name << " takes " << how_much;
|
||||
if(how_much_spec > 0)
|
||||
sout << '+' << how_much_spec;
|
||||
print_result(sout.str());
|
||||
}
|
||||
|
||||
void cCreature::killed_msg() {
|
||||
if(!print_result) return;
|
||||
print_result(" " + m_name + " dies.");
|
||||
}
|
||||
76
src/universe/creature.hpp
Normal file
76
src/universe/creature.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// creature.hpp
|
||||
// BoE
|
||||
//
|
||||
// Created by Celtic Minstrel on 15-01-24.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef BoE_creature_hpp
|
||||
#define BoE_creature_hpp
|
||||
|
||||
#include <iosfwd>
|
||||
#include "location.hpp"
|
||||
#include "monster.hpp"
|
||||
#include "living.hpp"
|
||||
|
||||
class cCreature : public cMonster, public cTownperson, public iLiving {
|
||||
public:
|
||||
static const short charm_odds[21];
|
||||
short active = 0;
|
||||
eAttitude attitude;
|
||||
location cur_loc;
|
||||
short summon_time = 0;
|
||||
bool party_summoned;
|
||||
short target = 6;
|
||||
location targ_loc;
|
||||
short health = 0;
|
||||
short mp = 0;
|
||||
short max_mp = 0;
|
||||
short morale = 0,m_morale = 0; // these are calculated in-game based on the level
|
||||
|
||||
cCreature();
|
||||
cCreature(int num);
|
||||
|
||||
void heal(int how_much);
|
||||
void poison(int how_much);
|
||||
void cure(int how_much);
|
||||
void acid(int how_much);
|
||||
void curse(int how_much);
|
||||
void slow(int how_much);
|
||||
void web(int how_much);
|
||||
void disease(int how_much);
|
||||
void dumbfound(int how_much);
|
||||
void scare(int how_much);
|
||||
void sleep(eStatus type, int how_much, int adj);
|
||||
void avatar();
|
||||
void drain_sp(int how_much);
|
||||
void restore_sp(int how_much);
|
||||
|
||||
int get_health() const;
|
||||
int get_magic() const;
|
||||
int get_level() const;
|
||||
|
||||
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;
|
||||
|
||||
int magic_adjust(int base);
|
||||
|
||||
void spell_note(int which);
|
||||
void cast_spell_note(eSpell spell);
|
||||
void print_attacks(iLiving* target);
|
||||
void breathe_note();
|
||||
void damaged_msg(int how_much, int extra);
|
||||
void killed_msg();
|
||||
bool on_space(location loc) const;
|
||||
|
||||
void import_legacy(legacy::creature_data_type old);
|
||||
void writeTo(std::ostream& file) const;
|
||||
void readFrom(std::istream& file);
|
||||
};
|
||||
|
||||
#endif
|
||||
75
src/universe/living.cpp
Normal file
75
src/universe/living.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// living.cpp
|
||||
// BoE
|
||||
//
|
||||
// Created by Celtic Minstrel on 15-01-24.
|
||||
//
|
||||
//
|
||||
|
||||
#include "living.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include "mathutil.hpp"
|
||||
|
||||
void iLiving::apply_status(eStatus which, int how_much) {
|
||||
if(!is_alive()) return;
|
||||
|
||||
static const std::set<eStatus> allow_negative = {
|
||||
// The obvious ones:
|
||||
eStatus::BLESS_CURSE, eStatus::HASTE_SLOW,
|
||||
// The ones that BoE previously allowed:
|
||||
eStatus::POISONED_WEAPON, eStatus::POISON, eStatus::ASLEEP,
|
||||
// (Note: Negative levels of sleep can be obtained from the Hyperactivity spell. The other two never go negative.)
|
||||
// The additional ones that make sense in the negative:
|
||||
eStatus::MAGIC_RESISTANCE, eStatus::DUMB,
|
||||
};
|
||||
|
||||
int lo = 0, hi = 8;
|
||||
|
||||
if(which == eStatus::MARTYRS_SHIELD)
|
||||
hi = 10;
|
||||
else if(which == eStatus::PARALYZED)
|
||||
hi = 5000;
|
||||
else if(which == eStatus::FORCECAGE)
|
||||
hi = 1000;
|
||||
|
||||
if(allow_negative.count(which))
|
||||
lo = -hi;
|
||||
|
||||
if(which == eStatus::ASLEEP || which == eStatus::DUMB) {
|
||||
// No "wrapping" allowed for these effects.
|
||||
if(status[which] < 0) hi = 0;
|
||||
else if(status[which] > 0) lo = 0;
|
||||
}
|
||||
|
||||
status[which] = minmax(lo,hi,status[which] + how_much);
|
||||
}
|
||||
|
||||
void iLiving::clear_bad_status() {
|
||||
std::map<eStatus, short> old;
|
||||
status.swap(old);
|
||||
std::remove_copy_if(old.begin(), old.end(), std::inserter(status, status.begin()), [](std::pair<const eStatus, short> kv) {
|
||||
return isStatusNegative(kv.first) ? kv.second > 0 : kv.second < 0;
|
||||
});
|
||||
}
|
||||
|
||||
void iLiving::clear_brief_status() {
|
||||
std::map<eStatus, short> old;
|
||||
status.swap(old);
|
||||
std::remove_copy_if(old.begin(), old.end(), std::inserter(status, status.begin()), [](std::pair<const eStatus, short> kv) -> bool {
|
||||
if(kv.first == eStatus::POISON) return false;
|
||||
if(kv.first == eStatus::DISEASE) return false;
|
||||
if(kv.first == eStatus::DUMB) return false;
|
||||
if(kv.first == eStatus::ACID && kv.second > 2)
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void iLiving::void_sanctuary() {
|
||||
if(status[eStatus::INVISIBLE] > 0)
|
||||
status[eStatus::INVISIBLE] = 0;
|
||||
}
|
||||
|
||||
void(* iLiving::print_result)(std::string) = nullptr;
|
||||
62
src/universe/living.hpp
Normal file
62
src/universe/living.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// living.hpp
|
||||
// BoE
|
||||
//
|
||||
// Created by Celtic Minstrel on 15-01-24.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef BoE_living_hpp
|
||||
#define BoE_living_hpp
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "location.hpp"
|
||||
#include "damage.hpp"
|
||||
|
||||
class iLiving {
|
||||
public:
|
||||
// HACK: This is only really marked mutable so that I can use operator[] from const methods
|
||||
mutable std::map<eStatus,short> status;
|
||||
short ap = 0;
|
||||
eDirection direction = DIR_HERE;
|
||||
short marked_damage = 0; // for use during animations
|
||||
|
||||
virtual bool is_alive() 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.
|
||||
|
||||
virtual void apply_status(eStatus which, int how_much);
|
||||
virtual void clear_brief_status();
|
||||
virtual void clear_bad_status();
|
||||
virtual void void_sanctuary();
|
||||
|
||||
virtual void heal(int how_much) = 0;
|
||||
virtual void poison(int how_much) = 0;
|
||||
virtual void cure(int how_much) = 0;
|
||||
virtual void acid(int how_much) = 0;
|
||||
virtual void curse(int how_much) = 0;
|
||||
virtual void slow(int how_much) = 0;
|
||||
virtual void web(int how_much) = 0;
|
||||
virtual void disease(int how_much) = 0;
|
||||
virtual void dumbfound(int how_much) = 0;
|
||||
virtual void scare(int how_much) = 0;
|
||||
virtual void sleep(eStatus type, int how_much, int adj) = 0; // Also handles paralysis, charm, and forcecage
|
||||
virtual void avatar() = 0;
|
||||
virtual void drain_sp(int how_much) = 0;
|
||||
virtual void restore_sp(int how_much) = 0;
|
||||
|
||||
virtual int get_health() const = 0;
|
||||
virtual int get_magic() const = 0;
|
||||
virtual int get_level() const = 0;
|
||||
virtual location get_loc() const = 0;
|
||||
|
||||
virtual ~iLiving() = default;
|
||||
|
||||
static void(* print_result)(std::string);
|
||||
};
|
||||
|
||||
#endif
|
||||
1269
src/universe/party.cpp
Normal file
1269
src/universe/party.cpp
Normal file
File diff suppressed because it is too large
Load Diff
237
src/universe/party.hpp
Normal file
237
src/universe/party.hpp
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* party.h
|
||||
* BoE
|
||||
*
|
||||
* Created by Celtic Minstrel on 24/04/09.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOE_DATA_PARTY_H
|
||||
#define BOE_DATA_PARTY_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <boost/iterator/indirect_iterator.hpp>
|
||||
|
||||
#include "vehicle.hpp"
|
||||
#include "population.hpp"
|
||||
#include "item.hpp"
|
||||
#include "pc.hpp"
|
||||
#include "outdoors.hpp"
|
||||
#include "monster.hpp"
|
||||
#include "living.hpp"
|
||||
#include "quest.hpp"
|
||||
|
||||
namespace legacy {
|
||||
struct party_record_type;
|
||||
struct big_tr_type;
|
||||
struct stored_items_list_type;
|
||||
struct talk_save_type;
|
||||
struct creature_list_type;
|
||||
struct pc_record_type;
|
||||
struct setup_save_type;
|
||||
};
|
||||
|
||||
struct campaign_flag_type{
|
||||
unsigned char idx[25][25];
|
||||
};
|
||||
|
||||
struct job_bank_t {
|
||||
std::array<int,6> jobs;
|
||||
int anger = 0;
|
||||
bool inited = false;
|
||||
};
|
||||
|
||||
enum eEncNoteType {
|
||||
NOTE_SCEN,
|
||||
NOTE_OUT,
|
||||
NOTE_TOWN,
|
||||
};
|
||||
|
||||
class cUniverse;
|
||||
class cItem;
|
||||
|
||||
class cParty : public iLiving {
|
||||
public:
|
||||
class cConvers { // conversation; formerly talk_save_type
|
||||
public:
|
||||
bool filled = false;
|
||||
std::string who_said, in_town, the_str1, the_str2, in_scen;
|
||||
|
||||
void import_legacy(legacy::talk_save_type old, const cScenario& scenario);
|
||||
};
|
||||
class cJournal {
|
||||
public:
|
||||
unsigned short day;
|
||||
std::string the_str, in_scen;
|
||||
};
|
||||
class cEncNote {
|
||||
public:
|
||||
eEncNoteType type;
|
||||
std::string the_str, where, in_scen;
|
||||
|
||||
void import_legacy(int16_t(& old)[2], const cScenario& scenario);
|
||||
};
|
||||
// formerly party_record_type
|
||||
// TODO: Should we make age a long long?
|
||||
long next_pc_id = 1000;
|
||||
unsigned long age;
|
||||
unsigned short gold;
|
||||
unsigned short food;
|
||||
unsigned char stuff_done[350][50];
|
||||
// These used to be stored as magic SDFs
|
||||
unsigned char hostiles_present;
|
||||
bool easy_mode = false, less_wm = false;
|
||||
// End former magic SDFs
|
||||
std::array<unsigned char,90> magic_ptrs;
|
||||
short light_level;
|
||||
location outdoor_corner;
|
||||
location i_w_c;
|
||||
// TODO: Does this duplicate cCurTown::p_loc? If not, why not?
|
||||
location out_loc, town_loc;
|
||||
location loc_in_sec;
|
||||
short town_num;
|
||||
std::vector<cVehicle> boats;
|
||||
std::vector<cVehicle> horses;
|
||||
std::array<cPopulation,4> creature_save;
|
||||
short in_boat;
|
||||
short in_horse;
|
||||
std::array<cOutdoors::cCreature,10> out_c;
|
||||
std::map<int,std::array<cItem,30>> magic_store_items;
|
||||
std::map<int,std::map<int,int>> store_limited_stock;
|
||||
std::vector<job_bank_t> job_banks;
|
||||
std::array<mon_num_t,4> imprisoned_monst; // Soul Crystal
|
||||
std::set<mon_num_t> m_noted; // has the monster been scried?
|
||||
std::set<mon_num_t> m_seen; // has the monster ever been seen? (this used to have the above meaning)
|
||||
std::vector<cJournal> journal;
|
||||
std::vector<cEncNote> special_notes;
|
||||
std::vector<cConvers> talk_save;
|
||||
std::map<ePartyStatus,short> status;
|
||||
std::map<int, cJob> active_quests;
|
||||
location left_at;
|
||||
size_t left_in;
|
||||
eDirection direction;
|
||||
short at_which_save_slot;
|
||||
std::bitset<20> alchemy;
|
||||
std::map<int,int> key_times;
|
||||
std::vector<cTimer> party_event_timers;
|
||||
std::set<int> spec_items;
|
||||
long long total_m_killed, total_dam_done, total_xp_gained, total_dam_taken;
|
||||
std::string scen_name;
|
||||
private:
|
||||
std::array<cPlayer*,6> adven;
|
||||
public:
|
||||
unsigned short setup[4][64][64]; // formerly setup_save_type
|
||||
std::array<std::vector<cItem>,3> stored_items; // formerly stored_items_list_type
|
||||
|
||||
std::vector<cMonster> summons; // an array of monsters which can be summoned by the party's items yet don't originate from this scenario
|
||||
unsigned short scen_won, scen_played; // numbers of scenarios won and played respectively by this party
|
||||
std::map<std::string,campaign_flag_type> campaign_flags;
|
||||
private:
|
||||
std::map<unsigned short,std::pair<unsigned short,unsigned char>> pointers;
|
||||
using sd_array = decltype(stuff_done);
|
||||
public:
|
||||
static const int sdx_max = std::extent<sd_array, 0>::value - 1;
|
||||
static const int sdy_max = std::extent<sd_array, 1>::value - 1;
|
||||
|
||||
void set_ptr(unsigned short p, unsigned short sdfx, unsigned short sdfy);
|
||||
void force_ptr(unsigned short p, unsigned short val);
|
||||
void clear_ptr(unsigned short p);
|
||||
unsigned char get_ptr(unsigned short p);
|
||||
|
||||
void import_legacy(legacy::party_record_type& old, cUniverse& univ);
|
||||
void import_legacy(legacy::big_tr_type& old);
|
||||
void import_legacy(legacy::stored_items_list_type& old,short which_list);
|
||||
void import_legacy(legacy::setup_save_type& old);
|
||||
void import_legacy(legacy::pc_record_type(& old)[6]);
|
||||
|
||||
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;
|
||||
|
||||
void apply_status(eStatus which, int how_much);
|
||||
void heal(int how_much);
|
||||
void poison(int how_much);
|
||||
void cure(int how_much);
|
||||
void acid(int how_much);
|
||||
void curse(int how_much);
|
||||
void slow(int how_much);
|
||||
void web(int how_much);
|
||||
void disease(int how_much);
|
||||
void dumbfound(int how_much);
|
||||
void scare(int how_much);
|
||||
void sleep(eStatus type, int how_much, int adj);
|
||||
void clear_bad_status();
|
||||
void avatar();
|
||||
void drain_sp(int how_much);
|
||||
void restore_sp(int how_much);
|
||||
|
||||
int get_health() const;
|
||||
int get_magic() const;
|
||||
int get_level() const;
|
||||
int calc_day() const;
|
||||
|
||||
void new_pc(size_t spot);
|
||||
void replace_pc(size_t spot, cPlayer* with);
|
||||
size_t free_space();
|
||||
size_t count(eMainStatus type = eMainStatus::ALIVE);
|
||||
void void_pcs();
|
||||
bool save_talk(const std::string& who, const std::string& where, const std::string& str1, const std::string& str2);
|
||||
bool add_to_journal(const std::string& event, short day);
|
||||
bool record(eEncNoteType type, const std::string& what, const std::string& where);
|
||||
bool start_timer(short time, short node, short type);
|
||||
cPlayer& operator[](unsigned short n);
|
||||
const cPlayer& operator[](unsigned short n) const;
|
||||
void writeTo(std::ostream& file, const cScenario& scen) const;
|
||||
void readFrom(std::istream& file, cScenario& scen);
|
||||
|
||||
bool give_item(cItem item,int flags);
|
||||
bool forced_give(cItem item,eItemAbil abil,short dat = -1);
|
||||
bool has_abil(eItemAbil abil, short dat = -1);
|
||||
bool take_abil(eItemAbil abil, short dat = -1);
|
||||
bool check_class(unsigned int item_class,bool take);
|
||||
|
||||
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;
|
||||
iLiving& pc_present() const; // If only one pc is present, returns that pc. Otherwise returns party.
|
||||
void swap_pcs(size_t a, size_t b);
|
||||
|
||||
bool sd_legit(short a, short b);
|
||||
|
||||
auto begin() -> boost::indirect_iterator<decltype(adven)::iterator> {
|
||||
return boost::make_indirect_iterator(adven.begin());
|
||||
}
|
||||
|
||||
auto end() -> boost::indirect_iterator<decltype(adven)::iterator> {
|
||||
return boost::make_indirect_iterator(adven.end());
|
||||
}
|
||||
|
||||
typedef std::vector<cEncNote>::iterator encIter;
|
||||
typedef std::vector<cJournal>::iterator journalIter;
|
||||
typedef std::vector<cConvers>::iterator talkIter;
|
||||
cParty(long party_preset = 'dflt');
|
||||
~cParty();
|
||||
// Copy-and-swap
|
||||
void swap(cParty& other);
|
||||
cParty(const cParty& other);
|
||||
cParty(cParty&& other);
|
||||
cParty& operator=(cParty other);
|
||||
};
|
||||
|
||||
bool operator==(const cParty::cConvers& one, const cParty::cConvers& two);
|
||||
bool operator==(const cParty::cJournal& one, const cParty::cJournal& two);
|
||||
bool operator==(const cParty::cEncNote& one, const cParty::cEncNote& two);
|
||||
|
||||
std::istream& operator>>(std::istream& in, eEncNoteType& type);
|
||||
std::ostream& operator<<(std::ostream& out, eEncNoteType type);
|
||||
|
||||
#endif
|
||||
1323
src/universe/pc.cpp
Normal file
1323
src/universe/pc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
179
src/universe/pc.hpp
Normal file
179
src/universe/pc.hpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* pc.h
|
||||
* BoE
|
||||
*
|
||||
* Created by Celtic Minstrel on 24/04/09.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOE_DATA_PC_H
|
||||
#define BOE_DATA_PC_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <iosfwd>
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
|
||||
#include "item.hpp"
|
||||
#include "pictypes.hpp"
|
||||
#include "living.hpp"
|
||||
#include "skills_traits.hpp"
|
||||
#include "race.hpp"
|
||||
#include "spell.hpp"
|
||||
|
||||
namespace legacy { struct pc_record_type; };
|
||||
|
||||
enum class eBuyStatus {OK, NO_SPACE, NEED_GOLD, TOO_HEAVY, HAVE_LOTS};
|
||||
|
||||
enum {
|
||||
GIVE_DO_PRINT = 1,
|
||||
GIVE_ALLOW_OVERLOAD = 2,
|
||||
// These three are mutually exclusive:
|
||||
GIVE_EQUIP_SOFT = 4,
|
||||
GIVE_EQUIP_TRY = 8,
|
||||
GIVE_EQUIP_FORCE = 12,
|
||||
};
|
||||
|
||||
class cParty;
|
||||
class cPlayer;
|
||||
|
||||
struct cInvenSlot {
|
||||
unsigned int slot;
|
||||
explicit cInvenSlot(cPlayer& owner) : slot(std::numeric_limits<unsigned int>::max()), owner(owner) {}
|
||||
cInvenSlot(cPlayer& owner, int slot) : slot(slot), owner(owner) {}
|
||||
void clear() {
|
||||
slot = std::numeric_limits<unsigned int>::max();
|
||||
}
|
||||
explicit operator bool() const;
|
||||
bool operator !() const;
|
||||
cItem* operator->();
|
||||
const cItem* operator->() const;
|
||||
cItem& operator*();
|
||||
const cItem& operator*() const;
|
||||
friend bool operator==(const cInvenSlot& a, const cInvenSlot& b) {
|
||||
return &a.owner == &b.owner && a.slot == b.slot;
|
||||
}
|
||||
private:
|
||||
cPlayer& owner;
|
||||
};
|
||||
|
||||
inline bool operator!=(const cInvenSlot& a, const cInvenSlot& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
class cPlayer : public iLiving {
|
||||
cParty* party;
|
||||
template<typename Fcn>
|
||||
cInvenSlot find_item_matching(Fcn fcn);
|
||||
static const int INVENTORY_SIZE = 24;
|
||||
public:
|
||||
// A nice convenient bitset with just the low 30 bits set, for initializing spells
|
||||
static const uint32_t basic_spells;
|
||||
static void(* give_help)(short,short);
|
||||
eMainStatus main_status;
|
||||
std::string name;
|
||||
// HACK: This is only really marked mutable so that I can use operator[] from const methods
|
||||
mutable std::map<eSkill, short> skills;
|
||||
unsigned short max_health;
|
||||
short cur_health;
|
||||
unsigned short max_sp;
|
||||
short cur_sp;
|
||||
unsigned short experience;
|
||||
short skill_pts;
|
||||
short level;
|
||||
std::array<cItem,INVENTORY_SIZE> items;
|
||||
std::bitset<INVENTORY_SIZE> equip;
|
||||
std::bitset<62> priest_spells;
|
||||
std::bitset<62> mage_spells;
|
||||
pic_num_t which_graphic;
|
||||
cInvenSlot weap_poisoned;
|
||||
// HACK: This is only really marked mutable so that I can use operator[] from const methods
|
||||
mutable std::map<eTrait,bool> traits;
|
||||
eRace race;
|
||||
long unique_id;
|
||||
// transient stuff
|
||||
std::map<eSkill,eSpell> last_cast;
|
||||
location combat_pos;
|
||||
short parry = 0;
|
||||
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;
|
||||
|
||||
int get_health() const;
|
||||
int get_magic() const;
|
||||
int get_level() const;
|
||||
location get_loc() const;
|
||||
|
||||
void finish_create();
|
||||
void void_sanctuary();
|
||||
void heal(int how_much);
|
||||
void poison(int how_much);
|
||||
void cure(int how_much);
|
||||
void acid(int how_much);
|
||||
void curse(int how_much);
|
||||
void slow(int how_much);
|
||||
void web(int how_much);
|
||||
void disease(int how_much);
|
||||
void dumbfound(int how_much);
|
||||
void scare(int how_much);
|
||||
void sleep(eStatus type, int how_much, int adj);
|
||||
void avatar();
|
||||
void drain_sp(int how_much);
|
||||
void restore_sp(int how_much);
|
||||
|
||||
void combine_things();
|
||||
void sort_items();
|
||||
bool give_item(cItem item, int flags);
|
||||
bool equip_item(int which_item, bool do_print);
|
||||
bool unequip_item(int which_item, bool do_print);
|
||||
std::pair<cInvenSlot, cInvenSlot> get_weapons();
|
||||
void take_item(int which_item);
|
||||
void remove_charge(int which_item);
|
||||
const cInvenSlot has_space() const;
|
||||
cInvenSlot has_space();
|
||||
short max_weight() const;
|
||||
short cur_weight() const;
|
||||
short free_weight() const;
|
||||
short get_prot_level(eItemAbil abil, short dat = -1) const;
|
||||
|
||||
const cInvenSlot has_abil_equip(eItemAbil abil, short dat = -1) const;
|
||||
cInvenSlot has_abil_equip(eItemAbil abil, short dat = -1);
|
||||
const cInvenSlot has_abil(eItemAbil abil, short dat = -1) const;
|
||||
cInvenSlot has_abil(eItemAbil abil, short dat = -1);
|
||||
const cInvenSlot has_type_equip(eItemType type) const;
|
||||
cInvenSlot has_type_equip(eItemType type);
|
||||
const cInvenSlot has_type(eItemType type) const;
|
||||
cInvenSlot has_type(eItemType type);
|
||||
const cInvenSlot has_class_equip(unsigned int item_class) const;
|
||||
cInvenSlot has_class_equip(unsigned int item_class);
|
||||
const cInvenSlot has_class(unsigned int item_class) const;
|
||||
cInvenSlot has_class(unsigned int item_class);
|
||||
|
||||
short skill(eSkill skill) const;
|
||||
short stat_adj(eSkill skill) const;
|
||||
eBuyStatus ok_to_buy(short cost,cItem item) const;
|
||||
|
||||
void join_party(cParty& p) {party = &p;}
|
||||
cPlayer* leave_party() {party = nullptr; return this;}
|
||||
|
||||
void import_legacy(legacy::pc_record_type old);
|
||||
cPlayer(cParty& party);
|
||||
cPlayer(cParty& party,long key,short slot);
|
||||
short get_tnl();
|
||||
void writeTo(std::ostream& file) const;
|
||||
void readFrom(std::istream& file);
|
||||
virtual ~cPlayer() = default;
|
||||
// Copy-and-swap
|
||||
void swap(cPlayer& other);
|
||||
cPlayer(const cPlayer& other);
|
||||
cPlayer(cPlayer&& other);
|
||||
// For now, not assignable because of an issue of how to handle the unique_id
|
||||
cPlayer& operator=(cPlayer other) = delete;
|
||||
};
|
||||
|
||||
#endif
|
||||
79
src/universe/population.cpp
Normal file
79
src/universe/population.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* creatlist.cpp
|
||||
* BoE
|
||||
*
|
||||
* Created by Celtic Minstrel on 24/04/09.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "population.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
||||
#include "oldstructs.hpp"
|
||||
|
||||
void cPopulation::import_legacy(legacy::creature_list_type old){
|
||||
dudes.resize(60);
|
||||
for(int i = 0; i < 60; i++)
|
||||
dudes[i].import_legacy(old.dudes[i]);
|
||||
which_town = old.which_town;
|
||||
hostile = old.hostile;
|
||||
}
|
||||
|
||||
const cCreature& cPopulation::operator[](size_t n) const {
|
||||
return dudes[n];
|
||||
}
|
||||
|
||||
cCreature& cPopulation::operator[](size_t n){
|
||||
return dudes[n];
|
||||
}
|
||||
|
||||
void cPopulation::init(size_t n) {
|
||||
if(n >= dudes.size()) dudes.resize(n + 1);
|
||||
dudes[n].active = 1;
|
||||
}
|
||||
|
||||
// This function combines a cTownperson from a scenario town record with a cMonster from the scenario record
|
||||
// into a cCreature, and prepares it for use in-game according to the user's preferences and party strength
|
||||
// replaces return_monster_template() from boe.monsters.cpp
|
||||
void cPopulation::assign(size_t n, const cTownperson& other, const cMonster& base, bool easy, int difficulty_adjust){
|
||||
// Make sure the space exists
|
||||
if(n >= dudes.size()) dudes.resize(n + 1);
|
||||
// First copy over the superclass fields
|
||||
static_cast<cTownperson&>(dudes[n]) = other;
|
||||
static_cast<cMonster&>(dudes[n]) = base;
|
||||
// Now set up extra stuff
|
||||
dudes[n].active = 1; // TODO: Is this right?
|
||||
if(dudes[n].invisible) dudes[n].picture_num = 0;
|
||||
dudes[n].m_health /= easy ? 2 : 1;
|
||||
dudes[n].m_health *= difficulty_adjust;
|
||||
dudes[n].health = dudes[n].m_health;
|
||||
dudes[n].ap = 0;
|
||||
if(dudes[n].mu > 0 || dudes[n].cl > 0)
|
||||
dudes[n].max_mp = dudes[n].mp = 12 * dudes[n].level;
|
||||
else dudes[n].max_mp = dudes[n].mp = 0;
|
||||
dudes[n].m_morale = 10 * dudes[n].level;
|
||||
if(dudes[n].level > 20)
|
||||
dudes[n].m_morale += 10 * (dudes[n].level - 20);
|
||||
dudes[n].morale = dudes[n].m_morale;
|
||||
dudes[n].direction = DIR_HERE;
|
||||
dudes[n].status.clear();
|
||||
dudes[n].attitude = dudes[n].start_attitude;
|
||||
dudes[n].cur_loc = dudes[n].start_loc;
|
||||
dudes[n].target = 6; // No target
|
||||
dudes[n].summon_time = 0;
|
||||
}
|
||||
|
||||
void cPopulation::swap(cPopulation& other) {
|
||||
std::swap(dudes, other.dudes);
|
||||
std::swap(which_town, other.which_town);
|
||||
std::swap(hostile, other.hostile);
|
||||
}
|
||||
|
||||
void cPopulation::readFrom(std::istream& in, size_t n) {
|
||||
if(n >= dudes.size()) dudes.resize(n + 1);
|
||||
dudes[n].readFrom(in);
|
||||
}
|
||||
43
src/universe/population.hpp
Normal file
43
src/universe/population.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* creatlist.h
|
||||
* BoE
|
||||
*
|
||||
* Created by Celtic Minstrel on 24/04/09.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOE_DATA_CREATLIST_H
|
||||
#define BOE_DATA_CREATLIST_H
|
||||
|
||||
#include "monster.hpp"
|
||||
#include <iosfwd>
|
||||
#include "creature.hpp"
|
||||
|
||||
namespace legacy {
|
||||
struct creature_list_type;
|
||||
struct creature_data_type;
|
||||
};
|
||||
|
||||
class cPopulation {
|
||||
std::vector<cCreature> dudes;
|
||||
public:
|
||||
short which_town;
|
||||
bool hostile;
|
||||
|
||||
void import_legacy(legacy::creature_list_type old);
|
||||
void init(size_t n);
|
||||
void assign(size_t n, const cTownperson& other, const cMonster& base, bool easy, int difficulty_adjust);
|
||||
void readFrom(std::istream& in, size_t n);
|
||||
size_t size() const {return dudes.size();}
|
||||
void clear() {dudes.clear();}
|
||||
cCreature& operator[](size_t n);
|
||||
const cCreature& operator[](size_t n) const;
|
||||
cPopulation() : which_town(200) {}
|
||||
std::vector<cCreature>::iterator begin() {return dudes.begin();}
|
||||
std::vector<cCreature>::iterator end() {return dudes.end();}
|
||||
// Apparently Visual Studio needs this to work
|
||||
cPopulation& operator=(const cPopulation& other) = default;
|
||||
void swap(cPopulation& other);
|
||||
};
|
||||
|
||||
#endif
|
||||
1456
src/universe/universe.cpp
Normal file
1456
src/universe/universe.cpp
Normal file
File diff suppressed because it is too large
Load Diff
223
src/universe/universe.hpp
Normal file
223
src/universe/universe.hpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* universe.h
|
||||
* BoE
|
||||
*
|
||||
* Created by Celtic Minstrel on 24/04/09.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOE_DATA_UNIVERSE_H
|
||||
#define BOE_DATA_UNIVERSE_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <array>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include "party.hpp"
|
||||
#include "population.hpp"
|
||||
#include "item.hpp"
|
||||
#include "town.hpp"
|
||||
#include "talking.hpp"
|
||||
#include "scenario.hpp"
|
||||
#include "pictypes.hpp"
|
||||
|
||||
namespace legacy {
|
||||
struct out_info_type;
|
||||
struct current_town_type;
|
||||
struct town_item_list;
|
||||
struct stored_town_maps_type;
|
||||
struct stored_outdoor_maps_type;
|
||||
struct big_tr_type;
|
||||
};
|
||||
|
||||
class cCurTown {
|
||||
short cur_talk_loaded = -1;
|
||||
bool free_for_sfx(short x, short y);
|
||||
cUniverse& univ;
|
||||
cTown* arena;
|
||||
cTown*const record() const;
|
||||
public:
|
||||
bool quickfire_present = false, belt_present = false;
|
||||
// formerly current_town_type
|
||||
short difficulty;
|
||||
cPopulation monst;
|
||||
|
||||
std::vector<cItem> items; // formerly town_item_list type
|
||||
|
||||
unsigned long fields[64][64];
|
||||
|
||||
void import_legacy(legacy::current_town_type& old);
|
||||
void import_legacy(legacy::town_item_list& old);
|
||||
void import_legacy(unsigned char(& old_sfx)[64][64], unsigned char(& old_misc_i)[64][64]);
|
||||
void import_legacy(legacy::big_tr_type& old);
|
||||
|
||||
cTown* operator -> ();
|
||||
explicit cCurTown(cUniverse& univ);
|
||||
short countMonsters();
|
||||
cSpeech& cur_talk(); // Get the currently loaded speech
|
||||
bool prep_talk(short which); // Prepare for loading specified speech, returning true if already loaded
|
||||
void prep_arena(); // Set up for a combat arena
|
||||
void place_preset_fields();
|
||||
|
||||
bool is_explored(short x, short y) const;
|
||||
bool is_force_wall(short x, short y) const;
|
||||
bool is_fire_wall(short x, short y) const;
|
||||
bool is_antimagic(short x, short y) const;
|
||||
bool is_scloud(short x, short y) const; // stinking cloud
|
||||
bool is_ice_wall(short x, short y) const;
|
||||
bool is_blade_wall(short x, short y) const;
|
||||
bool is_sleep_cloud(short x, short y) const;
|
||||
bool is_block(short x, short y) const; // currently unused
|
||||
bool is_spot(short x, short y) const;
|
||||
bool is_special(short x, short y) const;
|
||||
bool is_web(short x, short y) const;
|
||||
bool is_crate(short x, short y) const;
|
||||
bool is_barrel(short x, short y) const;
|
||||
bool is_fire_barr(short x, short y) const;
|
||||
bool is_force_barr(short x, short y) const;
|
||||
bool is_quickfire(short x, short y) const;
|
||||
bool is_sm_blood(short x, short y) const;
|
||||
bool is_med_blood(short x, short y) const;
|
||||
bool is_lg_blood(short x, short y) const;
|
||||
bool is_sm_slime(short x, short y) const;
|
||||
bool is_lg_slime(short x, short y) const;
|
||||
bool is_ash(short x, short y) const;
|
||||
bool is_bones(short x, short y) const;
|
||||
bool is_rubble(short x, short y) const;
|
||||
bool is_force_cage(short x, short y) const;
|
||||
bool is_road(short x, short y) const;
|
||||
bool set_explored(short x, short y, bool b);
|
||||
bool set_force_wall(short x, short y, bool b);
|
||||
bool set_fire_wall(short x, short y, bool b);
|
||||
bool set_antimagic(short x, short y, bool b);
|
||||
bool set_scloud(short x, short y, bool b); // stinking cloud
|
||||
bool set_ice_wall(short x, short y, bool b);
|
||||
bool set_blade_wall(short x, short y, bool b);
|
||||
bool set_sleep_cloud(short x, short y, bool b);
|
||||
bool set_block(short x, short y, bool b); // currently unused
|
||||
bool set_spot(short x, short y, bool b);
|
||||
bool set_web(short x, short y, bool b);
|
||||
bool set_crate(short x, short y, bool b);
|
||||
bool set_barrel(short x, short y, bool b);
|
||||
bool set_fire_barr(short x, short y, bool b);
|
||||
bool set_force_barr(short x, short y, bool b);
|
||||
bool set_quickfire(short x, short y, bool b);
|
||||
bool set_sm_blood(short x, short y, bool b);
|
||||
bool set_med_blood(short x, short y, bool b);
|
||||
bool set_lg_blood(short x, short y, bool b);
|
||||
bool set_sm_slime(short x, short y, bool b);
|
||||
bool set_lg_slime(short x, short y, bool b);
|
||||
bool set_ash(short x, short y, bool b);
|
||||
bool set_bones(short x, short y, bool b);
|
||||
bool set_rubble(short x, short y, bool b);
|
||||
bool set_force_cage(short x, short y, bool b);
|
||||
bool set_road(short x, short y, bool b);
|
||||
bool is_impassable(short x, short y);
|
||||
void writeTo(std::ostream& file) const;
|
||||
void readFrom(std::istream& file);
|
||||
|
||||
~cCurTown();
|
||||
// It's not directly copyable due to the cUniverse reference, which must always point to the cUniverse that contains it.
|
||||
// The cUniverse copy constructor is thus responsible for performing the copy.
|
||||
cCurTown(const cCurTown&) = delete;
|
||||
cCurTown& operator=(const cCurTown&) = delete;
|
||||
// Not movable for similar reasons
|
||||
cCurTown(const cCurTown&& other) = delete;
|
||||
cCurTown& operator=(const cCurTown&& other) = delete;
|
||||
// This implements the actual copy/move.
|
||||
void copy(const cCurTown& other);
|
||||
void swap(cCurTown& other);
|
||||
};
|
||||
|
||||
class cCurOut {
|
||||
cUniverse& univ;
|
||||
public:
|
||||
char expl[96][96]; // formerly out_info_type
|
||||
ter_num_t out[96][96];
|
||||
unsigned char out_e[96][96];
|
||||
|
||||
// These take global coords (ie 0..95)
|
||||
bool is_spot(int x, int y);
|
||||
bool is_road(int x, int y);
|
||||
|
||||
void import_legacy(legacy::out_info_type& old);
|
||||
|
||||
typedef ter_num_t arr_96[96];
|
||||
arr_96& operator [] (size_t i);
|
||||
ter_num_t& operator [] (location loc);
|
||||
void writeTo(std::ostream& file) const;
|
||||
void readFrom(std::istream& file);
|
||||
cOutdoors* operator->();
|
||||
explicit cCurOut(cUniverse& univ);
|
||||
// It's not directly copyable due to the cUniverse reference, which must always point to the cUniverse that contains it.
|
||||
// The cUniverse copy constructor is thus responsible for performing the copy.
|
||||
cCurOut(const cCurOut&) = delete;
|
||||
cCurOut& operator=(const cCurOut&) = delete;
|
||||
// Not movable for similar reasons
|
||||
cCurOut(const cCurOut&& other) = delete;
|
||||
cCurOut& operator=(const cCurOut&& other) = delete;
|
||||
// This implements the actual copy/move.
|
||||
void copy(const cCurOut& other);
|
||||
void swap(cCurOut& other);
|
||||
};
|
||||
|
||||
enum eTargetType {TARG_ANY, TARG_PC, TARG_MONST};
|
||||
|
||||
class cUniverse{
|
||||
template<typename T> using update_info = std::set<T*>;
|
||||
// All these maps are transient data that doesn't need to be saved
|
||||
std::map<pic_num_t, update_info<cItem>> update_items;
|
||||
std::map<pic_num_t, update_info<cMonster>> update_monsters;
|
||||
std::map<pic_num_t, update_info<cPlayer>> update_pcs;
|
||||
std::map<pic_num_t, update_info<miss_num_t>> update_missiles;
|
||||
std::set<pic_num_t> used_graphics;
|
||||
pic_num_t addGraphic(pic_num_t pic, ePicType type);
|
||||
void check_monst(cMonster& monst);
|
||||
void check_item(cItem& item);
|
||||
// The string buffer currently isn't saved
|
||||
std::string strbuf;
|
||||
std::map<int,std::string> extrabufs;
|
||||
cItem get_random_store_item(int loot_type, bool allow_junk_treasure);
|
||||
public:
|
||||
void exportSummons();
|
||||
void exportGraphics();
|
||||
|
||||
iLiving& get_target(size_t which);
|
||||
iLiving* target_there(location pos, eTargetType type = TARG_ANY);
|
||||
size_t get_target_i(iLiving& who);
|
||||
|
||||
std::string& get_buf() {return strbuf;}
|
||||
void swap_buf(int newbuf) {std::swap(strbuf, extrabufs[newbuf]);}
|
||||
|
||||
unsigned char& cpn_flag(unsigned int x, unsigned int y, std::string id = "");
|
||||
|
||||
short cur_pc = 0;
|
||||
cPlayer& current_pc();
|
||||
|
||||
cScenario scenario;
|
||||
cParty party;
|
||||
std::map<long,cPlayer*> stored_pcs;
|
||||
cCurTown town;
|
||||
cCurOut out;
|
||||
fs::path file;
|
||||
bool debug_mode, ghost_mode, node_step_through;
|
||||
|
||||
void clear_stored_pcs();
|
||||
void import_legacy(legacy::stored_town_maps_type& old);
|
||||
void import_legacy(legacy::stored_outdoor_maps_type& old);
|
||||
void enter_scenario(const std::string& name);
|
||||
void refresh_store_items();
|
||||
void generate_job_bank(int which, job_bank_t& bank);
|
||||
short difficulty_adjust() const;
|
||||
explicit cUniverse(long party_type = 'dflt');
|
||||
~cUniverse();
|
||||
// Copy-and-swap
|
||||
void swap(cUniverse& other);
|
||||
cUniverse(const cUniverse& other);
|
||||
cUniverse(cUniverse&& other);
|
||||
cUniverse& operator=(cUniverse other);
|
||||
static void(* print_result)(std::string);
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user