void ChatManager::SendTell(psChatMessage& msg, const char* who,Client *client,Client *target) { Debug2(LOG_CHAT, client->GetClientNum(), "SendTell: %s!", msg.sText.GetDataSafe()); // Sanity check that we are sending to correct clientnum! csString targetName = msg.sPerson; targetName = NormalizeCharacterName(targetName); CS_ASSERT(strcasecmp(target->GetName(), targetName) == 0); // Create a new message and send it to that person if found psChatMessage cmsg(target->GetClientNum(), client->GetActor()->GetEID(), who, 0, msg.sText, msg.iChatType, msg.translate); cmsg.SendMessage(); // Echo the message back to the speaker also psChatMessage cmsg2(client->GetClientNum(), client->GetActor()->GetEID(), targetName, 0, msg.sText, CHAT_TELLSELF, msg.translate); cmsg2.SendMessage(); // Save to both actors' chat history (PS#2789) client->GetActor()->LogChatMessage(who, msg); target->GetActor()->LogChatMessage(who, msg); }
void CharCreationManager::HandleUploadMessage(MsgEntry* me, Client* client) { Debug1(LOG_NEWCHAR, me->clientnum,"New Character is being created"); psCharUploadMessage upload(me); if(!upload.valid) { Debug2(LOG_NET,me->clientnum,"Received unparsable psUploadMessage from client %u.",me->clientnum); return; } AccountID acctID = client->GetAccountID(); if(!acctID.IsValid()) { Error2("Player tried to upload a character to unknown account %s.", ShowID(acctID)); psCharRejectedMessage reject(me->clientnum); psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET); psserver->RemovePlayer(me->clientnum,"Could not find your account."); return; } // Check to see if the player already has 4 accounts; csString query; query.Format("SELECT id FROM characters WHERE account_id=%d", acctID.Unbox()); Result result(db->Select(query)); if(result.IsValid() && result.Count() >= CHARACTERS_ALLOWED) { psserver->RemovePlayer(me->clientnum,"At your character limit."); return; } csString playerName = upload.name; csString lastName = upload.lastname; playerName = NormalizeCharacterName(playerName); lastName = NormalizeCharacterName(lastName); // Check banned names if(psserver->GetCharManager()->IsBanned(playerName)) { csString error; error.Format("The name %s is banned", playerName.GetData()); psCharRejectedMessage reject(me->clientnum, psCharRejectedMessage::RESERVED_NAME, (char*)error.GetData()); reject.SendMessage(); return; } if(psserver->GetCharManager()->IsBanned(lastName)) { csString error; error.Format("The lastname %s is banned", lastName.GetData()); psCharRejectedMessage reject(me->clientnum, psCharRejectedMessage::RESERVED_NAME, (char*)error.GetData()); reject.SendMessage(); return; } Debug3(LOG_NEWCHAR, me->clientnum,"Got player firstname (%s) and lastname (%s)\n",playerName.GetData(), lastName.GetData()); /////////////////////////////////////////////////////////////// // Check to see if the player name is valid /////////////////////////////////////////////////////////////// if(playerName.Length() == 0 || !FilterName(playerName)) { psCharRejectedMessage reject(me->clientnum, psCharRejectedMessage::NON_LEGAL_NAME, "The name you specifed is not a legal player name."); psserver->GetEventManager()->SendMessage(reject.msg); return; } if(lastName.Length() != 0 && !FilterName(lastName)) { psCharRejectedMessage reject(me->clientnum, psCharRejectedMessage::NON_LEGAL_NAME, "The name you specifed is not a legal lastname."); psserver->GetEventManager()->SendMessage(reject.msg); return; } Debug2(LOG_NEWCHAR, me->clientnum,"Checking player firstname '%s'..\n",playerName.GetData()); /////////////////////////////////////////////////////////////// // Check to see if the character name is unique in 'characters'. /////////////////////////////////////////////////////////////// if(!IsUnique(playerName)) { psCharRejectedMessage reject(me->clientnum, psCharRejectedMessage::NON_UNIQUE_NAME, "The firstname you specifed is not unique."); psserver->GetEventManager()->SendMessage(reject.msg); return; } if(lastName.Length()) { Debug2(LOG_NEWCHAR, me->clientnum,"Checking player lastname '%s'..\n",lastName.GetData()); if(!IsLastNameAvailable(lastName, acctID)) { psCharRejectedMessage reject(me->clientnum, psCharRejectedMessage::NON_UNIQUE_NAME, "The lastname you specifed is not unique."); psserver->GetEventManager()->SendMessage(reject.msg); return; } } /////////////////////////////////////////////////////////////// // Check to see if the character name is on the reserve list. /////////////////////////////////////////////////////////////// int reservedName = IsReserved(playerName, acctID); if(reservedName == NAME_RESERVED) { csString error; error.Format("The name %s is reserved", playerName.GetData()); psCharRejectedMessage reject(me->clientnum, psCharRejectedMessage::RESERVED_NAME, (char*)error.GetData()); psserver->GetEventManager()->SendMessage(reject.msg); return; } csString error; if(!psserver->charCreationManager->Validate(upload, error)) { error.Append(", your creation choices are invalid."); psCharRejectedMessage reject(me->clientnum, psCharRejectedMessage::INVALID_CREATION, (char*)error.GetData()); reject.SendMessage(); return; } /////////////////////////////////////////////////////////////// // Create the psCharacter structure for the player. /////////////////////////////////////////////////////////////// psCharacter* chardata=new psCharacter(); chardata->SetCharType(PSCHARACTER_TYPE_PLAYER); chardata->SetFullName(playerName,lastName); chardata->SetCreationInfo(upload.bio); psRaceInfo* raceinfo=psserver->GetCacheManager()->GetRaceInfoByNameGender(upload.race, (PSCHARACTER_GENDER)upload.gender); if(raceinfo==NULL) { Error3("Invalid race/gender combination on character creation: Race='%d' Gender='%d'", upload.race, upload.gender); psCharRejectedMessage reject(me->clientnum); psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET); psserver->RemovePlayer(me->clientnum,"Player tried to create an invalid race/gender."); delete chardata; return; } chardata->SetRaceInfo(raceinfo); chardata->SetHitPoints(50.0); chardata->GetMaxHP().SetBase(0.0); chardata->GetMaxMana().SetBase(0.0); //range is unused here float x,y,z,yrot,range; const char* sectorname; InstanceID newinstance = DEFAULT_INSTANCE; //get the option entries for tutorial from the server options. Note it's tutorial:variousdata optionEntry* tutorialEntry = psserver->GetCacheManager()->getOptionSafe("tutorial",""); sectorname = tutorialEntry->getOptionSafe("sectorname", "tutorial")->getValue(); psSectorInfo* sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName(sectorname); if(!sectorinfo || PlayerHasFinishedTutorial(acctID, sectorinfo->uid)) { raceinfo->GetStartingLocation(x,y,z,yrot,range,sectorname); sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName(sectorname); //As we aren't going in the tutorial disable the tutorial help messages disable them for(int i = 0; i < TutorialManager::TUTOREVENTTYPE_COUNT; i++) chardata->CompleteHelpEvent(i); } else { // Try tutorial level first. x = tutorialEntry->getOptionSafe("sectorx", "-225.37")->getValueAsDouble(); y = tutorialEntry->getOptionSafe("sectory", "-21.32")->getValueAsDouble(); z = tutorialEntry->getOptionSafe("sectorz", "26.79")->getValueAsDouble(); yrot = tutorialEntry->getOptionSafe("sectoryrot", "-2.04")->getValueAsDouble(); } bool sectorFound = true; if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name) == NULL) { Error2("Sector='%s' found but no map file was detected for it. Using NPCroom1", sectorname); sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName("NPCroom1"); if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name) == NULL) { Error1("NPCroom1 failed - Critical"); sectorFound = false; } else if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name)) { sectorFound = true; } else { sectorFound = false; } } else if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name)) { sectorFound = true; } else { sectorFound = false; } if(!sectorFound) { Error2("Unresolvable starting sector='%s'", sectorname); psCharRejectedMessage reject(me->clientnum); psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET); psserver->RemovePlayer(me->clientnum,"No starting Sector."); delete chardata; return; } chardata->SetLocationInWorld(newinstance, sectorinfo, x, y, z, yrot); psTrait* trait; // CPrintf(CON_DEBUG, "Trait: %d\n", upload.selectedFace ); trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedFace); if(trait) chardata->SetTraitForLocation(trait->location, trait); trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedHairStyle); if(trait) chardata->SetTraitForLocation(trait->location, trait); trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedBeardStyle); if(trait) chardata->SetTraitForLocation(trait->location, trait); trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedHairColour); if(trait) chardata->SetTraitForLocation(trait->location, trait); trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedSkinColour); if(trait) chardata->SetTraitForLocation(trait->location, trait); gemActor* actor = new gemActor(gemSupervisor, cacheManager, entityManager, chardata, raceinfo->mesh_name, newinstance, EntityManager::GetSingleton().FindSector(sectorinfo->name), csVector3(x,y,z),yrot, client->GetClientNum()); actor->SetupCharData(); if(!upload.verify) { if(!psServer::CharacterLoader.NewCharacterData(acctID,chardata)) { Error1("Character could not be created."); psCharRejectedMessage reject(me->clientnum); psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET); psserver->RemovePlayer(me->clientnum,"Your character could not be created in the database."); delete chardata; return; } } // Check to see if a path name was set. If so we will use that to generate // the character starting stats and skills. if(upload.path != "None") { // Progression Event name is PATH_PathName csString name("PATH_"); name.Append(upload.path); ProgressionScript* script = psserver->GetProgressionManager()->FindScript(name.GetData()); if(script) { // The script uses the race base character points to calculate starting stats. MathEnvironment env; env.Define("CharPoints", raceinfo->initialCP); env.Define("Actor", actor); script->Run(&env); } } else { //int cpUsage = psserver->charCreationManager->CalculateCPChoice( upload.choices ) + // psserver->charCreationManager->CalculateCPLife(upload.lifeEvents ); for(size_t ci = 0; ci < upload.choices.GetSize(); ci++) { CharCreationManager::CreationChoice* choice = psserver->charCreationManager->FindChoice(upload.choices[ci]); if(choice) { csString name(psserver->charCreationManager->FindChoice(upload.choices[ci])->name.GetData()); Debug3(LOG_NEWCHAR, me->clientnum,"Choice: %s Creation Script: %s", name.GetData(), choice->eventScript.GetData()); MathEnvironment env; env.Define("Actor", actor); if(choice->choiceArea == FATHER_JOB || choice->choiceArea == MOTHER_JOB) { int modifier = (choice->choiceArea == FATHER_JOB) ? upload.fatherMod : upload.motherMod; if(modifier > 3 || modifier < 1) modifier = 1; env.Define("ParentStatus", modifier); } ProgressionScript* script = psserver->GetProgressionManager()->FindScript(choice->eventScript); if(script) script->Run(&env); } else { Debug2(LOG_NEWCHAR, me->clientnum,"Character Choice %d not found\n", upload.choices[ci]); } } for(size_t li = 0; li < upload.lifeEvents.GetSize(); li++) { MathEnvironment env; env.Define("Actor", actor); LifeEventChoiceServer* lifeEvent = psserver->charCreationManager->FindLifeEvent(upload.lifeEvents[li]); if(!lifeEvent) { Error2("No LifeEvent Script found: %d", upload.lifeEvents[li]); continue; } csString scriptName(lifeEvent->eventScript.GetData()); Debug2(LOG_NEWCHAR, me->clientnum, "LifeEvent Script: %s", scriptName.GetDataSafe()); ProgressionScript* script = psserver->GetProgressionManager()->FindScript(scriptName); if(script) script->Run(&env); } } if(!upload.verify) { if(reservedName == NAME_RESERVED_FOR_YOU) { AssignScript(chardata); } // This function recalculates the Max HP, Mana and Stamina of the new character chardata->RecalculateStats(); // Make sure the new player have HP, Mana and Samina that was calculated chardata->SetHitPoints(chardata->GetMaxHP().Base()); chardata->SetMana(chardata->GetMaxMana().Base()); chardata->SetStamina(chardata->GetMaxPStamina().Base(),true); chardata->SetStamina(chardata->GetMaxMStamina().Base(),false); psServer::CharacterLoader.SaveCharacterData(chardata, actor); Debug1(LOG_NEWCHAR,me->clientnum,"Player Creation Complete"); // Remove cached objects to make sure that the client gets a fresh character // list from the database if it logs out and in within 2 minutes. iCachedObject* obj = psserver->GetCacheManager()->RemoveFromCache(psserver->GetCacheManager()->MakeCacheName("list",client->GetAccountID().Unbox())); if(obj) { obj->ProcessCacheTimeout(); obj->DeleteSelf(); } obj = psserver->GetCacheManager()->RemoveFromCache(psserver->GetCacheManager()->MakeCacheName("auth",client->GetAccountID().Unbox())); if(obj) { obj->ProcessCacheTimeout(); obj->DeleteSelf(); } // Here everything is ok client->SetPID(chardata->GetPID()); client->SetName(playerName); psCharApprovedMessage app(me->clientnum); if(app.valid) psserver->GetEventManager()->SendMessage(app.msg); else Bug2("Could not create valid psCharApprovedMessage for client %u.\n",me->clientnum); } else { psCharVerificationMesg mesg(me->clientnum); size_t z; //unfortunately count goes out of valid area so we need to check on charisma for(z = 0; z < psserver->GetCacheManager()->GetSkillAmount(); z++) { unsigned int rank = chardata->Skills().GetSkillRank((PSSKILL) z).Base(); psSkillInfo* info = psserver->GetCacheManager()->GetSkillByID(z); csString name("Not found"); if(info) name.Replace(info->name); if(rank > 0) { if(z >= PSSKILL_AGI && z <= PSSKILL_WILL) { mesg.AddStat(rank, name); } else { mesg.AddSkill(rank, name); } } } mesg.Construct(); mesg.SendMessage(); } delete actor; if(!upload.verify) { // Remove char data from the cache iCachedObject* obj = psserver->GetCacheManager()->RemoveFromCache(psserver->GetCacheManager()->MakeCacheName("char", chardata->GetPID().Unbox())); if(obj) { obj->ProcessCacheTimeout(); obj->DeleteSelf(); } } }
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 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); }