void commandWhere( cUOSocket *socket, const QString &command, QStringList &args ) throw() { Q_UNUSED(args); Q_UNUSED(command); P_PLAYER pChar = socket->player(); if( !pChar ) return; cTerritory *mRegion = AllTerritories::instance()->region( pChar->pos().x, pChar->pos().y, pChar->pos().map ); QString message = tr( "You are" ); if( mRegion ) message.append( " " + tr( "in %1" ).arg( mRegion->name() ) ); message.append( " " + tr( "at %1,%2,%3 on map %4" ).arg( pChar->pos().x ).arg( pChar->pos().y ).arg( pChar->pos().z ).arg( pChar->pos().map ) ); pChar->message( message ); }
void cDragItems::dropItem( cUOSocket *socket, cUORxDropItem *packet ) { P_PLAYER pChar = socket->player(); if( !pChar ) return; // Get the data SERIAL contId = packet->cont(); Coord_cl dropPos = pChar->pos(); // plane dropPos.x = packet->x(); dropPos.y = packet->y(); dropPos.z = packet->z(); // Get possible containers P_ITEM pItem = FindItemBySerial( packet->serial() ); if( !pItem ) return; P_ITEM iCont = FindItemBySerial( packet->cont() ); P_CHAR cCont = FindCharBySerial( packet->cont() ); // >> SEE LORD BINARIES DROPFIX << // A completely invalid Drop packet if( !iCont && !cCont && ( dropPos.x == 0xFFFF ) && ( dropPos.y == 0xFFFF ) && ( (unsigned char)dropPos.z == 0xFF ) ) { socket->bounceItem( pItem, BR_NO_REASON ); return; } UINT32 weight = pChar->weight(); // Item dropped on Ground if( !iCont && !cCont ) dropOnGround( socket, pItem, dropPos ); // Item dropped on another item else if( iCont ) dropOnItem( socket, pItem, iCont, dropPos ); // Item dropped on char else if( cCont ) dropOnChar( socket, pItem, cCont ); // Handle the sound-effect if( pItem->id() == 0xEED ) goldsfx( socket, pItem->amount(), true ); // Update our weight. if( weight != pChar->weight() ) socket->sendStatWindow(); }
// 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); } } }
///////////////// // name: response // purpose: tries to get a response from an npc standing around // history: heavily revamped/rewritten by Duke, Oct 2001 // remark: The new logic tries to minimize the # of strstr() calls by *first* checking // what kind of npcs are standing around and then checking only those keywords // that they might be interested in. // This is especially usefull in crowded places. bool Speech::response( cUOSocket* socket, P_PLAYER pPlayer, const QString& comm, QValueVector<Q_UINT16>& keywords ) { if ( !pPlayer->socket() || pPlayer->isDead() ) { return false; } QString speechUpr = comm.upper(); MapCharsIterator ri = MapObjects::instance()->listCharsInCircle( pPlayer->pos(), 18 ); for ( P_CHAR pChar = ri.first(); pChar; pChar = ri.next() ) { P_NPC pNpc = dynamic_cast<P_NPC>( pChar ); // We will only process NPCs here if ( !pNpc ) continue; // at least they should be on the screen if ( pPlayer->dist( pNpc ) > 16 ) continue; if ( pNpc->canHandleEvent( EVENT_SPEECH ) ) { PyObject* pkeywords = PyTuple_New( keywords.size() ); // Set Items for ( unsigned int i = 0; i < keywords.size(); ++i ) PyTuple_SetItem( pkeywords, i, PyInt_FromLong( keywords[i] ) ); PyObject* args = Py_BuildValue( "(NNNO)", pNpc->getPyObject(), pPlayer->getPyObject(), QString2Python( comm ), pkeywords ); bool result = pNpc->callEventHandler( EVENT_SPEECH, args ); Py_DECREF( args ); Py_DECREF( pkeywords ); if ( result ) return true; } if ( pNpc->ai() ) { pNpc->ai()->onSpeechInput( pPlayer, speechUpr ); } if ( QuestionSpeech( socket, pPlayer, pNpc, speechUpr ) ) return true; } return false; }
void cDragItems::dropOnGround( cUOSocket *socket, P_ITEM pItem, const Coord_cl &pos ) { P_PLAYER pChar = socket->player(); // Check if the destination is in line of sight if( !lineOfSight( pChar->pos(), pos, WALLS_CHIMNEYS|DOORS|LAVA_WATER ) ) { socket->bounceItem( pItem, BR_OUT_OF_SIGHT ); return; } if( !pChar->canPickUp( pItem ) ) { socket->bounceItem( pItem, BR_CANNOT_PICK_THAT_UP ); return; } if( pItem->onDropOnGround( pos ) ) { // We're still dragging something if( socket->dragging() ) socket->bounceItem( socket->dragging(), BR_NO_REASON ); return; } pItem->removeFromCont(); pItem->moveTo( pos ); pItem->update(); if( pItem->priv() & 0x01 ) pItem->startDecay(); // Multi handling // Has it been dropped into a multi cMulti* pMulti = cMulti::findMulti( pos ); if( pMulti ) { pMulti->addItem( pItem ); } }
/*! This handles if a character actually tries to walk (NPC & Player) */ bool cMovement::Walking( P_CHAR pChar, Q_UINT8 dir, Q_UINT8 sequence ) { if ( !pChar ) return false; // Scripting if ( pChar->onWalk( dir, sequence ) ) return false; P_PLAYER player = dynamic_cast<P_PLAYER>( pChar ); // Is the sequence in order ? if ( player && player->socket() && !verifySequence( player->socket(), sequence ) ) return false; // If checking for weight is more expensive, shouldn't we check for frozen first? if ( pChar->isFrozen() ) { if ( player && player->socket() ) player->socket()->denyMove( sequence ); return false; } // save our original location before we even think about moving const Coord oldpos( pChar->pos() ); // If the Direction we're moving to is different from our current direction // We're turning and NOT moving into a specific direction // Clear the running flag here (!) // If the direction we're moving is already equal to our current direction bool running = dir & 0x80; dir = dir & 0x7; // Remove all unneeded stuff pChar->setRunning( running ); bool turning = dir != pChar->direction(); // This happens if we're moving if ( !turning ) { // Note: Do NOT use the copy constructor as it'll create a reference Coord newCoord = calcCoordFromDir( dir, pChar->pos() ); // Check if the stamina parameters if ( player && !consumeStamina( player, running ) ) { if ( player->socket() ) player->socket()->denyMove( sequence ); return false; } // Check if we're going to collide with characters if ( player ) { // Player vs characters if ( player->socket() && player->pos().map == 0 && !player->account()->isStaff() ) { // Currently hard-limiting collisions to Felucca; this should be a server option! MapCharsIterator charCollisions = MapObjects::instance()->listCharsAtCoord( newCoord ); for ( P_CHAR them = charCollisions.first(); them; them = charCollisions.next() ) { if ( them == player ) continue; P_PLAYER otherplayer = dynamic_cast<P_PLAYER>( them ); if ( otherplayer && otherplayer->account()->isStaff() ) continue; // no collisions against the staff if ( wpAbs<SI08>( newCoord.z - them->pos().z ) < P_M_MAX_Z_CLIMB ) { // to push another char we must have maximum stamina if ( player->stamina() >= player->maxStamina() ) { player->socket()->clilocMessage( them->isHidden() ? 1019043 : 1019042 ); player->setStamina( player->stamina() - 10 ); break; } else { player->socket()->denyMove( sequence ); return false; } } } } } else { // NPC vs characters P_NPC npc = dynamic_cast<P_NPC>( pChar ); if ( npc && CheckForCharacterAtXYZ( pChar, newCoord ) ) { npc->clearPath(); return false; } } // Check if the char can move to those new coordinates // It is going to automatically calculate the new coords (!) if ( !mayWalk( pChar, newCoord ) ) { if ( player && player->socket() ) player->socket()->denyMove( sequence ); return false; } else { if ( player && player->socket() ) player->socket()->allowMove( sequence ); } // We moved so let's update our location pChar->moveTo( newCoord ); pChar->setStepsTaken( pChar->stepsTaken() + 1 ); pChar->setLastMovement( Server::instance()->time() ); checkStealth( pChar ); // Reveals the user if neccesary } else { if ( player && player->socket() ) player->socket()->allowMove( sequence ); } // do all of the following regardless of whether turning or moving i guess // set the player direction to contain only the cardinal direction bits pChar->setDirection( dir ); Coord upperLeft = pChar->pos() - Coord( ( VISRANGE + 1 ), ( VISRANGE + 1 ) ); Coord lowerRight = pChar->pos() + Coord( ( VISRANGE + 1 ), ( VISRANGE + 1 ) ); MapCharsIterator ri = MapObjects::instance()->listCharsInRect( upperLeft, lowerRight ); for ( P_CHAR observer = ri.first(); observer; observer = ri.next() ) { if ( observer == pChar ) continue; bool wasVisible = observer->pos().distance( oldpos ) < VISRANGE; // We were previously in range bool isVisible = pChar->dist( observer ) < VISRANGE; // We are now in range // If we are a player, send us new characters if ( player && player->socket() ) { // Send the observer to us if he was previously not visible and came into range recently if ( !wasVisible && isVisible ) { player->socket()->sendChar( observer ); } } // Send our movement to the observer P_PLAYER otherplayer = dynamic_cast<P_PLAYER>( observer ); if ( !otherplayer || !otherplayer->socket() ) { continue; // Skip this character, it's a player. // TODO: OnSeePlayer, OnLoosePlayer } if ( wasVisible ) { if ( isVisible ) { otherplayer->socket()->updateChar( pChar ); // We walked inside the visible range } else { otherplayer->socket()->removeObject( pChar ); // We walked out of visible range } } else if ( isVisible ) { otherplayer->socket()->sendChar( pChar ); // We walked into visible range } } // If we really moved handle teleporters and new items if ( !turning ) { handleItems( pChar, oldpos ); handleMultis( pChar, oldpos ); handleTeleporters( pChar, oldpos ); } 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(); } } }
void cSpeech::talking( P_PLAYER pChar, const QString &lang, const QString &speech, QValueVector< UINT16 > &keywords, UINT16 color, UINT16 font, UINT8 type ) // PC speech { // handle things like renaming or describing an item if( !pChar->socket() ) return; cUOSocket *socket = pChar->socket(); if( InputSpeech( socket, pChar, speech ) ) return; // not allowed to talk if( pChar->isMuted() ) { socket->sysMessage( tr( "You re squelched and cannot talk" ) ); return; } pChar->unhide(); // Check for Bogus Color if( !isNormalColor( color ) ) color = 0x2; if( type == 0 || type == 2) pChar->setSaycolor( color ); if( SrvParams->speechLog() ) { QFile lFile( "speech.log" ); if( lFile.open( IO_Append ) ) { QString logMessage( "[%1] %2: %3 [%4, 0x%5]" ); logMessage = logMessage.arg( QDateTime::currentDateTime().toString() ).arg( pChar->name() ).arg( speech ).arg( pChar->account()->login() ).arg( pChar->serial(), 8, 16 ); lFile.writeBlock( logMessage.latin1(), logMessage.length() ); lFile.close(); } } if( pChar->onTalk( type, color, font, speech, lang ) ) return; if( ( type == 0x09 ) && ( pChar->mayBroadcast() ) ) { pChar->talk( speech, color, type ); return; } pChar->talk( speech, color, type ); QString speechUpr = speech.upper(); if( response( socket, pChar, speech, keywords ) ) return; // Vendor responded already // 0x0007 -> Speech-id for "Guards" for( QValueVector< UINT16 >::const_iterator iter = keywords.begin(); iter != keywords.end(); ++iter ) { UINT16 keyword = *iter; if( keyword == 0x07 ) pChar->callGuards(); } // well,i had a strange problem with duplicate speech input // its quite easy to understand.... // the former loop searched for the tiller man and when it // was found, the speechInput method of that boat was called. // in this method the tiller had been removed from the mapregion // and appended to the end of the cell vector... hence, the // tiller was found twice... // therefore we produce a QPtrList of cBoat* pointers and // then go through it for applying speech --- sereg RegionIterator4Items rj( pChar->pos() ); QPtrList< cBoat > pboats; for( rj.Begin(); !rj.atEnd(); rj++ ) { P_ITEM pi = rj.GetData(); if( !pi ) continue; if( pi->type() == 117 && pi->tags().get( "tiller" ).toInt() == 1 ) { cBoat* pBoat = dynamic_cast< cBoat* >(FindItemBySerial( pi->tags().get("boatserial").toInt() )); if( pBoat ) pboats.append( pBoat ); } } QPtrListIterator< cBoat > pit( pboats ); while( pit.current() ) { pit.current()->speechInput( socket, speechUpr ); ++pit; } // this makes it so npcs do not respond to isDead people - HEALERS ?? if( pChar->isDead() ) return; /* P_CHAR pc = NULL; ??? P_CHAR pNpc = NULL; RegionIterator4Chars ri( pChar->pos() ); for( ri.Begin(); !ri.atEnd(); ri++ ) { pc = ri.GetData(); if (!pc->isSameAs( pChar ) && pc->isNpc() && pc->dist( pChar ) <= 2) { pNpc = pc; break; } } */ }
///////////////// // name: response // purpose: tries to get a response from an npc standing around // history: heavily revamped/rewritten by Duke, Oct 2001 // remark: The new logic tries to minimize the # of strstr() calls by *first* checking // what kind of npcs are standing around and then checking only those keywords // that they might be interested in. // This is especially usefull in crowded places. bool cSpeech::response( cUOSocket *socket, P_PLAYER pPlayer, const QString& comm, QValueVector< UINT16 > &keywords ) { if( !pPlayer->socket() || pPlayer->isDead() ) return false; QString speechUpr = comm.upper(); RegionIterator4Chars ri( pPlayer->pos() ); for( ri.Begin(); !ri.atEnd(); ri++ ) { P_NPC pNpc = dynamic_cast<P_NPC>(ri.GetData()); // We will only process NPCs here if( !pNpc ) continue; // at least they should be on the screen if( pPlayer->dist( pNpc ) > 16 ) continue; // Check if the NPC has a script that can handle // speech events and then check if it can handle everything // or just certain things std::vector< WPDefaultScript* > events = pNpc->getEvents(); for( std::vector< WPDefaultScript* >::const_iterator iter = events.begin(); iter != events.end(); ++iter ) { WPDefaultScript *script = *iter; if( !script->handleSpeech() ) continue; if( script->catchAllSpeech() || script->canHandleSpeech( comm, keywords ) ) if( script->onSpeech( pNpc, pPlayer, comm, keywords ) ) return true; } cNPC_AI* pAI = pNpc->ai(); if( pAI && pAI->currState() ) { pAI->currState()->speechInput( pPlayer, speechUpr ); pAI->updateState(); } if( BankerSpeech( socket, pPlayer, pNpc, speechUpr ) ) return true; if( PetCommand( socket, pPlayer, pNpc, speechUpr ) ) return true; if( StableSpeech( socket, pPlayer, pNpc, speechUpr ) ) return true; if( UnStableSpeech( socket, pPlayer, pNpc, speechUpr ) ) return true; if( ShieldSpeech( socket, pPlayer, pNpc, speechUpr ) ) return true; if( QuestionSpeech( socket, pPlayer, pNpc, speechUpr ) ) return true; if( TrainerSpeech( socket, pPlayer, pNpc, speechUpr ) ) return true; if( PlayerVendorSpeech( socket, pPlayer, pNpc, speechUpr ) ) return true; } return false; }
bool InputSpeech( cUOSocket *socket, P_PLAYER pChar, const QString &speech ) { if( pChar->inputMode() == cPlayer::enNone ) return false; P_ITEM pItem = FindItemBySerial( pChar->inputItem() ); if( !pItem ) return false; bool ok; INT32 num = speech.toInt( &ok ); // Generally try to convert it QString notification; switch (pChar->inputMode()) { // Pricing an item - PlayerVendors case cPlayer::enPricing: if (ok) { pItem->setPrice( num ); socket->sysMessage( tr( "This item's price has been set to %1." ).arg( num ) ); } else socket->sysMessage( tr( "You have to enter a numeric price" ) ); pChar->setInputMode(cPlayer::enDescription); socket->sysMessage( tr( "Enter a description for this item." ) ); break; // Describing an item case cPlayer::enDescription: pItem->setDescription( speech ); socket->sysMessage( tr( "This item is now described as %1." ).arg( speech ) ); pChar->setInputMode(cPlayer::enNone); pChar->setInputItem(INVALID_SERIAL); break; // Renaming a rune case cPlayer::enRenameRune: pItem->setName( tr( "Rune to: %1" ).arg( speech ) ); socket->sysMessage( tr( "Rune renamed to: Rune to: %1" ).arg( speech ) ); pChar->setInputMode(cPlayer::enNone); pChar->setInputItem(INVALID_SERIAL); break; // Renaming ourself case cPlayer::enNameDeed: pChar->setName( speech ); socket->sysMessage( tr( "Your new name is: %1" ).arg( speech ) ); pChar->setInputMode(cPlayer::enNone); pChar->setInputItem(INVALID_SERIAL); break; // Renaming a house sign case cPlayer::enHouseSign: pItem->setName( speech ); socket->sysMessage( tr( "Your house has been renamed to: %1" ).arg( speech ) ); pChar->setInputMode(cPlayer::enNone); pChar->setInputItem(INVALID_SERIAL); break; // Paging a GM case cPlayer::enPageGM: { cPage* pPage = new cPage( pChar->serial(), PT_GM, speech, pChar->pos() ); cPagesManager::getInstance()->push_back( pPage ); notification = tr( "GM Page from %1: %2" ).arg( pChar->name() ).arg( speech ); for ( cUOSocket *mSock = cNetwork::instance()->first(); mSock; mSock = cNetwork::instance()->next()) if( mSock->player() && mSock->player()->isGM() ) mSock->sysMessage( notification ); if( cNetwork::instance()->count() > 0 ) socket->sysMessage( tr( "Available Game Masters have been notified of your request." ) ); else socket->sysMessage( tr( "There was no Game Master available, page queued." ) ); pChar->setInputMode(cPlayer::enNone); } break; // Paging a Counselor case cPlayer::enPageCouns: { cPage* pPage = new cPage( pChar->serial(), PT_COUNSELOR, speech, pChar->pos() ); cPagesManager::getInstance()->push_back( pPage ); notification = tr( "Counselor Page from %1: %2" ).arg( pChar->name() ).arg( speech ); for ( cUOSocket *mSock = cNetwork::instance()->first(); mSock; mSock = cNetwork::instance()->next()) if( mSock->player() && (socket->player()->isCounselor() || socket->player()->isGM()) ) mSock->sysMessage( notification ); if( cNetwork::instance()->count() > 0 ) socket->sysMessage( tr( "Available Counselors have been notified of your request." ) ); else socket->sysMessage( tr( "There was no Counselor available, page queued." ) ); pChar->setInputMode(cPlayer::enNone); } break; default: break; // do nothing } return true; }