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

Improvements that the Bestiary needs. #4412

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
6 changes: 3 additions & 3 deletions data/lib/core/player.lua
Original file line number Diff line number Diff line change
Expand Up @@ -513,11 +513,11 @@ function Player.addBestiaryKills(self, raceId)
return false
end

local info = monsterType:getBestiaryInfo()
local kills = self:getBestiaryKills(raceId)
local newKills = kills + 1
local bestiaryInfo = monsterType:getBestiaryInfo()
for _, totalKills in pairs({bestiaryInfo.prowess, bestiaryInfo.expertise, bestiaryInfo.mastery}) do
if kills == 0 or (kills < totalKills and newKills >= totalKills) then
for _, amount in pairs({info.prowess, info.expertise, info.mastery}) do
if kills == 0 or (kills < amount and newKills >= amount) then
self:sendTextMessage(MESSAGE_EVENT_DEFAULT, string.format("You unlocked details for the creature %s.", monsterType:getName()))
self:sendBestiaryMilestoneReached(raceId)
break
Expand Down
10 changes: 5 additions & 5 deletions data/monster/lua/#example.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ monster.flags = {
monster.bestiary = {
class = "Dragon",
raceId = 39,
prowess = 50,
expertise = 500,
mastery = 1000,
charmPoints = 25,
difficulty = "medium", -- harmless, trivial, easy, medium, hard, challenging
occurrence = 0,
occurrence = "common", -- common, uncommon, rare, very rare
prowess = 100,
expertise = 250,
mastery = 500,
charmPoints = 25,
locations = "Example locations"
}

Expand Down
3 changes: 1 addition & 2 deletions data/monster/monsters/dragon_lord.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
<flag staticattack="80" />
<flag runonhealth="300" />
</flags>
<bestiary class="Dragon" prowess="50" expertise="500" mastery="1000"
charmPoints="25" difficulty="medium" occurrence="0" locations="Dragon Lord locations"/>
<bestiary class="Dragon" difficulty="medium" occurrence="common" locations="Dragon Lord locations"/>
<attacks>
<attack name="melee" interval="2000" min="0" max="-230" />
<attack name="fire" interval="2000" chance="20" range="7" radius="4" target="1" min="-100" max="-200">
Expand Down
2 changes: 1 addition & 1 deletion data/scripts/creaturescripts/player/bestiary_kills.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function creatureEvent.onKill(player, target)
return true
end

local raceId = monster:getType():getBestiaryInfo().raceId
local raceId = monster:getType():raceId()
if raceId == 0 then
return true
end
Expand Down
24 changes: 17 additions & 7 deletions data/scripts/lib/register_monster_type.lua
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,27 @@ registerMonsterType.flags = function(mtype, mask)
end
do
local difficulties = {
harmless = 0,
trivial = 1,
easy = 2,
medium = 3,
hard = 4,
challenging = 5
["harmless"] = 0,
["trivial"] = 1,
["easy"] = 2,
["medium"] = 3,
["hard"] = 4,
["challenging"] = 5
}

local occurrences = {
["common"] = 0,
["uncommon"] = 1,
["rare"] = 2,
["very rare"] = 3
}

registerMonsterType.bestiary = function(mtype, mask)
if mask.bestiary then
mask.bestiary.difficulty = difficulties[mask.bestiary.difficulty:lower()]
mask.bestiary.difficulty =
difficulties[mask.bestiary.difficulty:lower()]
mask.bestiary.occurrence =
occurrences[mask.bestiary.occurrence:lower()]
mtype:bestiaryInfo(mask.bestiary)
end
end
Expand Down
15 changes: 7 additions & 8 deletions data/scripts/network/bestiary_classes.lua
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
local function getUnlockedBestiary(player, monsterTypes)
local count = 0
for _, monsterType in pairs(monsterTypes) do
local info = monsterType:getBestiaryInfo()
if player:getStorageValue(PlayerStorageKeys.bestiaryKillsBase + info.raceId) >= info.prowess then
count = count + 1
end
local unlocked = 0
for _, mType in pairs(monsterTypes) do
if player:getStorageValue(PlayerStorageKeys.bestiaryKillsBase +
mType:raceId()) >=
mType:getBestiaryInfo().prowess then unlocked = unlocked + 1 end
end
return count
return unlocked
end

