Beispiel #1
0
void Monster::updateRetargeting(Duration elapsedTime) {
	assert(elapsedTime >= Duration::zero());

	if (_retargetDelay <= Duration::zero()) {
		return;
	}

	if (attackedCreature == nullptr) {
		return;
	}

	if (hasMaster()) {
		return;
	}

	if (elapsedTime >= _retargetDelay) {
		_retargetDelay = _type->retargetInterval;

		if (_type->retargetChance < random_range(1, 100)) {
			return;
		}

		retarget();
	}
	else {
		_retargetDelay -= elapsedTime;
	}
}
Beispiel #2
0
bool Monster::canAttack(const Creature& creature) const {
	if (!creature.isAlive()) {
		return false;
	}

	if (hasMaster()) {
		return _master->canAttack(creature);
	}

	// TODO name "isAttackable" is too broad
	if (!creature.isAttackable()) {
		return false;
	}

	// TODO merge with isAttackable?
	if (creature.getZone() == ZONE_PROTECTION) {
		return false;
	}

	if (creature.isInvisible() && !canSeeInvisibility()) {
		return false;
	}

	PlayerPC controller = creature.getController();
	if (controller != nullptr) {
		if (controller->isGhost()) {
			return false;
		}
	}

	return true;
}
Beispiel #3
0
void Monster::onAttackedCreature(Creature* target) {
	Creature::onAttackedCreature(target);

	if (hasMaster()) {
		_master->onSummonAttackedCreature(this, target);
	}
}
Beispiel #4
0
void Monster::onAttackedCreatureDrain(Creature* target, int32_t points) {
	Creature::onAttackedCreatureDrain(target, points);

	if (hasMaster()) {
		_master->onSummonAttackedCreatureDrain(this, target, points);
	}
}
Beispiel #5
0
//
// All unlocking activity ultimately funnels through this method.
// This unlocks a DbCommon using the secrets setup in its crypto core
// component, and performs all the housekeeping needed to represent
// the state change.
// Returns true if unlock was successful, false if it failed due to
// invalid/insufficient secrets. Throws on other errors.
//
bool KeychainDbCommon::unlockDb(DbBlob *blob, void **privateAclBlob)
{
	try {
		// Tell the cryptocore to (try to) decode itself. This will fail
		// in an astonishing variety of ways if the passphrase is wrong.
		assert(hasMaster());
		decodeCore(blob, privateAclBlob);
		secdebug("KCdb", "%p unlock successful", this);
	} catch (...) {
		secdebug("KCdb", "%p unlock failed", this);
		return false;
	}
	
	// get the database parameters only if we haven't got them yet
	if (!mValidParams) {
		mParams = blob->params;
		n2hi(mParams.idleTimeout);
		mValidParams = true;	// sticky
	}

	bool isLocked = mIsLocked;
	
	setUnlocked();		// mark unlocked
	
	if (isLocked) {
		// broadcast unlock notification, but only if we were previously locked
		notify(kNotificationEventUnlocked);
		SECURITYD_KEYCHAIN_UNLOCK(this, (char*)this->dbName());
	}
    return true;
}
Beispiel #6
0
void Monster::notifyMasterChanged(const CreatureP& previousMaster) {
	SpectatorList spectators;

	if (isAlive()) {
		Game& game = server.game();

		game.getSpectators(spectators, getPosition(), false, true);
		if (hasMaster()) {
			game.getSpectators(spectators, _master->getPosition(), true, true);
		}

		if (previousMaster != nullptr && std::find(spectators.begin(), spectators.end(), previousMaster) == spectators.end()) {
			spectators.push_back(previousMaster);
		}
		if (_master != nullptr && std::find(spectators.begin(), spectators.end(), _master) == spectators.end()) {
			spectators.push_back(_master);
		}
	}
	else {
		if (previousMaster != nullptr) {
			spectators.push_back(previousMaster);
		}
		if (_master != nullptr) {
			spectators.push_back(_master);
		}
	}

	for (const auto& spectator : spectators) {
		spectator->onMonsterMasterChanged(this, previousMaster);
	}
}
Beispiel #7
0
void Monster::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
{
	Creature::getPathSearchParams(creature, fpp);
	fpp.minTargetDist = 1;
	fpp.maxTargetDist = _type->targetDistance;
	if(hasMaster())
	{
		if(getMaster() == creature)
		{
			fpp.maxTargetDist = 2;
			fpp.fullPathSearch = true;
		}
		else if(_type->targetDistance <= 1)
			fpp.fullPathSearch = true;
		else
			fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
	}
	else if(isFleeing())
	{
		//Distance should be higher than the client view range (Map::maxClientViewportX/Map::maxClientViewportY)
		fpp.maxTargetDist = Map::maxViewportX;
		fpp.clearSight = fpp.fullPathSearch = false;
		fpp.keepDistance = true;
	}
	else if(_type->targetDistance <= 1)
		fpp.fullPathSearch = true;
	else
		fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
}
Beispiel #8
0
uint32_t Monster::getPreferredFollowDistance() const {
	if (getAttackedCreature() != nullptr) {
		return std::max(_type->targetDistance, 1u);
	}
	if (hasMaster()) {
		return 2;
	}

	return Creature::getPreferredFollowDistance();
}
Beispiel #9
0
void KeychainDbCommon::makeNewSecrets()
{
	// we already have a master key (right?)
	assert(hasMaster());

	// tell crypto core to generate the use keys
	DatabaseCryptoCore::generateNewSecrets();
	
	// we're now officially "unlocked"; set the timer
	setUnlocked();
}
Beispiel #10
0
void Monster::updateFollowing() {
	if (attackedCreature != nullptr) {
		startFollowing(attackedCreature);
	}
	else if (hasMaster()) {
		startFollowing(_master.get());
	}
	else {
		stopFollowing();
	}
}
Beispiel #11
0
bool Monster::shouldTeleportToMaster() const {
	if (!hasMaster()) {
		return false;
	}

	ConfigManager& config = server.configManager();
	if (!config.getBool(ConfigManager::TELEPORT_SUMMONS) && (_master->getPlayer() == nullptr || !config.getBool(ConfigManager::TELEPORT_PLAYER_SUMMONS))) {
		return false;
	}

	if (isMasterInRange()) {
		return false;
	}

	return true;
}
Beispiel #12
0
bool Monster::teleportToMaster() {
	if (!hasMaster()) {
		return false;
	}

	Game& game = server.game();

	Position initialPosition = getPosition();
	if (game.internalTeleport(this, game.getClosestFreeTile(this, _master->getPosition(), true), false) != RET_NOERROR) {
		return false;
	}

	game.addMagicEffect(initialPosition, MAGIC_EFFECT_POFF);
	game.addMagicEffect(getPosition(), MAGIC_EFFECT_TELEPORT);

	return true;
}
Beispiel #13
0
DbBlob *KeychainDbCommon::encode(KeychainDatabase &db)
{
    assert(!isLocked());	// must have been unlocked by caller
    
    // export database ACL to blob form
    CssmData pubAcl, privAcl;
    db.acl().exportBlob(pubAcl, privAcl);
    
    // tell the cryptocore to form the blob
    DbBlob form;
    form.randomSignature = identifier();
    form.sequence = sequence;
    form.params = mParams;
	h2ni(form.params.idleTimeout);
	
	assert(hasMaster());
    DbBlob *blob = encodeCore(form, pubAcl, privAcl);
    
    // clean up and go
    db.acl().allocator.free(pubAcl);
    db.acl().allocator.free(privAcl);
	return blob;
}
Beispiel #14
0
bool Monster::isEnemy(const Creature& creature) const {
	if (hasMaster()) {
		return _master->isEnemy(creature);
	}

	if (!isHostile()) {
		return false;
	}

	PlayerPC controller = creature.getController();
	if (controller == nullptr) {
		return false;
	}

	if (controller->hasFlag(PlayerFlag_IgnoredByMonsters)) {
		return false;
	}

	if (controller->hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_SNEAKY, false)) {
		return false;
	}

	return true;
}
Beispiel #15
0
void Monster::updateTarget() {
	if (hasMaster()) {
		target(_master->getAttackedCreature());
	}
	else {
		CreatureP attackedCreature = this->attackedCreature;
		if (attackedCreature == nullptr || !canAttack(*attackedCreature)) {
			retarget();
		}
		else {
			// retarget if target is out of sight + we cannot walk there
			auto& game = server.game();
			if (!game.isSightClear(getPosition(), attackedCreature->getPosition(), true)) {
				FindPathParams parameters;
				getPathSearchParams(attackedCreature.get(), parameters);

				DirectionRoute route;
				if (!server.game().getPathToEx(this, attackedCreature->getPosition(), route, parameters)) {
					retarget();
				}
			}
		}
	}
}
Beispiel #16
0
bool Monster::canBeConvincedBy(const CreatureP& convincer, bool forced) const {
	if (convincer == this) {
		return false;
	}

	if (!forced) {
		Player* convincingPlayer = convincer->getPlayer();
		if (convincingPlayer != nullptr && !_type->isConvinceable && !convincingPlayer->hasFlag(PlayerFlag_CanConvinceAll)) {
			return false;
		}
	}

	if (hasMaster()) {
		if (!forced && _master->hasController()) {
			return false;
		}

		if (convincer == _master) {
			return false;
		}
	}

	return true;
}
Beispiel #17
0
void Monster::onThinkDefense(uint32_t interval) {
	auto& game = server.game();

	resetTicks = true;
	defenseTicks += interval;
	for(SpellList::iterator it = _type->spellDefenseList.begin(); it != _type->spellDefenseList.end(); ++it)
	{
		if(it->speed > defenseTicks)
		{
			if(resetTicks)
				resetTicks = false;

			continue;
		}

		if(defenseTicks % it->speed >= interval) //already used this spell for this round
			continue;

		if((it->chance >= (uint32_t)random_range(1, 100)))
		{
			minCombatValue = it->minCombatValue;
			maxCombatValue = it->maxCombatValue;
			it->spell->castSpell(this, this);
		}
	}

	if(!hasMaster())
	{
		if(_type->maxSummons < 0 || (int32_t)summons.size() < _type->maxSummons)
		{
			for(SummonList::iterator it = _type->summonList.begin(); it != _type->summonList.end(); ++it)
			{
				if((int32_t)summons.size() >= _type->maxSummons)
					break;

				if(it->interval > defenseTicks)
				{
					if(resetTicks)
						resetTicks = false;

					continue;
				}

				if(defenseTicks % it->interval >= interval)
					continue;

				uint32_t typeCount = 0;
				for(MonsterList::iterator cit = summons.begin(); cit != summons.end(); ++cit)
				{
					if(!(*cit)->isAlive() && (*cit)->getMonster() &&
						(*cit)->getMonster()->getName() == it->name)
						typeCount++;
				}

				if(typeCount >= it->amount)
					continue;

				if((it->chance >= (uint32_t)random_range(1, 100))) {
					if (game.placeSummon(this, it->name)) {
						game.addMagicEffect(getPosition(), MAGIC_EFFECT_WRAPS_BLUE);
					}
				}
			}
		}
	}

	if(resetTicks)
		defenseTicks = 0;
}
Beispiel #18
0
bool Monster::isMasterInRange() const {
	return (hasMaster() && canSee(_master->getPosition()));
}