Where do I edited the chance of a rare item dropping?
local tiers = {
[1] = {
prefix = 'rare',
showattr = true, -- attr prefix will be shown instead
extra = {0, 0},
chance = {
[1] = 10000, -- chance for basic stat
[2] = 5000 -- chance for second stat
}
},
[2] = {
prefix = 'epic',
extra = {7, 20}, -- additional percent bonus
chance = {
[1] = 3333,
[2] = 25000
}
},
[3] = {
prefix = 'legendary',
extra = {20, 35},
chance = {
[1] = 1000,
[2] = 100000 -- 2 bonuses always
}
},
}
-- Replace article if item rolls as epic
if tiers[tier].prefix == "epic" then
it_u:setAttribute(ITEM_ATTRIBUTE_ARTICLE, "an")
end
....
dofile('data/lib/core/lualoot.lua')
<!-- RPG Items -->
<event type="death" name="DropMonsterLoot" script="drop_monster_loot.lua"/>
function onDeath(monster, corpse, killer, mostdamagekiller, lasthitunjustified, mostdamageunjustified)
if not monster:isMonster() or monster:getMaster() then
return true
end
if not corpse:isContainer() then
return true
end
local owner = mostdamagekiller
if killer and killer:isPlayer() then
owner = killer
end
local modifier = 1
if owner and owner:isPlayer() then
corpse:setAttribute(ITEM_ATTRIBUTE_CORPSEOWNER, owner:getId())
end
monster:getType():createLoot(corpse, 1)
return true
end
<!-- Monster method -->
<event class="Monster" method="onSpawn" enabled="1" />
function Monster:onSpawn(pos, forced)
self:registerEvent("DropMonsterLoot")
return true
end
playerOnTradeRequest = -1;
playerOnTradeAccept = -1;
playerOnGainExperience = -1;
playerOnLoseExperience = -1;
playerOnGainSkillTries = -1;
// Monster
monsterOnSpawn = -1;
} else if (methodName == "onGainSkillTries") {
playerOnGainSkillTries = event;
} else {
std::cout << "[Warning - Events::load] Unknown player method: " << methodName << std::endl;
}
} else if (className == "Monster") {
if (methodName == "onSpawn") {
monsterOnSpawn = event;
} else {
std::cout << "[Warning - Events::load] Unknown monster method: " << methodName << std::endl;
}
if (scriptInterface.protectedCall(L, 3, 1) != 0) {
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
} else {
tries = LuaScriptInterface::getNumber<uint64_t>(L, -1);
lua_pop(L, 1);
}
scriptInterface.resetScriptEnv();
}
// Monster
bool Events::eventMonsterOnSpawn(Monster* monster, const Position& position, bool forced) {
// Monster:onSpawn(pos, forced)
if (monsterOnSpawn == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventMonsterOnSpawn] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(monsterOnSpawn, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(monsterOnSpawn);
LuaScriptInterface::pushUserdata<Monster>(L, monster);
LuaScriptInterface::setMetatable(L, -1, "Monster");
LuaScriptInterface::pushPosition(L, position);
LuaScriptInterface::pushBoolean(L, forced);
return scriptInterface.callFunction(3);
}
void eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp);
void eventPlayerOnLoseExperience(Player* player, uint64_t& exp);
void eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries);
// Monster
bool eventMonsterOnSpawn(Monster* monster, const Position& pos, bool forced);
int32_t playerOnTradeAccept;
int32_t playerOnGainExperience;
int32_t playerOnLoseExperience;
int32_t playerOnGainSkillTries;
// Monster
int32_t monsterOnSpawn;
registerMethod("Container", "hasItem", LuaScriptInterface::luaContainerHasItem);
registerMethod("Container", "addItem", LuaScriptInterface::luaContainerAddItem);
registerMethod("Container", "addItemEx", LuaScriptInterface::luaContainerAddItemEx);
registerMethod("Container", "getContentDescription", LuaScriptInterface::luaContainerGetContentDescription);
registerMethod("Party", "isSharedExperienceEnabled", LuaScriptInterface::luaPartyIsSharedExperienceEnabled);
registerMethod("Party", "shareExperience", LuaScriptInterface::luaPartyShareExperience);
registerMethod("Party", "setSharedExperience", LuaScriptInterface::luaPartySetSharedExperience);
registerMethod("Party", "broadcastLoot", LuaScriptInterface::luaPartyBroadcastLoot);
int32_t index = getNumber<int32_t>(L, 3, INDEX_WHEREEVER);
uint32_t flags = getNumber<uint32_t>(L, 4, 0);
ReturnValue ret = g_game.internalAddItem(container, item, index, flags);
if (ret == RETURNVALUE_NOERROR) {
ScriptEnvironment::removeTempItem(item);
}
lua_pushnumber(L, ret);
return 1;
}
int LuaScriptInterface::luaContainerGetContentDescription(lua_State* L)
{
// container:getContentDescription()
Container* container = getUserdata<Container>(L, 1);
if (container) {
pushString(L, container->getContentDescription());
} else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPartySetSharedExperience(lua_State* L)
{
// party:setSharedExperience(active)
bool active = getBoolean(L, 2);
Party* party = getUserdata<Party>(L, 1);
if (party) {
pushBoolean(L, party->setSharedExperience(party->getLeader(), active));
} else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPartyBroadcastLoot(lua_State* L)
{
// party:broadcastLoot(lootMessage)
const std::string& lootMessage = getString(L, 2);
Party* party = getUserdata<Party>(L, 1);
if (party) {
party->broadcastPartyLoot(lootMessage);
pushBoolean(L, true);
} else {
lua_pushnil(L);
}
return 1;
}
static int luaContainerGetItem(lua_State* L);
static int luaContainerHasItem(lua_State* L);
static int luaContainerAddItem(lua_State* L);
static int luaContainerAddItemEx(lua_State* L);
static int luaContainerGetContentDescription(lua_State* L);
static int luaPartyIsSharedExperienceActive(lua_State* L);
static int luaPartyIsSharedExperienceEnabled(lua_State* L);
static int luaPartyShareExperience(lua_State* L);
static int luaPartySetSharedExperience(lua_State* L);
static int luaPartyBroadcastLoot(lua_State* L);
//scripting event - onDeath
for (CreatureEvent* deathEvent : getCreatureEvents(CREATURE_EVENT_DEATH)) {
deathEvent->executeOnDeath(this, corpse, _lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
}
if (corpse) {
dropLoot(corpse->getContainer(), _lastHitCreature);
}
void Monster::setNormalCreatureLight()
{
internalLight.level = mType->lightLevel;
internalLight.color = mType->lightColor;
}
void Monster::dropLoot(Container* corpse, Creature*)
{
if (corpse && lootDrop) {
mType->createLoot(corpse);
}
}
uint16_t getLookCorpse() const final {
return mType->lookcorpse;
}
void dropLoot(Container* corpse, Creature* _lastHitCreature) final;
Monsters::Monsters()
{
loaded = false;
}
uint32_t Monsters::getLootRandom()
{
return uniform_random(0, MAX_LOOTCHANCE) / g_config.getNumber(ConfigManager::RATE_LOOT);
}
void MonsterType::createLoot(Container* corpse)
{
if (g_config.getNumber(ConfigManager::RATE_LOOT) == 0) {
corpse->startDecaying();
return;
}
Player* owner = g_game.getPlayerByID(corpse->getCorpseOwner());
if (!owner || owner->getStaminaMinutes() > 840) {
for (auto it = lootItems.rbegin(), end = lootItems.rend(); it != end; ++it) {
auto itemList = createLootItem(*it);
if (itemList.empty()) {
continue;
}
for (Item* item : itemList) {
//check containers
if (Container* container = item->getContainer()) {
if (!createLootContainer(container, *it)) {
delete container;
continue;
}
}
if (g_game.internalAddItem(corpse, item) != RETURNVALUE_NOERROR) {
corpse->internalAddThing(item);
}
}
}
if (owner) {
std::ostringstream ss;
ss << "Loot of " << nameDescription << ": " << corpse->getContentDescription();
if (owner->getParty()) {
owner->getParty()->broadcastPartyLoot(ss.str());
} else {
owner->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
}
}
} else {
std::ostringstream ss;
ss << "Loot of " << nameDescription << ": nothing (due to low stamina)";
if (owner->getParty()) {
owner->getParty()->broadcastPartyLoot(ss.str());
} else {
owner->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
}
}
corpse->startDecaying();
}
std::vector<Item*> MonsterType::createLootItem(const LootBlock& lootBlock)
{
int32_t itemCount = 0;
uint32_t randvalue = Monsters::getLootRandom();
if (randvalue < lootBlock.chance) {
if (Item::items[lootBlock.id].stackable) {
itemCount = randvalue % lootBlock.countmax + 1;
} else {
itemCount = 1;
}
}
std::vector<Item*> itemList;
while (itemCount > 0) {
uint16_t n = static_cast<uint16_t>(std::min<int32_t>(itemCount, 100));
Item* tmpItem = Item::CreateItem(lootBlock.id, n);
if (!tmpItem) {
break;
}
itemCount -= n;
if (lootBlock.subType != -1) {
tmpItem->setSubType(lootBlock.subType);
}
if (lootBlock.actionId != -1) {
tmpItem->setActionId(lootBlock.actionId);
}
if (!lootBlock.text.empty()) {
tmpItem->setText(lootBlock.text);
}
itemList.push_back(tmpItem);
}
return itemList;
}
bool MonsterType::createLootContainer(Container* parent, const LootBlock& lootblock)
{
auto it = lootblock.childLoot.begin(), end = lootblock.childLoot.end();
if (it == end) {
return true;
}
for (; it != end && parent->size() < parent->capacity(); ++it) {
auto itemList = createLootItem(*it);
for (Item* tmpItem : itemList) {
if (Container* container = tmpItem->getContainer()) {
if (!createLootContainer(container, *it)) {
delete container;
} else {
parent->internalAddThing(container);
}
} else {
parent->internalAddThing(tmpItem);
}
}
}
return !parent->empty();
}
bool canPushItems;
bool canPushCreatures;
bool pushable;
bool isSummonable;
bool isIllusionable;
bool isConvinceable;
bool isAttackable;
bool isHostile;
bool hiddenHealth;
void createLoot(Container* corpse);
bool createLootContainer(Container* parent, const LootBlock& lootblock);
std::vector<Item*> createLootItem(const LootBlock& lootBlock);
MonsterType* getMonsterType(const std::string& name);
uint32_t getIdByName(const std::string& name);
static uint32_t getLootRandom();
If you read the code, it runs on every corpse - checks its contents and runs the rarity rolls off each item.Does this apply to ever single weapon dropped?
If you read the code, it runs on every corpse - checks its contents and runs the rarity rolls off each item.
It won't roll on NPC bought or quest items, would need to be modified for that.
In file included from /home/otsmanager/forgottenserver/src/baseevents.h:23:0,
from /home/otsmanager/forgottenserver/src/actions.h:23,
from /home/otsmanager/forgottenserver/src/actions.cpp:22:
/home/otsmanager/forgottenserver/src/luascript.h:347:12: error: ‘T’ does not name a type
static T popNumber(lua_State* L) {
^
/home/otsmanager/forgottenserver/src/luascript.h:359:12: error: declaration of ‘class T’
template<typename T>
^
/home/otsmanager/forgottenserver/src/luascript.h:357:12: error: shadows template parm ‘class T’
template<typename T>
^
/home/otsmanager/forgottenserver/src/luascript.h:360:12: error: too many template-parameter-lists
static T getField(lua_State* L, int32_t arg, const std::string& key)
^
make[2]: *** [CMakeFiles/tfs.dir/src/actions.cpp.o] Error 1
make[1]: *** [CMakeFiles/tfs.dir/all] Error 2
make: *** [all] Error 2
I tried the code you posted but the following error occurs
Code:In file included from /home/otsmanager/forgottenserver/src/baseevents.h:23:0, from /home/otsmanager/forgottenserver/src/actions.h:23, from /home/otsmanager/forgottenserver/src/actions.cpp:22: /home/otsmanager/forgottenserver/src/luascript.h:347:12: error: ‘T’ does not name a type static T popNumber(lua_State* L) { ^ /home/otsmanager/forgottenserver/src/luascript.h:359:12: error: declaration of ‘class T’ template<typename T> ^ /home/otsmanager/forgottenserver/src/luascript.h:357:12: error: shadows template parm ‘class T’ template<typename T> ^ /home/otsmanager/forgottenserver/src/luascript.h:360:12: error: too many template-parameter-lists static T getField(lua_State* L, int32_t arg, const std::string& key) ^ make[2]: *** [CMakeFiles/tfs.dir/src/actions.cpp.o] Error 1 make[1]: *** [CMakeFiles/tfs.dir/all] Error 2 make: *** [all] Error 2
It works to compile but all monsters are completely empty :/I've edited my original post.
Replace your LUASCRIPT.H file with the original, before attempting these edits.
Then edit it again using the instructions on my original post.
This might be a stupid question and it might be reason why it doesn\t work, but is the code you wrote only for TFS 1.1?
Im not using lower, Im using 1.2Haven't tested on anything lower.
So, maybe.