• 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!

Solved parcel stack block

xKrazyx

Old School
Joined
Oct 23, 2012
Messages
899
Solutions
6
Reaction score
677
Trying to replicate the 7.4 stack block for parcel and boxes but cant seem to find the code.. anyone know where that might be located in the old otserv distros? otserv.cpp??


EDIT: ive been searching.. is this it????

Code:
void Game::internalGetPosition(Item* item, Position& pos, uint8_t& stackpos)
{
    pos.x = 0;
    pos.y = 0;
    pos.z = 0;
    stackpos = 0;

    Cylinder* topParent = item->getTopParent();
    if(topParent){
        if(Player* player = dynamic_cast<Player*>(topParent)){
            pos.x = 0xFFFF;

            Container* container = dynamic_cast<Container*>(item->getParent());
            if(container){
                pos.y = ((uint16_t) ((uint16_t)0x40) | ((uint16_t)player->getContainerID(container)) );
                pos.z = container->__getIndexOfThing(item);
                stackpos = pos.z;
            }
            else{
                pos.y = player->__getIndexOfThing(item);
                stackpos = pos.y;
            }
        }
        else if(Tile* tile = topParent->getTile()){
            pos = tile->getPosition();
            stackpos = tile->__getIndexOfThing(item);
        }
    }
}


Heres some other code..
Code:
Cylinder* Game::internalGetCylinder(Player* player, const Position& pos)
{
    if(pos.x != 0xFFFF){
        return getTile(pos.x, pos.y, pos.z);
    }
    else{
        //container
        if(pos.y & 0x40){
            uint8_t from_cid = pos.y & 0x0F;
            return player->getContainer(from_cid);
        }
        //inventory
        else{
            return player;
        }
    }
}

Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index,
    uint32_t spriteId /*= 0*/, stackPosType_t type /*= STACKPOS_NORMAL*/)
{
    if(pos.x != 0xFFFF){
        Tile* tile = getTile(pos.x, pos.y, pos.z);

        if(tile){
            /*look at*/
            if(type == STACKPOS_LOOK){
                return tile->getTopVisibleThing(player);
            }

            Thing* thing = NULL;

            /*for move operations*/
            if(type == STACKPOS_MOVE){
                Item* item = tile->getTopDownItem();
                if(item && !item->isNotMoveable())
                    thing = item;
                else
                    thing = tile->getTopVisibleCreature(player);
            }
            /*use item*/
            else if(type == STACKPOS_USE){
                thing = tile->getTopDownItem();
            }
            else if(type == STACKPOS_USEITEM){
                //the first down item is usually the right item unless there is topOrder items with scripts
                Item* downItem = tile->getTopDownItem();

                //check items with topOrder 2 (ladders, signs, splashes)
                Item* topOrderItem =  tile->getItemByTopOrder(2);
                if(topOrderItem && g_actions->hasAction(topOrderItem) ){
                    const ItemType& it = Item::items[topOrderItem->getID()];
                    //if the top order item has a height or allows pickupable items we use the first down item instead
                    if(!(downItem && (it.hasHeight || it.allowPickupable))){
                        thing = topOrderItem;
                    }
                }

                if(thing == NULL){
                    //first down item
                    thing = downItem;
                }

                if(thing == NULL){
                    //then items with topOrder 3 (doors etc)
                    thing = tile->getTopTopItem();
                }

                if(thing == NULL){
                    //and finally the ground
                    thing = tile->ground;
                }
            }
            else{
                thing = tile->__getThing(index);
            }

            if(player){
                //do extra checks here if the thing is accessable
                if(thing && thing->getItem()){
                    if(tile->hasProperty(ISVERTICAL)){
                        if(player->getPosition().x + 1 == tile->getPosition().x){
                            thing = NULL;
                        }
                    }
                    else if(tile->hasProperty(ISHORIZONTAL)){
                        if(player->getPosition().y + 1 == tile->getPosition().y){
                            thing = NULL;
                        }
                    }
                }
            }

            return thing;
        }
    }
    else{
        //container
        if(pos.y & 0x40){
            uint8_t fromCid = pos.y & 0x0F;
            uint8_t slot = pos.z;

            Container* parentcontainer = player->getContainer(fromCid);
            if(!parentcontainer)
                return NULL;

            return parentcontainer->getItem(slot);
        }
        else if(pos.y == 0 && pos.z == 0){
            const ItemType& it = Item::items.getItemIdByClientId(spriteId);
            if(it.id == 0){
                return NULL;
            }

            int32_t subType = -1;
            if(it.isFluidContainer()){
                subType = index;
            }

            return findItemOfType(player, it.id, true, subType);
        }
        //inventory
        else{
            slots_t slot = (slots_t)static_cast<unsigned char>(pos.y);
            return player->getInventoryItem(slot);
        }
    }

    return NULL;
}