local handler = PacketHandler(0xE1)

function handler.onReceive(player)
local bestiaryClasses = Game.getBestiary()
local bestiaryClasses = Game.getBestiaryClasses()
local msg = NetworkMessage()
msg:addByte(0xD5)
msg:addU16(#bestiaryClasses)
Expand Down
51 changes: 15 additions & 36 deletions data/scripts/network/bestiary_info.lua
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
local function getLootDifficulty(chance)
if chance < 200 then
return 4
elseif chance < 1000 then
return 3
elseif chance < 5000 then
return 2
elseif chance < 25000 then
return 1
end
return 0
for i = 0, 4 do if chance < 200 * 5 ^ i then return 4 - i end end
end

local bestiaryElements = {
COMBAT_PHYSICALDAMAGE,
COMBAT_FIREDAMAGE,
COMBAT_EARTHDAMAGE,
COMBAT_ENERGYDAMAGE,
COMBAT_ICEDAMAGE,
COMBAT_HOLYDAMAGE,
COMBAT_DEATHDAMAGE,
COMBAT_HEALING
COMBAT_PHYSICALDAMAGE, COMBAT_FIREDAMAGE, COMBAT_EARTHDAMAGE,
COMBAT_ENERGYDAMAGE, COMBAT_ICEDAMAGE, COMBAT_HOLYDAMAGE,
COMBAT_DEATHDAMAGE, COMBAT_HEALING
}

local function getBestiaryElements(monsterType)
Expand All @@ -36,33 +22,26 @@ local handler = PacketHandler(0xE3)
function handler.onReceive(player, msg)
local raceId = msg:getU16()
local monsterType = MonsterType(raceId)
if not monsterType then
return
end
if not monsterType then return end

local info = monsterType:getBestiaryInfo()
local kills = player:getBestiaryKills(raceId)
local progress = 0
local monsterKills = {0, info.prowess, info.expertise, info.mastery}
local step = kills == 0 and 0 or 4
if kills ~= 0 then
progress = 4
for i, amount in pairs({info.prowess, info.expertise, info.mastery}) do
if kills < amount then
progress = i
break
end
for i, amount in ipairs(monsterKills) do
step = kills >= amount and i or step
end
end

local response = NetworkMessage()
response:addByte(0xD7)
response:addU16(raceId)
response:addString(info.class)
response:addByte(progress)
response:addByte(step)
response:addU32(kills)

response:addU16(info.prowess)
response:addU16(info.expertise)
response:addU16(info.mastery)
for i = 2, 4 do response:addU16(monsterKills[i]) end

response:addByte(info.difficulty)
response:addByte(info.occurrence)
Expand All @@ -72,7 +51,7 @@ function handler.onReceive(player, msg)

for _, lootItem in pairs(loot) do
local lootDifficulty = getLootDifficulty(lootItem.chance)
local knowLoot = lootDifficulty <= progress
local knowLoot = lootDifficulty <= step
local itemType = ItemType(lootItem.itemId)
response:addU16(knowLoot and itemType:getClientId() or 0)
response:addByte(lootDifficulty)
Expand All @@ -83,7 +62,7 @@ function handler.onReceive(player, msg)
end
end

if progress > 1 then
if step > 1 then
response:addU16(info.charmPoints)
response:addByte(monsterType:isHostile() and 2 or 1)
response:addByte(2)
Expand All @@ -93,7 +72,7 @@ function handler.onReceive(player, msg)
response:addU16(monsterType:getArmor())
end

if progress > 2 then
if step > 2 then
local elements = getBestiaryElements(monsterType)
response:addByte(#elements)
for index, value in pairs(elements) do
Expand All @@ -105,7 +84,7 @@ function handler.onReceive(player, msg)
response:addString(info.locations)
end

if progress > 3 then
if step > 3 then
response:addByte(0)
response:addByte(1)
end
Expand Down
34 changes: 14 additions & 20 deletions data/scripts/network/bestiary_monster_types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ local handler = PacketHandler(0xE2)
function handler.onReceive(player, msg)
local monsterTypes = {}
local className = ""
if msg:getByte() == 1 then -- search
local amount = msg:getU16()
for i = 1, amount do
if msg:getByte() == 1 then -- Search Mode
for i = 1, msg:getU16() do
local raceId = msg:getU16()
local monsterType = MonsterType(raceId)
if monsterType and player:getBestiaryKills(raceId) > 0 then
Expand All @@ -14,39 +13,34 @@ function handler.onReceive(player, msg)
end
else
className = msg:getString()
local bestiaryClasses = Game.getBestiary()
for _, class in pairs(bestiaryClasses) do
for _, class in pairs(Game.getBestiaryClasses()) do
if class.name == className then
monsterTypes = class.monsterTypes
break
end
end
end

if #monsterTypes == 0 then
return
end
if #monsterTypes == 0 then return end

local response = NetworkMessage()
response:addByte(0xD6)
response:addString(className)
response:addU16(#monsterTypes)

for _, monsterType in pairs(monsterTypes) do
local info = monsterType:getBestiaryInfo()
response:addU16(info.raceId)
local kills = player:getBestiaryKills(info.raceId)
for _, mType in pairs(monsterTypes) do
local raceId = mType:raceId()
response:addU16(raceId)
local kills = player:getBestiaryKills(raceId)
if kills == 0 then
response:addByte(0)
else
local progress = 4
for i, amount in pairs({info.prowess, info.expertise, info.mastery}) do
if kills < amount then
progress = i
break
end
end
response:addU16(progress)
local info = mType:getBestiaryInfo()
local step = 0
for i, amount in pairs({
0, info.prowess, info.expertise, info.mastery
}) do step = kills >= amount and i or step end
response:addU16(step)
end
end

Expand Down
50 changes: 33 additions & 17 deletions src/luascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,16 +844,15 @@ Reflect LuaScriptInterface::getReflect(lua_State* L, int32_t arg)
BestiaryInfo LuaScriptInterface::getBestiaryInfo(lua_State* L, int32_t arg)
{
std::string className = getFieldString(L, arg, "class");
uint32_t raceId = getField<uint32_t>(L, arg, "raceId");
uint8_t difficulty = getField<uint8_t>(L, arg, "difficulty");
uint8_t occurrence = getField<uint8_t>(L, arg, "occurrence");
uint32_t prowess = getField<uint32_t>(L, arg, "prowess");
uint32_t expertise = getField<uint32_t>(L, arg, "expertise");
uint32_t mastery = getField<uint32_t>(L, arg, "mastery");
uint32_t charmPoints = getField<uint32_t>(L, arg, "charmPoints");
uint32_t difficulty = getField<uint32_t>(L, arg, "difficulty");
uint32_t occurrence = getField<uint32_t>(L, arg, "occurrence");
std::string locations = getFieldString(L, arg, "locations");
lua_pop(L, 9);
return {className, raceId, prowess, expertise, mastery, charmPoints, difficulty, occurrence, locations};
lua_pop(L, 8);
return {className, difficulty, occurrence, {prowess, expertise, mastery}, charmPoints, locations};
}

Thing* LuaScriptInterface::getThing(lua_State* L, int32_t arg)
Expand Down Expand Up @@ -1036,15 +1035,14 @@ void LuaScriptInterface::pushReflect(lua_State* L, const Reflect& reflect)

void LuaScriptInterface::pushBestiaryInfo(lua_State* L, const BestiaryInfo& info)
{
lua_createtable(L, 0, 9);
lua_createtable(L, 0, 8);
setField(L, "class", info.className);
setField(L, "raceId", info.raceId);
setField(L, "prowess", info.prowess);
setField(L, "expertise", info.expertise);
setField(L, "mastery", info.mastery);
setField(L, "charmPoints", info.charmPoints);
setField(L, "difficulty", info.difficulty);
setField(L, "occurrence", info.occurrence);
setField(L, "prowess", std::get<0>(info.totalKills));
setField(L, "expertise", std::get<1>(info.totalKills));
setField(L, "mastery", std::get<2>(info.totalKills));
setField(L, "charmPoints", info.charmPoints);
setField(L, "locations", info.locations);
}

Expand Down Expand Up @@ -2225,7 +2223,7 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Game", "getPlayerCount", LuaScriptInterface::luaGameGetPlayerCount);
registerMethod("Game", "getNpcCount", LuaScriptInterface::luaGameGetNpcCount);
registerMethod("Game", "getMonsterTypes", LuaScriptInterface::luaGameGetMonsterTypes);
registerMethod("Game", "getBestiary", LuaScriptInterface::luaGameGetBestiary);
registerMethod("Game", "getBestiaryClasses", LuaScriptInterface::luaGameGetBestiaryClasses);
registerMethod("Game", "getCurrencyItems", LuaScriptInterface::luaGameGetCurrencyItems);
registerMethod("Game", "getItemTypeByClientId", LuaScriptInterface::luaGameGetItemTypeByClientId);
registerMethod("Game", "getMountIdByLookType", LuaScriptInterface::luaGameGetMountIdByLookType);
Expand Down Expand Up @@ -3058,6 +3056,7 @@ void LuaScriptInterface::registerFunctions()

registerMethod("MonsterType", "name", LuaScriptInterface::luaMonsterTypeName);
registerMethod("MonsterType", "nameDescription", LuaScriptInterface::luaMonsterTypeNameDescription);
registerMethod("MonsterType", "raceId", LuaScriptInterface::luaMonsterTypeRaceId);

registerMethod("MonsterType", "health", LuaScriptInterface::luaMonsterTypeHealth);
registerMethod("MonsterType", "maxHealth", LuaScriptInterface::luaMonsterTypeMaxHealth);
Expand Down Expand Up @@ -4558,17 +4557,17 @@ int LuaScriptInterface::luaGameGetMonsterTypes(lua_State* L)
return 1;
}

int LuaScriptInterface::luaGameGetBestiary(lua_State* L)
int LuaScriptInterface::luaGameGetBestiaryClasses(lua_State* L)
{
// Game.getBestiary()
lua_createtable(L, 0, g_monsters.bestiary.size());
// Game.getBestiaryClasses()
lua_createtable(L, g_monsters.bestiary.size(), 0);
int classIndex = 0;
for (const auto& [className, monsters] : g_monsters.bestiary) {
lua_createtable(L, 0, 2);
pushString(L, className);
lua_setfield(L, -2, "name");

lua_createtable(L, 0, monsters.size());
lua_createtable(L, monsters.size(), 0);
int index = 0;
for (const auto& monsterName : monsters) {
pushUserdata<const MonsterType>(L, g_monsters.getMonsterType(monsterName));
Expand Down Expand Up @@ -14220,6 +14219,23 @@ int LuaScriptInterface::luaMonsterTypeNameDescription(lua_State* L)
return 1;
}

int LuaScriptInterface::luaMonsterTypeRaceId(lua_State* L)
{
// get: monsterType:raceId() set: monsterType:raceId(id)
MonsterType* monsterType = getUserdata<MonsterType>(L, 1);
if (monsterType) {
if (lua_gettop(L) == 1) {
lua_pushnumber(L, monsterType->raceId);
} else {
monsterType->raceId = getNumber<uint32_t>(L, 2);
pushBoolean(L, true);
}
} else {
lua_pushnil(L);
}
return 1;
}

int LuaScriptInterface::luaMonsterTypeHealth(lua_State* L)
{
// get: monsterType:health() set: monsterType:health(health)
Expand Down Expand Up @@ -15011,7 +15027,7 @@ int LuaScriptInterface::luaMonsterTypeBestiaryInfo(lua_State* L)
pushBestiaryInfo(L, monsterType->bestiaryInfo);
} else if (isTable(L, 2)) {
auto info = getBestiaryInfo(L, 2);
if (g_monsters.isValidBestiaryInfo(info)) {
if (info.isValid()) {
monsterType->bestiaryInfo = std::move(info);
pushBoolean(L, g_monsters.addBestiaryMonsterType(monsterType));
} else {
Expand Down
Loading