
NOT WORKING PROPERLY! FIX:
https://otland.net/threads/reward-chest-boss-reward-tfs-1-2.238554/page-2#post-2314080
Thanks to @imkingran
Credits:
Based on cbrm's code:
https://otland.net/threads/reward-chest-boss-reward-tfs-1-2.233397/
Instructions:
src/const.h:
Below...
Code:
ITEM_MARKET = 14405,
...Add:
Code:
ITEM_REWARD_BAG = 21518,
ITEM_REWARD_CHEST = 21584,
REWARD_CHEST_DEPOTID = 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_DEPOTID) {
return RETURNVALUE_NOTPOSSIBLE;
}
src/depotlocker.h:
Above...
Code:
//cylinder implementations
...Add:
Code:
void setMaxLockerItems(uint32_t maxitems) {
maxSize = maxitems;
}
src/player.h:
Below...
Code:
DepotLocker* getDepotLocker(uint32_t depotId);
...Add:
Code:
DepotChest* getRewardBag(uint32_t depotId, bool autoCreate);
DepotLocker* getRewardChest(uint16_t itemId);
src/player.cpp:
Above...
Code:
void Player::sendCancelMessage(ReturnValue message) const
...Add:
Code:
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;
}
Change:
Code:
if (!item->isPickupable()) {
For:
Code:
if (item->getID() != 21518 && !item->isPickupable()) {
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->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:
Above...
Code:
if (!item->isPushable() || item->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID)) {
...Add:
Code:
if (item->getID() == ITEM_REWARD_BAG || item->getActionId() == ITEM_REWARD_CHEST) {
player->sendCancelMessage(RETURNVALUE_NOTMOVEABLE);
return;
}
src/monsters.h:
Below...
Code:
int32_t subType;
int32_t actionId;
std::string text;
...Add:
Code:
bool uniquedrop;
Below...
Code:
actionId = -1;
...Add:
Code:
uniquedrop = false;
Below...
Code:
bool hiddenHealth;
...Add:
Code:
bool rewardChest;
src/monsters.cpp:
Below...
Code:
healthMax = 100;
...Add:
Code:
rewardChest = false;
Below...
Code:
} else if (strcasecmp(attrName, "hidehealth") == 0) {
mType->hiddenHealth = attr.as_bool();
Code:
} else if (strcasecmp(attrName, "rewardchest") == 0) {
mType->rewardChest = attr.as_bool();
Above...
Code:
if ((attr = node.attribute("actionId"))) {
...Add:
Code:
if ((attr = node.attribute("uniquedrop"))) {
lootBlock.uniquedrop = attr.as_bool();
}
src/iologindata.cpp:
Below...
Code:
//load depot items
...Add:
Code:
player->getRewardChest(ITEM_REWARD_CHEST);
Change:
Code:
if (pid >= 0 && pid < 100) {
DepotChest* depotChest = player->getDepotChest(pid, true);
if (depotChest) {
depotChest->internalAddThing(item);
}
For:
Code:
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:
Above...
Code:
// Combat
...Add:
Code:
// Reward
static int luaItemGetNameDescription(lua_State* L);
static int luaMonsterTypeUseRewardChest(lua_State* L);
Above...
Code:
// Party
registerClass("Party", "", nullptr);
...Add:
Code:
// Reward
registerMethod("MonsterType", "useRewardChest", LuaScriptInterface::luaMonsterTypeUseRewardChest);
registerMethod("Item", "getNameDescription", LuaScriptInterface::luaItemGetNameDescription);
Above...
Code:
// Combat
int LuaScriptInterface::luaCombatCreate(lua_State* L)
...Add:
Code:
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;
}
Change:
Code:
int LuaScriptInterface::luaMonsterTypeGetLoot(lua_State* L)
{
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;
}
For:
Code:
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;
}
Last edited: