Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ignore spawn block monster flag #3601

Merged
merged 4 commits into from
Aug 29, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions data/monster/lua/#example.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ monster.flags = {
hostile = true,
challengeable = true,
convinceable = false,
ignoreSpawnBlock = false,
illusionable = false,
canPushItems = true,
canPushCreatures = true,
Expand Down
1 change: 1 addition & 0 deletions data/monster/monsters/black_knight.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<flag summonable="0" />
<flag attackable="1" />
<flag hostile="1" />
<flag ignorespawnblock="0" />
<flag illusionable="0" />
<flag convinceable="0" />
<flag pushable="0" />
Expand Down
5 changes: 4 additions & 1 deletion data/scripts/lib/register_monster_type.lua
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ registerMonsterType.flags = function(mtype, mask)
mtype:isConvinceable(mask.flags.convinceable)
end
if mask.flags.summonable ~= nil then
mtype.isSummonable(mask.flags.summonable)
This conversation was marked as resolved.
Show resolved Hide resolved
mtype:isSummonable(mask.flags.summonable)
end
if mask.flags.ignoreSpawnBlock ~= nil then
mtype:isIgnoringSpawnBlock(mask.flags.ignoreSpawnBlock)
end
if mask.flags.illusionable ~= nil then
mtype:isIllusionable(mask.flags.illusionable)
Expand Down
18 changes: 18 additions & 0 deletions src/luascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2789,6 +2789,7 @@ void LuaScriptInterface::registerFunctions()
registerMethod("MonsterType", "isChallengeable", LuaScriptInterface::luaMonsterTypeIsChallengeable);
registerMethod("MonsterType", "isConvinceable", LuaScriptInterface::luaMonsterTypeIsConvinceable);
registerMethod("MonsterType", "isSummonable", LuaScriptInterface::luaMonsterTypeIsSummonable);
registerMethod("MonsterType", "isIgnoringSpawnBlock", LuaScriptInterface::luaMonsterTypeIsIgnoringSpawnBlock);
registerMethod("MonsterType", "isIllusionable", LuaScriptInterface::luaMonsterTypeIsIllusionable);
registerMethod("MonsterType", "isHostile", LuaScriptInterface::luaMonsterTypeIsHostile);
registerMethod("MonsterType", "isPushable", LuaScriptInterface::luaMonsterTypeIsPushable);
Expand Down Expand Up @@ -13037,6 +13038,23 @@ int LuaScriptInterface::luaMonsterTypeIsSummonable(lua_State* L)
return 1;
}

int LuaScriptInterface::luaMonsterTypeIsIgnoringSpawnBlock(lua_State* L)
{
// get: monsterType:isIgnoringSpawnBlock() set: monsterType:isIgnoringSpawnBlock(bool)
MonsterType* monsterType = getUserdata<MonsterType>(L, 1);
if (monsterType) {
if (lua_gettop(L) == 1) {
pushBoolean(L, monsterType->info.isIgnoringSpawnBlock);
} else {
monsterType->info.isIgnoringSpawnBlock = getBoolean(L, 2);
pushBoolean(L, true);
}
} else {
lua_pushnil(L);
}
return 1;
}

