• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Feature Reward Chest & Boss Reward [TFS 1.2]

Status
Not open for further replies.

hodleo

Formerly cbrm -Crypto enthusiast, Retired scripter
Staff member
Global Moderator
Joined
Jan 6, 2009
Messages
6,598
Solutions
3
Reaction score
955
Location
Caribbean Sea
Tested on TFS 1.2, 10.77/78
Based on
http://www.tibia.com/news/?subtopic=newsarchive&id=2486

reward_system2.png

achievement-grade-symbol.gif
Features
*Custom depot as reward chest to store the unclaimed loot of bosses.
*Individual reward for each player that hits the boss.
*Loot chance determined by % of damage dealt to boss.
*Player may "pick up" his reward container directly from the corpse.
*Unclaimed reward is sent to online and offline participant players when corpse rots.
*Unclaimed loot containers get erased after seven days of being stored.
*Only items may be taken out from reward chest, cannot put items in there.
*Players' reward containers are stored as encoded, serialized tables on database.
*Exhaustion limit to open reward chest, in order to avoid the spam of sql queries.

achievement-grade-symbol.gif
To-Do
*Damage taken by the boss leads to a % of loot drop.
*Healers' amount of health given to boss slayers leads to a % of loot drop.
*Open reward chest as an inner depot.
*Set the corpses of the bosses as virtual and temporary depots to make it more realistic.

achievement-grade-symbol.gif
Changelog
(0.1) initial release
(0.2) base64 coding for serialized rewards
(0.3) fix for infinite corpses' decay
(0.4) fix for bosses with lowercase names

achievement-grade-symbol.gif
Comments
This is a system which I got requested to write a year ago, now released with the consent of the customer. It's kinda like Tibia's Boss Reward feature that lets all participant players that kill a boss to get a part of his loot. It is still far away from the original creation, but at least it's something that many OTS owners want. I welcome all developers, programmers and scripters that desire to improve this code, so this can get closer to perfection.

achievement-grade-symbol.gif
Special thanks to
@Dalkon, for his tips of C++
@gugahoa, for the loot functions
@Colandus and @Cykotitan, for the string.diff function
@Printer, for updating the exhaustion functions

achievement-grade-symbol.gif
Setup instructions
Execute query at database
Code:
CREATE TABLE IF NOT EXISTS `player_rewardchest` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `player_id` int(11) NOT NULL,
    `reward` text NOT NULL,
    `date` bigint(20) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;

src/const.h
Below...

Code:
ITEM_MARKET = 14405
...Add:
Code:
ITEM_REWARD_CHEST = 21584,
REWARD_CHEST_DEPOT = 99,

src/depotchest.h
Below...

Code:
explicit DepotChest(uint16_t _type);
...Add:
Code:
uint32_t getDepotId() const {
    return depotId;
}

void setDepotId(uint32_t id) {
    depotId = id;
}
Below...
Code:
uint32_t maxDepotItems;
...Add:
Code:
uint32_t depotId;

src/depotchest.cpp
Below...

Code:
maxDepotItems = 1500;
...Add:
Code:
depotId = 0;
Above...
Code:
return Container::queryAdd(index, thing, count, flags, actor);
...Add:
Code:
if (actor != nullptr && getDepotId() == REWARD_CHEST_DEPOT) {
    return RETURNVALUE_NOTPOSSIBLE;
}

src/depotlocker.h
Above...

Code:
//cylinder implementations
...Add:
Code:
void setMaxLockerItems(uint32_t maxitems) {
    maxSize = maxitems;
}

src/luascript.h
Above...

Code:
static int luaContainerGetSize(lua_State* L);
...Add:
Code:
static int luaContainerGetContentDescription(lua_State* L);
src/luascript.cpp
Above...

Code:
registerMethod("Container", "getSize", LuaScriptInterface::luaContainerGetSize);
...Add:
Code:
registerMethod("Container", "getContentDescription", LuaScriptInterface::luaContainerGetContentDescription);
Above...
Code:
int LuaScriptInterface::luaContainerGetSize(lua_State* L)
...Add:
Code:
int LuaScriptInterface::luaContainerGetContentDescription(lua_State* L)
{
    // container:getContentDescription()
    Container* container = getUserdata<Container>(L, 1);
    if (container) {
        std::ostringstream ss;
        ss << container->getContentDescription();
        pushString(L, ss.str());
    } else {
        lua_pushnil(L);
    }
    return 1;
}

