void cNewMagic::execSpell( P_CHAR pMage, UINT8 spell, UINT8 type, cUORxTarget* target ) { stNewSpell *sInfo = findSpell( spell ); P_PLAYER pp = dynamic_cast<P_PLAYER>(pMage); if( ( ( pp || !pp->isGM() ) && !checkReagents( pMage, spell ) ) || !useMana( pMage, spell ) ) { pMage->setCasting( false ); return; } if( !pp || !pp->isGM() ) useReagents( pMage, spell ); if( !checkSkill( pMage, spell, false ) ) { disturb( pMage, true, -1 ); return; } // Call the Spell Effect for this Spell if( sInfo->script ) sInfo->script->onSpellSuccess( pMage, spell, type, target ); // End Casting pMage->setCasting( false ); }
// All ai controlled creatures can be controlled by a gm // or by their owner if tamed void AbstractAI::onSpeechInput( P_PLAYER pTalker, const QString &comm ) { if (!pTalker->isGM() && (!m_npc->isTamed() || m_npc->owner() != pTalker)) { return; } // too far away to hear us if (pTalker->dist(m_npc) > 7) { return; } if (comm.contains(" FOLLOW")) { if (comm.contains(" ME")) { m_npc->setWanderFollowTarget(pTalker); m_npc->setWanderType(enFollowTarget); m_npc->bark(cBaseChar::Bark_Attacking); } else { pTalker->socket()->attachTarget(new cFollowTarget(m_npc)); } } else if ((comm.contains(" KILL")) || (comm.contains(" ATTACK"))) { if (m_npc->inGuardedArea()) { pTalker->message(tr("You can't have pets attack in town!")); } } else if ((comm.contains(" FETCH")) || (comm.contains(" GET"))) { //pPlayer->setGuarded(false); // >> LEGACY //addx[s]=pPet->serial(); //target(s, 0, 1, 0, 124, "Click on the object to fetch."); } else if (comm.contains(" COME")) { m_npc->setWanderDestination(pTalker->pos()); m_npc->setWanderType(enDestination); m_npc->bark(cBaseChar::Bark_Attacking); } else if (comm.contains(" GUARD")) { } else if ((comm.contains(" STOP")) || (comm.contains(" STAY"))) { m_npc->fight(0); m_npc->setWanderType( enHalt ); m_npc->bark(cBaseChar::Bark_Attacking); } else if (comm.contains(" TRANSFER")) { } else if (comm.contains(" RELEASE")) { // Has it been summoned ? Let's dispel it if (m_npc->summoned()) { m_npc->setSummonTime(uiCurrentTime); } m_npc->setWanderType(enFreely); m_npc->setOwner(0); m_npc->setTamed(false); m_npc->bark(cBaseChar::Bark_Attacking); if (SrvParams->tamedDisappear()) { m_npc->soundEffect(0x01Fe); cCharStuff::DeleteChar(m_npc); } } }
// For the Paperdoll QString cSkills::getSkillTitle( P_CHAR pChar ) const { QString skillTitle; P_PLAYER player = dynamic_cast<P_PLAYER>( pChar ); if ( Config::instance()->showSkillTitles() && player && !player->isGM() ) { unsigned short skill = 0; unsigned short skillValue = 0; for ( int i = 0; i < ALLSKILLS; ++i ) { if ( pChar->skillValue( i ) > skillValue ) { skill = i; skillValue = pChar->skillValue( i ); } } unsigned char title = QMAX( 1, ( ( int ) pChar->skillValue( skill ) - 300 ) / 100 ); if ( title >= skillRanks.size() ) { pChar->log( LOG_ERROR, "Invalid skill rank information.\n" ); return skillTitle; } // Skill not found if ( skill >= skills.size() ) { pChar->log( LOG_ERROR, QString( "Skill id out of range: %u.\n" ).arg( skill ) ); return skillTitle; } skillTitle = QString( "%1 %2" ).arg( skillRanks[title] ).arg( skills[skill].title ); } return skillTitle; }
// May a character walk here ? // If yes we auto. set the new z value for pos bool mayWalk( P_CHAR pChar, Coord& pos ) { // Go trough the array top-to-bottom and check // If we find a tile to walk on vector<stBlockItem> blockList = getBlockingItems( pChar, pos ); bool found = false; Q_UINT32 i; bool priviledged = false; Q_INT32 oldz = pos.z; P_PLAYER player = dynamic_cast<P_PLAYER>( pChar ); priviledged = player && player->isGM(); for ( i = 0; i < blockList.size(); ++i ) { stBlockItem item = blockList[i]; Q_INT32 itemTop = ( item.z + item.height ); // If we found something to step on and the next tile // below would block us, use the good one instead if ( found && ( itemTop > pos.z - P_M_MAX_Z_BLOCKS || !item.walkable ) ) { break; } // If we encounter any object with itemTop <= pos.z which is NOT walkable // Then we can as well just return false as while falling we would be // blocked by that object if ( !item.walkable && !priviledged && itemTop <= pos.z ) return false; if ( item.walkable || priviledged ) { // If the top of the item is within our max-climb reach // then the first check passed. in addition we need to // check if the "bottom" of the item is reachable // I would say 2 is a good "reach" value for the bottom // of any item if ( itemTop < pos.z + P_M_MAX_Z_CLIMB && itemTop >= pos.z - P_M_MAX_Z_FALL ) { // We already found something to step on above. // See if it's easier to step down. if ( found && abs( oldz - pos.z ) < abs( oldz - itemTop ) ) { break; } pos.z = itemTop; found = true; if ( item.height > 1 ) { break; } // break; - We can't break here anymore since we have to check if the ground would be easier // to step on // Climbing maptiles is 5 tiles easier } else if ( item.maptile && itemTop < pos.z + P_M_MAX_Z_CLIMB + 5 && itemTop >= pos.z - P_M_MAX_Z_FALL ) { // We already found something to step on above. // See if it's easier to step down. if ( found && abs( oldz - pos.z ) < abs( oldz - itemTop ) ) { break; } pos.z = itemTop; found = true; //break; } else if ( itemTop < pos.z ) { // We already found something to step on above. // See if it's easier to step down. if ( found && abs( oldz - pos.z ) < abs( oldz - itemTop ) ) { break; } pos.z = itemTop; found = true; break; } } } if ( priviledged ) { return true; } // If we're still at the same position // We didn't find anything to step on if ( !found ) return false; // Another loop *IS* needed here (at least that's what i think) for ( i = 0; i < blockList.size(); ++i ) { // So we know about the new Z position we are moving to // Lets check if there is enough space ABOVE that position (at least 15 z units) // If there is ANY impassable object between pos.z and pos.z + 15 we can't walk here stBlockItem item = blockList[i]; Q_INT8 itemTop = ( item.z + item.height ); // If the item is below what we step on, ignore it if ( itemTop <= pos.z ) { continue; } // Does the top of the item looms into our space // Like before 15 is the assumed height of ourself // Use the new position here. if ( ( itemTop > pos.z ) && ( itemTop < pos.z + P_M_MAX_Z_BLOCKS ) ) return false; // Or the bottom ? // note: the following test was commented out. by putting the code back in, // npcs stop wandering through the walls of multis. I am curious if this code // has other (negative) affects besides that. if ( ( item.z >= oldz ) && ( item.z < oldz + P_M_MAX_Z_BLOCKS / 2 ) ) return false; // Or does it spread the whole range ? if ( ( item.z <= oldz ) && ( itemTop >= oldz + P_M_MAX_Z_BLOCKS / 2 ) ) return false; // Is it at the new position ? if ( ( item.z >= pos.z ) && ( item.z < pos.z + P_M_MAX_Z_BLOCKS ) ) return false; } // All Checks passed return true; }
// All ai controlled creatures can be controlled by a gm // or by their owner if tamed void AbstractAI::onSpeechInput( P_PLAYER pTalker, const QString& comm ) { if ( !pTalker->isGM() && ( !m_npc->isTamed() || m_npc->owner() != pTalker ) ) { return; } // too far away to hear us if ( pTalker->dist( m_npc ) > 7 ) { return; } if ( comm.contains( " FOLLOW" ) ) { if ( comm.contains( " ME" ) ) { m_npc->setWanderFollowTarget( pTalker ); m_npc->setWanderType( enFollowTarget ); m_npc->bark( cBaseChar::Bark_Attacking ); } else { pTalker->socket()->attachTarget( new cFollowTarget( m_npc ) ); } } else if ( ( comm.contains( " KILL" ) ) || ( comm.contains( " ATTACK" ) ) ) { if ( m_npc->inGuardedArea() ) { pTalker->message( tr( "You can't have pets attack in town!" ) ); } } else if ( ( comm.contains( " FETCH" ) ) || ( comm.contains( " GET" ) ) ) { //#pragma note( Implement me ) pTalker->message( tr( "Sorry, not implemented yet :(" ) ); } else if ( comm.contains( " COME" ) ) { m_npc->setWanderDestination( pTalker->pos() ); m_npc->setWanderType( enDestination ); m_npc->bark( cBaseChar::Bark_Attacking ); } else if ( comm.contains( " GUARD" ) ) { } else if ( ( comm.contains( " STOP" ) ) || ( comm.contains( " STAY" ) ) ) { m_npc->fight( 0 ); m_npc->setWanderType( enHalt ); m_npc->bark( cBaseChar::Bark_Attacking ); } else if ( comm.contains( " TRANSFER" ) ) { } else if ( comm.contains( " RELEASE" ) ) { // Has it been summoned ? Let's dispel it if ( m_npc->summoned() ) { m_npc->setSummonTime( Server::instance()->time() ); } m_npc->setWanderType( enFreely ); m_npc->setOwner( 0 ); m_npc->setTamed( false ); m_npc->bark( cBaseChar::Bark_Attacking ); if ( Config::instance()->tamedDisappear() ) { m_npc->soundEffect( 0x01Fe ); m_npc->remove(); } } }
bool PetCommand( cUOSocket *socket, P_PLAYER pPlayer, P_NPC pPet, const QString& comm ) { if( pPet->owner() != pPlayer && !pPlayer->isGM() ) return false; // player vendor /* if( pPet->npcaitype() == 17 ) return false;*/ // too far away to hear us if( pPlayer->dist( pPet ) > 7 ) return false; QString petname = pPet->name(); bool bAllCommand = false; if( !comm.contains( petname, false ) ) if( comm.contains( "ALL", false ) ) bAllCommand = true; else return false; bool bReturn = false; if( comm.contains( " FOLLOW" ) ) { if( comm.contains( " ME" ) ) { #pragma note( "TODO: implement state change here" ) // pPet->setWanderFollowTarget( pPlayer->serial() ); // pPet->setWanderType( enFollowTarget ); playmonstersound( pPet, pPet->bodyID(), SND_STARTATTACK ); } else { // LEGACY: target( s, 0, 1, 0, 117, "Click on the target to follow." ); } bReturn = true; } else if( ( comm.contains( " KILL" ) ) || ( comm.contains( " ATTACK" ) ) ) { if( pPet->inGuardedArea() ) // Ripper..No pet attacking in town. { pPlayer->message( tr( "You can't have pets attack in town!" ) ); return false; } //pPlayer->setGuarded( false ); // >> LEGACY //addx[s]=pPet->serial(); //target(s, 0, 1, 0, 118, "Select the target to attack.");//AntiChrist bReturn = true; } else if( ( comm.contains( " FETCH" ) ) || ( comm.contains( " GET" ) ) ) { //pPlayer->setGuarded(false); // >> LEGACY //addx[s]=pPet->serial(); //target(s, 0, 1, 0, 124, "Click on the object to fetch."); bReturn = true; } else if( comm.contains( " COME" ) ) { //pPlayer->setGuarded( false ); #pragma note( "TODO: implement state change here" ) // pPet->setWanderFollowTarget( pPlayer->serial() ); // pPet->setWanderType( enFollowTarget ); pPet->setNextMoveTime(); pPlayer->message( tr( "Your pet begins following you." ) ); bReturn = true; } else if( comm.contains( " GUARD" ) ) { // LEGACY /*addx[s] = pPet->serial(); // the pet's serial addy[s] = 0; if( comm.find( " ME" ) != string::npos ) addy[s]=1; // indicates we already know whom to guard (for future use) // for now they still must click on themselves (Duke) target(s, 0, 1, 0, 120, "Click on the char to guard.");*/ bReturn = true; } else if( ( comm.contains( " STOP" ) ) || ( comm.contains(" STAY") ) ) { //pPlayer->setGuarded( false ); #pragma note( "TODO: implement state change here" ) // pPet->setWanderFollowTarget( INVALID_SERIAL ); pPet->setCombatTarget( INVALID_SERIAL ); if (pPet->isAtWar()) pPet->toggleCombat(); pPet->setWanderType( enHalt ); bReturn = true; } else if( comm.contains( " TRANSFER" ) ) { //pPlayer->setGuarded( false ); // >> LEGACY /*addx[s]=pPet->serial(); target(s, 0, 1, 0, 119, "Select character to transfer your pet to.");*/ bReturn = true; } else if( comm.contains( " RELEASE" ) ) { //pPlayer->setGuarded( false ); // Has it been summoned ? Let's dispel it if( pPet->summonTime() > uiCurrentTime ) pPet->setSummonTime( uiCurrentTime ); #pragma note( "TODO: implement state change here" ) // pPet->setWanderFollowTarget( INVALID_SERIAL ); pPet->setWanderType( enFreely ); pPet->setOwner( NULL ); pPet->setTamed( false ); pPet->emote( tr( "%1 appears to have decided that it is better off without a master" ).arg( pPet->name() ) ); if( SrvParams->tamedDisappear() ==1 ) { pPet->soundEffect( 0x01FE ); cCharStuff::DeleteChar( pPet ); } bReturn = true; } // give other pets opotunity to process command if ( bReturn && bAllCommand ) return false; else return bReturn; }
// 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 );*/ }
// May a character walk here ? // If yes we auto. set the new z value for pos bool mayWalk( P_CHAR pChar, Coord_cl& pos ) { // Go trough the array top-to-bottom and check // If we find a tile to walk on vector<stBlockItem> blockList = getBlockingItems( pChar, pos ); bool found = false; Q_UINT32 i; bool priviledged = false; Q_INT32 oldz = pos.z; P_PLAYER player = dynamic_cast<P_PLAYER>( pChar ); priviledged = player && player->isGM(); for ( i = 0; i < blockList.size(); ++i ) { stBlockItem item = blockList[i]; Q_INT8 itemTop = ( item.z + item.height ); // If we encounter any object with itemTop <= pos.z which is NOT walkable // Then we can as well just return false as while falling we would be // blocked by that object if ( !item.walkable && !priviledged && itemTop < pos.z ) return false; if ( item.walkable || priviledged ) { // If the top of the item is within our max-climb reach // then the first check passed. in addition we need to // check if the "bottom" of the item is reachable // I would say 2 is a good "reach" value for the bottom // of any item if ( itemTop < pos.z + P_M_MAX_Z_CLIMB && itemTop >= pos.z - P_M_MAX_Z_FALL ) { pos.z = itemTop; found = true; break; // Climbing maptiles is 5 tiles easier } else if ( item.maptile && itemTop < pos.z + P_M_MAX_Z_CLIMB + 5 && itemTop >= pos.z - P_M_MAX_Z_FALL ) { pos.z = itemTop; found = true; break; } } } if ( priviledged ) { return true; } // If we're still at the same position // We didn't find anything to step on if ( !found ) return false; // Another loop *IS* needed here (at least that's what i think) for ( i = 0; i < blockList.size(); ++i ) { // So we know about the new Z position we are moving to // Lets check if there is enough space ABOVE that position (at least 15 z units) // If there is ANY impassable object between pos.z and pos.z + 15 we can't walk here stBlockItem item = blockList[i]; Q_INT8 itemTop = ( item.z + item.height ); // If the item is below what we step on, ignore it if (itemTop <= pos.z) { continue; } // Does the top of the item looms into our space // Like before 15 is the assumed height of ourself // Use the new position here. if ( ( itemTop > pos.z ) && ( itemTop < pos.z + P_M_MAX_Z_BLOCKS ) ) return false; // Or the bottom ? // if ( ( item.z > oldz ) && ( item.z < oldz + P_M_MAX_Z_BLOCKS ) ) // return false; // Or does it spread the whole range ? if ( ( item.z <= oldz ) && ( itemTop >= oldz + P_M_MAX_Z_BLOCKS ) ) return false; } // All Checks passed return true; }
void cSkills::SkillUse( cUOSocket* socket, Q_UINT16 id ) // Skill is clicked on the skill list { P_PLAYER pChar = socket->player(); // No Char no Skill use if ( !pChar ) return; /* TODO: reimplementation of jail system if( pChar->cell() > 0 ) { socket->sysMessage( tr( "You are in jail and cant use skills here!" ) ); return; } */ if ( pChar->isDead() ) { socket->sysMessage( tr( "You cannot do that as a ghost." ) ); return; } if ( id != STEALTH ) pChar->unhide(); // Don't unhide if we're trying to stealth pChar->disturbMed(); // Disturb meditation if we're using a skill if ( pChar->isCasting() ) { socket->sysMessage( tr( "You can't do that while you are casting." ) ); return; } if ( pChar->skillDelay() > Server::instance()->time() && !pChar->isGM() ) { socket->sysMessage( tr( "You must wait a few moments before using another skill." ) ); return; } if ( pChar->onSkillUse( id ) ) return; cTargetRequest* targetRequest = NULL; QString message; switch ( id ) { case MEDITATION: Skills::instance()->Meditation( socket ); break; default: socket->sysMessage( tr( "That skill has not been implemented yet." ) ); return; } if ( targetRequest ) socket->attachTarget( targetRequest ); if ( !message.isEmpty() ) pChar->message( message ); pChar->setSkillDelay( Server::instance()->time() + Config::instance()->skillDelay() * MY_CLOCKS_PER_SEC ); }
void cNewMagic::castSpell( P_PLAYER pMage, UINT8 spell ) { P_PLAYER pp = dynamic_cast<P_PLAYER>(pMage); if( !pp || !pp->socket() ) return; stNewSpell *sInfo = findSpell( spell ); if( !sInfo ) { pp->socket()->sysMessage( tr( "This spell is either not implemented or invalid" ) ); return; } // Check if we can cast this spell if( !hasSpell( pMage, spell ) ) { pp->socket()->sysMessage( tr( "You don't know this spell." ) ); return; } // Check for required mana and required reagents, if not present: cancel casting if( !checkMana( pMage, spell ) ) { pp->message( tr( "You don't have enough mana to cast this spell." ) ); return; } if( !pp->isGM() && !checkReagents( pMage, spell ) ) return; if( pMage->isCasting() ) disturb( pMage, true ); // We start casting here pMage->setCasting( true ); // We get frozen here too pMage->setFrozen( true ); // Say the mantra // Type 0x0A : Spell pMage->talk( sInfo->mantra, pMage->saycolor() ); // This is a very interesting move of OSI // They send all action-packets the character has to perform in a row. // But they use the action 0xE9 instead of 0x10, maybe it's a bitmask // of 0xD9 but i am unsure. // This will repeat the animation until // We are done casting or until we are being // disturbed. //pMage->startRepeatedAction( sInfo->action, sInfo->actiondelay ); // Repeat every 1250 ms // I *do* know that this is a drawback but for now a single animation is exactly what we need. pMage->action( sInfo->action ); // Now we have to do the following: // We show the target cursor after a given amount of time (set in the scripts) // So what we are adding here is cEndCasting() supplying the Serial of our Mage // And the ID of our Spell. TempEffects::instance()->insert( new cEndCasting( pMage, spell, CT_BOOK, sInfo->delay ) ); }
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(); }
// New Class implementation void DragAndDrop::grabItem( cUOSocket* socket, cUORxDragItem* packet ) { // Get our character P_PLAYER pChar = socket->player(); if ( !pChar ) return; float 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; } // Check if the item can be reached if (pItem->getOutmostChar() != pChar && !pChar->lineOfSight(pItem)) { socket->bounceItem( pItem, BR_OUT_OF_REACH ); 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 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 = true;//( GuildCompare( pChar, outmostCont->owner() ) != 0 ); if ( outmostCont->hasTag( "notoriety" ) && outmostCont->getTag( "notoriety" ).toInt() == 1 && !pChar->owns( outmostCont ) && !sameGuild ) { // pChar->karma -= 5; pChar->setKarma( pChar->karma() - 5 ); pChar->setCriminalTime( Server::instance()->time() + Config::instance()->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 ==== // 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 = pItem->dupe(); // Create a new item to pick that up splitItem->setAmount( pItem->amount() - pickedAmount ); // Add tags to the splitted item QStringList keys = pItem->getTags(); QStringList::const_iterator it = keys.begin(); for ( ; it != keys.end(); ++it ) { splitItem->setTag( *it, pItem->getTag( *it ) ); } P_ITEM pContainer = dynamic_cast<P_ITEM>( pItem->container() ); if ( pContainer ) pContainer->addItem( splitItem, false ); splitItem->SetOwnSerial( pItem->ownSerial() ); splitItem->setSpawnregion( pItem->spawnregion() ); // 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->setAmount( pickedAmount ); } } // *normally* we should exclude the dragging socket here. but it works so as well. pItem->removeFromView( true ); // Remove from spawnregion pItem->setSpawnregion( 0 ); // 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 ); // Remove eventual item-bonusses if we're unequipping something if ( pItem->container() && pItem->container()->isChar() ) { P_CHAR wearer = dynamic_cast<P_CHAR>( pItem->container() ); // resend the stat window if ( wearer && wearer->objectType() == enPlayer ) { P_PLAYER pp = dynamic_cast<P_PLAYER>( wearer ); if ( pp->socket() ) pp->socket()->sendStatWindow(); } } pChar->addItem( cBaseChar::Dragging, pItem ); if ( weight != pChar->weight() ) { socket->sendStatWindow(); } }
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 ); } } }
void cSkills::SkillUse( cUOSocket* socket, quint16 id ) // Skill is clicked on the skill list { P_PLAYER pChar = socket->player(); // No Char no Skill use if ( !pChar ) return; if ( pChar->isJailed() ) { socket->sysMessage( tr("You cannot use skills while you are in jail.") ); return; } if ( pChar->isDead() ) { socket->clilocMessage( 1019048 ); // I am dead and cannot do that. return; } /* if ( id != STEALTH ) pChar->unhide(); // Don't unhide if we're trying to stealth */ pChar->disturbMed(); // Disturb meditation if we're using a skill if ( pChar->isCasting() ) { socket->sysMessage( 1061131 ); // You cannot do that while casting a spell. return; } if ( pChar->skillDelay() > Server::instance()->time() && !pChar->isGM() ) { socket->sysMessage( 500118 ); // You must wait a few moments to use another skill. return; } if ( pChar->onSkillUse( id ) ) return; cTargetRequest* targetRequest = NULL; QString message; switch ( id ) { case MEDITATION: Skills::instance()->Meditation( socket ); break; default: socket->sysMessage( tr( "That skill has not been implemented yet." ) ); return; } if ( targetRequest ) socket->attachTarget( targetRequest ); if ( !message.isEmpty() ) pChar->message( message ); pChar->setSkillDelay( Server::instance()->time() + Config::instance()->skillDelay() * MY_CLOCKS_PER_SEC ); }