/* * Advicemanager.cpp * * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation (version 2 of the License) * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include #include "client.h" #include "clients.h" #include "psserver.h" #include "playergroup.h" #include "util/serverconsole.h" #include "gem.h" #include "util/eventmanager.h" #include "netmanager.h" #include "util/pserror.h" #include "util/log.h" #include "util/strutil.h" #include "globals.h" #include "advicemanager.h" #include "bulkobjects/pscharacterloader.h" /** * This class is the relationship of Advisor to Advisee. */ class AdviceSession : public iDeleteObjectCallback { protected: csWeakRef advisor, // Safe reference to the client who has indicated they can assist other users. advisee; // Safe refereneces to the client who is requesting help. AdviceManager *manager; // The parent controller public: uint32_t AdvisorClientNum; // cache the client number for the Advisor uint32_t AdviseeClientNum; // cache the client number for the Advisee csString adviseeName; // cache the name of the advisee psAdviceRequestTimeoutGameEvent *requestEvent; // event to cancel the current request psAdviceSessionTimeoutGameEvent *timeoutEvent; // event to cancel the current session csString lastRequest; // cache the text of the last request int status; // current status of the session -- this should be changed to an enum bool answered; // has the initial question been answered? int advisorPoints; // current value in advisor points for this session. int requestRetries; // how many times the current request has been resent. AdviceSession() { advisorPoints = 0; AdviseeClientNum = (uint32_t)-1; AdvisorClientNum = (uint32_t)-1; requestRetries = 0; answered = false; status = SESSION_STATUS_UNKNOWN; timeoutEvent = NULL; requestEvent = NULL; }; AdviceSession( AdviceManager *mgr, Client *Advisor, Client *Advisee, const char *request) { manager = mgr; requestEvent = NULL; timeoutEvent = NULL; AdviseeClientNum = (uint32_t)-1; AdvisorClientNum = (uint32_t)-1; advisorPoints = 1; requestRetries = 0; SetAdvisor( Advisor ); if (Advisee) { advisee = Advisee; AdviseeClientNum = Advisee->GetClientNum(); adviseeName = Advisee->GetName(); advisee->GetActor()->RegisterCallback( this ); } lastRequest = request; answered = false; status = SESSION_STATUS_UNKNOWN; }; virtual ~AdviceSession() { if ( advisor.IsValid()) advisor->GetActor()->UnregisterCallback( this ); if ( advisee.IsValid()) advisee->GetActor()->UnregisterCallback( this ); // Cancel any timeouts tied to this session if ( timeoutEvent ) timeoutEvent->valid = false; if ( requestEvent ) requestEvent->valid = false; }; Client* GetAdvisee() { return advisee; }; void SetAdvisor( Client *newAdvisor) { // A NULL advisor is valid here, just clear the current advisor and return if ( newAdvisor == NULL ) { RemoveAdvisor(); return; } // if there is a current advisor, unattach ourselves if ( advisor.IsValid() ) advisor->GetActor()->UnregisterCallback( this ); // assign new advisor advisor = newAdvisor; AdvisorClientNum = advisor->GetClientNum(); advisor->GetActor()->RegisterCallback( this ); }; Client* GetAdvisor() { return advisor; }; void RemoveAdvisor() { advisorPoints = 1; if ( advisor.IsValid() ) advisor->GetActor()->UnregisterCallback( this ); advisor = NULL; AdvisorClientNum = (uint32_t)-1; }; virtual void DeleteObjectCallback(iDeleteNotificationObject * object) { gemActor *sender = (gemActor *)object; if ( advisor.IsValid() && sender == advisor->GetActor() ) { manager->CancelAdvisorSession( sender, this, "been canceled" ); SetAdvisor( NULL ); manager->RemoveSession( this ); } else if ( advisee.IsValid() && sender == advisee->GetActor() ) { manager->CancelAdvisorSession( sender, this, "been canceled" ); SetAdvisor( NULL ); advisee->GetActor()->UnregisterCallback( this ); manager->RemoveSession( this ); } }; void SessionTimeout() { manager->CancelAdvisorSession( NULL, this, "timed out" ); RemoveAdvisor(); }; // The == and < operators for BinaryTree<> MUST be the same criteria! int operator==(AdviceSession& other) const { return (AdviseeClientNum == other.AdviseeClientNum); }; int operator<(AdviceSession& other) const { return (AdviseeClientNum < other.AdviseeClientNum); }; }; /****************************************************************************/ psAdviceRequestTimeoutGameEvent::psAdviceRequestTimeoutGameEvent( AdviceManager *mgr, int delayticks, gemActor *advisee, AdviceSession *adviceRequest ) : psGEMEvent( 0, delayticks, NULL,"psAdviceRequestTimeoutGameEvent" ) { advicemanager = mgr; adviceSession = adviceRequest; //Handle dependencies ourselves since we have two. if ( adviceSession->GetAdvisee() ) { adviseeActor = adviceSession->GetAdvisee()->GetActor(); if ( adviseeActor ) adviseeActor->RegisterCallback( this ); } else adviseeActor = NULL; if ( adviceSession->GetAdvisor() ) { advisorActor = adviceSession->GetAdvisor()->GetActor(); if ( advisorActor ) advisorActor->RegisterCallback( this ); } else advisorActor = NULL; }; psAdviceRequestTimeoutGameEvent::~psAdviceRequestTimeoutGameEvent() { if ( adviseeActor != NULL ) adviseeActor->UnregisterCallback( this ); adviseeActor = NULL; if ( advisorActor != NULL ) advisorActor->UnregisterCallback( this ); advisorActor = NULL; if ( adviceSession->requestEvent == this ) adviceSession->requestEvent = NULL; } void psAdviceRequestTimeoutGameEvent::DeleteObjectCallback(iDeleteNotificationObject * object) { gemActor *sender = (gemActor *)object; if ( adviseeActor ) { if ( sender == adviseeActor ) { psGEMEvent::DeleteObjectCallback( object ); adviseeActor->UnregisterCallback( this ); if ( advisorActor ) advisorActor->UnregisterCallback( this ); adviseeActor = advisorActor = NULL; return; } } if ( advisorActor ) { if ( sender == advisorActor ) { advisorActor->UnregisterCallback( this ); advisorActor = NULL; adviceSession->RemoveAdvisor(); advicemanager->AdviceRequestTimeout( adviceSession ); } } } void psAdviceRequestTimeoutGameEvent::Trigger() { advicemanager->AdviceRequestTimeout( adviceSession ); }; /****************************************************************************/ /****************************************************************************/ psAdviceSessionTimeoutGameEvent::psAdviceSessionTimeoutGameEvent( AdviceManager *mgr, int delayticks, gemActor *advisee, AdviceSession *adviceRequest) : psGEMEvent( 0, delayticks, NULL,"psAdviceSessionTimeoutGameEvent" ) { adviseeActor = NULL; advisorActor = NULL; advicemanager = mgr; adviceSession = adviceRequest; //Handle dependencies ourselves since we have two. if ( adviceSession->GetAdvisee() != NULL ) { adviseeActor = adviceSession->GetAdvisee()->GetActor(); if ( adviseeActor ) adviseeActor->RegisterCallback( this ); } // This should only happen when this is an unanswered question. // This event is canceled and recreated each time there is any activity on the session, // so this should be filled in when an advisor either claims or answers the question. if ( adviceSession->GetAdvisor() != NULL ) { advisorActor = adviceSession->GetAdvisor()->GetActor(); if ( advisorActor ) advisorActor->RegisterCallback( this ); } }; psAdviceSessionTimeoutGameEvent::~psAdviceSessionTimeoutGameEvent() { if ( adviseeActor != NULL ) adviseeActor->UnregisterCallback( this ); adviseeActor = NULL; if ( advisorActor != NULL ) advisorActor->UnregisterCallback( this ); advisorActor = NULL; if ( adviceSession->timeoutEvent == this )adviceSession->timeoutEvent = NULL; } void psAdviceSessionTimeoutGameEvent::DeleteObjectCallback(iDeleteNotificationObject * object) { psGEMEvent::DeleteObjectCallback(object); //Handle dependencies ourselves since we have two. if ( adviseeActor != NULL) adviseeActor->UnregisterCallback( this ); adviseeActor = NULL; if ( advisorActor != NULL ) advisorActor->UnregisterCallback( this ); advisorActor = NULL; }; void psAdviceSessionTimeoutGameEvent::Trigger() { adviceSession->SessionTimeout(); }; /****************************************************************************/ AdviceManager::AdviceManager(psDatabase *db) { advisors.Empty(); advisorPos = 0; database = db; psserver->GetEventManager()->Subscribe( this, MSGTYPE_ADVICE,REQUIRE_READY_CLIENT ); } AdviceManager::~AdviceManager() { psserver->GetEventManager()->Unsubscribe( this, MSGTYPE_ADVICE ); } void AdviceManager::HandleMessage(MsgEntry *me,Client *client) { psAdviceMessage msg(me); if (!msg.valid) { psserver->SendSystemError(me->clientnum, "Invalid AdviceRequest Message."); Error2("Failed to parse psAdviceRequestMsg from client %u.",me->clientnum); return; } if ( msg.sCommand == "/advisormode" ) { if ( msg.sMessage == "on" ) { AddAdvisor(client); } else if ( msg.sMessage == "off" ) { RemoveAdvisor(client->GetClientNum(), me->clientnum); } else if ( msg.sMessage == "listsessions" ) { //psserver->SendSystemInfo(client->GetClientNum(), "This command is under construction."); HandleAdviseeList( client ); } else { if (client->GetAdvisor()) { psserver->SendSystemInfo(client->GetClientNum(),"You are an advisor."); } else { psserver->SendSystemInfo(client->GetClientNum(),"You are not an advisor."); } } } else if ( msg.sCommand == "/list_advice_requests" ) { HandleAdviceList( client ); } else if ( msg.sCommand == "/advisor" ) { if (!client->IsMute()) { HandleAdviceRequest( client, msg.sMessage ); } 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."); } FloodControl( msg.sMessage, client ); } else if ( msg.sCommand == "/advice" ) { if (!client->IsMute()) { HandleAdviceResponse( client, msg.sTarget, msg.sMessage ); } 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 ( msg.sMessage.Length() != 0 ) FloodControl( msg.sMessage, client ); } } bool AdviceManager::FloodControl(csString& newmessage, Client *client) { size_t count=0; //Shovel 1 back client->ShovelFlood(newmessage); //Delete everything older than 10 (or if other defined) secs client->CheckBuffer(); for (int i = 0; i <= (int)(client->GetFloodMax()-1); i++) { if (client->GetFlood(i).str==newmessage) count++; } //Now when the loops is finished, check what count is if (count==client->GetFloodWarn()) { psserver->SendSystemInfo(client->GetClientNum(),"Flood warning. Stop or you will be muted."); } if (count==client->GetFloodMax()) { client->SetMute(true); client->ClearFlood(); psserver->SendSystemInfo(client->GetClientNum(),"BAM! Muted."); return false; } return true; } void AdviceManager::HandleAdviseeList( Client *advisor ) { if ( !advisor->GetAdvisor() ) { psserver->SendSystemInfo(advisor->GetClientNum(),"You need to be an advisor to use this command."); return; } // find existing Advicee in the List AdviceSession *activeSession; csString message("You are currently advising:"); BinaryRBIterator< AdviceSession > loop( &AdviseeList ); bool found = false; for ( activeSession = loop.First(); activeSession; activeSession = ++loop ) { if (activeSession && activeSession->adviseeName.GetData() && activeSession->AdvisorClientNum == advisor->GetClientNum() ) { message.Append("\n " ); message.Append( activeSession->adviseeName.GetData() ); found = true; } else { // bad activeSession here } } if ( !found ) message.Append("\n noone"); psserver->SendSystemInfo(advisor->GetClientNum(), message.GetData() ); } void AdviceManager::HandleAdviceList( Client *advisor ) { if ( !advisor->GetAdvisor() ) { psserver->SendSystemInfo(advisor->GetClientNum(),"You need to be an advisor to use this command."); return; } // find existing Advicee in the List AdviceSession *activeSession; BinaryRBIterator< AdviceSession > loop( &AdviseeList ); bool found = false; for ( activeSession = loop.First(); activeSession; activeSession = ++loop ) { if (activeSession && activeSession->adviseeName.GetData() && activeSession->lastRequest.GetData() && activeSession->status == SESSION_STATUS_UNKNOWN) { psChatMessage msgAdvisor( advisor->GetClientNum(), activeSession->adviseeName, activeSession->lastRequest, CHAT_ADVICE_LIST, false); msgAdvisor.SendMessage(); found = true; } else { // bad activeSession here } } if ( !found ) psserver->SendSystemInfo(advisor->GetClientNum(),"There are no messengers waiting for an advisor."); } void AdviceManager::HandleAdviceRequest( Client *advisee, csString message ) { CPrintf(CON_DEBUG,"User asked for advice.\n"); // psserver->SendSystemInfo( advisee->GetClientNum(), "Sorry for the inconvenience, you cannot request advice right now. The advice system is under maintenaince and will be available after a server restart soon."); // return; if ( advisee->GetAdvisor() ) { psserver->SendSystemInfo( advisee->GetClientNum(), "You cannot request advice while you are an advisor. Lay down your advisor role using \"/advisormode off\", then request advice."); return; } if ( advisors.Length() == 0) //No advisors are online { //Send back an message that there is no advisor online psserver->SendSystemInfo( advisee->GetClientNum(),"The world has no advisors at the moment. You are now allowed to shout your question to other players. You can do it this way \"/shout \"."); return; } // find existing Advicee in the List AdviceSession key; key.AdviseeClientNum = advisee->GetClientNum(); AdviceSession *activeSession = AdviseeList.Find(&key); // Create an adviceSession if one doesn't exist if ( !activeSession ) { Debug2( LOG_ANY, advisee->GetClientNum(), "Creating AdviceSession for %d", advisee->GetClientNum() ); activeSession = new AdviceSession( this, NULL, advisee, message ); AdviseeList.Insert(activeSession); // Advice is no longer pending. } else { // One unadvised unanswered question at a time if ( ( activeSession->GetAdvisor() == NULL ) && ( activeSession->answered == false ) ) { psserver->SendSystemError(advisee->GetClientNum(), "Please wait for an advisor to respond to your previous inquiry before asking another question."); return; } } // Create psAdviceRequestTimeoutGameEvent to timout question. if ( activeSession && activeSession->requestEvent == NULL ) { WordArray words(message); // Check to make sure the request is 'good' if ( words.GetCount() < 2 ) { psserver->SendSystemInfo(advisee->GetClientNum(), "An Advisor will need more information than this to help you, please include as much as you can in your request."); activeSession->answered = true; return; } psAdviceRequestTimeoutGameEvent *ev = new psAdviceRequestTimeoutGameEvent( this, ADVICE_QUESTION_TIMEOUT, advisee->GetActor(), activeSession ); activeSession->requestEvent = ev; psserver->GetEventManager()->Push(ev); activeSession->answered = false; } else if ( activeSession ) { 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); } activeSession->lastRequest = message; csString buf; if ( activeSession->AdvisorClientNum != (uint32_t)-1 ) { // Source Client Name, Target Client Name, Message buf.Format("%s, %s, \"%s\"", advisee->GetName(), activeSession->GetAdvisor()->GetActor()->GetName(), message.GetData() ); psserver->GetLogCSV()->Write(CSV_ADVICE, buf); psChatMessage msgAdvisor( activeSession->AdvisorClientNum, advisee->GetName(), message , CHAT_ADVICE, false ); msgAdvisor.SendMessage(); } else { // Source Client Name, Target Client Name, Message buf.Format("%s, %s, \"%s\"", advisee->GetName(), "All Advisors", message.GetData() ); psserver->GetLogCSV()->Write(CSV_ADVICE, buf); for (size_t i = 0; i < advisors.Length(); i++) { psChatMessage msgAdvisor( advisors[i].id, advisee->GetName(), message, CHAT_ADVICE, false); msgAdvisor.SendMessage(); } } psChatMessage msgChat( advisee->GetClientNum() , advisee->GetName(), message, CHAT_ADVICE, false); msgChat.SendMessage(); } 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; } CPrintf(CON_DEBUG,"Advisor has responded.\n"); 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.Find(&key); 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; BinaryRBIterator< AdviceSession > loop( &AdviseeList ); for ( loopSession = loop.First(); loopSession; loopSession = ++loop ) { if (loopSession && 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.Length(); 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,advisor->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.Length(); i++) { if ( advisors[i].id != activeSession->AdvisorClientNum ) { psserver->SendSystemInfo( advisors[i].id, "%s has been assigned to %s.", advisee->GetName(), advisor->GetName() ); 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(); } // 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 AdviceManager::AddAdvisor(Client *client) { uint32_t id = client->GetClientNum(); // make sure we didn't do an "/advisormode on" twice... for (size_t i = 0; i < advisors.Length(); i++) { if ( id == advisors[i].id) return; } //check to see if there is an advice session from this user, and close it AdviceSession key; key.AdviseeClientNum = id; AdviceSession *adviceSession = AdviseeList.Find(&key); if (adviceSession) { CancelAdvisorSession( NULL, adviceSession, "been canceled" ); RemoveSession( adviceSession ); } // Create new Advisor structure AdvisorStruct advisor; advisor.id = id; advisor.ready = true; advisors.Push(advisor); if ( client ) client->SetAdvisor( true ); //Send message to advisor that he/she is an advisor psserver->SendSystemInfo(id,"Your request to become an advisor has been granted."); //psserver->SendSystemInfo(id, "You currently have %d advisor points.", client->GetAdvisorPoints() ); CPrintf(CON_DEBUG,"Advisor has been added\n"); } void AdviceManager::RemoveAdvisor(uint32_t id, int connectionId) { //Remove an advisor for (size_t i = 0; i < advisors.Length(); i++) { if (advisors[i].id == id) { Client * client = psserver->GetConnections()->Find(advisors[i].id); if (client) client->SetAdvisor( false ); advisors.DeleteIndex(i); break; } } // find existing Advisee in the List AdviceSession key; key.AdvisorClientNum = id; key.AdviseeClientNum = 0; AdviceSession *activeSession = AdviseeList.Find(&key); while ( activeSession ) { // Notify advisee his/her advisor is no longer available. CancelAdvisorSession( NULL, activeSession, "been canceled"); RemoveSession( activeSession ); activeSession = AdviseeList.Find(&key); } //Send message to non-advisor that he/she isn't an advisor any more psserver->SendSystemInfo(connectionId,"You have just laid down your advisor role."); CPrintf(CON_DEBUG,"Advisor has been removed\n"); } 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,adviseeClient->GetName(), adviceSession->lastRequest, CHAT_ADVICE_LIST, false); msgAdvisor.SendMessage(); } else { for (size_t i = 0; i < advisors.Length(); i++) { psserver->SendSystemInfo(advisors[i].id,"%s's messenger taps his foot impatiently.",adviseeClient->GetName()); //psChatMessage msgAdvisor(advisors[i].client_id,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::CancelAdvisorSession(gemActor *who, AdviceSession *adviceSession, const char * msg) { CPrintf(CON_DEBUG, "Advice session cancelling now.\n"); if ( adviceSession->GetAdvisee() ) { if ( ( who == NULL ) || (adviceSession->GetAdvisor() && who == adviceSession->GetAdvisor()->GetActor() ) ) { if ( adviceSession->AdviseeClientNum != (uint32_t)-1 ) { psserver->SendSystemInfo(adviceSession->AdviseeClientNum,"Your advice session has %s.", msg); switch ( adviceSession->status ) { case SESSION_STATUS_OWNED: psserver->SendSystemInfo(adviceSession->AdviseeClientNum,"Your next request may be handled by a different advisor."); if ( adviceSession->requestEvent) { adviceSession->requestEvent->valid = false; adviceSession->requestEvent = NULL; } adviceSession->answered = true; break; case SESSION_STATUS_CLAIMED: psserver->SendSystemInfo(adviceSession->AdviseeClientNum,"Your request will be sent to all advisors."); break; case SESSION_STATUS_UNKNOWN: break; } } } } if ( adviceSession->GetAdvisor() ) { if ( ( who == NULL ) || ( ( adviceSession->GetAdvisee() && who == adviceSession->GetAdvisee()->GetActor() ) ) ) { if ( adviceSession->AdvisorClientNum != (uint32_t)-1 ) { if ( who == adviceSession->GetAdvisor()->GetActor() || who == NULL ) { switch ( adviceSession->status ) { case SESSION_STATUS_OWNED: psserver->SendSystemInfo(adviceSession->AdvisorClientNum,"Your advice session with %s has %s.",adviceSession->adviseeName.GetData(), msg); break; case SESSION_STATUS_CLAIMED: psserver->SendSystemInfo(adviceSession->AdvisorClientNum,"You have forfieted your session with %s.",adviceSession->adviseeName.GetData()); // Notify all other advisors for ( size_t i = 0; i < advisors.Length(); i++ ) { if ( advisors[i].id != adviceSession->AdvisorClientNum ) psserver->SendSystemInfo(advisors[i].id,"%s has relinquished their claim as %s's advisor.",adviceSession->GetAdvisor()->GetName(), adviceSession->adviseeName.GetData() ); } adviceSession->SetAdvisor( NULL ); break; case SESSION_STATUS_UNKNOWN: break; } } else { psserver->SendSystemInfo(adviceSession->AdvisorClientNum,"Your advice session with %s has %s.",adviceSession->adviseeName.GetData(), msg); } } } } adviceSession->status = SESSION_STATUS_UNKNOWN; } void AdviceManager::RemoveSession( AdviceSession * adviceSession) { Debug2( LOG_ANY, adviceSession->AdviseeClientNum, "Removing AdviceSession: ", adviceSession->AdviseeClientNum ); if (adviceSession->requestEvent) { adviceSession->requestEvent->valid = false; adviceSession->requestEvent = NULL; } AdviseeList.Delete( adviceSession ); delete adviceSession; } #if 0 bool AdviceManager::GetAdvisorMode( int id, int connectionId ) { //Search loop that will found the right advisor nr in the advisors array and use it as an id for (size_t i = 0; i < advisors.Length(); i++) { if ( ( advisors[i].id == id ) ) return true; } return false; } #endif