src/actions.cpp
Change:

Code:
//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;
}
For:
Code:
//reward chest and depot container
if (item->getID() == ITEM_REWARD_CHEST) {
    DepotLocker* myRewardChest = player->getRewardChest();
    myRewardChest->setParent(item->getTile());
    openContainer = myRewardChest;
    player->setLastDepotId(REWARD_CHEST_DEPOT);
} 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/player.h
Below...

Code:
DepotLocker* getDepotLocker(uint32_t depotId);
...Add:
Code:
DepotLocker* getRewardChest();

src/player.cpp
Below...

Code:
DepotChest* depotChest = new DepotChest(ITEM_DEPOT);
...Add:
Code:
depotChest->setDepotId(depotId);
Above..
Code:
void Player::sendCancelMessage(ReturnValue message) const
...Add:
Code:
DepotLocker* Player::getRewardChest()
{
    auto it = depotLockerMap.find(REWARD_CHEST_DEPOT);
    if (it != depotLockerMap.end()) {
        inbox->setParent(it->second);
        return it->second;
    }

    DepotLocker* rewardChest = new DepotLocker(ITEM_LOCKER1);
    rewardChest->setDepotId(REWARD_CHEST_DEPOT);
    rewardChest->setMaxLockerItems(1);
    rewardChest->internalAddThing(getDepotChest(REWARD_CHEST_DEPOT, true));
    depotLockerMap[REWARD_CHEST_DEPOT] = rewardChest;
    return rewardChest;
}

On player.cpp, container.cpp, inbox.cpp
Change:

Code:
if (!item->isPickupable()) {
For:
Code:
if (item->getID() != 21518 && !item->isPickupable()) {
 
Add @ data/actions/actions.xml
Code:
<!-- Reward Chest System -->
<action itemid="21584" script="reward_chest.lua"/>
<action actionid="21584" script="reward_chest.lua"/>

Create @ data/actions/scripts/reward_chest.lua
Code:
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    --Reward Chest
    if item:getId() == 21584 then
        if player:getExhaustion(REWARD_CHEST.STORAGE) > 0 then
            return player:sendCancelMessage('You need to wait ' .. string.diff(player:getStorageValue(REWARD_CHEST.STORAGE)-os.time()) .. ' before using this chest again.')
        end
        player:updateRewardChest()
    --Boss Corpse
    elseif item:getActionId() == 21584 then
        local reward = REWARD_CHEST.LOOT[tonumber(item:getAttribute('text'))][player:getGuid()]
        if reward ~= nil then
            local rewardBag = Container(doCreateItemEx(REWARD_CHEST.CONTAINER, 1))
            addContainerItems(rewardBag, reward)
            if player:getCapacity() < rewardBag:getCapacity() then
                return player:sendCancelMessage(RETURNVALUE_NOTENOUGHCAPACITY)
            end
            if player:addItemEx(rewardBag, false) == RETURNVALUE_NOERROR then
                REWARD_CHEST.LOOT[tonumber(item:getAttribute('text'))][player:getGuid()] = nil
                player:sendCancelMessage('You have picked up a reward container.')
            else
                player:sendCancelMessage(RETURNVALUE_NOTENOUGHROOM)
                return true
            end
        end
    end
    return false
end

Add @ data/creaturescripts/creaturescripts.xml
Code:
<event type="kill" name="RewardChest" script="reward_chest.lua"/>

Register @data/creaturescripts/scripts/login.lua
Code:
player:registerEvent("RewardChest")

Add @ data/items/items.xml
Code:
<item id="21518" article="a" name="reward container">
    <attribute key="weight" value="1800" />
    <attribute key="containersize" value="24" />
    <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>

Add @ data/lib/core/player.lua
Code:
function Player.setExhaustion(self, value, time)
    return self:setStorageValue(value, time + os.time())
end

function Player.getExhaustion(self, value)
    local storage = self:getStorageValue(value)
    if storage <= 0 then
        return 0
    end
    return storage - os.time()
end
 
OMG, what a nice script! I use it of course. Thanks for sharing! :)
 
2 much info in 1 thread
pretty good release *****
 
Baby, nice script <3






y entonces cyber dijo: "este es mi poder actual" (todos comenzaron a creer en will smith)
 
VERY NICE!!!! I LOVE YOU <3
edit: Only a question now hehe
The reward chest will are in depot chest too?
if I not want this, want the chest just in adverturers island, how I can do it?
edit: thanks...
i'm confuse here...
I have an error in sintax
Code:
/home/cesar/forgottenserver/src/player.cpp: In member function ‘DepotChest* Player::getDepotChest(uint32_t, bool)’:
/home/cesar/forgottenserver/src/player.cpp:912:1: error: a function-definition is not allowed here before ‘{’ token
 {
 ^
/home/cesar/forgottenserver/src/player.cpp:4699:1: error: expected ‘}’ at end of input
 }
 ^
/home/cesar/forgottenserver/src/player.cpp:4699:1: error: control reaches end of non-void function [-Werror=return-type]
 }
 ^