void Game::internalGetPosition(Item* item, Position& pos, uint8_t& stackpos)
{
    pos.x = 0;
    pos.y = 0;
    pos.z = 0;
    stackpos = 0;

    Cylinder* topParent = item->getTopParent();
    if(topParent){
        if(Player* player = dynamic_cast<Player*>(topParent)){
            pos.x = 0xFFFF;

            Container* container = dynamic_cast<Container*>(item->getParent());
            if(container){
                pos.y = ((uint16_t) ((uint16_t)0x40) | ((uint16_t)player->getContainerID(container)) );
                pos.z = container->__getIndexOfThing(item);
                stackpos = pos.z;
            }
            else{
                pos.y = player->__getIndexOfThing(item);
                stackpos = pos.y;
            }
        }
        else if(Tile* tile = topParent->getTile()){
            pos = tile->getPosition();
            stackpos = tile->__getIndexOfThing(item);
        }
    }
}
 
Last edited:
Im sure the code is the same.. or close to the same... they both come from otserv... if we can confirm this is indeed the code that effects parcels/boxes I can fix it.. im just not at home no compiler so I cant trial and error.. trying to do it in notepad++ before I get home from vacation
 
You can simply edit first post a change to solved.. for the title.
If possible post the solution so others who search im the future will get some help if they run into the same issue.
 
you mean... if your standing on the ground floor.. your not suppose to be able to drag parcels underneath of you to raise height? from lvl 0? without walking up them? I thought you could do that in 74, or do you mean physically pushing someone onto the stack of parcels ?@53701688


I think this is the code right? Just have to add a new instance to check for items... SO HERES MY QUESTION. in 740 could you push yourself onto 1 parcel? or none.
Code:
bool Game::playerMoveCreature(uint32_t playerId, uint32_t movingCreatureId,
    const Position& movingCreatureOrigPos, const Position& toPos)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveCreatures))
        return false;

    if(!player->canDoAction()){
        uint32_t delay = player->getNextActionTime();
        SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveCreature, this, playerId, movingCreatureId,
            movingCreatureOrigPos, toPos));
        player->setNextActionTask(task);
        return false;
    }

    player->setNextActionTask(NULL);

    Creature* movingCreature = getCreatureByID(movingCreatureId);

    if(!movingCreature || movingCreature->isRemoved())
        return false;

    if(!Position::areInRange<1,1,0>(movingCreatureOrigPos, player->getPosition())){
        //need to walk to the creature first before moving it
        std::list<Direction> listDir;
        if(getPathToEx(player, movingCreatureOrigPos, listDir, 0, 1, true, true)){
            g_dispatcher.addTask(createTask(boost::bind(&Game::playerAutoWalk,
                this, player->getID(), listDir)));
            SchedulerTask* task = createSchedulerTask(g_config.getNumber(ConfigManager::PUSH_INTERVAL), boost::bind(&Game::playerMoveCreature, this,
                playerId, movingCreatureId, movingCreatureOrigPos, toPos));
            g_dispatcher.addTask(createTask(boost::bind(&Game::playerRegisterWalkAction,
                this, player->getID(), task)));
            return true;
        }
        else{
            player->sendCancelMessage(RET_THEREISNOWAY);
            return false;
        }
    }

    Tile* toTile = getTile(toPos);
    const Position& movingCreaturePos = movingCreature->getPosition();

    if(!toTile){
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }


    if (!movingCreature->canBePushedBy(player)){
        player->sendCancelMessage(RET_NOTMOVEABLE);
        return false;
    }


    //check throw distance
    if((std::abs(movingCreaturePos.x - toPos.x) > movingCreature->getThrowRange()) ||
            (std::abs(movingCreaturePos.y - toPos.y) > movingCreature->getThrowRange()) ||
            (std::abs(movingCreaturePos.z - toPos.z) * 4 > movingCreature->getThrowRange())){
        player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
        return false;
    }

    if(player != movingCreature){
        if(toTile->hasProperty(BLOCKPATH)){
            player->sendCancelMessage(RET_NOTENOUGHROOM);
            return false;
        }
        else if(movingCreature->getZone() == ZONE_PROTECTION && !toTile->hasFlag(TILESTATE_PROTECTIONZONE)){
            player->sendCancelMessage(RET_NOTPOSSIBLE);
            return false;
        }
        else if(toTile->getCreatures() && !toTile->getCreatures()->empty()
            && !player->hasFlag(PlayerFlag_CanPushAllCreatures)){
            player->sendCancelMessage(RET_NOTPOSSIBLE);
            return false;
        }
        else if(movingCreature->getNpc() && !Spawns::getInstance()->isInZone(movingCreature->masterPos, movingCreature->masterRadius, toPos)){
            player->sendCancelMessage(RET_NOTENOUGHROOM);
            return false;
        }
    }

    ReturnValue ret = internalMoveCreature(movingCreature, movingCreature->getTile(), toTile);
    if(ret != RET_NOERROR){
        player->sendCancelMessage(ret);
        return false;
    }

    return true;
}
 
