///////////////// // 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; }
/*! Calculates the amount of Stamina needed for a move of the passed character. */ bool cMovement::consumeStamina( P_PLAYER pChar, bool running ) { // Dead people and gms don't care about weight if ( pChar->isDead() || pChar->isGMorCounselor() ) { return true; } // Calculate the stones we weight too much int overWeight = ( int ) ( pChar->weight() - pChar->maxWeight() ); bool mounted = pChar->atLayer( cBaseChar::Mount ) != 0; bool update = false; // We carry too much if ( overWeight > 0 ) { // How much stamina we loose int amount = 5 + ( overWeight / 25 ); // Only one third loss if mounted if ( mounted ) { amount = amount / 3; } // Double loss if running if ( running ) { amount = amount * 2; } // Set the new stamina pChar->setStamina( wpMax<Q_INT16>( 0, pChar->stamina() - amount ), false ); update = true; // We are overloaded if ( pChar->stamina() == 0 ) { pChar->socket()->updateStamina(); pChar->socket()->clilocMessage( 500109 ); return false; } } // If we have less than 10% stamina left, we loose // stamina more quickly if ( ( pChar->stamina() * 100 ) / wpMax<ushort>( 1, pChar->maxStamina() ) < 10 ) { pChar->setStamina( wpMax<Q_INT16>( 0, pChar->stamina() - 1 ), false ); update = true; } // We can't move anymore because we are exhausted if ( pChar->stamina() == 0 ) { pChar->socket()->updateStamina(); pChar->socket()->clilocMessage( 500110 ); return false; } // Normally reduce stamina every few steps if ( pChar->stepsTaken() % ( mounted ? 48 : 16 ) == 0 ) { pChar->setStamina( wpMax<Q_INT16>( 0, pChar->stamina() - 1 ) ); update = true; } if ( update ) { pChar->socket()->updateStamina(); } return true; }
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; }
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 ); } } }
void Speech::talking( P_PLAYER pChar, const QString& lang, const QString& speech, QValueVector<Q_UINT16>& keywords, Q_UINT16 color, Q_UINT16 font, Q_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; pChar->unhide(); // Check for Bogus Color if ( !isNormalColor( color ) ) color = 0x2; if ( type == 0 ) pChar->setSaycolor( color ); else if ( type == 2 ) pChar->setEmoteColor( color ); 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 // this makes it so npcs do not respond to isDead people - HEALERS ?? if ( pChar->isDead() ) return; // 0x0007 -> Speech-id for "Guards" for ( QValueVector<Q_UINT16>::const_iterator iter = keywords.begin(); iter != keywords.end(); ++iter ) { Q_UINT16 keyword = *iter; if ( keyword == 0x07 ) pChar->callGuards(); } /* 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; } } */ }
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 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 ); }