cc1plus: all warnings being treated as errors
make[2]: *** [CMakeFiles/tfs.dir/src/player.cpp.o] Error 1
make[1]: *** [CMakeFiles/tfs.dir/all] Error 2
make: *** [all] Error 2
I'm completly copying what you told in player.cpp but have this error... I'll try see where I'm mistaken
 
Last edited:
i'm confuse here...
I have an error in sintax
Code:
/home/cesar/forgottenserver/src/player.cpp: In member function ‘DepotChest* Player::getDepotChest(uint32_t, bool)’:
/home/cesar/forgottenserver/src/player.cpp:912:1: error: a function-definition is not allowed here before ‘{’ token
{
^
/home/cesar/forgottenserver/src/player.cpp:4699:1: error: expected ‘}’ at end of input
}
^
/home/cesar/forgottenserver/src/player.cpp:4699:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
cc1plus: all warnings being treated as errors
make[2]: *** [CMakeFiles/tfs.dir/src/player.cpp.o] Error 1
make[1]: *** [CMakeFiles/tfs.dir/all] Error 2
make: *** [all] Error 2
I'm completly copying what you told in player.cpp but have this error... I'll try see where I'm mistaken
I fixed it on the main post now. Re-do again the part of player.cpp, it's just a bad typo when I was creating the thread.

I just tested it with clean sources from the github and it's all fine
1>------ Rebuild All started: Project: theforgottenserver, Configuration: Release x64 ------
1> otpch.cpp
1> actions.cpp
1> ban.cpp
1> baseevents.cpp
1> bed.cpp
1> chat.cpp
1> combat.cpp
1> commands.cpp
1> condition.cpp
1> configmanager.cpp
1> connection.cpp
1> container.cpp
1> creature.cpp
1> creatureevent.cpp
1> cylinder.cpp
1> database.cpp
1> databasemanager.cpp
1> databasetasks.cpp
1> depotchest.cpp
1> depotlocker.cpp
1> events.cpp
1> fileloader.cpp
1> game.cpp
1> globalevent.cpp
1> groups.cpp
1> guild.cpp
1> house.cpp
1> housetile.cpp
1> inbox.cpp
1> ioguild.cpp
1> iologindata.cpp
1> iomap.cpp
1> iomapserialize.cpp
1> iomarket.cpp
1> item.cpp
1> items.cpp
1> luascript.cpp
1> mailbox.cpp
1> map.cpp
1> monster.cpp
1> monsters.cpp
1> mounts.cpp
1> movement.cpp
1> networkmessage.cpp
1> npc.cpp
1> otserv.cpp
1> outfit.cpp
1> outputmessage.cpp
1> party.cpp
1> player.cpp
1> position.cpp
1> protocol.cpp
1> protocolgame.cpp
1> protocollogin.cpp
1> protocolold.cpp
1> quests.cpp
1> raids.cpp
1> rsa.cpp
1> scheduler.cpp
1> scriptmanager.cpp
1> server.cpp
1> spawn.cpp
1> spells.cpp
1> protocolstatus.cpp
1> talkaction.cpp
1> tasks.cpp
1> teleport.cpp
1> thing.cpp
1> tile.cpp
1> tools.cpp
1> trashholder.cpp
1> vocation.cpp
1> waitlist.cpp
1> weapons.cpp
1> wildcardtree.cpp
1> Generating code
1> Finished generating code
1> theforgottenserver.vcxproj -> C:\Users\Leo\Desktop\OTS\1.2 (10.78)\vc12\x64\Release\theforgottenserver.exe
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
 