Last edited:
How to fix, pushing yourself on stacked parcels.

Find the function playerMoveCreature :

Code:
bool Game::playerMoveCreature(uint32_t playerId, uint32_t movingCreatureId,
    const Position& movingCreatureOrigPos, const Position& toPos)

In the function playerMoveCreature find this code :
Code:
if(!toTile){
    player->sendCancelMessage(RET_NOTPOSSIBLE);
    return false;
}

Then you paste this code underneath it :
Code:
if (toTile->getHeight() > 1) {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
}

Any further instructions are compile the sources and your done.
 
Last edited by a moderator:
So, where is the solution or the piece of code? I'm using TFS 1.2, where can I find that piece code that is referring to player height on parcel / box / creates / chairs stacking, I suppose in game.cpp, but where?

@xKrazyx
@53701688

Same Piece of codes

C++:
void Game::internalGetPosition(Item* item, Position& pos, uint8_t& stackpos)
{
    pos.x = 0;
    pos.y = 0;
    pos.z = 0;
    stackpos = 0;

    Cylinder* topParent = item->getTopParent();
    if (topParent) {
        if (Player* player = dynamic_cast<Player*>(topParent)) {
            pos.x = 0xFFFF;

            Container* container = dynamic_cast<Container*>(item->getParent());
            if (container) {
                pos.y = static_cast<uint16_t>(0x40) | static_cast<uint16_t>(player->getContainerID(container));
                pos.z = container->getThingIndex(item);
                stackpos = pos.z;
            } else {
                pos.y = player->getThingIndex(item);
                stackpos = pos.y;
            }
        } else if (Tile* tile = topParent->getTile()) {
            pos = tile->getPosition();
            stackpos = tile->getThingIndex(item);
        }
    }
}


C++:
Cylinder* Game::internalGetCylinder(Player* player, const Position& pos) const
{
    if (pos.x != 0xFFFF) {
        return map.getTile(pos);
    }

    //container
    if (pos.y & 0x40) {
        uint8_t from_cid = pos.y & 0x0F;
        return player->getContainerByID(from_cid);
    }

    //inventory
    return player;
}

Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index, uint32_t spriteId, stackPosType_t type) const
{
    if (pos.x != 0xFFFF) {
        Tile* tile = map.getTile(pos);
        if (!tile) {
            return nullptr;
        }

        Thing* thing;
        switch (type) {
            case STACKPOS_LOOK: {
                return tile->getTopVisibleThing(player);
            }

            case STACKPOS_MOVE: {
                Item* item = tile->getTopDownItem();
                if (item && item->isMoveable()) {
                    thing = item;
                } else {
                    thing = tile->getTopVisibleCreature(player);
                }
                break;
            }

            case STACKPOS_USEITEM: {
                thing = tile->getUseItem();
                break;
            }

            case STACKPOS_TOPDOWN_ITEM: {
                thing = tile->getTopDownItem();
                break;
            }

            case STACKPOS_USETARGET: {
                thing = tile->getTopCreature();
                if (!thing) {
                    thing = tile->getUseItem();
                }
                break;
            }

            default: {
                thing = nullptr;
                break;
            }
        }

        if (player && tile->hasFlag(TILESTATE_SUPPORTS_HANGABLE)) {
            //do extra checks here if the thing is accessable
            if (thing && thing->getItem()) {
                if (tile->hasProperty(CONST_PROP_ISVERTICAL)) {
                    if (player->getPosition().x + 1 == tile->getPosition().x) {
                        thing = nullptr;
                    }
                } else { // horizontal
                    if (player->getPosition().y + 1 == tile->getPosition().y) {
                        thing = nullptr;
                    }
                }
            }
        }
        return thing;
    }

    //container
    if (pos.y & 0x40) {
        uint8_t fromCid = pos.y & 0x0F;

        Container* parentContainer = player->getContainerByID(fromCid);
        if (!parentContainer) {
            return nullptr;
        }

        uint8_t slot = pos.z;
        return parentContainer->getItemByIndex(player->getContainerIndex(fromCid) + slot);
    } else if (pos.y == 0 && pos.z == 0) {
        const ItemType& it = Item::items.getItemType(spriteId);
        if (it.id == 0) {
            return nullptr;
        }

        int32_t subType;
        if (it.isFluidContainer()) {
            subType = static_cast<FluidTypes_t>(index);
        } else {
            subType = -1;
        }

        return findItemOfType(player, it.id, true, subType);
    }

    //inventory
    slots_t slot = static_cast<slots_t>(pos.y);
    return player->getInventoryItem(slot);
}
 
Last edited by a moderator:
Back
Top