예제 #1
0
psMiniGameSession::~psMiniGameSession()
{

    // Unregister pending call-backs. Right now clients are disconnected before deleting game
    // sessions, but it might be changed in the future.
    ClientConnectionSet* clients = psserver->GetConnections();
    if(clients)
    {
        csPDelArray<MinigamePlayer>::Iterator pIter = players.GetIterator();
        while(pIter.HasNext())
        {
            MinigamePlayer* p = pIter.Next();
            if(p && p->playerID != (uint32_t)-1)
            {
                Client* client = clients->Find(p->playerID);
                if(client && client->GetActor())
                {
                    client->GetActor()->UnregisterCallback(this);
                }
            }
        }
        players.DeleteAll();

        csArray<uint32_t>::Iterator iter = watchers.GetIterator();
        while(iter.HasNext())
        {
            Client* client = clients->Find(iter.Next());
            if(client && client->GetActor())
            {
                client->GetActor()->UnregisterCallback(this);
            }
        }
        watchers.DeleteAll();
    }
}
예제 #2
0
void ChatManager::SendSay(uint32_t clientNum, gemActor *actor, psChatMessage& msg,const char* who)
{
    float range = 0;
    psSectorInfo * sectorinfo = NULL;
    iSector * sector = actor->GetMeshWrapper()->GetMovable()->GetSectors()->Get(0);

    if (sector)
    {
        sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName(sector->QueryObject()->GetName());
        if (sectorinfo)
        {
            range = sectorinfo->say_range;
        }
    }

    if (range == 0) // If 0 set default
        range = CHAT_SAY_RANGE;

    psChatMessage newMsg(clientNum, actor->GetEID(), who, 0, msg.sText, msg.iChatType, msg.translate);
    csArray<PublishDestination>& clients = actor->GetMulticastClients();
    newMsg.Multicast(clients, 0, range);

    // The message is saved to the chat history of all the clients around (PS#2789)
    for (size_t i = 0; i < clients.GetSize(); i++)
    {
        Client *target = psserver->GetConnections()->Find(clients[i].client);
        if (target && clients[i].dist < range)
            target->GetActor()->LogChatMessage(actor->GetFirstName(), newMsg);
    }
}
예제 #3
0
bool GMEventManager::EraseGMEvent(Client* client, GMEvent* gmEvent)
{
    PID discarderGMID = client->GetPID();
    int clientnum = client->GetClientNum();

    // If event belongs to another GM, only proceed if that GM not online.
    ClientConnectionSet* clientConnections = psserver->GetConnections();
    Client* target;
    if (discarderGMID != gmEvent->gmID && gmEvent->gmID != UNDEFINED_GMID)
    {
        if ((target = clientConnections->FindPlayer(gmEvent->gmID)))
        {
            psserver->SendSystemInfo(clientnum,
                                     "The \'%s\' event's GM, %s, is online: you cannot discard their event.",
                                     gmEvent->eventName.GetDataSafe(),
                                     target->GetName());
            return false;
        }
    }

    // Remove players.
    size_t noPlayers = gmEvent->Player.GetSize();
    for (size_t p = 0; p < noPlayers; p++)
    {
        PID playerID = gmEvent->Player[p].PlayerID;
        if ((target = clientConnections->FindPlayer(playerID)))
        {
            // psCharacter
            target->GetActor()->GetCharacterData()->RemoveGMEvent(gmEvent->id);

            psserver->SendSystemInfo(target->GetClientNum(),
                                     "Event '%s' has been discarded.",
                                     gmEvent->eventName.GetDataSafe());
        }
    }
    gmEvent->Player.DeleteAll();

    // remove GM
    if (discarderGMID == gmEvent->gmID  && gmEvent->gmID != UNDEFINED_GMID)
    {
        client->GetActor()->GetCharacterData()->RemoveGMEvent(gmEvent->id, true);
    }

    // remove from DB
    db->Command("DELETE FROM character_events WHERE event_id = %d", gmEvent->id);
    db->Command("DELETE FROM gm_events WHERE id = %d", gmEvent->id);

    psserver->SendSystemInfo(client->GetClientNum(),
                             "Event '%s' has been discarded.",
                             gmEvent->eventName.GetDataSafe());

    // remove gmEvent ref
    gmEvents.Delete(gmEvent);

    return true;
}
예제 #4
0
void ChatManager::SendServerChannelMessage(psChatMessage& msg, uint32_t channelID)
{
    csArray<uint32_t> subscribers = channelSubscribers.GetAll(channelID);
    csArray<PublishDestination> destArray;
    for (size_t i = 0; i < subscribers.GetSize(); i++)
    {
        destArray.Push(PublishDestination(subscribers[i], NULL, 0, 0));
        Client *target = psserver->GetConnections()->Find(subscribers[i]);
        if (target && target->IsReady())
            target->GetActor()->LogChatMessage("Server Admin", msg);
    }

    msg.Multicast(destArray, 0, PROX_LIST_ANY_RANGE );
}
예제 #5
0
bool GMEventManager::CompleteGMEvent (Client* client, PID gmID, bool byTheControllerGM)
{
    int zero = 0;

    // if this GM does not have an active event, he/she can't end it.
    GMEvent* theEvent;
    int clientnum = client->GetClientNum();

    if ((theEvent = GetGMEventByGM(gmID, RUNNING, zero)) == NULL)
    {
        psserver->SendSystemInfo(clientnum, "You are not running an event.");
        return false;
    }

    // inform players
    ClientConnectionSet* clientConnections = psserver->GetConnections();
    Client* target;
    for (size_t p = 0; p < theEvent->Player.GetSize(); p++)
    {
        if ((target = clientConnections->FindPlayer(theEvent->Player[p].PlayerID)))
        {
            // psCharacter
            target->GetActor()->GetCharacterData()->CompleteGMEvent(false);

            psserver->SendSystemInfo(target->GetClientNum(),
                                     "Event '%s' complete.",
                                     theEvent->eventName.GetDataSafe());
        }
    }

    // GMs psCharacter
    if (byTheControllerGM)
        client->GetActor()->GetCharacterData()->CompleteGMEvent(true);

    // Update description & flag the event complete
    if (theEvent->gmID == UNDEFINED_GMID)
        theEvent->eventDescription += " (No GM)";
    else
        theEvent->eventDescription += " (" + csString(client->GetName()) + ")";
    csString EscEventDescription;
    db->Escape(EscEventDescription, theEvent->eventDescription);
    db->Command("UPDATE gm_events SET status = %d, description = '%s' WHERE id = %d",
                COMPLETED, EscEventDescription.GetDataSafe(), theEvent->id);
    theEvent->status = COMPLETED;
    theEvent->EndTime = csGetTicks();
    psserver->SendSystemInfo(clientnum, "Event '%s' complete.", theEvent->eventName.GetDataSafe());

    return true;
}
예제 #6
0
void Client::ClearAllDuelClients()
{
    for (int i = 0; i < GetDuelClientCount(); i++)
    {
        Client *duelClient = psserver->GetConnections()->Find(duel_clients[i]);
        if (duelClient)
        {
            // Also remove us from their list.
            duelClient->RemoveDuelClient(this);

            if (actor)
                actor->RemoveAttackerHistory(duelClient->GetActor());
        }
    }
    duel_clients.Empty();
}
예제 #7
0
void psEndChatLoggingEvent::Trigger()
{
#ifdef _psEndChatLoggingEvent_DEBUG_
CPrintf(CON_DEBUG, "EndOfChatLoggingEvent is about to happen on clientnum %i!", clientnum);
#endif

    Client *client = NULL;

    client = psserver->GetConnections()->Find(clientnum);
    if (!client)
    {
#ifdef _psEndChatLoggingEvent_DEBUG_
CPrintf(CON_DEBUG, "EndOfChatLoggingEvent on unknown client!");
#endif
        return;
    }
    client->GetActor()->RemoveChatReport();
}
예제 #8
0
void ChatManager::SendAlliance(const csString & sender, EID senderEID, psGuildAlliance * alliance, psChatMessage& msg)
{
    ClientIterator iter(*psserver->GetConnections());
    psGuildMember * member;

    while(iter.HasNext())
    {
        Client *client = iter.Next();
        if (!client->IsReady()) continue;
        if (client->GetAllianceID() != alliance->GetID()) continue;
        member = client->GetCharacterData()->GetGuildMembership();
        if ( (!member) || (!member->HasRights(RIGHTS_VIEW_CHAT_ALLIANCE)) ) continue;
        // Send the chat message
        psChatMessage newMsg(client->GetClientNum(), senderEID, sender, 0, msg.sText, msg.iChatType, msg.translate);
        newMsg.SendMessage();
        // The message is saved to the chat history of all the clients in the same alliance (PS#2789)
        client->GetActor()->LogChatMessage(sender.GetData(), msg);
    }
}
예제 #9
0
csString ChatManager::channelsToString()
{
    csString string;
    for(uint32_t i = 1; i <= channelNames.GetSize(); i++)
    {
        csArray<uint32_t> subscribers = channelSubscribers.GetAll(i);
        string += channelNames.Get(i, "");
        string += " : ";
        for (size_t i = 0; i < subscribers.GetSize(); i++)
        {
            Client *target = psserver->GetConnections()->Find(subscribers[i]);
            if (target && target->IsReady())
            {
                string += target->GetActor()->GetName();
                string += " ";
            }
        }
        string += "\n";
    }
    return string;
}
예제 #10
0
void ChatManager::SendShout(Client *c, psChatMessage& msg)
{
    psChatMessage newMsg(c->GetClientNum(), c->GetActor()->GetEID(), c->GetName(), 0, msg.sText, msg.iChatType, msg.translate);

    if (c->GetActor()->GetCharacterData()->GetTotalOnlineTime() > 3600 || c->GetActor()->GetSecurityLevel() >= GM_LEVEL_0)
    {
        csArray<PublishDestination>& clients = c->GetActor()->GetMulticastClients();
        newMsg.Multicast(clients, 0, PROX_LIST_ANY_RANGE );

        // The message is saved to the chat history of all the clients around
        for (size_t i = 0; i < clients.GetSize(); i++)
        {
            Client *target = psserver->GetConnections()->Find(clients[i].client);
            if (target && target->IsReady())
                target->GetActor()->LogChatMessage(c->GetActor()->GetFirstName(), newMsg);
        }
    }
    else
    {
        psserver->SendSystemError(c->GetClientNum(), "You are not allowed to shout or auction until you have been in-game for at least 1 hour.");
        psserver->SendSystemInfo(c->GetClientNum(), "Please use the Help tab or /help if you need help.");
    }
}
예제 #11
0
void AdviceManager::AdviceRequestTimeout(AdviceSession *adviceSession)
{
    Client * adviseeClient = adviceSession->GetAdvisee();
    if (!adviseeClient)  // Questioner has himself gone offline now
        return;

    if ( adviceSession->AdvisorClientNum != (uint32_t)-1 )
    {
        //adviceSession->advisorPoints = 0;
        psserver->SendSystemInfo(adviceSession->AdviseeClientNum,"Your advisor appears to be busy at the moment, the messenger is still waiting for an answer.");
        psserver->SendSystemInfo(adviceSession->AdvisorClientNum,"%s is still waiting for an answer to their question.",adviseeClient->GetName());
        psChatMessage msgAdvisor(adviceSession->AdvisorClientNum, 0, adviseeClient->GetName(), 0, adviceSession->lastRequest, CHAT_ADVICE_LIST, false);
        msgAdvisor.SendMessage();
    }
    else
    {
        for (size_t i = 0; i < advisors.GetSize(); i++)
        {
            psserver->SendSystemInfo(advisors[i].id,"%s's messenger taps his foot impatiently.",adviseeClient->GetName());
            //psChatMessage msgAdvisor(advisors[i].client_id, 0, adviseeClient->GetName(), "RESEND:" + adviceSession->lastRequest,CHAT_ADVICE,false);
            //msgAdvisor.SendMessage();
        }
        psserver->SendSystemInfo(adviceSession->AdviseeClientNum,"All advisors appear to be busy at the moment, the messenger is still waiting for an answer.");
    }

    adviceSession->requestRetries += 1;
    if ( adviceSession->requestRetries < ADVICE_QUESTION_RETRIES )
    {
        psAdviceRequestTimeoutGameEvent *ev = new psAdviceRequestTimeoutGameEvent( this, ADVICE_QUESTION_TIMEOUT, adviseeClient->GetActor(), adviceSession);
        adviceSession->requestEvent = ev;
        psserver->GetEventManager()->Push(ev);
    }
    else
    {
        adviceSession->requestRetries = 0;
        adviceSession->answered = true;
        adviceSession->requestEvent = NULL;
        psserver->SendSystemInfo(adviceSession->AdviseeClientNum,"Your messenger has returned without an answer, please try again later.");
    }

}
예제 #12
0
void AdviceManager::HandleAdviceResponse( Client *advisor, csString sAdvisee, csString message)
{
    if ( !advisor->GetAdvisor() )
    {
        psserver->SendSystemInfo(advisor->GetClientNum(),"You need to be an advisor to use this command.");
        return;
    }

    csString buf;
    // Source Client Name, Target Client Name, Message
    buf.Format("%s, %s, \"%s\"", advisor->GetName(), sAdvisee.GetData() , message.GetData());
    psserver->GetLogCSV()->Write(CSV_ADVICE, buf);

    // Find Advisee Client by name
    if (sAdvisee.Length())
    {
        sAdvisee = NormalizeCharacterName(sAdvisee);
    }
    Client *advisee = psserver->GetConnections()->Find(sAdvisee);
    if (!advisee)
    {
        // Create a new message to report TELL error and send
        // back to original person.
        csString sMsg("No player named ");
        sMsg += sAdvisee;
        sMsg += " is logged on to the system currently.";
        psserver->SendSystemError(advisor->GetClientNum(), sMsg);
        return;
    }

    // Can't allow you to advise yourself
    if ( advisee == advisor )
    {
        psserver->SendSystemError(advisor->GetClientNum(), "You are not allowed to advise yourself. Please wait for another advisor.");
        return;
    }

    // find existing Advicee in the List
    AdviceSession key;
    key.AdviseeClientNum = advisee->GetClientNum();
    AdviceSession *activeSession = AdviseeList.Get(advisee->GetClientNum(), NULL);

    if (!activeSession || (activeSession  && ( !activeSession->requestEvent ) && ( activeSession->GetAdvisor() == NULL ) ) )
    {
        psserver->SendSystemError(advisor->GetClientNum(), "%s has not requested help.", advisee->GetName());
        return;
    }

    if (activeSession  && ( activeSession->AdviseeClientNum != advisee->GetClientNum() ) )
    {
        Debug2( LOG_ANY, advisee->GetClientNum(), "Grabbed wrong advisor session: %d", activeSession->AdviseeClientNum );
    }

    if ( ( activeSession->GetAdvisor() != NULL ) && ( activeSession->AdvisorClientNum != advisor->GetClientNum() ) )
    {
        psserver->SendSystemError(advisor->GetClientNum(), "%s is being advised already, thank you.",  advisee->GetName());
        return;
    }

    if ( message.Length() == 0  && activeSession->status == SESSION_STATUS_UNKNOWN ) // advisor is claiming a session
    {
        // check to make sure advisor has only one claimed session.
        AdviceSession *loopSession;

        csHash< AdviceSession* >::GlobalIterator loop( AdviseeList.GetIterator() );

        while(loop.HasNext())
        {
        	loopSession = loop.Next();
            if (activeSession->status == SESSION_STATUS_CLAIMED && loopSession->GetAdvisor() == advisor )
            {
                psserver->SendSystemInfo(advisor->GetClientNum(), "You cannot have two messengers waiting for you at the same time, please answer %s's request first." , loopSession->adviseeName.GetData() );
                return;
            }
        }

        activeSession->SetAdvisor( advisor );
        psserver->SendSystemInfo(advisee->GetClientNum(), "An advisor is preparing an answer to your question, please be patient.");
        psserver->SendSystemInfo(advisor->GetClientNum(), "You have claimed the session with %s. Please provide an answer." , advisee->GetName() );

        for (size_t i = 0; i < advisors.GetSize(); i++)
        {
            if ( advisors[i].id != activeSession->AdvisorClientNum )
            {
                psserver->SendSystemInfo(advisors[i].id, "%s has proclaimed they know the answer to %s's question.", advisor->GetName(), advisee->GetName() );
            }
        }
        activeSession->status = SESSION_STATUS_CLAIMED;
    }
    else
    {
        if (message.IsEmpty())
        {
            psserver->SendSystemInfo(advisor->GetClientNum(), "Please enter the advice you wish to give.");
            return;
        }

        psChatMessage msgChat(activeSession->AdviseeClientNum, 0, advisor->GetName(), advisee->GetName(), message ,CHAT_ADVISOR,false);

        if ( activeSession->GetAdvisor() == NULL || activeSession->status != SESSION_STATUS_OWNED )
        {
            // Check to make sure the advice is 'good'
            // if ( message.Length() < 20 )
            // {
                // psserver->SendSystemInfo(advisor->GetClientNum(), "Please be more specific when answering questions. Your advice has been ignored.");
                // return;
            // }

            //activeSession->AdvisorClientNum = me->clientnum;
            activeSession->SetAdvisor( advisor );
            advisor->IncrementAdvisorPoints(activeSession->advisorPoints);
            psserver->CharacterLoader.SaveCharacterData( advisor->GetCharacterData(), advisor->GetActor(), true );

            // Send Confirmation to advisor
            psserver->SendSystemInfo( advisor->GetClientNum(), "You are now advising %s.",advisee->GetName());

            // Send Confirmation to all other advisors so they know they lost this one.
            for (size_t i = 0; i < advisors.GetSize(); i++)
            {
                if ( advisors[i].id != activeSession->AdvisorClientNum )
                {
                    psserver->SendSystemInfo( advisors[i].id, "%s has been assigned to %s.",  advisee->GetName(), advisor->GetName() );
                    if ( advisors[i].GM )
                        continue;
                    msgChat.msg->clientnum = advisors[i].id;
                    msgChat.SendMessage();
                }
            }
            activeSession->status = SESSION_STATUS_OWNED;
        }

        if ( activeSession->requestEvent )
            activeSession->requestEvent->valid = false;  // This keeps the cancellation timeout from firing.

        activeSession->answered = true;

        // Send Message to Advisee
        msgChat.msg->clientnum = activeSession->AdviseeClientNum;
        msgChat.SendMessage();

        // Send Message to advisor
        msgChat.msg->clientnum = activeSession->AdvisorClientNum;
        msgChat.SendMessage();

        // Send message to GM chars as well
        for (size_t i = 0; i < advisors.GetSize(); i++)
        {
            if (!advisors[i].GM || advisors[i].id == activeSession->AdvisorClientNum)
                continue;
            msgChat.msg->clientnum = advisors[i].id;
            msgChat.SendMessage();
        }
    }

    // Add timeout for Advisor-Advisee relationship
    // this will allow later questions by the same client to go to a different advisor
    // spreading the wealth and burden amongst all ;)
    if ( activeSession->timeoutEvent )
    {
        activeSession->timeoutEvent->valid = false;
    }
    psAdviceSessionTimeoutGameEvent *ev = new psAdviceSessionTimeoutGameEvent( this, activeSession->answered?ADVICE_SESSION_TIMEOUT:ADVICE_SESSION_TIMEOUT/2, advisee->GetActor(), activeSession );
    activeSession->timeoutEvent = ev;
    psserver->GetEventManager()->Push(ev);

}
예제 #13
0
void SpawnManager::HandleLootItem(MsgEntry *me,Client *client)
{
    psLootItemMessage msg(me);

    // Possible hack here?  We are trusting the client to send the right msg.entity?
    gemObject *object = gem->FindObject(msg.entity);
    if (!object)
    {
        Error3("LootItem Message from %s specified an erroneous entity id: %s.\n", client->GetName(), ShowID(msg.entity));
        return;
    }

    gemActor *obj = object->GetActorPtr();
    if (!obj)
    {
        Error3("LootItem Message from %s specified a non-actor entity id: %s.\n", client->GetName(), ShowID(msg.entity));
        return;
    }
    psCharacter *chr = obj->GetCharacterData();
    if (!chr)
    {
        Error3("LootItem Message from %s specified a non-character entity id: %s.\n", client->GetName(), ShowID(msg.entity));
        return;
    }

    // Check the range to the lootable object.
    if (client->GetActor()->RangeTo(obj) > RANGE_TO_LOOT )
    {
        psserver->SendSystemError(client->GetClientNum(), "Too far away to loot %s.", obj->GetName() );
        return;
    }

    psItem *item = chr->RemoveLootItem(msg.lootitem);
    if (!item)
    {
        // Take this out because it is just the result of duplicate loot commands due to lag
        //Warning3(LOG_COMBAT,"LootItem Message from %s specified bad item id of %d.\n",client->GetName(), msg.lootitem);
        return;
    }

    item->SetLoaded();

    csRef<PlayerGroup> group = client->GetActor()->GetGroup();
    Client *randfriendclient = NULL;
    if (group.IsValid())
    {
        randfriendclient = obj->GetRandomLootClient(RANGE_TO_LOOT*10);
        if (!randfriendclient)
        {
            Error3("GetRandomLootClient failed for loot msg from %s, object %s.\n", client->GetName(), item->GetName() );
            return;
        }
    }

    csString type;
    Client *looterclient;  // Client that gets the item
    if ( msg.lootaction == msg.LOOT_SELF || !group.IsValid() )
    {
        looterclient = client;
        type = "Loot Self";
    }
    else
    {
        looterclient = randfriendclient;
        type = "Loot Roll";
    }

    // Ask group member before take
    if (msg.lootaction == msg.LOOT_SELF && group.IsValid() && client != randfriendclient && obj->HasBeenAttackedBy(randfriendclient->GetActor()))
    {
        psserver->SendSystemInfo(client->GetClientNum(),
                                 "Asking roll winner %s if you may take the %s...",
                                  randfriendclient->GetName(), item->GetName() );
        csString request;
        request.Format("You have won the roll for a %s, but %s wants to take it."
                       "  Will you allow this action?",
                       item->GetName(), client->GetName());

        // Item will be held in the prompt until answered.

        PendingLootPrompt *p = new PendingLootPrompt(client, randfriendclient, item, chr, request, cacheManager, gem);
        psserver->questionmanager->SendQuestion(p);

        type.Append(" Pending");
    }
    // Continue with normal looting if not prompting
    else
    {
        // Create the loot message
        csString lootmsg;
        if (group.IsValid())
            lootmsg.Format("%s won the roll and",looterclient->GetName());
        else
            lootmsg.Format("You");
        lootmsg.AppendFmt(" looted a %s",item->GetName());

        // Attempt to give to looter
        bool dropped = looterclient->GetActor()->GetCharacterData()->Inventory().AddOrDrop(item);

        if (!dropped)
        {
            lootmsg.Append(", but can't hold anymore");
            type.Append(" (dropped)");
        }

        // Send out the loot message
        psSystemMessage loot(me->clientnum, MSG_LOOT, lootmsg.GetData() );
        looterclient->GetActor()->SendGroupMessage(loot.msg);

        item->Save(false);
    }

    // Trigger item removal on every client in the group which has intrest
    if (group.IsValid())
    {
        for (int i=0; i < (int)group->GetMemberCount(); i++)
        {
            int cnum = group->GetMember(i)->GetClientID();
            if (obj->IsLootableClient(cnum))
            {
                psLootRemoveMessage rem(cnum,msg.lootitem);
                rem.SendMessage();
            }
        }
    }
    else
    {
        psLootRemoveMessage rem(client->GetClientNum(),msg.lootitem);
        rem.SendMessage();
    }

    psLootEvent evt(
                   chr->GetPID(),
                   chr->GetCharName(),
                   looterclient->GetCharacterData()->GetPID(),
                   looterclient->GetCharacterData()->GetCharName(),
                   item->GetUID(),
                   item->GetName(),
                   item->GetStackCount(),
                   (int)item->GetCurrentStats()->GetQuality(),
                   0
                   );
    evt.FireEvent();

}
예제 #14
0
void ChatManager::HandleChatMessage(MsgEntry *me, Client *client)
{
    psChatMessage msg(me);

    // Dont
    if (!msg.valid)
    {
        Debug2(LOG_NET,me->clientnum,"Received unparsable psChatMessage from client %u.\n",me->clientnum);
        return;
    }

    const char *pType = msg.GetTypeText();

    if (msg.iChatType != CHAT_TELL && msg.iChatType != CHAT_AWAY)
    {
        Debug4(LOG_CHAT, client->GetClientNum(),
                "%s %s: %s\n", client->GetName(),
                pType, msg.sText.GetData());
    }
    else
    {
        Debug5(LOG_CHAT,client->GetClientNum(), "%s %s %s: %s\n", client->GetName(),
               pType, msg.sPerson.GetData(),msg.sText.GetData());
    }

    bool saveFlood = true;

    if (!client->IsMute())
    {
      // Send Chat to other players
      switch (msg.iChatType)
      {
          case CHAT_GUILD:
          {
              SendGuild(client, msg);
              break;
          }
          case CHAT_ALLIANCE:
          {
              SendAlliance(client, msg);
              break;
          }
          case CHAT_GROUP:
          {
              SendGroup(client, msg);
              break;
           }
          case CHAT_AUCTION:
          case CHAT_SHOUT:
          {
              SendShout(client, msg);
              break;
          }
          case CHAT_CHANNEL:
          {
              csArray<uint32_t> subscribed = channelSubscriptions.GetAll(client->GetClientNum());
              bool found = false;
              for(size_t i = 0; i < subscribed.GetSize(); i++)
              {
                  if(subscribed[i] == msg.channelID)
                      found = true;
              }
              if(!found)
              {
                  psserver->SendSystemError(client->GetClientNum(), "You have not yet joined this channel.");
                  break;
              }

              // channel 1 is public
              if(msg.channelID == 1)
                  CPrintf (CON_WARNING, "Gossip %s: %s\n", client->GetName(), msg.sText.GetData());

              psChatMessage newMsg(client->GetClientNum(), client->GetActor()->GetEID(), client->GetName(), 0, msg.sText, msg.iChatType, msg.translate, msg.channelID);

              csArray<uint32_t> subscribers = channelSubscribers.GetAll(msg.channelID);
              csArray<PublishDestination> destArray;
              for (size_t i = 0; i < subscribers.GetSize(); i++)
              {
                  destArray.Push(PublishDestination(subscribers[i], NULL, 0, 0));
                  Client *target = psserver->GetConnections()->Find(subscribers[i]);
                  if (target && target->IsReady())
                      target->GetActor()->LogChatMessage(client->GetActor()->GetFirstName(), newMsg);
              }

              newMsg.Multicast(destArray, 0, PROX_LIST_ANY_RANGE );
              break;
          }
          case CHAT_PET_ACTION:
          {
              gemNPC *pet = NULL;

              // Check if a specific pet's name was specified, in one of these forms:
              // - /mypet Petname ...
              // - /mypet Petname's ...
              size_t numPets = client->GetNumPets();
              for (size_t i = 0; i < numPets; i++)
              {
                  if ((pet = dynamic_cast <gemNPC*>(client->GetPet(i)))
                      && msg.sText.StartsWith(pet->GetCharacterData()->GetCharName(), true))
                  {
                      size_t n = strlen(pet->GetCharacterData()->GetCharName());
                      if (msg.sText.Length() >= n + 1 && msg.sText.GetAt(n) == ' ')
                      {
                          msg.sText.DeleteAt(0, n);
                          msg.sText.LTrim();
                          break;
                      }
                      else if (msg.sText.Length() >= n + 3 && msg.sText.GetAt(n) == '\''
                               && msg.sText.GetAt(n + 1) == 's' && msg.sText.GetAt(n + 2) == ' ')
                      {
                          msg.sText.DeleteAt(0, n);
                          break;
                      }
                  }
                  else pet = NULL;
              }
              // If no particular pet was specified, assume the default familiar...
              if (!pet)
                  pet = dynamic_cast <gemNPC*>(client->GetFamiliar());

              // Send the message or an appropriate error...
              if (!pet)
                  psserver->SendSystemInfo(me->clientnum, "You have no familiar to command.");
              else
                  SendSay(client->GetClientNum(), pet, msg, pet->GetCharacterData()->GetCharFullName());

              break;
          }
          case CHAT_SAY:
          {
              // Send to all if there's no NPC response or the response is public
              SendSay(client->GetClientNum(), client->GetActor(), msg, client->GetName());
              break;
          }
          case CHAT_NPC:
          {
              // Only the speaker sees his successful chatting with an npc.
              // This helps quests stay secret.
              //psChatMessage newMsg(client->GetClientNum(), client->GetName(), 0,
            //    msg.sText, msg.iChatType, msg.translate);
              //newMsg.SendMessage();
              saveFlood = false;

              gemObject *target = client->GetTargetObject();
              gemNPC *targetnpc = dynamic_cast<gemNPC*>(target);
              NpcResponse *resp = CheckNPCResponse(msg,client,targetnpc);
              if (resp)
              {
                  csTicks delay = resp->ExecuteScript(client->GetActor(), targetnpc);
                  if (delay != (csTicks)-1 && resp->menu )
                      resp->menu->ShowMenu(client, delay, targetnpc);
              }
              break;
          }
          case CHAT_AWAY:
          {
              saveFlood = false; //do not check Away messages for flooding
              msg.iChatType = CHAT_TELL; //do regard it as tell message from now on
              //intentionally no break, so it falls through to CHAT_TELL
          }
          case CHAT_TELL:
          {
              if ( msg.sPerson.Length() == 0 )
              {
                  psserver->SendSystemError(client->GetClientNum(), "You must specify name of player.");
                  break;
              }

              Client *target = FindPlayerClient(msg.sPerson);
              if (target && !target->IsSuperClient())
              {
                  if (!target->IsReady())
                      psserver->SendSystemError(client->GetClientNum(), "%s is not ready yet.", msg.sPerson.GetDataSafe());
                  else
                      SendTell(msg, client->GetName(), client, target);
              }
              else
                  psserver->SendSystemError(client->GetClientNum(), "%s is not found online.", msg.sPerson.GetDataSafe());

              break;
          }
          case CHAT_REPORT:
          {
              // First thing to extract the name of the player to log
              csString targetName;
              int index = (int)msg.sText.FindFirst(' ', 0);
              targetName = (index == -1) ? msg.sText : msg.sText.Slice(0, index);
              targetName = NormalizeCharacterName(targetName);

              if ( targetName.Length() == 0 )
              {
                  psserver->SendSystemError(client->GetClientNum(), "You must specify name of player.");
                  break;
              }

              Client * target = psserver->GetConnections()->Find(targetName);
              if ( !target )
              {
                  psserver->SendSystemError(client->GetClientNum(), "%s is not found online.", targetName.GetData());
                  break;
              }
              if (target->IsSuperClient())
              {
                  psserver->SendSystemError(client->GetClientNum(), "Can't report NPCs.");
                  break;
              }

              // Add an active report to the target.
              if (target->GetActor()->AddChatReport(client->GetActor()))
              {
                  // Add report removal event.
                  psserver->GetEventManager()->Push(new psEndChatLoggingEvent(target->GetClientNum(), 300000));
                  psserver->SendSystemInfo(client->GetClientNum(), "Last 5 minutes of %s's chat were logged. Logging will continue for another 5 minutes.", targetName.GetData());
              }
              else
                  psserver->SendSystemError(client->GetClientNum(), "Could not start logging %s, due to a server error.", targetName.GetData());
              break;
         }
         case CHAT_ADVISOR:
         case CHAT_ADVICE:
             break;

         default:
         {
              Error2("Unknown Chat Type: %d\n",msg.iChatType);
              break;
         }
       }
    }
    else
    {
        //User is muted but tries to chat anyway. Remind the user that he/she/it is muted
        psserver->SendSystemInfo(client->GetClientNum(),"You can't send messages because you are muted.");
    }

    if (saveFlood)
        client->FloodControl(msg.iChatType, msg.sText, msg.sPerson);
}
예제 #15
0
int Client::GetTargetType(gemObject* target)
{
    if (!target)
    {
        return TARGET_NONE; /* No Target */
    }

    if (target->GetActorPtr() == NULL)
    {
        return TARGET_ITEM; /* Item */
    }

    if (!target->IsAlive())
    {
        return TARGET_DEAD;
    }

    if (IsGM())
    {
        // GMs can interpret targets as either friends or foe...even self.
        // This allows them to attack or cast spells on anyone.
        return TARGET_SELF | TARGET_FRIEND | TARGET_FOE;
    }

    if (GetActor() == target)
    {
        return TARGET_SELF; /* Self */
    }

    if (target->GetCharacterData()->impervious_to_attack)
    {
        return TARGET_FRIEND; /* Impervious NPC */
    }

    // Is target a NPC?
    Client* targetclient = psserver->GetNetManager()->GetAnyClient(target->GetClientID());
    if (!targetclient)
    {
        if (target->GetCharacterData()->IsPet())
        {
            // Pet's target type depends on its owner's (enable when they can defend themselves)
            gemObject* owner = GEMSupervisor::GetSingleton().FindPlayerEntity( target->GetCharacterData()->GetOwnerID() );
            if ( !owner || !IsAllowedToAttack(owner,false) )
                return TARGET_FRIEND;
        }
        return TARGET_FOE; /* Foe */
    }

    if (targetclient->GetActor()->GetInvincibility())
        return TARGET_FRIEND; /* Invincible GM */

    if (targetclient->GetActor()->attackable)
        return TARGET_FOE; /* attackable GM */

    // Challenged to a duel?
    if (IsDuelClient(target->GetClientID())
        || targetclient->IsDuelClient(clientnum))
    {
        return TARGET_FOE; /* Attackable player */
    }

    // In PvP region?
    csVector3 attackerpos, targetpos;
    float yrot;
    iSector* attackersector, *targetsector;
    GetActor()->GetPosition(attackerpos, yrot, attackersector);
    target->GetPosition(targetpos, yrot, targetsector);

    if (psserver->GetCombatManager()->InPVPRegion(attackerpos,attackersector)
        && psserver->GetCombatManager()->InPVPRegion(targetpos,targetsector))
    {
        return TARGET_FOE; /* Attackable player */
    }

    // Is this a player who has hit you and run out of a PVP area?
    for (size_t i=0; i< GetActor()->GetDamageHistoryCount(); i++)
    {
        const DamageHistory *dh = GetActor()->GetDamageHistory((int)i);
        // If the target has ever hit you, you can attack them back.  Logging out clears this.
        if (dh->attacker_ref.IsValid() && dh->attacker_ref->GetActorPtr() == target)
            return TARGET_FOE;
    }

    // Declared war?
    psGuildInfo* attackguild = GetActor()->GetGuild();
    psGuildInfo* targetguild = targetclient->GetActor()->GetGuild();
    if (attackguild && targetguild &&
        targetguild->IsGuildWarActive(attackguild))
    {
        return TARGET_FOE; /* Attackable player */
    }
    
    if(GetActor()->InGroup() && targetclient->GetActor()->InGroup())
    {
        csRef<PlayerGroup> AttackerGroup = GetActor()->GetGroup();
        csRef<PlayerGroup> TargetGroup = targetclient->GetActor()->GetGroup();
        if(AttackerGroup->IsInDuelWith(TargetGroup))
            return TARGET_FOE;
    }

    return TARGET_FRIEND; /* Friend */
}