int LuaScriptInterface::luaMonsterTypeIsIllusionable(lua_State* L)
{
// get: monsterType:isIllusionable() set: monsterType:isIllusionable(bool)
Expand Down
1 change: 1 addition & 0 deletions src/luascript.h
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,7 @@ class LuaScriptInterface
static int luaMonsterTypeIsChallengeable(lua_State* L);
static int luaMonsterTypeIsConvinceable(lua_State* L);
static int luaMonsterTypeIsSummonable(lua_State* L);
static int luaMonsterTypeIsIgnoringSpawnBlock(lua_State* L);
static int luaMonsterTypeIsIllusionable(lua_State* L);
static int luaMonsterTypeIsHostile(lua_State* L);
static int luaMonsterTypeIsPushable(lua_State* L);
Expand Down
2 changes: 2 additions & 0 deletions src/monsters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,8 @@ MonsterType* Monsters::loadMonster(const std::string& file, const std::string& m
mType->info.isAttackable = attr.as_bool();
} else if (strcasecmp(attrName, "hostile") == 0) {
mType->info.isHostile = attr.as_bool();
} else if (strcasecmp(attrName, "ignorespawnblock") == 0) {
mType->info.isIgnoringSpawnBlock = attr.as_bool();
} else if (strcasecmp(attrName, "illusionable") == 0) {
mType->info.isIllusionable = attr.as_bool();
} else if (strcasecmp(attrName, "challengeable") == 0) {
Expand Down
11 changes: 6 additions & 5 deletions src/monsters.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,15 @@ class MonsterType
bool canPushItems = false;
bool canPushCreatures = false;
bool pushable = true;
bool isSummonable = false;
bool isIllusionable = false;
bool isConvinceable = false;
bool isAttackable = true;
bool isHostile = true;
bool hiddenHealth = false;
bool isBoss = false;
bool isChallengeable = true;
bool isConvinceable = false;
bool isHostile = true;
bool isIgnoringSpawnBlock = false;
bool isIllusionable = false;
bool isSummonable = false;
bool hiddenHealth = false;
bool canWalkOnEnergy = true;
bool canWalkOnFire = true;
bool canWalkOnPoison = true;
Expand Down
43 changes: 33 additions & 10 deletions src/spawn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,18 +287,42 @@ bool Spawn::isInSpawnZone(const Position& pos)

bool Spawn::spawnMonster(uint32_t spawnId, spawnBlock_t sb, bool startup/* = false*/)
{
if (sb.mTypes.size() == 1) {
return spawnMonster(spawnId, std::get<0>(sb.mTypes.front()), sb.pos, sb.direction, startup);
}
bool isBlocked = !startup && findPlayer(sb.pos);
size_t monstersCount = sb.mTypes.size(), blockedMonsters = 0;

auto spawnFunc = [&](bool roll) {
MonsterType *mType;
for (std::tuple<MonsterType*, uint16_t> tuple : sb.mTypes) {
marmichalski marked this conversation as resolved.
Show resolved Hide resolved
mType = std::get<0>(tuple);
if (isBlocked && !mType->info.isIgnoringSpawnBlock) {
++blockedMonsters;
continue;
}

for (std::tuple<MonsterType*, uint16_t> tuple : sb.mTypes) {
if (std::get<1>(tuple) >= normal_random(1, 100) && spawnMonster(spawnId, std::get<0>(tuple), sb.pos, sb.direction, startup)) {
return true;
if (!roll) {
return spawnMonster(spawnId, mType, sb.pos, sb.direction, startup);
}

if (std::get<1>(tuple) >= normal_random(1, 100) && spawnMonster(spawnId, mType, sb.pos, sb.direction, startup)) {
return true;
}
}

return false;
};

// Try to spawn something with chance check
if (spawnFunc(true)) {
return true;
}

// Every monster spawn is blocked, bail out
if (monstersCount == blockedMonsters) {
return false;
}

// Just spawn the one with highest chance
return spawnMonster(spawnId, std::get<0>(sb.mTypes.front()), sb.pos, sb.direction, startup);
// Just try to spawn something without chance check
return spawnFunc(false);
}

bool Spawn::spawnMonster(uint32_t spawnId, MonsterType* mType, const Position& pos, Direction dir, bool startup/*= false*/)
Expand Down Expand Up @@ -356,12 +380,11 @@ void Spawn::checkSpawn()

spawnBlock_t& sb = it.second;
if (OTSYS_TIME() >= sb.lastSpawn + sb.interval) {
if (findPlayer(sb.pos)) {
if (!spawnMonster(spawnId, sb)) {
sb.lastSpawn = OTSYS_TIME();
continue;
}

spawnMonster(spawnId, sb);
if (++spawnCount >= static_cast<uint32_t>(g_config.getNumber(ConfigManager::RATE_SPAWN))) {
break;
}
Expand Down