Boa garoto! haha, eu não tfs 1.0+.. porem é um codigo bacana.. vou tentar fazer um pra tfs 0.3.6 até 10.10
- Fórum
- OTServ
- Recursos
- Linguagens de Programação
- Reward Chest & Boss Reward
Reward Chest & Boss Reward
Por MatheusGlad, 03 de dez. de 2015 em Linguagens de Programação
info
Grupo: Herói
Registrado: 25/10/11
Posts: 2.2k
Reputação: +862
Gênero: Masculino
Char no Tibia: Sociopata

info
Grupo: Campones
Registrado: 25/06/15
Posts: 30
Reputação: 0
Gênero: Masculino

[
Creditos:
Baseado no code do cbrm:
https://otland.net/threads/reward-chest-boss-reward-tfs-1-2.233397/
Instruções::
src/const.h:
Embaixo de...ITEM_MARKET = 14405,...Adicione:ITEM_REWARD_BAG = 21518, ITEM_REWARD_CHEST = 21584, REWARD_CHEST_DEPOTID = 99,src/depotchest.h:
Embaixo de...explicit DepotChest(uint16_t _type);...Adicione:uint32_t getDepotId() const { return depotId; } void setDepotId(uint32_t id) { depotId = id; }Embaixo de...uint32_t maxDepotItems;...Adicione:uint32_t depotId;src/depotchest.cpp:
Embaixo de...maxDepotItems = 1500;...Adicione:depotId = 0;Em cima de...return Container::queryAdd(index, thing, count, flags, actor);...Adicione:if (actor != nullptr && getDepotId() == REWARD_CHEST_DEPOTID) { return RETURNVALUE_NOTPOSSIBLE; }src/depotlocker.h:
Em cima de...//cylinder implementations...Adicione:void setMaxLockerItems(uint32_t maxitems) { maxSize = maxitems; }src/player.h:
Embaixo de...DepotLocker* getDepotLocker(uint32_t depotId);...Adicione:DepotChest* getRewardBag(uint32_t depotId, bool autoCreate); DepotLocker* getRewardChest(uint16_t itemId);src/player.cpp:
Em cima de...void Player::sendCancelMessage(ReturnValue message) const...Adicione:DepotChest* Player::getRewardBag(uint32_t depotId, bool autoCreate) { auto it = depotChests.find(depotId); if (it != depotChests.end()) { return it->second; } if (!autoCreate) { return nullptr; } DepotChest* bagReward = new DepotChest(ITEM_REWARD_BAG); bagReward->setDepotId(depotId); bagReward->incrementReferenceCounter(); bagReward->setMaxDepotItems(getMaxDepotItems()); depotChests[depotId] = bagReward; return bagReward; } DepotLocker* Player::getRewardChest(uint16_t itemId) { auto it = depotLockerMap.find(REWARD_CHEST_DEPOTID); if (it != depotLockerMap.end()) { it->second->setID(itemId); return it->second; } DepotLocker* rewardChest = new DepotLocker(ITEM_REWARD_CHEST); rewardChest->setID(itemId); rewardChest->setDepotId(REWARD_CHEST_DEPOTID); rewardChest->setMaxLockerItems(1); rewardChest->internalAddThing(getRewardBag(REWARD_CHEST_DEPOTID, true)); depotLockerMap[REWARD_CHEST_DEPOTID] = rewardChest; return rewardChest; }Em player.cpp, container.cpp, inbox.cpp:
Mude:if (!item->isPickupable()) {Por:if (item->getID() != 21518 && !item->isPickupable()) {src/actions.cpp:
Mude://depot container if (DepotLocker* depot = container->getDepotLocker()) { DepotLocker* myDepotLocker = player->getDepotLocker(depot->getDepotId()); myDepotLocker->setParent(depot->getParent()->getTile()); openContainer = myDepotLocker; player->setLastDepotId(depot->getDepotId()); } else { openContainer = container; }Por://reward chest and depot container if (item->getActionId() == ITEM_REWARD_CHEST || item->getID() == ITEM_REWARD_CHEST) { DepotLocker* myRewardChest = player->getRewardChest(item->getID()); myRewardChest->setParent(item->getTile()); openContainer = myRewardChest; player->setLastDepotId(REWARD_CHEST_DEPOTID); } else if (DepotLocker* depot = container->getDepotLocker()) { DepotLocker* myDepotLocker = player->getDepotLocker(depot->getDepotId()); myDepotLocker->setParent(depot->getParent()->getTile()); openContainer = myDepotLocker; player->setLastDepotId(depot->getDepotId()); } else { openContainer = container; }src/game.cpp:
Em cima de...if (!item->isPushable() || item->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID)) {...Adicione:if (item->getID() == ITEM_REWARD_BAG || item->getActionId() == ITEM_REWARD_CHEST) { player->sendCancelMessage(RETURNVALUE_NOTMOVEABLE); return; }src/monsters.h:
Embaixo de...int32_t subType; int32_t actionId; std::string text;...Adicione:bool uniquedrop;Embaixo de...actionId = -1;...Adicione:uniquedrop = false;Embaixo de...bool hiddenHealth;...Adicione:bool rewardChest;src/monsters.cpp:
Embaixo de...healthMax = 100;...Adicione:rewardChest = false;Embaixo de...} else if (strcasecmp(attrName, "hidehealth") == 0) { mType->hiddenHealth = attr.as_bool();...Adicione:} else if (strcasecmp(attrName, "rewardchest") == 0) { mType->rewardChest = attr.as_bool();Em cima de...if ((attr = node.attribute("actionId"))) {...Adicione:if ((attr = node.attribute("uniquedrop"))) { lootBlock.uniquedrop = attr.as_bool(); }src/iologindata.cpp:
Embaixo de...//load depot items...Adicione:player->getRewardChest(ITEM_REWARD_CHEST);Mude:if (pid >= 0 && pid < 100) { DepotChest* depotChest = player->getDepotChest(pid, true); if (depotChest) { depotChest->internalAddThing(item); }Por:if (pid >= 0 && pid < 100) { if (pid == REWARD_CHEST_DEPOTID) { DepotChest* depotChest = player->getRewardBag(pid, true); if (depotChest) { depotChest->internalAddThing(item); } } else { DepotChest* depotChest = player->getDepotChest(pid, true); if (depotChest) { depotChest->internalAddThing(item); } }src/luascript.h:
Em cima de...// Combat...Adicione:// Reward static int luaItemGetNameDescription(lua_State* L); static int luaMonsterTypeUseRewardChest(lua_State* L);src/luascript.cpp:
Em cima de...// Party registerClass("Party", "", nullptr);...Adicione:// Reward registerMethod("MonsterType", "useRewardChest", LuaScriptInterface::luaMonsterTypeUseRewardChest); registerMethod("Item", "getNameDescription", LuaScriptInterface::luaItemGetNameDescription);Em cima de...// Combat int LuaScriptInterface::luaCombatCreate(lua_State* L)...Adicione:int LuaScriptInterface::luaItemGetNameDescription(lua_State* L) { // item:getNameDescription() const Item* item = getUserdata<const Item>(L, 1); int32_t subType; bool addArticle = true; if (item) { subType = item->getSubType(); const ItemType& it = Item::items[item->getID()]; std::ostringstream s; const std::string& name = (item ? item->getName() : it.name); if (!name.empty()) { if (it.stackable && subType > 1) { if (it.showCount) { s << subType << ' '; } s << (item ? item->getPluralName() : it.getPluralName()); } else { if (addArticle) { const std::string& article = (item ? item->getArticle() : it.article); if (!article.empty()) { s << article << ' '; } } s << name; } } else { s << "an item of type " << it.id; } pushString(L, s.str()); } else { lua_pushnil(L); } return 1; } int LuaScriptInterface::luaMonsterTypeUseRewardChest(lua_State* L) { // monsterType:useRewardChest() MonsterType* monsterType = getUserdata<MonsterType>(L, 1); if (monsterType) { pushBoolean(L, monsterType->rewardChest); } else { lua_pushnil(L); } return 1; }Mude:int LuaScriptInterface::luaMonsterTypeGetLoot(lua_State* L) { // monsterType:getLoot() MonsterType* monsterType = getUserdata<MonsterType>(L, 1); if (!monsterType) { lua_pushnil(L); return 1; } static const std::function<void(const std::vector<LootBlock>&)> parseLoot = [&](const std::vector<LootBlock>& lootList) { lua_createtable(L, lootList.size(), 0); int index = 0; for (const auto& lootBlock : lootList) { lua_createtable(L, 0, 7); setField(L, "itemId", lootBlock.id); setField(L, "chance", lootBlock.chance); setField(L, "subType", lootBlock.subType); setField(L, "maxCount", lootBlock.countmax); setField(L, "actionId", lootBlock.actionId); setField(L, "text", lootBlock.text); parseLoot(lootBlock.childLoot); lua_setfield(L, -2, "childLoot"); lua_rawseti(L, -2, ++index); } }; parseLoot(monsterType->lootItems); return 1; }Por:int LuaScriptInterface::luaMonsterTypeGetLoot(lua_State* L) { // monsterType:getLoot() MonsterType* monsterType = getUserdata<MonsterType>(L, 1); if (!monsterType) { lua_pushnil(L); return 1; } static const std::function<void(const std::vector<LootBlock>&)> parseLoot = [&](const std::vector<LootBlock>& lootList) { lua_createtable(L, lootList.size(), 0); int index = 0; for (const auto& lootBlock : lootList) { lua_createtable(L, 0, 8); setField(L, "itemId", lootBlock.id); setField(L, "chance", lootBlock.chance); setField(L, "subType", lootBlock.subType); setField(L, "maxCount", lootBlock.countmax); setField(L, "actionId", lootBlock.actionId); setField(L, "text", lootBlock.text); pushBoolean(L, lootBlock.uniquedrop); lua_setfield(L, -2, "uniquedrop"); parseLoot(lootBlock.childLoot); lua_setfield(L, -2, "childLoot"); lua_rawseti(L, -2, ++index); } }; parseLoot(monsterType->lootItems); return 1; }Pronto, a parte de C++ acabou agora o resto:
Adicione @ data/items/items/xml<item id="21518" article="a" name="reward container"> <attribute key="weight" value="1800" /> <attribute key="containersize" value="100" /> <attribute key="slotType" value="backpack" /> </item> <item id="21584" article="a" name="reward chest"> <attribute key="type" value="depot" /> <attribute key="containerSize" value="1" /> <attribute key="description" value="This chest contains your rewards earned in battles." /> </item>Adicione @ data/creaturescripts/creaturescripts.xml<event type="kill" name="RewardLoot" script="rewardloot.lua"/>Registre @ data/creaturescripts/scripts/login.luaplayer:registerEvent("RewardLoot")Crie data/creaturescripts/scripts/rewardloot.lua:function sort_descending(t) local tmp = {} for k, v in pairs(t) do table.insert(tmp, {k, v}) end table.sort(tmp, function(a, b) return a[2] > b[2] end) return tmp end function table.find(t, v) for i,x in pairs(t) do if x == v then return true end end end function Player:addItemRewardBag(itemid, count) local rewardbag = self:getDepotChest(99) return rewardbag:addItem(itemid, count) end function MonsterType:getBossReward(chance, unique) local ret = {} local function randomItem(lootBlock, chance) local randvalue = math.random(0, 100000) / (getConfigInfo("rateLoot") * chance) if randvalue < lootBlock.chance then if (ItemType(lootBlock.itemId):isStackable()) then return (randvalue%lootBlock.maxCount) + 1 else return 1 end end end local lootBlockList = self:getLoot() for _, loot in pairs(lootBlockList) do local rd = randomItem(loot, chance) if rd then if loot.uniquedrop then if unique then table.insert(ret, {loot, rd}) end else table.insert(ret, {loot, rd}) end end end return ret end BossLoot = {} BossUids = {} function BossLoot:new(boss) if not table.find(BossUids, boss:getId()) then table.insert(BossUids, boss:getId()) return setmetatable({creature=boss}, {__index = BossLoot}) end end function BossLoot:updateDamage() if self.creature then local tmp = {} local totaldmg = 0 for killer, damage in pairs(self.creature:getDamageMap()) do totaldmg = totaldmg+damage.total tmp[killer] = damage.total end self.players = sort_descending(tmp) self.totaldmg = totaldmg else error("Creature not found.") end end function BossLoot:setRewards() if self.totaldmg and self.creature then if getConfigInfo("rateLoot") > 0 then local mt = MonsterType(self.creature:getName()) for i, playertab in ipairs(self.players) do local loot if i == 1 then loot = mt:getBossReward(playertab[2] / self.totaldmg, true) else loot = mt:getBossReward(playertab[2] / self.totaldmg, false) end table.insert(self.players[i], loot) end end else error("Error") end end function BossLoot:addRewards() if self.players and self.players[1] and self.players[1][3] then for i, playertab in ipairs(self.players) do local player = Player(playertab[1]) if player then local str = "The following items are available in your reward chest: " for i, lootTable in ipairs(playertab[3]) do local item = player:addItemRewardBag(lootTable[1].itemId, math.ceil(lootTable[2])) if item then str = str .. item:getNameDescription() .. ", " end end str = str:sub(1, #str-2) player:sendTextMessage(MESSAGE_EVENT_ADVANCE, str) end end else error("Error") end end function onKill(creature, target) if (Monster(target) ~= nil) then local mt = MonsterType(target:getName()) if mt:useRewardChest() then local loot = BossLoot:new(target) if loot then local corpse = Item(doCreateItem(MonsterType(target:getName()):getCorpseId(), 1, target:getPosition())) corpse:decay() target:setDropLoot(false) loot:updateDamage() loot:setRewards() loot:addRewards() corpse:setAttribute('aid', 21584) end end end endCOMO USAR !!
Simplesmente adicione essa flag no monstro:<flag rewardchest="1" />Você tambem pode fazer um drop ser unique, assim somente a pessoa que fez a maior parte do dano vai pegar esse item.<item id="5903" chance="100000" uniquedrop="1" /><!-- ferumbras' hat -->
Foi você que fez esse sistema ou pegou na net?
Eu consegui fazer funcionar no TFS 1.0 porem as vezes quando mata o boss e vai abrir o loot "reward" da debug e o servidor cai, as vezes nem da debug já cai direto assim quando mata o boss.
Estou tentando resolver mais se alguém quiser ajudar por favor ajuda ai.
Editado Dezembro 11 por GustavaoTibia
info
Grupo: Conde
Registrado: 09/09/09
Posts: 528
Reputação: +424
Char no Tibia: Emekalo Makalo

Foi você que fez esse sistema ou pegou na net?
Eu consegui fazer funcionar no TFS 1.0 porem as vezes quando mata o boss e vai abrir o loot "reward" da debug e o servidor cai, as vezes nem da debug já cai direto assim quando mata o boss.
Estou tentando resolver mais se alguém quiser ajudar por favor ajuda ai.
O que acontece quando voce abre o reward chest em vez do corpo do boss? Ve se crasha ou se da debug.
Tenta mudar a function onKill no arquivo rewardloot.lua por:
function onKill(creature, target)
target = Monster(target)
if (target ~= nil) then
local mt = MonsterType(target:getName())
if mt:useRewardChest() then
local loot = BossLoot:new(target)
if loot then
local corpse = Item(doCreateItem(MonsterType(target:getName()):getCorpseId(), 1, target:getPosition()))
corpse:decay()
target:setDropLoot(false)
loot:updateDamage()
loot:setRewards()
loot:addRewards()
corpse:setAttribute('aid', 21584)
end
end
end
end
Se continuar crashando, não posso te ajudar porque eu fiz o sistema para TFS 1.2.
Editado Dezembro 11 por MatheusMkalo
info
Grupo: Campones
Registrado: 25/06/15
Posts: 30
Reputação: 0
Gênero: Masculino

O que acontece quando voce abre o reward chest em vez do corpo do boss? Ve se crasha ou se da debug.
Tenta mudar a function onKill no arquivo rewardloot.lua por:
function onKill(creature, target) target = Monster(target) if (target ~= nil) then local mt = MonsterType(target:getName()) if mt:useRewardChest() then local loot = BossLoot:new(target) if loot then local corpse = Item(doCreateItem(MonsterType(target:getName()):getCorpseId(), 1, target:getPosition())) corpse:decay() target:setDropLoot(false) loot:updateDamage() loot:setRewards() loot:addRewards() corpse:setAttribute('aid', 21584) end end end endSe continuar crashando, não posso te ajudar porque eu fiz o sistema para TFS 1.2.
Ja tenho esse onkill.
Tanto faz eu abrir o loot ou o reward chest tem vez que debuga e as vezes nem debuga já cai direto ou quando matar o boss dar um "/save" se não cair é porque da pra abrir normal o loot ou o reward chest agora se der um "/save" e cair o server é porque ta dando debug na hora de abrir o loot ou reward chest.
Mesmo dando debug da pra entrar no jogo, ou seja, quando debugar o cliente eu vou la e entro de novo o char continua on só não vou poder abrir o loot ou o reward porque vai debugar de novo logico, mais dai quando o server for salvar tanto no save normal ou no "/save" vai cair :\
Ja tenho esse onkill.
Tanto faz eu abrir o loot ou o reward chest tem vez que debuga e as vezes nem debuga já cai direto ou quando matar o boss dar um "/save" se não cair é porque da pra abrir normal o loot ou o reward chest agora se der um "/save" e cair o server é porque ta dando debug na hora de abrir o loot ou reward chest.
Mesmo dando debug da pra entrar no jogo, ou seja, quando debugar o cliente eu vou la e entro de novo o char continua on só não vou poder abrir o loot ou o reward porque vai debugar de novo logico, mais dai quando o server for salvar tanto no save normal ou no "/save" vai cair :\
Ta usando qual versao do TFS?






info
Grupo: Conde
Registrado: 09/09/09
Posts: 528
Reputação: +424
Char no Tibia: Emekalo Makalo
Creditos:
Baseado no code do cbrm:
https://otland.net/threads/reward-chest-boss-reward-tfs-1-2.233397/
Instruções::
src/const.h:
Embaixo de...
...Adicione:
src/depotchest.h:
Embaixo de...
...Adicione:
uint32_t getDepotId() const { return depotId; } void setDepotId(uint32_t id) { depotId = id; }Embaixo de...
...Adicione:
src/depotchest.cpp:
Embaixo de...
...Adicione:
Em cima de...
...Adicione:
if (actor != nullptr && getDepotId() == REWARD_CHEST_DEPOTID) { return RETURNVALUE_NOTPOSSIBLE; }src/depotlocker.h:
Em cima de...
...Adicione:
void setMaxLockerItems(uint32_t maxitems) { maxSize = maxitems; }src/player.h:
Embaixo de...
...Adicione:
src/player.cpp:
Em cima de...
...Adicione:
DepotChest* Player::getRewardBag(uint32_t depotId, bool autoCreate) { auto it = depotChests.find(depotId); if (it != depotChests.end()) { return it->second; } if (!autoCreate) { return nullptr; } DepotChest* bagReward = new DepotChest(ITEM_REWARD_BAG); bagReward->setDepotId(depotId); bagReward->incrementReferenceCounter(); bagReward->setMaxDepotItems(getMaxDepotItems()); depotChests[depotId] = bagReward; return bagReward; } DepotLocker* Player::getRewardChest(uint16_t itemId) { auto it = depotLockerMap.find(REWARD_CHEST_DEPOTID); if (it != depotLockerMap.end()) { it->second->setID(itemId); return it->second; } DepotLocker* rewardChest = new DepotLocker(ITEM_REWARD_CHEST); rewardChest->setID(itemId); rewardChest->setDepotId(REWARD_CHEST_DEPOTID); rewardChest->setMaxLockerItems(1); rewardChest->internalAddThing(getRewardBag(REWARD_CHEST_DEPOTID, true)); depotLockerMap[REWARD_CHEST_DEPOTID] = rewardChest; return rewardChest; }Em player.cpp, container.cpp, inbox.cpp:
Mude:
if (!item->isPickupable()) {Por:
if (item->getID() != 21518 && !item->isPickupable()) {src/actions.cpp:
Mude:
//depot container if (DepotLocker* depot = container->getDepotLocker()) { DepotLocker* myDepotLocker = player->getDepotLocker(depot->getDepotId()); myDepotLocker->setParent(depot->getParent()->getTile()); openContainer = myDepotLocker; player->setLastDepotId(depot->getDepotId()); } else { openContainer = container; }Por:
//reward chest and depot container if (item->getActionId() == ITEM_REWARD_CHEST || item->getID() == ITEM_REWARD_CHEST) { DepotLocker* myRewardChest = player->getRewardChest(item->getID()); myRewardChest->setParent(item->getTile()); openContainer = myRewardChest; player->setLastDepotId(REWARD_CHEST_DEPOTID); } else if (DepotLocker* depot = container->getDepotLocker()) { DepotLocker* myDepotLocker = player->getDepotLocker(depot->getDepotId()); myDepotLocker->setParent(depot->getParent()->getTile()); openContainer = myDepotLocker; player->setLastDepotId(depot->getDepotId()); } else { openContainer = container; }src/game.cpp:
Em cima de...
if (!item->isPushable() || item->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID)) {...Adicione:
if (item->getID() == ITEM_REWARD_BAG || item->getActionId() == ITEM_REWARD_CHEST) { player->sendCancelMessage(RETURNVALUE_NOTMOVEABLE); return; }src/monsters.h:
Embaixo de...
...Adicione:
Embaixo de...
...Adicione:
Embaixo de...
...Adicione:
src/monsters.cpp:
Embaixo de...
...Adicione:
Embaixo de...
} else if (strcasecmp(attrName, "hidehealth") == 0) { mType->hiddenHealth = attr.as_bool();...Adicione:
} else if (strcasecmp(attrName, "rewardchest") == 0) { mType->rewardChest = attr.as_bool();Em cima de...
if ((attr = node.attribute("actionId"))) {...Adicione:
if ((attr = node.attribute("uniquedrop"))) { lootBlock.uniquedrop = attr.as_bool(); }src/iologindata.cpp:
Embaixo de...
...Adicione:
Mude:
if (pid >= 0 && pid < 100) { DepotChest* depotChest = player->getDepotChest(pid, true); if (depotChest) { depotChest->internalAddThing(item); }Por:
if (pid >= 0 && pid < 100) { if (pid == REWARD_CHEST_DEPOTID) { DepotChest* depotChest = player->getRewardBag(pid, true); if (depotChest) { depotChest->internalAddThing(item); } } else { DepotChest* depotChest = player->getDepotChest(pid, true); if (depotChest) { depotChest->internalAddThing(item); } }src/luascript.h:
Em cima de...
...Adicione:
src/luascript.cpp:
Em cima de...
// Party registerClass("Party", "", nullptr);...Adicione:
// Reward registerMethod("MonsterType", "useRewardChest", LuaScriptInterface::luaMonsterTypeUseRewardChest); registerMethod("Item", "getNameDescription", LuaScriptInterface::luaItemGetNameDescription);Em cima de...
...Adicione:
int LuaScriptInterface::luaItemGetNameDescription(lua_State* L) { // item:getNameDescription() const Item* item = getUserdata<const Item>(L, 1); int32_t subType; bool addArticle = true; if (item) { subType = item->getSubType(); const ItemType& it = Item::items[item->getID()]; std::ostringstream s; const std::string& name = (item ? item->getName() : it.name); if (!name.empty()) { if (it.stackable && subType > 1) { if (it.showCount) { s << subType << ' '; } s << (item ? item->getPluralName() : it.getPluralName()); } else { if (addArticle) { const std::string& article = (item ? item->getArticle() : it.article); if (!article.empty()) { s << article << ' '; } } s << name; } } else { s << "an item of type " << it.id; } pushString(L, s.str()); } else { lua_pushnil(L); } return 1; } int LuaScriptInterface::luaMonsterTypeUseRewardChest(lua_State* L) { // monsterType:useRewardChest() MonsterType* monsterType = getUserdata<MonsterType>(L, 1); if (monsterType) { pushBoolean(L, monsterType->rewardChest); } else { lua_pushnil(L); } return 1; }Mude:
int LuaScriptInterface::luaMonsterTypeGetLoot(lua_State* L) { // monsterType:getLoot() MonsterType* monsterType = getUserdata<MonsterType>(L, 1); if (!monsterType) { lua_pushnil(L); return 1; } static const std::function<void(const std::vector<LootBlock>&)> parseLoot = [&](const std::vector<LootBlock>& lootList) { lua_createtable(L, lootList.size(), 0); int index = 0; for (const auto& lootBlock : lootList) { lua_createtable(L, 0, 7); setField(L, "itemId", lootBlock.id); setField(L, "chance", lootBlock.chance); setField(L, "subType", lootBlock.subType); setField(L, "maxCount", lootBlock.countmax); setField(L, "actionId", lootBlock.actionId); setField(L, "text", lootBlock.text); parseLoot(lootBlock.childLoot); lua_setfield(L, -2, "childLoot"); lua_rawseti(L, -2, ++index); } }; parseLoot(monsterType->lootItems); return 1; }Por:
int LuaScriptInterface::luaMonsterTypeGetLoot(lua_State* L) { // monsterType:getLoot() MonsterType* monsterType = getUserdata<MonsterType>(L, 1); if (!monsterType) { lua_pushnil(L); return 1; } static const std::function<void(const std::vector<LootBlock>&)> parseLoot = [&](const std::vector<LootBlock>& lootList) { lua_createtable(L, lootList.size(), 0); int index = 0; for (const auto& lootBlock : lootList) { lua_createtable(L, 0, 8); setField(L, "itemId", lootBlock.id); setField(L, "chance", lootBlock.chance); setField(L, "subType", lootBlock.subType); setField(L, "maxCount", lootBlock.countmax); setField(L, "actionId", lootBlock.actionId); setField(L, "text", lootBlock.text); pushBoolean(L, lootBlock.uniquedrop); lua_setfield(L, -2, "uniquedrop"); parseLoot(lootBlock.childLoot); lua_setfield(L, -2, "childLoot"); lua_rawseti(L, -2, ++index); } }; parseLoot(monsterType->lootItems); return 1; }Pronto, a parte de C++ acabou agora o resto:
Adicione @ data/items/items/xml
Adicione @ data/creaturescripts/creaturescripts.xml
Registre @ data/creaturescripts/scripts/login.lua
player:registerEvent("RewardLoot")Crie data/creaturescripts/scripts/rewardloot.lua:
function sort_descending(t) local tmp = {} for k, v in pairs(t) do table.insert(tmp, {k, v}) end table.sort(tmp, function(a, b) return a[2] > b[2] end) return tmp end function table.find(t, v) for i,x in pairs(t) do if x == v then return true end end end function Player:addItemRewardBag(itemid, count) local rewardbag = self:getDepotChest(99) return rewardbag:addItem(itemid, count) end function MonsterType:getBossReward(chance, unique) local ret = {} local function randomItem(lootBlock, chance) local randvalue = math.random(0, 100000) / (getConfigInfo("rateLoot") * chance) if randvalue < lootBlock.chance then if (ItemType(lootBlock.itemId):isStackable()) then return (randvalue%lootBlock.maxCount) + 1 else return 1 end end end local lootBlockList = self:getLoot() for _, loot in pairs(lootBlockList) do local rd = randomItem(loot, chance) if rd then if loot.uniquedrop then if unique then table.insert(ret, {loot, rd}) end else table.insert(ret, {loot, rd}) end end end return ret end BossLoot = {} BossUids = {} function BossLoot:new(boss) if not table.find(BossUids, boss:getId()) then table.insert(BossUids, boss:getId()) return setmetatable({creature=boss}, {__index = BossLoot}) end end function BossLoot:updateDamage() if self.creature then local tmp = {} local totaldmg = 0 for killer, damage in pairs(self.creature:getDamageMap()) do totaldmg = totaldmg+damage.total tmp[killer] = damage.total end self.players = sort_descending(tmp) self.totaldmg = totaldmg else error("Creature not found.") end end function BossLoot:setRewards() if self.totaldmg and self.creature then if getConfigInfo("rateLoot") > 0 then local mt = MonsterType(self.creature:getName()) for i, playertab in ipairs(self.players) do local loot if i == 1 then loot = mt:getBossReward(playertab[2] / self.totaldmg, true) else loot = mt:getBossReward(playertab[2] / self.totaldmg, false) end table.insert(self.players[i], loot) end end else error("Error") end end function BossLoot:addRewards() if self.players and self.players[1] and self.players[1][3] then for i, playertab in ipairs(self.players) do local player = Player(playertab[1]) if player then local str = "The following items are available in your reward chest: " for i, lootTable in ipairs(playertab[3]) do local item = player:addItemRewardBag(lootTable[1].itemId, math.ceil(lootTable[2])) if item then str = str .. item:getNameDescription() .. ", " end end str = str:sub(1, #str-2) player:sendTextMessage(MESSAGE_EVENT_ADVANCE, str) end end else error("Error") end end function onKill(creature, target) if (Monster(target) ~= nil) then local mt = MonsterType(target:getName()) if mt:useRewardChest() then local loot = BossLoot:new(target) if loot then local corpse = Item(doCreateItem(MonsterType(target:getName()):getCorpseId(), 1, target:getPosition())) corpse:decay() target:setDropLoot(false) loot:updateDamage() loot:setRewards() loot:addRewards() corpse:setAttribute('aid', 21584) end end end endCOMO USAR !!
Simplesmente adicione essa flag no monstro:
Você tambem pode fazer um drop ser unique, assim somente a pessoa que fez a maior parte do dano vai pegar esse item.
Editado Dezembro 3 por MatheusMkalo