int response(UOXSOCKET s, P_CHAR pPlayer, char* SpeechUpr) { char *comm=SpeechUpr; if (strstr( comm, "#EMPTY") && online(currchar[s]) && !pPlayer->dead && pPlayer->isGM()) { // restricted to GMs for now. It's too powerful (Duke, 5.6.2001) target(s, 0, 1, 0, 71, "Select container to empty:"); return 1; } if (!online(DEREF_P_CHAR(pPlayer)) || pPlayer->dead) return 0; P_CHAR pc; cRegion::RegionIterator4Chars ri(pPlayer->pos); for (ri.Begin(); (pc=ri.GetData()) != ri.End(); ri++) { if (pc->isPlayer()) // only npcs will respond automagically, players still have to do that themselves ;) continue; if (pPlayer->dist(pc) > 16) // at least they should be on the screen continue; if (pPlayer->isSameAs(pc)) // not talking to ourselves continue; if (StableSpeech(pc, comm, pPlayer, s)) return 1; if (UnStableSpeech(pc, comm, pPlayer, s)) return 1; if (ShieldSpeech(pc, comm, pPlayer, s)) return 1; if (QuestionSpeech(pc, comm, pPlayer, s)) return 1; if (PackupSpeech(pc, comm, pPlayer, s)) return 1; if (TriggerSpeech(pc, comm, pPlayer, s)) return 1; if (EscortSpeech(pc, comm, pPlayer, s)) return 1; if (BankerSpeech(pc, comm, pPlayer, s)) return 1; if (TrainerSpeech(pc, comm, pPlayer, s)) return 1; if (PetCommand(pc, comm, pPlayer, s)) return 1; if (VendorSpeech(pc, comm, pPlayer, s)) return 1; } return 0; }
virtual void handleResponse( cUOSocket *socket, const gumpChoice_st& choice ) { P_PLAYER player = socket->player(); if( !player ) return; P_CHAR pChar = FindCharBySerial( choice.button ); if( !pChar || pChar->dist( player ) > 32 ) return; // Start the refresh-timer // Start the wearoff-timer player->setTrackingTime( uiCurrentTime + ( 30 * MY_CLOCKS_PER_SEC ) ); TempEffects::instance()->insert( new cRefreshTracking( player->serial(), choice.button ) ); }
/*! 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; }
// check if something is attacking us P_CHAR Action_Defend::findAttacker() { if ( !m_ai ) { return 0; } P_CHAR attacker = m_npc->attackTarget(); unsigned int distance = ~0; // check our current target if ( attacker && validTarget( m_npc, attacker ) ) { m_ai->setcurrentVictimSer( attacker->serial() ); return attacker; } // check our current victim attacker = m_ai->currentVictim(); if ( !attacker ) { m_ai->setcurrentVictimSer( INVALID_SERIAL ); } // is it still valid? if ( attacker && invalidTarget( m_npc, attacker ) ) { attacker = 0; m_ai->setcurrentVictimSer( INVALID_SERIAL ); m_npc->fight( 0 ); } if ( m_ai->getnextVictimCheck() < Server::instance()->time() ) { // Don't switch if we can hit it... if ( !attacker || attacker->dist( m_npc ) > 1 ) { // Search for attackers in our list of current fights QPtrList<cFightInfo> fights = m_npc->fights(); for ( cFightInfo*info = fights.first(); info; info = fights.next() ) { //are they attacking us? P_CHAR victim = info->victim(); if ( victim == m_npc ) { victim = info->attacker(); } // We don't already attack the target, right? if ( victim != attacker ) { // See if it's a target we want unsigned int dist = m_npc->dist( victim ); if ( dist < distance && validTarget( m_npc, victim, dist ) ) { attacker = victim; distance = dist; } } } // we found someone attacking us, so let's defend! if ( attacker ) { m_ai->setcurrentVictimSer( attacker->serial() ); m_npc->fight( attacker ); } } m_ai->setnextVictimCheck( Server::instance()->time() + 1500 ); } return attacker; }
void Action_Wander::execute() { m_npc->fight(0); // If the next wandertype hasn't come yet. if (m_npc->nextMoveTime() > uiCurrentTime) { return; } m_npc->setNextMoveTime(); switch( m_npc->wanderType() ) { case enFreely: { UINT8 dir = m_npc->direction(); if( RandomNum(0, 100) < 20 ) dir = RandomNum( 0, 7 ); m_npc->setDirection( dir ); Movement::instance()->Walking( m_npc, dir, 0xFF ); break; } case enRectangle: { // get any point out of the rectangle and calculate the direction to it UINT16 rndx = RandomNum( m_npc->wanderX1(), m_npc->wanderX2() ); UINT16 rndy = RandomNum( m_npc->wanderY1(), m_npc->wanderY2() ); UINT8 dir = m_npc->pos().direction( Coord_cl( rndx, rndy ) ); m_npc->setDirection( dir ); Movement::instance()->Walking( m_npc, dir, 0xFF ); break; } case enCircle: { Coord_cl pos = m_npc->pos(); pos.x = m_npc->wanderX1(); pos.y = m_npc->wanderY1(); // get any point within the circle and calculate the direction to it // first a random distance which can be max. the length of the radius float rnddist = (float)RandomNum( 1, m_npc->wanderRadius() ); // now get a point on this circle around the m_npc float rndphi = (float)RandomNum( 0, 100 ) / 100.0f * 2.0f * 3.14159265358979323846f; pos.x = pos.x + (INT16)floor( cos( rndphi ) * rnddist ); pos.y = pos.y + (INT16)floor( sin( rndphi ) * rnddist ); UINT8 dir = m_npc->pos().direction( pos ); m_npc->setDirection( dir ); Movement::instance()->Walking( m_npc, dir, 0xFF ); break; } case enFollowTarget: { if( SrvParams->pathfind4Follow() ) { P_CHAR pTarget = m_npc->wanderFollowTarget(); if( pTarget ) { movePath( pTarget->pos() ); } if( pTarget->dist( m_npc ) > 3 ) m_npc->setAICheckTime( uiCurrentTime + (float)m_npc->aiCheckInterval() * 0.0005f * MY_CLOCKS_PER_SEC ); } else { P_CHAR pTarget = m_npc->wanderFollowTarget(); if( pTarget ) { moveTo( pTarget->pos() ); } } break; } case enDestination: { movePath( m_npc->wanderDestination() ); break; } } }