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(); } }
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); } }
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; }
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 ); }
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; }
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(); }
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(); }
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); } }
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; }
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."); } }
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."); } }
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); }
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(); }
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); }
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 */ }