Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 124 additions & 73 deletions areas/room.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,59 +429,85 @@ int Monster::doDeleteFromRoom(std::shared_ptr<BaseRoom> room, bool delPortal) {
return(0);
}

//********************************************************************
// addPermCrt
//********************************************************************
// This function checks a room to see if any permanent monsters need to
// be loaded. If so, the monsters are loaded to the room, and their
// permanent flag is set.

void UniqueRoom::addPermCrt() {
std::map<int, CRLastTime>::iterator it, nt;
CRLastTime* crtm;
std::map<int, bool> checklist;
std::shared_ptr<Monster> monster=nullptr;
long t = time(nullptr);
int j=0, m=0, n=0;
std::shared_ptr<Monster> monster = nullptr;
long t = time(nullptr);
std::vector<CRLastTime*> groupedTimers;

for(it = permMonsters.begin(); it != permMonsters.end() ; it++) {
for (it = permMonsters.begin(); it != permMonsters.end(); ++it) {
crtm = &(*it).second;

if(checklist[(*it).first])
if (checklist[(*it).first])
continue;
if(!crtm->cr.id)
if (!crtm->cr.id)
continue;
if(crtm->ltime + crtm->interval > t)
if (crtm->ltime + crtm->interval > t)
continue;

n = 1;
m = 0;
groupedTimers.clear();
groupedTimers.push_back(crtm);

nt = it;
nt++;
for(; nt != permMonsters.end() ; nt++) {
if( crtm->cr == (*nt).second.cr &&
((*nt).second.ltime + (*nt).second.interval) < t
) {
n++;
++nt;
for (; nt != permMonsters.end(); ++nt) {
if (crtm->cr == (*nt).second.cr &&
((*nt).second.ltime + (*nt).second.interval) < t)
{
checklist[(*nt).first] = true;
groupedTimers.push_back(&(*nt).second);
}
}

if(!loadMonster(crtm->cr, monster))
// Count how many of this monster are already spawned
if (!loadMonster(crtm->cr, monster))
continue;

for(const auto& mons : monsters) {
if( mons->flagIsSet(M_PERMANENT_MONSTER) && mons->getName() == monster->getName() )
m++;
int existingCount = 0;
for (const auto& mons : monsters) {
if (mons->flagIsSet(M_PERMANENT_MONSTER) && mons->getName() == monster->getName()) {
existingCount++;
}
}

monster.reset();

for(j=0; j<n-m; j++) {
// Now process ONLY missing monsters
int missing = groupedTimers.size() - existingCount;
if (missing <= 0)
continue; // Nothing missing, skip

for (size_t i = 0; i < groupedTimers.size(); ++i) {
if (i < existingCount)
continue; // Already spawned

if(!loadMonster(crtm->cr, monster))
if (!loadMonster(crtm->cr, monster))
continue;

int spawnChance = monster->getPermSpawnChance();
if (spawnChance > 0) {
int roll = Random::get(1, 1000);

if (roll > spawnChance) {
// Failed spawn chance
broadcast(isCt, "^y### PermCrt '%s' in room %s (%s) FAILED perm spawn chance (%d on %d/1000) and did not spawn.^x",
monster->getCName(), info.displayStr().c_str(), getCName(), roll, spawnChance);
groupedTimers[i]->ltime = t; // Reset only this monster's timer
monster.reset();
continue;
}

// Passed spawn chance
broadcast(isCt, "^y### PermCrt '%s' in room %s (%s) PASSED perm spawn chance (%d on %d/1000) and has spawned.^x",
monster->getCName(), info.displayStr().c_str(), getCName(), roll, spawnChance);
} else {
// No spawn chance set, guaranteed spawn
broadcast(isCt, "^y### PermCrt '%s' ^yhas respawned in room %s (%s).^x",
monster->getCName(), info.displayStr().c_str(), getCName());
}

// Spawn the monster
monster->initMonster();
monster->setFlag(M_PERMANENT_MONSTER);
monster->daily[DL_BROAD].cur = 20;
Expand All @@ -490,86 +516,111 @@ void UniqueRoom::addPermCrt() {
monster->validateAc();
monster->addToRoom(BaseRoom::downcasted_shared_from_this<UniqueRoom>(), 0);

if(!players.empty())
if (!players.empty())
gServer->addActive(monster);

monster.reset();
}
}
}


//*********************************************************************
// addPermObj
//*********************************************************************
// This function checks a room to see if any permanent objects need to
// be loaded. If so, the objects are loaded to the room, and their
// permanent flag is set.

void UniqueRoom::addPermObj() {
std::map<int, CRLastTime>::iterator it, nt;
CRLastTime* crtm=nullptr;
CRLastTime* crtm = nullptr;
std::map<int, bool> checklist;
std::shared_ptr<Object> object=nullptr;
long t = time(nullptr);
int j=0, m=0, n=0;
std::shared_ptr<Object> object = nullptr;
long t = time(nullptr);
std::vector<CRLastTime*> groupedTimers;

for(it = permObjects.begin(); it != permObjects.end() ; it++) {
for (it = permObjects.begin(); it != permObjects.end(); ++it) {
crtm = &(*it).second;

if(checklist[(*it).first])
if (checklist[(*it).first])
continue;
if(!crtm->cr.id)
if (!crtm->cr.id)
continue;
if(crtm->ltime + crtm->interval > t)
if (crtm->ltime + crtm->interval > t)
continue;

n = 1;
m = 0;
groupedTimers.clear();
groupedTimers.push_back(crtm);

nt = it;
nt++;
for(; nt != permObjects.end() ; nt++) {
if( crtm->cr == (*nt).second.cr &&
((*nt).second.ltime + (*nt).second.interval) < t )
{
n++;
++nt;
for (; nt != permObjects.end(); ++nt) {
if (crtm->cr == (*nt).second.cr &&
((*nt).second.ltime + (*nt).second.interval) < t) {
checklist[(*nt).first] = true;
groupedTimers.push_back(&(*nt).second);
}
}

if(!loadObject(crtm->cr, object))
// Load object once to check name/info for comparison
if (!loadObject(crtm->cr, object))
continue;

for(const auto& obj : objects) {
if(obj->flagIsSet(O_PERM_ITEM)) {
if(obj->getName() == object->getName() && obj->info == object->info)
m++;
else if( object->getName() == obj->droppedBy.getName() &&
object->info.str() == obj->droppedBy.getIndex())
m++;
}
int existingCount = 0;
for (const auto& obj : objects) {
if (obj->flagIsSet(O_PERM_ITEM)) {
if (obj->getName() == object->getName() && obj->info == object->info)
++existingCount;
else if (object->getName() == obj->droppedBy.getName() &&
object->info.str() == obj->droppedBy.getIndex())
++existingCount;
}
}

object.reset();

for(j=0; j<n-m; j++) {
if(!loadObject(crtm->cr, object))
int missing = groupedTimers.size() - existingCount;
if (missing <= 0)
continue;

for (size_t i = 0; i < groupedTimers.size(); ++i) {
if (i < existingCount)
continue;
if (!object->randomObjects.empty())
object->init();
else
object->setDroppedBy(shared_from_this(), "PermObject");

if (!loadObject(crtm->cr, object))
continue;

if(object->flagIsSet(O_RANDOM_ENCHANT))
object->randomEnchant();
int spawnChance = object->getPermSpawnChance();
if (spawnChance > 0) {
int roll = Random::get(1, 1000);
if (roll > spawnChance) {
// Spawn failed
broadcast(isCt, "^y### PermObj '%s' in room %s (%s) FAILED spawn chance (%d on %d/1000) and did not spawn.^x",
object->getCName(), info.displayStr().c_str(), getCName(), roll, spawnChance);
groupedTimers[i]->ltime = t;
object.reset();
continue;
}

object->setFlag(O_PERM_ITEM);
broadcast(isCt, "^y### PermObj '%s' in room %s (%s) PASSED spawn chance (%d on %d/1000) and has spawned.^x",
object->getCName(), info.displayStr().c_str(), getCName(), roll, spawnChance);
} else {
// Guaranteed spawn
broadcast(isCt, "^y### PermObj '%s' ^yhas respawned in room %s (%s).^x",
object->getCName(), info.displayStr().c_str(), getCName());
}

if (!object->randomObjects.empty())
object->init();
else
object->setDroppedBy(shared_from_this(), (spawnChance?"VariablePermObject":"PermObject"));

if (object->flagIsSet(O_RANDOM_ENCHANT))
object->randomEnchant();

object->setFlag(O_PERM_ITEM);
object->addToRoom(BaseRoom::downcasted_shared_from_this<UniqueRoom>());

groupedTimers[i]->ltime = t;
object.reset();
}
}
}



//*********************************************************************
// roomEffStr
//*********************************************************************
Expand Down
28 changes: 21 additions & 7 deletions areas/startlocs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,16 @@ bool startingChoices(std::shared_ptr<Player> player, std::string str, char *loca

// set race equal to their parent race, use player->getRace() if checking
// for subraces
const RaceData *r = gConfig->getRace(race);
if (r && r->getParentRace())
race = r->getParentRace();

//**********************************************
// Not sure why we wanted subraces to always have same startloc options as parent race.
// Doesn't make sense when subraces are very often not even close to the same as
// their parent race. i.e. Dwarf vs Duergar or Elf vs Aquatic Elf. Removing this for now. -TC

//const RaceData *r = gConfig->getRace(race);
//if (r && r->getParentRace())
// race = r->getParentRace();
//**********************************************

if (player->getClass() == CreatureClass::DRUID) {

Expand All @@ -118,11 +125,15 @@ bool startingChoices(std::shared_ptr<Player> player, std::string str, char *loca
// religious states
options.emplace_back("sigil");

} else if (player->getDeity() == ARAMON || player->getRace() == CAMBION) {
} else if (player->getDeity() == ARAMON) {

// religious states
options.emplace_back("caladon");

} else if (player->getDeity() == LINOTHAN || player->getDeity() == MARA) {

options.emplace_back("eldinwood");

} else if (race == HUMAN && player->getClass() == CreatureClass::CLERIC) {

// all other human clerics have to start in HP because
Expand All @@ -142,7 +153,8 @@ bool startingChoices(std::shared_ptr<Player> player, std::string str, char *loca

options.emplace_back("schnai");

} else if (race == DWARF) {
// When duergar city built, and/or Ironguard is expanded, this will change
} else if (race == DWARF || race == DUERGAR) {

options.emplace_back("highport");

Expand Down Expand Up @@ -176,11 +188,12 @@ bool startingChoices(std::shared_ptr<Player> player, std::string str, char *loca
options.emplace_back("caladon");
options.emplace_back("orc");

} else if (race == ORC) {
} else if (race == ORC || race == OROG) {

options.emplace_back("orc");

} else if (race == ELF || player->getDeity() == LINOTHAN) {
} else if (race == ELF ||
race == GREYELF || race == WILDELF) {

options.emplace_back("eldinwood");

Expand All @@ -201,6 +214,7 @@ bool startingChoices(std::shared_ptr<Player> player, std::string str, char *loca
switch (player->getClass()) {
case CreatureClass::RANGER:
options.emplace_back("druidwood");
options.emplace_back("highport");
break;
// even seraphs of these classes cannot start in Sigil
case CreatureClass::ASSASSIN:
Expand Down
14 changes: 9 additions & 5 deletions bards/identify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,18 @@ int cmdIdentify(const std::shared_ptr<Player>& player, cmd* cmnd) {
player->checkImprove("identify", false);
broadcast(player->getSock(), player->getParent(), "%M carefully studies %P.",player.get(), object.get());
player->lasttime[LT_IDENTIFY].ltime = t;
player->lasttime[LT_IDENTIFY].interval = 45L;
player->lasttime[LT_IDENTIFY].interval = 15L;
return(0);
} else {
broadcast(player->getSock(), player->getParent(), "%M carefully studies %P.", player.get(), object.get());
broadcast(player->getSock(), player->getParent(), "%s successfully identifies it!", player->upHeShe());
player->printColor("You carefully study %P.\n",object.get());
player->printColor("You manage to learn about %P!\n", object.get());
player->printColor("You managed to learn about %P !\n\n", object.get());
player->checkImprove("identify", true);

object->clearFlag(O_JUST_BOUGHT);

player->lasttime[LT_IDENTIFY].ltime = t;
player->lasttime[LT_IDENTIFY].interval = 45L;
player->lasttime[LT_IDENTIFY].interval = 60L;

if(object->increase) {

Expand All @@ -168,6 +167,11 @@ int cmdIdentify(const std::shared_ptr<Player>& player, cmd* cmnd) {
} else if(object->getType() == ObjectType::WEAPON) {
player->printColor("%O is a %s, with an average damage of %d.\n", object.get(), object->getTypeName().c_str(),
std::max(1, object->damage.average() + object->getAdjustment()));

if(object->getMagicpower() && object->flagIsSet(O_WEAPON_CASTS)) {
player->printColor("%O will %s the ^W%s^x spell on its enemies.\n", object.get(), object->getCastChance()?"sometimes cast":"cast", get_spell_name(object->getMagicpower()-1));
}

} else if(object->getType() == ObjectType::POISON) {
player->printColor("%O is a poison.\n", object.get());
player->print("It has a maximum duration of %d seconds.\n", object->getEffectDuration());
Expand Down Expand Up @@ -395,7 +399,7 @@ int cmdIdentify(const std::shared_ptr<Player>& player, cmd* cmnd) {
output = object->value.str();
player->print("It is worth %s", output.c_str());
if(object->getType() != ObjectType::CONTAINER && object->getType() != ObjectType::MONEY) {
player->print(", and is ", object.get());
player->print(", and it is ", object.get());
if(object->getShotsCur() >= object->getShotsMax() * .99)
player->print("brand new");
else if(object->getShotsCur() >= object->getShotsMax() * .90)
Expand Down
Loading