Ir para conteúdo

Reward Chest & Boss Reward


Posts Recomendados

cg0QG0q.png

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.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
end

COMO 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 -->
Editado por MatheusMkalo
Link para o comentário
Compartilhar em outros sites

 

 

[cg0QG0q.png

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.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
end
COMO 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 por GustavaoTibia
Link para o comentário
Compartilhar em outros sites

 

 

 

 

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 por MatheusMkalo
Link para o comentário
Compartilhar em outros sites

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.

 

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 :\

Link para o comentário
Compartilhar em outros sites

  • 4 weeks later...

 

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?

Link para o comentário
Compartilhar em outros sites

×
×
  • Criar Novo...