// New Class implementation void cDragItems::grabItem( cUOSocket *socket, cUORxDragItem *packet ) { // Get our character P_PLAYER pChar = socket->player(); if( !pChar ) return; UINT32 weight = pChar->weight(); // Fetch the grab information UI16 amount = packet->amount(); if( !amount ) amount = 1; P_ITEM pItem = FindItemBySerial( packet->serial() ); // If it's an invalid pointer we can't even bounce if( !pItem ) return; // Are we already dragging an item ? // Bounce it and reject the move // (Logged out while dragging an item) if( socket->dragging() ) { socket->bounceItem( socket->dragging(), BR_ALREADY_DRAGGING ); return; } if( pItem->onPickup( pChar ) ) return; if( pChar->onPickup( pItem ) ) return; // Do we really want to let him break his meditation // When he picks up an item ? // Maybe a meditation check here ?!? pChar->disturbMed(); // Meditation P_CHAR itemOwner = pItem->getOutmostChar(); // Try to pick something out of another characters posessions if( !pChar->isGM() && itemOwner && ( itemOwner != pChar ) && ( itemOwner->objectType() == enNPC && dynamic_cast<P_NPC>(itemOwner)->owner() != pChar ) ) { socket->bounceItem( pItem, BR_BELONGS_TO_SOMEONE_ELSE ); return; } // Check if the user can grab the item if( !pChar->canPickUp( pItem ) ) { socket->bounceItem( pItem, BR_CANNOT_PICK_THAT_UP ); return; } // The user can't see the item // Basically thats impossible as the socket should deny moving the item // if it's not in line of sight but to prevent exploits /*if( !line_of_sight( socket->socket(), pChar->pos, pItem->pos, TREES_BUSHES|WALLS_CHIMNEYS|DOORS|ROOFING_SLANTED|FLOORS_FLAT_ROOFING|LAVA_WATER ) ) { socket->sysMessage( "You can't see the item." ); bounceItem( socket, pItem, true ); return; }*/ P_ITEM outmostCont = pItem->getOutmostItem(); // If it's a trade-window, reset the ack-status if( outmostCont && ( outmostCont->container() == pChar ) && ( outmostCont->layer() == 0 ) && ( outmostCont->id() == 0x1E5E ) ) { // Get the other sides tradewindow P_ITEM tradeWindow = FindItemBySerial( calcserial( outmostCont->moreb1(), outmostCont->moreb2(), outmostCont->moreb3(), outmostCont->moreb4() ) ); // If one of the trade-windows has the ack-status reset it if( tradeWindow && ( tradeWindow->morez() || outmostCont->morez() ) ) { tradeWindow->setMoreZ(0); outmostCont->setMoreZ(0); // sendtradestatus( tradeWindow, outmostCont ); } } // If the top-most container ( thats important ) is a corpse // and looting is a crime, flag the character criminal. if( !pChar->isGM() && outmostCont && outmostCont->corpse() ) { // For each item we take out we loose carma // if the corpse is innocent and not in our guild bool sameGuild = ( GuildCompare( pChar, outmostCont->owner() ) != 0 ); if( ( outmostCont->more2() == 1 ) && !pChar->Owns( outmostCont ) && !sameGuild ) { // pChar->karma -= 5; pChar->setKarma( pChar->karma() - 5 ); pChar->setCriminalTime( uiCurrentTime + SrvParams->crimtime() * MY_CLOCKS_PER_SEC ); socket->sysMessage( tr("You lost some karma.") ); } } // Check if the item is too heavy //if( !pc_currchar->isGMorCounselor() ) //{ //} << Deactivated (DarkStorm) // ==== Grabbing the Item is allowed here ==== // Remove eventual item-bonusses if we're unequipping something if( pItem->container() && pItem->container()->isChar() ) { P_CHAR wearer = dynamic_cast<P_CHAR>( pItem->container() ); if( wearer ) wearer->removeItemBonus( pItem ); // resend the stat window if( wearer && wearer->objectType() == enPlayer ) { P_PLAYER pp = dynamic_cast<P_PLAYER>(wearer); if( pp->socket() ) pp->socket()->sendStatWindow(); } } // Send the user a pickup sound if we're picking it up // From a container/paperdoll if( !pItem->isInWorld() ) socket->soundEffect( 0x57, pItem ); // If we're picking up a specific amount of what we got // Take that into account if( amount < pItem->amount() ) { UI32 pickedAmount = QMIN( amount, pItem->amount() ); // We only have to split if we're not taking it all if( pickedAmount != pItem->amount() ) { P_ITEM splitItem = new cItem( *pItem ); // Create a new item to pick that up splitItem->setSerial( World::instance()->findItemSerial() ); splitItem->setAmount( pItem->amount() - pickedAmount ); P_ITEM pContainer = dynamic_cast<P_ITEM>(pItem->container()); if ( pContainer ) pContainer->addItem( splitItem, false ); splitItem->SetOwnSerial( pItem->ownSerial() ); splitItem->SetSpawnSerial( pItem->spawnserial ); // He needs to see the new item splitItem->update(); // If we're taking something out of a spawn-region it's spawning "flag" is removed isn't it? pItem->SetSpawnSerial( INVALID_SERIAL ); pItem->setAmount( pickedAmount ); } } // *normally* we should exclude the dragging socket here. but it works so as well. pItem->removeFromView( true ); // Remove it from the World if it is in world, otherwise remove it from it's current container if( pItem->isInWorld() ) MapObjects::instance()->remove( pItem ); else pItem->removeFromCont( true ); // The item was in a multi if( pItem->multis() != INVALID_SERIAL ) { cMulti* pMulti = dynamic_cast< cMulti* >( FindItemBySerial( pItem->multis() ) ); if( pMulti ) pMulti->removeItem( pItem ); } pChar->addItem( cBaseChar::Dragging, pItem ); if( weight != pChar->weight() ) socket->sendStatWindow(); }
void cDragItems::dropOnItem( cUOSocket *socket, P_ITEM pItem, P_ITEM pCont, const Coord_cl &dropPos ) { P_PLAYER pChar = socket->player(); if( pItem->isMulti() ) { socket->sysMessage( tr( "You cannot put houses in containers" ) ); cUOTxBounceItem bounce; bounce.setReason( BR_NO_REASON ); socket->send( &bounce ); Items->DeleItem( pItem ); return; } if( pItem->onDropOnItem( pCont ) ) { if( socket->dragging() ) socket->bounceItem( socket->dragging(), BR_NO_REASON ); return; } else if( pCont->onDropOnItem( pItem ) ) { if( socket->dragging() ) socket->bounceItem( socket->dragging(), BR_NO_REASON ); return; } // If the target belongs to another character // It needs to be our vendor or else it's denied P_CHAR packOwner = pCont->getOutmostChar(); if( ( packOwner ) && ( packOwner != pChar ) && !pChar->isGM() ) { // For each item someone puts into there // He needs to do a snoop-check if( pChar->maySnoop() ) { if( !pChar->checkSkill( SNOOPING, 0, 1000 ) ) { socket->sysMessage( tr( "You fail to put that into %1's pack" ).arg( packOwner->name() ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } } if( packOwner->objectType() == enPlayer || ( packOwner->objectType() == enNPC && dynamic_cast<P_NPC>(packOwner)->owner() != pChar ) ) { socket->sysMessage( tr("You cannot put that into the belongings of another player") ); socket->bounceItem( pItem, BR_NO_REASON ); return; } } // If we put the item into a trade-window // Reset the trade-status for both players if( pCont->layer() == 0 && pCont->id() == 0x1E5E && pChar->Wears( pCont ) ) { // Trade window??? P_ITEM tradeWindow = FindItemBySerial( calcserial( pCont->moreb1(), pCont->moreb2(), pCont->moreb3(), pCont->moreb4() ) ); // If it *IS* a trade-window, replace the status if( tradeWindow && ( pCont->morez() || tradeWindow->morez() ) ) { tradeWindow->setMoreZ(0); pCont->setMoreZ(0); // sendtradestatus( tradeWindow, pCont ); } } if( !pChar->canPickUp( pItem ) ) { socket->bounceItem( pItem, BR_CANNOT_PICK_THAT_UP ); return; } // Trash can if( pCont->type()==87 ) { Items->DeleItem( pItem ); socket->sysMessage( tr( "As you let go of the item it disappears." ) ); return; } // Spell Book cSpellBook *pBook = dynamic_cast< cSpellBook* >( pCont ); if( pBook ) { SI08 spellId = NewMagic->calcSpellId( pItem->id() ); if( pItem->type() != 1105 || spellId < 0 ) { socket->sysMessage( tr( "You can only put scrolls into a spellbook" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } if( pBook->hasSpell( spellId ) ) { socket->sysMessage( tr( "That spellbook already contains this spell" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } if( pItem->amount() > 1 ) { socket->sysMessage( tr( "You can only put 1 scroll into a spellbook at a time" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } else { pBook->addSpell( spellId ); Items->DeleItem( pItem ); pBook->update( socket ); return; } } // We drop something on the belongings of one of our playervendors /* if( ( packOwner != NULL ) && ( packOwner->npcaitype() == 17 ) && packOwner->owner() == pChar ) { socket->sysMessage( tr( "You drop something into your playervendor (unimplemented)" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; }*/ // Playervendors (chest equipped by the vendor - opened to the client) /*if( !( pCont->pileable() && pItem->pileable() && pCont->id() == pItem->id() || ( pCont->type() != 1 && pCont->type() != 9 ) ) ) { P_CHAR pc_j = GetPackOwner(pCont); if (pc_j != NULL) { if (pc_j->npcaitype() == 17 && pc_j->isNpc() && pChar->Owns(pc_j)) { pChar->inputitem = pItem->serial; pChar->inputmode = cChar::enPricing; sysmessage(s, "Set a price for this item."); } } */ // We may also drop into *any* locked chest // So we can have post-boxes ;o) // Spellbooks are containers for us as well if( pCont->type() == 1 || pCont->type() == 8 || pCont->type() == 63 || pCont->type() == 65 || pCont->type() == 66 ) { // If we're dropping it onto the closed container if( dropPos.distance( pCont->pos() ) == 0 ) { pCont->addItem( pItem ); } else { pCont->addItem( pItem, false ); pItem->setPos( dropPos ); } // Dropped on another Container/in another Container pChar->soundEffect( 0x57 ); pItem->update(); return; } // Item matching needs to be extended !!! at least Color! (for certain types) else if ( pCont->isPileable() && pItem->isPileable() && ( pCont->id() == pItem->id() ) ) { if( pCont->amount() + pItem->amount() <= 65535 ) { pCont->setAmount( pCont->amount() + pItem->amount() ); Items->DeleItem( pItem ); pCont->update(); // Need to update the amount return; } // We have to *keep* our current item else { pCont->setAmount( 65535 ); // Max out the amount pCont->update(); // The delta between 65535 and pCont->amount() sub our Amount is the // new amount pItem->setAmount( pItem->amount() - ( 65535 - pCont->amount() ) ); } } // We dropped the item NOT on a container // And were *un*able to stack it (!) // >> Set it to the location of the item we dropped it on and stack it up by 2 pItem->moveTo( pCont->pos() ); pItem->setPos( pItem->pos() + Coord_cl(0, 0, 2) ); pItem->update(); /* // This needs to be checked // It annoyingly shows the spellbook // whenever you add a scroll // << could it be that addItemToContainer is enough?? >> if( pCont->type() == 9 ) Magic->openSpellBook( pChar, pCont );*/ }