during my tests if the system I see somethings...
1 - if player are offline he don't recieve any loot...
2 - when you kill a boss the loot you take all with the bag, will have spam of this bags
3 - the rewards not appears in reward chest anytime...
4 - if I hit sometimes in a boss and logout and another people hit after me, and logout, and I login again, and hit, I will lose my "hits" from the first time and my loot will disappear... and the another people will lose his loot too...


for the error of compiling I found the error... I've put the function inside another '-' is it why give error...
but later I fix this and works the compile
 
during my tests if the system I see somethings...
1 - if player are offline he don't recieve any loot...
2 - when you kill a boss the loot you take all with the bag, will have spam of this bags
3 - the rewards not appears in reward chest anytime...
4 - if I hit sometimes in a boss and logout and another people hit after me, and logout, and I login again, and hit, I will lose my "hits" from the first time and my loot will disappear... and the another people will lose his loot too...


for the error of compiling I found the error... I've put the function inside another '-' is it why give error...
but later I fix this and works the compile
Are you using the latest sources from the otland github?
I would recommend you to start again from zero since those errors might have screwed up the system.
It doesn't sound to me that you added the lua scripts, but make sure that you follow all the steps on the first, second and third posts of this thread.
This is still working flawlessly for me even after re-compiling and following all the steps, so you must be doing something wrong.
 
Are you using the latest sources from the otland github?
I would recommend you to start again from zero since those errors might have screwed up the system.
It doesn't sound to me that you added the lua scripts, but make sure that you follow all the steps on the first, second and third posts of this thread.
This is still working flawlessly for me even after re-compiling and following all the steps, so you must be doing something wrong.
I do this '-' take the latest source, start all from zero, I see all things again... I'm tired for see too much times '-' and are the same than before
the same things:
1 - if player are offline he don't recieve any loot...
2 - when you kill a boss the loot you take all with the bag, will have spam of this bags
3 - the rewards not appears in reward chest anytime...
4 - if I hit sometimes in a boss and logout and another people hit after me, and logout, and I login again, and hit, I will lose my "hits" from the first time and my loot will disappear... and the another people will lose his loot too...
 
I do this '-' take the latest source, start all from zero, I see all things again... I'm tired for see too much times '-' and are the same than before
the same things:
1 - if player are offline he don't recieve any loot...
2 - when you kill a boss the loot you take all with the bag, will have spam of this bags
3 - the rewards not appears in reward chest anytime...
4 - if I hit sometimes in a boss and logout and another people hit after me, and logout, and I login again, and hit, I will lose my "hits" from the first time and my loot will disappear... and the another people will lose his loot too...
Contact me in private, I don't see how this doesn't work for you.
 
Getting this using TFS 1.0:

Code:
Lua Script Error: [Main Interface]
in a timer event called from:
data/global.lua
data/creaturescripts/scripts/reward_chest.lua:116: attempt to index a nil value
stack traceback:
        [C]: in function '__index'
        data/creaturescripts/scripts/reward_chest.lua:116: in function <data/creaturescripts/scripts/reward_chest.lua:114>

I used the alternative version for older tfs 1.x btw
 
Last edited:
Yeah, there are a few things wrong with the alternate version for older revs. Once I take a look on it later I'll update it here.
 
Thank you, I'll be waiting for the update.
 
clever way to create virtual depot.

But the sourceCode part seems irrelevant.
Couldn't you just use existing depot with fake Town ID?
and do the query function in LUA?

But what do I know, haven't even read entire post of yours and little do I know about sourceCodes xD
 
Status
Not open for further replies.
Back
Top