Q_UINT16 DynTile( const Coord& pos ) { MapItemsIterator ri = MapObjects::instance()->listItemsInCircle( pos, 18 ); for ( P_ITEM mapitem = ri.first(); mapitem; mapitem = ri.next() ) { if ( mapitem->isMulti() ) { MultiDefinition* def = MultiCache::instance()->getMulti( mapitem->id() - 0x4000 ); if ( !def ) return 0; QValueVector<multiItem_st> multi = def->getEntries(); for ( Q_UINT32 j = 0; j < multi.size(); ++j ) { if ( ( multi[j].visible && ( mapitem->pos().x + multi[j].x == pos.x ) && ( mapitem->pos().y + multi[j].y == pos.y ) && ( abs( mapitem->pos().z + multi[j].z - pos.z ) <= 1 ) ) ) { return multi[j].tile; } } } else if ( mapitem->pos() == pos ) { return mapitem->id(); } } return ( Q_UINT16 ) - 1; }
P_ITEM findmulti(Coord_cl pos) //Sortta like getboat() only more general... use this for other multi stuff! { int lastdist = 30; P_ITEM multi = NULL; int ret; cRegion::RegionIterator4Items ri(pos); for (ri.Begin(); !ri.atEnd(); ri++) { P_ITEM mapitem = ri.GetData(); if (mapitem != NULL) { if (mapitem->isMulti()) { ret = pos.distance(mapitem->pos); if (ret <= lastdist) { lastdist = ret; if (inmulti(pos, mapitem)) multi = mapitem; } } } } return multi; }
Q_UINT16 DynTile( const Coord_cl& pos ) { RegionIterator4Items ri( pos ); for ( ri.Begin(); !ri.atEnd(); ri++ ) { P_ITEM mapitem = ri.GetData(); if ( mapitem ) { if ( mapitem->isMulti() ) { MultiDefinition* def = MultiCache::instance()->getMulti( mapitem->id() - 0x4000 ); if ( !def ) return 0; QValueVector<multiItem_st> multi = def->getEntries(); for ( Q_UINT32 j = 0; j < multi.size(); ++j ) { if ( ( multi[j].visible && ( mapitem->pos().x + multi[j].x == pos.x ) && ( mapitem->pos().y + multi[j].y == pos.y ) && ( abs( mapitem->pos().z + multi[j].z - pos.z ) <= 1 ) ) ) { return multi[j].tile; } } } else if ( mapitem->pos() == pos ) return mapitem->id(); } } return ( Q_UINT16 ) - 1; }
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 );*/ }
void cDragItems::equipItem( cUOSocket *socket, cUORxWearItem *packet ) { P_ITEM pItem = FindItemBySerial( packet->serial() ); P_CHAR pWearer = FindCharBySerial( packet->wearer() ); if( !pItem || !pWearer ) return; P_PLAYER pChar = socket->player(); // We're dead and can't do that if( pChar->isDead() ) { socket->clilocMessage( 0x7A4D5, "", 0x3b2 ); // You can't do that when you're dead. socket->bounceItem( pItem, BR_NO_REASON ); return; } // Our target is dead if( ( pWearer != pChar ) && pWearer->isDead() ) { socket->sysMessage( tr( "You can't equip dead players." ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Get our tile-information tile_st pTile = TileCache::instance()->getTile( pItem->id() ); // Is the item wearable ? ( layer == 0 | equip-flag not set ) // Multis are not wearable are they :o) if( pTile.layer == 0 || !( pTile.flag3 & 0x40 ) || pItem->isMulti() ) { socket->sysMessage( tr( "This item cannot be equipped." ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Required Strength if( pItem->st() > pWearer->strength() ) { if( pWearer == pChar ) socket->sysMessage( tr( "You cannot wear that item, you seem not strong enough" ) ); else socket->sysMessage( tr( "This person can't wear that item, it seems not strong enough" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Required Dexterity if( pItem->dx() > pWearer->dexterity() ) { if( pWearer == pChar ) socket->sysMessage( tr( "You cannot wear that item, you seem not agile enough" ) ); else socket->sysMessage( tr( "This person can't wear that item, it seems not agile enough" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Required Intelligence if( pItem->in() > pWearer->intelligence() ) { if( pWearer == pChar ) socket->sysMessage( tr( "You cannot wear that item, you seem not smart enough" ) ); else socket->sysMessage( tr( "This person can't wear that item, it seems not smart enough" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Males can't wear female armor if( ( pChar->bodyID() == 0x0190 ) && ( pItem->id() >= 0x1C00 ) && ( pItem->id() <= 0x1C0D ) ) { socket->sysMessage( tr( "You cannot wear female armor." ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Needs a check (!) // Checks for equipment on the same layer // If there is any it tries to unequip it // If that fails it cancels // we also need to check if there is a twohanded weapon if we want to equip another weapon. UI08 layer = pTile.layer; bool twohanded = false; P_ITEM equippedLayerItem = pWearer->atLayer( static_cast<cBaseChar::enLayer>(layer) ); if ( equippedLayerItem ) twohanded = equippedLayerItem->twohanded(); if( twohanded && ( layer == 1 || layer == 2 ) ) { socket->sysMessage( tr("You can't hold another item while wearing a twohanded weapon!") ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // we're equipping so we do the check if( equippedLayerItem ) { if( pChar->canPickUp( equippedLayerItem ) ) { equippedLayerItem->toBackpack( pWearer ); } else { socket->sysMessage( tr( "You can't wear another item there!" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } } // At this point we're certain that we can wear the item pWearer->addItem( static_cast<cBaseChar::enLayer>(pTile.layer), pItem ); // Apply the bonuses pWearer->giveItemBonus( pItem ); if( pWearer->objectType() == enPlayer ) { P_PLAYER pp = dynamic_cast<P_PLAYER>(pWearer); if( pp->socket() ) pp->socket()->sendStatWindow(); } // I don't think we need to remove the item // as it's only visible to the current char // And he looses contact anyway // Build our packets cUOTxCharEquipment wearItem; wearItem.fromItem( pItem ); cUOTxSoundEffect soundEffect; soundEffect.setSound( 0x57 ); soundEffect.setCoord( pWearer->pos() ); // Send to all sockets in range // ONLY the new equipped item and the sound-effect for( cUOSocket *mSock = cNetwork::instance()->first(); mSock; mSock = cNetwork::instance()->next() ) { if( mSock->player() && ( mSock->player()->dist( pWearer ) <= mSock->player()->visualRange() ) ) { mSock->send( &wearItem ); mSock->send( &soundEffect ); } } }
cSectorIterator* cSectorMaps::findObjects( MapType type, cSectorMap* sector, uint x1, uint y1, uint x2, uint y2 ) { // First step: count how many items we are going to hold unsigned int count = 0; unsigned int xBlock, yBlock; if ( x1 > x2 ) { std::swap( x1, x2 ); std::swap( y1, y2 ); } for ( xBlock = x1 / SECTOR_SIZE; xBlock <= x2 / SECTOR_SIZE; xBlock++ ) for ( yBlock = y1 / SECTOR_SIZE; yBlock <= y2 / SECTOR_SIZE; yBlock++ ) count += sector->countItems( ( xBlock * sector->gridHeight() ) + yBlock ); // Second step: actually "compile" our list of items cUObject** items = ( cUObject** ) malloc( count * sizeof( cUObject* ) ); unsigned int offset = 0; for ( xBlock = x1 / SECTOR_SIZE; xBlock <= x2 / SECTOR_SIZE; xBlock++ ) for ( yBlock = y1 / SECTOR_SIZE; yBlock <= y2 / SECTOR_SIZE; yBlock++ ) { // We *do* know that we allocated more memory than we need, but the effect is minimal! unsigned int block = ( xBlock * sector->gridHeight() ) + yBlock; if ( block >= sector->gridWidth() * sector->gridHeight() ) continue; if ( sector->grid[block] ) { for ( unsigned int i = 0; i < sector->grid[block]->count; ++i ) { cUObject* object = sector->grid[block]->data[i]; if ( object->pos().x >= x1 && object->pos().y >= y1 && object->pos().x <= x2 && object->pos().y <= y2 ) { // This sucks but we don't have much choice if (type == MT_CHARS) { P_PLAYER player = dynamic_cast<P_PLAYER>(object); // Exclude logged out players. if (!player || player->socket() || player->logoutTime()) { items[offset++] = object; } } else if (type == MT_MULTIS) { P_ITEM item = dynamic_cast<P_ITEM>(object); if (item && item->isMulti()) { items[offset++] = object; } } else { items[offset++] = object; } } } } } /* NOTE: Offset is our new count here. The count we measured previously was just there to measure the amount of memory we had to allocate for the list. */ switch ( type ) { case MT_ITEMS: case MT_MULTIS: return new cItemSectorIterator( offset, items ); case MT_CHARS: case MT_CHARSANDOFFLINE: return new cCharSectorIterator( offset, items ); default: return new cSectorIterator( offset, items ); }; }
// Get blocking tiles at the given x,y,map coordinate // Get floor tiles, that are not blocking, too // we need these floor tiles to know, if the 'black map' tile is the only floor here void getBlockingTiles( const Coord& pos, QList<stBlockingItem>& items ) { stBlockingItem item; // Maptiles first Maps::instance()->mapTileSpan( pos, item.id, item.bottom, item.top ); item.maptile = true; item.noblock = false; // Only include this maptile if it's relevant for our line of sight if ( item.id != 2 && item.id != 0x1DB && ( item.id <0x1AE || item.id> 0x1B5 ) ) { items.append( item ); } item.maptile = false; // Search for statics at the same position StaticsIterator statics = Maps::instance()->staticsIterator( pos, true ); // Find blocking statics for ( ; !statics.atEnd(); ++statics ) { const staticrecord &sitem = *statics; tile_st tile = TileCache::instance()->getTile( sitem.itemid ); if ( tile.flag2 & 0x30 ) { item.bottom = sitem.zoff; // Bridges are only half as high item.top = item.bottom + ( ( tile.flag2 & 0x04 ) ? ( tile.height / 2 ) : tile.height ); item.id = sitem.itemid; item.noblock = false; items.append( item ); } // floor tiles that aren't blocking else if ( tile.flag2 & 0x2 ) { item.bottom = sitem.zoff; // Bridges are only half as high item.top = item.bottom + ( ( tile.flag2 & 0x04 ) ? ( tile.height / 2 ) : tile.height ); item.id = sitem.itemid; item.noblock = true; items.append( item ); } } // Search for items at the given location MapItemsIterator itemIter = MapObjects::instance()->listItemsAtCoord( pos ); for ( P_ITEM pItem = itemIter.first(); pItem; pItem = itemIter.next() ) { // If the item is invisible or a multi, skip past it. if ( pItem->isMulti() ) continue; tile_st tile = TileCache::instance()->getTile( pItem->id() ); // Window and noshoot tiles block if ( tile.flag2 & 0x30 ) { item.id = pItem->id(); item.bottom = pItem->pos().z; // Bridges are only half as high item.top = item.bottom + ( ( tile.flag2 & 0x04 ) ? ( tile.height / 2 ) : tile.height ); item.noblock = false; items.append( item ); } // floor tiles that aren't blocking else if ( tile.flag2 & 0x2 ) { item.id = pItem->id(); item.bottom = pItem->pos().z; // Bridges are only half as high item.top = item.bottom + ( ( tile.flag2 & 0x04 ) ? ( tile.height / 2 ) : tile.height ); item.noblock = true; items.append( item ); } } // Check for multis around the area MapMultisIterator multis = MapObjects::instance()->listMultisInCircle( pos, BUILDRANGE ); // Check if there is an intersecting item for this multi for ( P_MULTI pMulti = multis.first(); pMulti; pMulti = multis.next() ) { // Get all items for this multi MultiDefinition *data = MultiCache::instance()->getMulti( pMulti->id() - 0x4000 ); if ( data ) { QList<multiItem_st> mitems = data->getEntries(); QList<multiItem_st>::iterator it; for ( it = mitems.begin(); it != mitems.end(); ++it ) { multiItem_st mitem = *it; // Skip this multi tile if it's not at the position we need it to be if ( !mitem.visible || pMulti->pos().x + mitem.x != pos.x || pMulti->pos().y + mitem.y != pos.y ) { continue; } tile_st tile = TileCache::instance()->getTile( mitem.tile ); // Has to be blocking if ( tile.flag2 & 0x30 ) { item.bottom = mitem.z + pMulti->pos().z; item.top = item.bottom + ( ( tile.flag2 & 0x04 ) ? ( tile.height / 2 ) : tile.height ); item.id = mitem.tile; item.noblock = false; items.append( item ); } // floor tiles that aren't blocking else if ( tile.flag2 & 0x2 ) { item.bottom = mitem.z + pMulti->pos().z; item.top = item.bottom + ( ( tile.flag2 & 0x04 ) ? ( tile.height / 2 ) : tile.height ); item.id = mitem.tile; item.noblock = true; items.append( item ); } } } } }
void cDragItems::dropOnItem( P_CLIENT client, P_ITEM pItem, P_ITEM pCont, const Coord_cl &dropPos ) { P_CHAR pChar = client->player(); if( pItem->isMulti() ) { client->sysMessage( "You cannot put houses in containers" ); bounceItem( client, pItem ); return; } // If the target belongs to another character // It needs to be our vendor or else it's denied P_CHAR packOwner = GetPackOwner( pCont ); if( ( packOwner != NULL ) && ( packOwner != pChar ) ) { // For each item someone puts into there // He needs to do a snoop-check if( pChar->canSnoop() ) { if( !Skills->CheckSkill( pChar, SNOOPING, 0, 1000 ) ) { client->sysMessage( QString( "You fail to put that into %1's pack" ).arg( packOwner->name.c_str() ) ); bounceItem( client, pItem ); return; } } if( !packOwner->isNpc() || ( packOwner->npcaitype() != 17 ) || !pChar->Owns( packOwner ) ) { client->sysMessage( "You cannot put that into the belongings of another player" ); bounceItem( client, pItem ); 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->morez = 0; pCont->morez = 0; sendtradestatus( tradeWindow, pCont ); } } if( !pChar->canPickUp( pItem ) ) { bounceItem( client, pItem ); return; } // Trash can if( pCont->type()==87 ) { Items->DeleItem( pItem ); client->sysMessage( "As you let go of the item it disappears." ); return; } // Spell Book if( pCont->type() == 9 ) { UI08 spellId = Magic->calcSpellId( pItem->id() ); if( spellId < 0 ) { client->sysMessage( "You can only put scrolls into a spellbook" ); bounceItem( client, pItem ); return; } if( Magic->hasSpell( pCont, spellId ) ) { client->sysMessage( "That spellbook already contains this spell" ); bounceItem( client, pItem ); return; } } // We drop something on the belongings of one of our playervendors if( ( packOwner != NULL ) && ( packOwner->npcaitype() == 17 ) && pChar->Owns( packOwner ) ) { client->sysMessage( "You drop something into your playervendor" ); bounceItem( client, pItem ); 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() == 9 || pCont->type() == 1 || pCont->type() == 8 || pCont->type() == 63 || pCont->type() == 65 || pCont->type() == 66 ) { pItem->setContSerial( pCont->serial ); pItem->setLayer( 0 ); // Remove it from our drag-layer // Huh ? - Make that random will you! pItem->pos = dropPos; SndRemoveitem( pItem->serial ); RefreshItem( pItem ); // Dropped on another Container/in another Container soundeffect2( pChar, 0x57 ); 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 ); RefreshItem( pCont ); // Need to update the amount return; } // We have to *keep* our current item else { pCont->setAmount( 65535 ); // Max out the amount RefreshItem( pCont ); // 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 1 pItem->moveTo( pCont->pos ); pItem->pos.z++; // Increase z by 1 pItem->pos.y++; // To get it visualized do that with y as well pItem->setLayer( 0 ); pItem->setContSerial( pCont->contserial ); RefreshItem( pItem ); // This needs to be checked // It annoyingly shows the spellbook // whenever you add a scroll if( pCont->type() == 9 ) Magic->openSpellBook( pChar, pCont ); // Glowing Objects moved between chars if( pItem->glow != INVALID_SERIAL ) { pChar->removeHalo( pItem ); if( packOwner != NULL ) { packOwner->addHalo(pItem); packOwner->glowHalo(pItem); } } }
void cDragItems::equipItem( P_CLIENT client ) { // Get the packet information SERIAL itemId = LongFromCharPtr( &buffer[ client->socket() ][ 1 ] ); SERIAL playerId = LongFromCharPtr( &buffer[ client->socket() ][ 6 ] ); P_ITEM pItem = FindItemBySerial( itemId ); P_CHAR pWearer = FindCharBySerial( playerId ); if( !pItem || !pWearer ) return; P_CHAR pChar = client->player(); // We're dead and can't do that if( pChar->dead ) { client->sysMessage( "You are dead and can't do that." ); bounceItem( client, pItem ); return; } // Our target is dead if( ( pWearer != pChar ) && pWearer->dead ) { client->sysMessage( "You can't equip dead players." ); bounceItem( client, pItem ); return; } // Get our tile-information tile_st pTile; Map->SeekTile( pItem->id(), &pTile ); // Is the item wearable ? ( layer == 0 | equip-flag not set ) // Multis are not wearable are they :o) if( pTile.layer == 0 || !( pTile.flag3 & 0x40 ) || pItem->isMulti() ) { client->sysMessage( "This item cannot be equipped." ); bounceItem( client, pItem ); return; } // Required Strength if( pItem->st > pWearer->st ) { if( pWearer == pChar ) client->sysMessage( "You cannot wear that item, you seem not strong enough" ); else client->sysMessage( "This person can't wear that armor, it seems not strong enough" ); bounceItem( client, pItem ); return; } // Required Dexterity if( pItem->dx > pWearer->effDex() ) { if( pWearer == pChar ) client->sysMessage( "You cannot wear that item, you seem not agile enough" ); else client->sysMessage( "This person can't wear that armor, it seems not agile enough" ); bounceItem( client, pItem ); return; } // Required Intelligence if( pItem->in > pWearer->in ) { if( pWearer == pChar ) client->sysMessage( "You cannot wear that item, you seem not smart enough" ); else client->sysMessage( "This person can't wear that armor, it seems not smart enough" ); bounceItem( client, pItem ); return; } // Males can't wear female armor if( ( pChar->id() == 0x0190 ) && ( pItem->id() >= 0x1C00 ) && ( pItem->id() <= 0x1C0D ) ) { client->sysMessage( "You cannot wear female armor." ); bounceItem( client, pItem ); return; } // Needs a check (!) // Checks for equipment on the same layer // If there is any it tries to unequip it // If that fails it cancels UI08 layer = pItem->layer(); vector< SERIAL > equipment = contsp.getData( pWearer->serial ); for( UI32 i = 0; i < equipment.size(); i++ ) { P_ITEM pEquip = FindItemBySerial( equipment[ i ] ); if( pEquip ) continue; // We found an item which is on the same layer (!) // Unequip it if we can bool twoHanded = false; if( pEquip->twohanded() && ( layer == 1 || layer == 2 ) ) twoHanded = true; if( pItem->twohanded() && ( pEquip->layer() == 1 || pEquip->layer() == 2 ) ) twoHanded = true; if( ( pEquip->layer() == layer ) || twoHanded ) { if( pChar->canPickUp( pEquip ) ) // we're equipping so we do the check pEquip->toBackpack( pWearer ); // If it's still on the char: cancel equipment if( pEquip->contserial == pWearer->serial ) { client->sysMessage( "You already have an item on that layer." ); bounceItem( client, pItem ); return; } } } // At this point we're certain that we can wear the item pItem->setContSerial( playerId ); pItem->setLayer( pTile.layer ); // Don't trust the user input on this one // Handle the weight if the item is leaving our "body" if( pWearer != pChar ) { pChar->weight -= pItem->getWeight(); pWearer->weight += pItem->getWeight(); // Update the status-windows statwindow( client->socket(), pChar ); statwindow( calcSocketFromChar( pWearer ), pWearer ); } if( pTile.layer == 0x19 ) pWearer->setOnHorse( true ); // Apply the bonuses pWearer->st += pItem->st2; pWearer->chgDex( pItem->dx2 ); pWearer->in += pItem->in2; // Show debug information if requested if( showlayer ) clConsole.send( QString( "Item (%1) equipped on layer %2" ).arg( pItem->name() ).arg( pItem->layer() ) ); // I don't think we need to remove the item // as it's only visible to the current char // And he looses contact anyway // SndRemoveitem( pi->serial ); // Build our packets cWornItems wearItem( pWearer->serial, pItem->serial, pItem->layer(), pItem->id(), pItem->color() ); cSoundEffect soundEffect( 0x57, pWearer->pos ); // Send to all sockets in range // ONLY the new equipped item and the sound-effect for( UOXSOCKET s = 0; s < now; s++ ) if( perm[s] && inrange1p( pWearer, currchar[s] ) ) { soundEffect.send( s ); wearItem.send( s ); } // Lord Binaries Glow stuff if( pItem->glow != INVALID_SERIAL ) { pChar->removeHalo( pItem ); pWearer->addHalo( pItem ); pWearer->glowHalo( pItem ); } }
void DragAndDrop::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 ); pItem->remove(); return; } if ( pItem->onDropOnItem( pCont ) ) { if ( pItem->free ) return; if ( socket->dragging() ) socket->bounceItem( socket->dragging(), BR_NO_REASON ); return; } else if ( pCont->onDropOnItem( pItem ) ) { if ( pItem->free ) return; 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 ( !pChar->canPickUp( pItem ) ) { socket->bounceItem( pItem, BR_CANNOT_PICK_THAT_UP ); 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) if ( pCont->type() == 1 ) { // If we're dropping it onto the closed container if ( dropPos.x == 0xFFFF && dropPos.y == 0xFFFF ) { pCont->addItem( pItem ); } else { pCont->addItem( pItem, false ); pItem->setPos( dropPos ); } // Dropped on another Container/in another Container pChar->soundEffect( 0x57 ); pItem->update(); return; } else if ( pCont->canStack( pItem ) ) { if ( pCont->amount() + pItem->amount() <= 65535 ) { pCont->setAmount( pCont->amount() + pItem->amount() ); pItem->remove(); pCont->update(); // Need to update the amount pCont->resendTooltip(); return; } else { // The delta between 65535 and pCont->amount() sub our Amount is the // new amount pItem->setAmount( pItem->amount() - ( 65535 - pCont->amount() ) ); pItem->resendTooltip(); pCont->setAmount( 65535 ); // Max out the amount pCont->update(); pCont->resendTooltip(); } } // 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 if ( pCont->container() ) { P_ITEM pNewCont = dynamic_cast<P_ITEM>( pCont->container() ); if ( pNewCont ) { pNewCont->addItem( pItem, false ); pItem->setPos( pCont->pos() + Coord_cl( 0, 0, 2 ) ); } else { pChar->getBackpack()->addItem( pItem ); } } else { pItem->removeFromCont(); pItem->moveTo( pCont->pos() + Coord_cl( 0, 0, 2 ) ); } pItem->update(); }
void DragAndDrop::equipItem( cUOSocket* socket, cUORxWearItem* packet ) { P_ITEM pItem = FindItemBySerial( packet->serial() ); P_CHAR pWearer = FindCharBySerial( packet->wearer() ); if ( !pItem || !pWearer ) return; P_PLAYER pChar = socket->player(); // We're dead and can't do that if ( pChar->isDead() ) { socket->clilocMessage( 0x7A4D5, "", 0x3b2 ); // You can't do that when you're dead. socket->bounceItem( pItem, BR_NO_REASON ); return; } // No Special Layer Equipping if ( ( packet->layer() > cBaseChar::InnerLegs || packet->layer() <= cBaseChar::TradeWindow ) && !pChar->isGM() ) { socket->sysMessage( tr( "You can't equip on that layer." ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Our target is dead if ( ( pWearer != pChar ) && pWearer->isDead() ) { socket->sysMessage( tr( "You can't equip dead players." ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Only GM's can equip other People if ( pWearer != pChar && !pChar->isGM() ) { P_NPC pNpc = dynamic_cast<P_NPC>( pWearer ); // But we are allowed to equip our own humans if ( !pNpc || ( pNpc->owner() != pChar && pWearer->isHuman() ) ) socket->sysMessage( tr( "You can't equip other players." ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Get our tile-information tile_st pTile = TileCache::instance()->getTile( pItem->id() ); // Is the item wearable ? ( layer == 0 | equip-flag not set ) // Multis are not wearable are they :o) if ( pTile.layer == 0 || !( pTile.flag3 & 0x40 ) || pItem->isMulti() ) { socket->sysMessage( tr( "This item cannot be equipped." ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Check the Script for it if ( pItem->onWearItem( pChar, pWearer, packet->layer() ) ) { socket->bounceItem( pItem, BR_NO_REASON ); return; } // Males can't wear female armor if ( ( pChar->body() == 0x0190 ) && ( pItem->id() >= 0x1C00 ) && ( pItem->id() <= 0x1C0D ) ) { socket->sysMessage( tr( "You cannot wear female armor." ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // Needs a check (!) // Checks for equipment on the same layer // If there is any it tries to unequip it // If that fails it cancels // we also need to check if there is a twohanded weapon if we want to equip another weapon. UI08 layer = pTile.layer; P_ITEM equippedLayerItem = pWearer->atLayer( static_cast<cBaseChar::enLayer>( layer ) ); // we're equipping so we do the check if ( equippedLayerItem ) { if ( pChar->canPickUp( equippedLayerItem ) ) { equippedLayerItem->toBackpack( pWearer ); } else { socket->sysMessage( tr( "You can't wear another item there!" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } } // Check other layers if neccesary bool occupied = false; if ( pItem->twohanded() && layer == 1 ) { occupied = pWearer->leftHandItem() != 0; // Twohanded weapon on layer 1 forbids item on layer 2 } else if ( pItem->twohanded() && layer == 2 ) { occupied = pWearer->rightHandItem() != 0; // Twohanded weapon on layer 2 forbids item on layer 1 } else if ( layer == 1 ) { P_ITEM lefthand = pWearer->leftHandItem(); occupied = lefthand && lefthand->twohanded(); } else if ( layer == 2 ) { P_ITEM righthand = pWearer->rightHandItem(); occupied = righthand && righthand->twohanded(); } if ( occupied ) { socket->sysMessage( tr( "You can't hold another item while wearing a twohanded item!" ) ); socket->bounceItem( pItem, BR_NO_REASON ); return; } // At this point we're certain that we can wear the item pWearer->addItem( static_cast<cBaseChar::enLayer>( pTile.layer ), pItem ); if ( pWearer->objectType() == enPlayer ) { P_PLAYER pp = dynamic_cast<P_PLAYER>( pWearer ); if ( pp->socket() ) pp->socket()->sendStatWindow(); } // I don't think we need to remove the item // as it's only visible to the current char // And he looses contact anyway // Build our packets cUOTxCharEquipment wearItem; wearItem.fromItem( pItem ); cUOTxSoundEffect soundEffect; soundEffect.setSound( 0x57 ); soundEffect.setCoord( pWearer->pos() ); // Send to all sockets in range // ONLY the new equipped item and the sound-effect for ( cUOSocket*mSock = Network::instance()->first(); mSock; mSock = Network::instance()->next() ) { if ( mSock->player() && ( mSock->player()->dist( pWearer ) <= mSock->player()->visualRange() ) ) { mSock->send( &wearItem ); mSock->send( &soundEffect ); } } }