QString RealFormat::doFormat(const Variant& val) const { QString result; const LongReal* vr = dynamic_cast<const LongReal*>((const VariantData*)val); if (!vr) return result; if (vr->isNaN()) return formatNaN(); if (vr->isZero()) return formatZero(); int usedigits = significandbase == base || precision == 0? getDigits() : (precision - 1) / _digitsz(base) + 1; RawFloatIO RawFloatIO = vr->convert(usedigits, mode, base); if (RawFloatIO.error != Success) return result; result = getSignificandPrefix(RawFloatIO) + formatInt(RawFloatIO) + formatFrac(RawFloatIO) + getSignificandSuffix(RawFloatIO); if (useScale(RawFloatIO)) result += getScalePrefix(RawFloatIO) + formatScale(RawFloatIO) + getScaleSuffix(RawFloatIO); return result; }
void OTTrade::UpdateContents() { // I release this because I'm about to repopulate it. m_xmlUnsigned.Release(); const String NOTARY_ID(GetNotaryID()), NYM_ID(GetSenderNymID()), INSTRUMENT_DEFINITION_ID(GetInstrumentDefinitionID()), ASSET_ACCT_ID(GetSenderAcctID()), CURRENCY_TYPE_ID(GetCurrencyID()), CURRENCY_ACCT_ID(GetCurrencyAcctID()); Tag tag("trade"); tag.add_attribute("version", m_strVersion.Get()); tag.add_attribute("hasActivated", formatBool(hasTradeActivated_)); tag.add_attribute("notaryID", NOTARY_ID.Get()); tag.add_attribute("instrumentDefinitionID", INSTRUMENT_DEFINITION_ID.Get()); tag.add_attribute("assetAcctID", ASSET_ACCT_ID.Get()); tag.add_attribute("currencyTypeID", CURRENCY_TYPE_ID.Get()); tag.add_attribute("currencyAcctID", CURRENCY_ACCT_ID.Get()); tag.add_attribute("nymID", NYM_ID.Get()); tag.add_attribute("completedNoTrades", formatInt(tradesAlreadyDone_)); tag.add_attribute("transactionNum", formatLong(m_lTransactionNum)); tag.add_attribute("creationDate", formatTimestamp(GetCreationDate())); tag.add_attribute("validFrom", formatTimestamp(GetValidFrom())); tag.add_attribute("validTo", formatTimestamp(GetValidTo())); // There are "closing" transaction numbers, used to CLOSE a transaction. // Often where Cron items are involved such as this payment plan, or in // baskets, // where many asset accounts are involved and require receipts to be closed // out. for (int32_t i = 0; i < GetCountClosingNumbers(); i++) { int64_t closingNumber = GetClosingTransactionNoAt(i); OT_ASSERT(closingNumber > 0); TagPtr tagClosing(new Tag("closingTransactionNumber")); tagClosing->add_attribute("value", formatLong(closingNumber)); tag.add_tag(tagClosing); } if (('<' == stopSign_) || ('>' == stopSign_)) { TagPtr tagStopOrder(new Tag("stopOrder")); tagStopOrder->add_attribute("hasActivated", formatBool(stopActivated_)); tagStopOrder->add_attribute("sign", formatChar(stopSign_)); tagStopOrder->add_attribute("price", formatLong(stopPrice_)); tag.add_tag(tagStopOrder); } if (marketOffer_.Exists()) { OTASCIIArmor ascOffer(marketOffer_); tag.add_tag("offer", ascOffer.Get()); } std::string str_result; tag.output(str_result); m_xmlUnsigned.Concatenate("%s", str_result.c_str()); }
char *getData(){ int totmem = totalMemory(); char *TOTAL_MEMORY = formatInt(totmem); float freemem = freeMemory(); float usedmem = usedMemory(); char *FREE_MEMORY = formatFloat(freemem); char *USED_MEMORY = formatFloat(usedmem); double loadavg[1]; getloadavg(loadavg, 1); char *CPU_LOAD_AVG = formatDouble(loadavg[0] * 10); double cpuLoad = getCpuReading(); char *CPU_LOAD_CURR = formatDouble(cpuLoad); double cpuTemp = getCpuTemp(); char *CPU_TEMP = formatDouble(cpuTemp); char host[40];//cuts username off if more than 40 characters. gethostname(host, sizeof(host)); char HOSTNAME[40] ="|"; strcat(HOSTNAME,host); int hostlen = strlen(HOSTNAME); for (int s = hostlen; s <40; s++){//fill excess space to prevent overflows. strcpy(&HOSTNAME[s], " "); } char *data = new char[75]; //original 35 strcpy(data,HOSTNAME); strcat(data,TOTAL_MEMORY); strcat(data,FREE_MEMORY); strcat(data,USED_MEMORY); strcat(data,CPU_LOAD_AVG); strcat(data,CPU_LOAD_CURR); strcat(data,CPU_TEMP); return data; }
UnicodeString & DigitFormatter::formatPositiveInt32( int32_t positiveValue, const IntDigitCountRange &range, FieldPositionHandler &handler, UnicodeString &appendTo) const { // super fast path if (fIsStandardDigits && SmallIntFormatter::canFormat(positiveValue, range)) { int32_t begin = appendTo.length(); SmallIntFormatter::format(positiveValue, range, appendTo); handler.addAttribute(UNUM_INTEGER_FIELD, begin, appendTo.length()); return appendTo; } uint8_t digits[10]; int32_t count = formatInt(positiveValue, digits); return formatDigits( digits, count, range, UNUM_INTEGER_FIELD, handler, appendTo); }
bool Format::format( VMachine *vm, const Item &source, String &target ) { String sBuffer; switch( source.type() ) { case FLC_ITEM_NIL: switch( m_nilFormat ) { case e_nilEmpty: break; case e_nilNil: sBuffer = "Nil"; break; case e_nilN: sBuffer = "N"; break; case e_nilnil: sBuffer = "nil"; break; case e_nilNA: sBuffer = "N/A"; break; case e_nilNone: sBuffer = "None"; break; case e_nilNULL: sBuffer = "NULL"; break; case e_nilNull: sBuffer = "Null"; break; case e_nilPad: sBuffer.append( m_paddingChr ); } applyPad( sBuffer ); break; case FLC_ITEM_UNB: sBuffer = "_"; applyPad( sBuffer ); break; //================================================== // Parse an integer // case FLC_ITEM_INT: { int64 num = source.asInteger(); // number formats are compatible with string formats if ( m_convType != e_tNum && m_convType != e_tStr ) { return processMismatch( vm, source, target ); } formatInt( num, sBuffer, true ); // minus sign must be added AFTER padding with parentesis/fixed size or with *End signs, // else it must be added before. if ( negBeforePad() ) { applyNeg( sBuffer, num ); applyPad( sBuffer ); } else { applyPad( sBuffer, negPadSize( num ) ); applyNeg( sBuffer, num ); } } break; //================================================== // Parse double format // case FLC_ITEM_NUM: { numeric num = source.asNumeric(); // number formats are compatible with string formats if ( m_convType != e_tNum && m_convType != e_tStr ) { return processMismatch( vm, source, target ); } if( m_numFormat == e_scientific ) { formatScientific( num, sBuffer ); } else { double intPart, fractPart; bool bNeg, bIntIsZero; fractPart = modf( num, &intPart ); if ( intPart < 0.0 ) { intPart = -intPart; fractPart = -fractPart; bNeg = true; bIntIsZero = false; } else { bIntIsZero = intPart > 0.0 ? false : true; if ( fractPart < 0.0 ) { fractPart = -fractPart; // draw neg sign only if < 0 but int bNeg = true; } else bNeg = false; } String precPart; int base = 10; switch( m_numFormat ) { case e_binary: case e_binaryB: base = 2; break; case e_octalZero: case e_octal: base = 8; break; case e_cHexUpper: case e_hexUpper: case e_cHexLower: case e_hexLower: base = 16; break; default: break; } while( intPart > 9e14 ) { intPart /= base; precPart.append( '0' ); } // manual round if( (pow((double)10.0,-(m_decimals+1)) *5)+fractPart >=1.0) { intPart++; bIntIsZero = false; } uint8 decs = m_decimals; m_decimals = 0; formatInt( (int64) intPart, sBuffer, false ); sBuffer.append( precPart ); // now we can add the grouping if ( m_grouping > 0 ) { String token; token.append( m_thousandSep ); uint32 pos = sBuffer.size(); while( pos > m_grouping ) { pos -= m_grouping; sBuffer.insert( pos, 0, token ); } } // finally add decimals m_decimals = decs; if( base == 10 && m_decimals > 0 ) { char bufFmt[32]; char buffer[255]; sprintf( bufFmt, "%%.%df", m_decimals ); sprintf( buffer, bufFmt, fractPart ); sBuffer.append( m_decimalSep ); sBuffer.append( buffer + 2 ); } else if ( bIntIsZero ) { // do not print -0! bNeg = false; } // we must fix the number. num = bNeg ? -1.0 : 1.0; } // minus sign must be added AFTER padding with parentesis/fixed size or with *End signs, // else it must be added before. if ( negBeforePad() ) { applyNeg( sBuffer, (int64) num ); applyPad( sBuffer ); } else { applyPad( sBuffer, negPadSize( (int64) num ) ); applyNeg( sBuffer, (int64) num ); } } break; case FLC_ITEM_RANGE: { // number formats are compatible with string formats if ( m_convType != e_tNum && m_convType != e_tStr ) { return processMismatch( vm, source, target ); } int64 begin = source.asRangeStart(); String sBuf1, sBuf2, sBuf3; formatInt( begin, sBuf1, true ); //apply negative format now. applyNeg( sBuf1, (int64) begin ); if ( ! source.asRangeIsOpen() ) { int64 end = source.asRangeEnd(); formatInt( end, sBuf2, true ); applyNeg( sBuf2, (int64) end ); int64 step = source.asRangeStep(); if ( (begin <= end && step != 1) || (begin > end && step != -1 ) ) { formatInt( step, sBuf3, true ); applyNeg( sBuf3, (int64) step ); sBuffer = "[" + sBuf1 + ":" + sBuf2 + ":" + sBuf3 + "]"; } else sBuffer = "[" + sBuf1 + ":" + sBuf2 + "]"; } else sBuffer = "[" + sBuf1 + ":" + sBuf2 + "]"; applyPad( sBuffer ); } break; case FLC_ITEM_STRING: { // number formats are compatible with string formats if ( m_convType != e_tStr ) { return processMismatch( vm, source, target ); } sBuffer = *source.asString(); applyPad( sBuffer ); } break; case FLC_ITEM_OBJECT: { // try to format the object if( vm != 0 ) { if( m_posOfObjectFmt != String::npos ) { vm->itemToString( sBuffer, &source, m_originalFormat.subString( m_posOfObjectFmt + 1 ) ); } else { vm->itemToString( sBuffer, &source ); } } else { return processMismatch( vm, source, target ); } applyPad( sBuffer ); } break; default: return processMismatch( vm, source, target ); } // out of bounds? if ( m_size > 0 && m_fixedSize && sBuffer.length() > m_size ) { return false; } target += sBuffer; return true; }
void LeagueOverseer::Event (bz_EventData *eventData) { switch (eventData->eventType) { case bz_eAllowFlagGrab: // This event is called each time a player attempts to grab a flag { bz_AllowFlagGrabData_V1* allowFlagGrabData = (bz_AllowFlagGrabData_V1*)eventData; std::string flagAbbr = allowFlagGrabData->flagType; int playerID = allowFlagGrabData->playerID; if (isPcProtectionEnabled()) // Is the server configured to protect against Pass Camping { // Check if the last capture was within the 'PC_PROTECTION_DELAY' amount of seconds if (LAST_CAP + getPcProtectionDelay() > bz_getCurrentTime()) { // Check to see if the flag being grabbed belongs to the team that just had their flag captured AND check // to see if someone not from the victim team grabbed it if ((getTeamTypeFromFlag(flagAbbr) == CAP_VICTIM_TEAM && bz_getPlayerTeam(playerID) != CAP_VICTIM_TEAM)) { // Disallow the flag grab if it's being grabbed by an enemy right after a flag capture allowFlagGrabData->allow = false; } } } } break; case bz_eAllowSpawn: // This event is called before a player respawns { bz_AllowSpawnData_V2* allowSpawnData = (bz_AllowSpawnData_V2*)eventData; int playerID = allowSpawnData->playerID; if (!pluginSettings.isGuestSpawningEnabled(getCurrentGameMode()) && !isLeagueMember(playerID)) { // Disable their spawning privileges allowSpawnData->handled = true; allowSpawnData->allow = false; allowSpawnData->kickPlayer = false; sendPluginMessage(playerID, pluginSettings.getGuestSpawningMessage(getCurrentGameMode())); } } break; case bz_eBZDBChange: // This event is called each time a BZDB variable is changed { bz_BZDBChangeData_V1* bzdbData = (bz_BZDBChangeData_V1*)eventData; if (bzdbData->key == "_pcProtectionDelay") { // Save the proposed value in a variable for easy access int proposedValue = std::stoi(bzdbData->value.c_str()); // Our PC protection delay should be between 3 and 30 seconds only, otherwise set it to the default 5 seconds if (proposedValue < 3 || proposedValue > 30) { bz_setBZDBInt("_pcProtectionDelay", 5); } } } break; case bz_eCaptureEvent: // This event is called each time a team's flag has been captured { if (isMatchInProgress()) { bz_CTFCaptureEventData_V1* captureData = (bz_CTFCaptureEventData_V1*)eventData; std::shared_ptr<bz_BasePlayerRecord> capperData(bz_getPlayerByIndex(captureData->playerCapping)); // Keep score (captureData->teamCapping == TEAM_ONE) ? currentMatch.incrementTeamOneScore() : currentMatch.incrementTeamTwoScore(); // Store data for PC Protection CAP_VICTIM_TEAM = captureData->teamCapped; CAP_WINNER_TEAM = captureData->teamCapping; LAST_CAP = captureData->eventTime; logMessage(pluginSettings.getDebugLevel(), "debug", "%s captured the flag at %s", capperData->callsign.c_str(), getMatchTime().c_str()); logMessage(pluginSettings.getDebugLevel(), "debug", "Match Score %s [%i] vs %s [%i]", currentMatch.getTeamOneName().c_str(), currentMatch.getTeamOneScore(), currentMatch.getTeamTwoName().c_str(), currentMatch.getTeamTwoScore()); CaptureMatchEvent capEvent = CaptureMatchEvent().setBZID(capperData->bzID.c_str()) .setTime(getMatchTime()); // If it's an official match, save the team ID if (isOfficialMatch()) { int teamID = (captureData->teamCapping == TEAM_ONE) ? currentMatch.getTeamOneID() : currentMatch.getTeamTwoID(); capEvent.setTeamID(teamID); } capEvent.save(); currentMatch.saveEvent(capEvent.getJsonObject()); currentMatch.stats_flagCapture(captureData->playerCapping); logMessage(pluginSettings.getVerboseLevel(), "debug", "CaptureMatchEvent JSON -> %s", capEvent.toString()); } } break; case bz_eGameEndEvent: // This event is called each time a game ends { logMessage(pluginSettings.getVerboseLevel(), "debug", "A match has ended."); // Get the current standard UTC time bz_Time stdTime; bz_getUTCtime(&stdTime); std::string recordingFileName; // Only save the recording buffer if we actually started recording when the match started if (RECORDING) { logMessage(pluginSettings.getVerboseLevel(), "debug", "Recording was in progress during the match."); std::stringstream recordingName; std::string _matchType = (isOfficialMatch()) ? "offi" : "fm", _teamOneName = currentMatch.getTeamOneName(), _teamTwoName = currentMatch.getTeamTwoName(); // (offi|fm)-YYYYMMDD recordingName << _matchType << "-" << stdTime.year << formatInt("%02d", stdTime.month) << formatInt("%02d", stdTime.day); if (!currentMatch.isRosterEmpty()) { std::replace(_teamOneName.begin(), _teamOneName.end(), ' ', '_'); std::replace(_teamTwoName.begin(), _teamTwoName.end(), ' ', '_'); // Team_A-vs-Team_B recordingName << "-" << _teamOneName << "-vs-" << _teamTwoName; } // -HHMM recordingName << "-" << formatInt("%02d", stdTime.hour) << formatInt("%02d", stdTime.minute); const std::string nameForHash = recordingName.str(); std::string hash = bz_MD5(nameForHash.c_str()); // -ACBD123 recordingName << "-" << hash.substr(0, 7); if (currentMatch.matchCanceled()) { // -Canceled recordingName << "-Canceled"; } recordingName << ".rec"; recordingFileName = recordingName.str(); logMessage(pluginSettings.getVerboseLevel(), "debug", "Replay file will be named: %s", recordingFileName.c_str()); // Save the recording buffer and stop recording bz_saveRecBuf(recordingFileName.c_str(), 0); bz_stopRecBuf(); logMessage(pluginSettings.getVerboseLevel(), "debug", "Replay file has been saved and recording has stopped."); // We're no longer recording, so set the boolean and announce to players that the file has been saved RECORDING = false; bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, "Match saved as: %s", recordingFileName.c_str()); } // Format the date to -> year-month-day hour:minute:second char matchDate[20]; sprintf(matchDate, "%02d-%02d-%02d %02d:%02d:%02d", stdTime.year, stdTime.month, stdTime.day, stdTime.hour, stdTime.minute, stdTime.second); currentMatch.save(matchDate, recordingFileName); if (pluginSettings.isMatchReportEnabled()) { if (!currentMatch.isRosterEmpty()) { MatchUrlRepo.set("query", "matchReport") .set("data", bz_urlEncode(currentMatch.toString().c_str())) .submit(); if (currentMatch.isFM()) { // It was a fun match, so there is no need to do anything logMessage(pluginSettings.getVerboseLevel(), "debug", "Fun match has completed."); } else if (currentMatch.matchCanceled()) { // The match was canceled for some reason so output the reason to both the players and the server logs logMessage(pluginSettings.getDebugLevel(), "debug", "%s", currentMatch.getCancelation().c_str()); bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, currentMatch.getCancelation().c_str()); } else { logMessage(pluginSettings.getDebugLevel(), "debug", "Reporting match data..."); bz_sendTextMessage(BZ_SERVER, BZ_ALLUSERS, "Reporting match..."); // Send the match data to the league website MATCH_INFO_SENT = true; } } } // Reset our match data currentMatch = Match(); // Empty our list of players since we don't need a history activePlayerList.clear(); } break; case bz_eGamePauseEvent: { bz_GamePauseResumeEventData_V2* gamePauseData = (bz_GamePauseResumeEventData_V2*)eventData; // Get the current UTC time MATCH_PAUSED = time(NULL); // Send the messages bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, " with %s remaining.", getMatchTime().c_str()); logMessage(pluginSettings.getVerboseLevel(), "debug", "Match paused at %s by %s.", getMatchTime().c_str(), bz_getPlayerCallsign(gamePauseData->playerID)); PauseResumeMatchEvent pauseEvent = PauseResumeMatchEvent(); pauseEvent.setState(true) .setTime(getMatchTime()) .setBZID(getPlayerBZID(gamePauseData->playerID)) .save(); currentMatch.saveEvent(pauseEvent.getJsonObject()); logMessage(pluginSettings.getVerboseLevel(), "debug", "PauseResumeMatchEvent JSON -> %s", pauseEvent.toString()); } break; case bz_eGameResumeEvent: { bz_GamePauseResumeEventData_V2* gameResumeData = (bz_GamePauseResumeEventData_V2*)eventData; // Get the current UTC time time_t now = time(NULL); // Do the math to determine how long the match was paused double timePaused = difftime(now, MATCH_PAUSED); // Create a temporary variable to store and manipulate the match start time struct tm modMatchStart = *localtime(&MATCH_START); // Manipulate the time by adding the amount of seconds the match was paused in order to be able to accurately // calculate the amount of time remaining with LeagueOverseer::getMatchTime() modMatchStart.tm_sec += timePaused; // Save the manipulated match start time MATCH_START = mktime(&modMatchStart); logMessage(pluginSettings.getVerboseLevel(), "debug", "Match paused for %.f seconds. Match continuing at %s.", timePaused, getMatchTime().c_str()); PauseResumeMatchEvent resumeEvent = PauseResumeMatchEvent(); resumeEvent.setState(false) .setTime(getMatchTime()) .setBZID(getPlayerBZID(gameResumeData->playerID)) .save(); currentMatch.saveEvent(resumeEvent.getJsonObject()); logMessage(pluginSettings.getVerboseLevel(), "debug", "PauseResumeMatchEvent JSON -> %s", resumeEvent.toString()); } break; case bz_eGameStartEvent: // This event is triggered when a timed game begins { logMessage(pluginSettings.getVerboseLevel(), "debug", "A match has started"); // Empty our list of players since we don't need a history activePlayerList.clear(); // We started recording a match, so save the status RECORDING = bz_startRecBuf(); // We want to notify the logs if we couldn't start recording just in case an issue were to occur and the server // owner needs to check to see if players were lying about there no replay if (RECORDING) { logMessage(pluginSettings.getVerboseLevel(), "debug", "Match recording has started successfully"); } else { logMessage(0, "error", "This match could not be recorded"); } currentMatch.setMatchDuration((int) bz_getTimeLimit()); MATCH_START = time(NULL); } break; case bz_eGetAutoTeamEvent: // This event is called for each new player is added to a team { bz_GetAutoTeamEventData_V1* autoTeamData = (bz_GetAutoTeamEventData_V1*)eventData; int playerID = autoTeamData->playerID; std::shared_ptr<bz_BasePlayerRecord> playerData(bz_getPlayerByIndex(playerID)); // Only force new players to observer if a match is in progress if (isMatchInProgress()) { // Automatically move non-league members or players who just joined to the observer team if (!isLeagueMember(playerID) || !playerAlreadyJoined(playerData->bzID.c_str())) { autoTeamData->handled = true; autoTeamData->team = eObservers; } } } break; case bz_eGetPlayerMotto: // This event is called when the player joins. It gives us the motto of the player { bz_GetPlayerMottoData_V2* mottoData = (bz_GetPlayerMottoData_V2*)eventData; if (pluginSettings.isMottoFetchEnabled()) { std::map<std::string, std::string> parameters; parameters["{motto}"] = mottoData->motto; parameters["{team}"] = getPlayerTeamNameByBZID(mottoData->record->bzID.c_str()); mottoData->motto = formatMotto(parameters); } } break; case bz_ePlayerDieEvent: // This event is called each time a tank is killed { bz_PlayerDieEventData_V1* dieData = (bz_PlayerDieEventData_V1*)eventData; std::shared_ptr<bz_BasePlayerRecord> victimData(bz_getPlayerByIndex(dieData->playerID)); std::shared_ptr<bz_BasePlayerRecord> killerData(bz_getPlayerByIndex(dieData->killerID)); if (isMatchInProgress()) { KillMatchEvent killEvent = KillMatchEvent(); killEvent.setKiller(killerData->bzID.c_str()) .setVictim(victimData->bzID.c_str()) .setTime(getMatchTime()) .save(); currentMatch.saveEvent(killEvent.getJsonObject()); logMessage(pluginSettings.getVerboseLevel(), "debug", "KillMatchEvent JSON -> %s", killEvent.toString()); } } break; case bz_ePlayerJoinEvent: // This event is called each time a player joins the game { bz_PlayerJoinPartEventData_V1* joinData = (bz_PlayerJoinPartEventData_V1*)eventData; int playerID = joinData->playerID; std::shared_ptr<bz_BasePlayerRecord> playerData(bz_getPlayerByIndex(playerID)); setLeagueMember(playerID); storePlayerInfo(playerID, playerData->bzID.c_str()); JoinMatchEvent joinEvent = JoinMatchEvent().setCallsign(playerData->callsign.c_str()) .setVerified(playerData->verified) .setIpAddress(playerData->ipAddress.c_str()) .setBZID(playerData->bzID.c_str()); joinEvent.save(); // Only notify a player if they exist, have joined the observer team, and there is a match in progress if (isMatchInProgress() && isValidPlayerID(joinData->playerID) && playerData->team == eObservers) { bz_sendTextMessagef(BZ_SERVER, joinData->playerID, "*** There is currently %s match in progress, please be respectful. ***", ((isOfficialMatch()) ? "an official" : "a fun")); } if (pluginSettings.isMottoFetchEnabled()) { // Only send a URL job if the user is verified if (playerData->verified) { requestTeamName(playerData->callsign.c_str(), playerData->bzID.c_str()); } } } break; case bz_ePlayerPartEvent: // This event is called each time a player leaves a game { bz_PlayerJoinPartEventData_V1* partData = (bz_PlayerJoinPartEventData_V1*)eventData; int playerID = partData->playerID; std::shared_ptr<bz_BasePlayerRecord> playerData(bz_getPlayerByIndex(playerID)); removePlayerInfo(partData->record->bzID.c_str()); // Only keep track of the parting player if they are a league member and there is a match in progress if (isLeagueMember(playerID) && isMatchInProgress()) { if (!playerAlreadyJoined(playerData->bzID.c_str())) { // Create a record for the player who just left Player partingPlayer(playerData->bzID.c_str(), playerData->team, bz_getCurrentTime()); // Push the record to our vector activePlayerList.push_back(partingPlayer); } } } break; case bz_eRawChatMessageEvent: // This event is called for each chat message the server receives. It is called before any filtering is done. { bz_ChatEventData_V1* chatData = (bz_ChatEventData_V1*)eventData; bz_eTeamType target = chatData->team; int playerID = chatData->from, recipient = chatData->to; // The server is always allowed to talk if (playerID == BZ_SERVER) { break; } // A non-league player is attempting to talk if (!isLeagueMember(playerID)) { std::string allowedChatTarget = pluginSettings.getAllowedTargetChat(getCurrentGameMode()); bool ignoreMessage = true; if (allowedChatTarget == "Observers") { if (recipient == eObservers || bz_getPlayerTeam(recipient) == eObservers) { ignoreMessage = false; } } else if (allowedChatTarget == "ObvserverAdmins") { if (bz_getPlayerTeam(recipient) == eObservers && isVisibleAdmin(recipient)) { ignoreMessage = false; } } else if (allowedChatTarget == "Admins") { if (target == eAdministrators || isVisibleAdmin(recipient)) { ignoreMessage = false; } } else if (allowedChatTarget == "All") { ignoreMessage = false; } if (ignoreMessage) { chatData->message = ""; sendPluginMessage(playerID, pluginSettings.getGuestMessagingMessage(getCurrentGameMode())); } } } break; case bz_eTickEvent: // This event is called once for each BZFS main loop { // Get the total number of tanks playing int totalTanks = bz_getTeamCount(eRedTeam) + bz_getTeamCount(eGreenTeam) + bz_getTeamCount(eBlueTeam) + bz_getTeamCount(ePurpleTeam); // If there are no tanks playing, then we need to do some clean up if (totalTanks == 0) { // If there is an official match and no tanks playing, we need to cancel it if (isOfficialMatch()) { currentMatch.cancelMatch("Official match automatically canceled due to all players leaving the match."); } // If we have players recorded and there's no one around, empty the list if (!activePlayerList.empty()) { activePlayerList.clear(); } // If there is a countdown active an no tanks are playing, then cancel it if (bz_isCountDownActive()) { bz_gameOver(253, eObservers); logMessage(pluginSettings.getVerboseLevel(), "debug", "Game ended because no players were found playing with an active countdown."); } } // Let's get the roll call only if there is an official match if (isOfficialMatch()) { // Check if the start time is not negative since our default value for the approxTimeProgress is -1. Also check // if it's time to do a roll call, which is defined as 90 seconds after the start of the match by default, // and make sure we don't have any match participants recorded and the match isn't paused if (getMatchProgress() > currentMatch.getMatchRollCall() && currentMatch.isRosterEmpty() && !bz_isCountDownPaused() && !bz_isCountDownInProgress()) { logMessage(pluginSettings.getVerboseLevel(), "debug", "Processing roll call..."); // @TODO Make sure all of these variables are used std::shared_ptr<bz_APIIntList> playerList(bz_getPlayerIndexList()); bool invalidateRollCall, teamOneError, teamTwoError; std::string teamOneMotto, teamTwoMotto; int teamOneID, teamTwoID; invalidateRollCall = teamOneError = teamTwoError = false; teamOneMotto = teamTwoMotto = ""; // We can't do a roll call if the player list wasn't created if (!playerList) { logMessage(pluginSettings.getVerboseLevel(), "error", "Failure to create player list for roll call."); return; } for (unsigned int i = 0; i < playerList->size(); i++) { bz_BasePlayerRecord* playerRecord = bz_getPlayerByIndex(playerList->get(i)); if (playerRecord && isLeagueMember(playerRecord->playerID) && bz_getPlayerTeam(playerList->get(i)) != eObservers) // If player is not an observer { currentMatch.savePlayer(playerRecord, getTeamIdFromBZID(playerRecord->bzID.c_str())); // @TODO Rewrite this function to be updated // Check if there is any need to invalidate a roll call from a team //validateTeamName(invalidateRollCall, teamOneError, currentPlayer, teamOneMotto, TEAM_ONE); //validateTeamName(invalidateRollCall, teamTwoError, currentPlayer, teamTwoMotto, TEAM_TWO); } bz_freePlayerRecord(playerRecord); } // We were asked to invalidate the roll call because of some issue so let's check if there is still time for // another roll call if (invalidateRollCall && currentMatch.incrementMatchRollCall(60) < currentMatch.getMatchDuration()) { logMessage(pluginSettings.getDebugLevel(), "debug", "Invalid player found on field at %s.", getMatchTime().c_str()); // There was an error with one of the members of either team, so request a team name update for all of // the team members to try to fix any inconsistencies of different team names //if (teamOneError) { requestTeamName(TEAM_ONE); } //if (teamTwoError) { requestTeamName(TEAM_TWO); } // Delay the next roll call by 60 seconds logMessage(pluginSettings.getVerboseLevel(), "debug", "Match roll call time has been delayed by 60 seconds."); // Clear the struct because it's useless data currentMatch.clearPlayerRoster(); logMessage(pluginSettings.getVerboseLevel(), "debug", "Match participants have been cleared."); } // There is no need to invalidate the roll call so the team names must be right so save them in the struct if (!invalidateRollCall) { currentMatch.setTeamOneID(teamOneID).setTeamOneName(teamOneMotto) .setTeamTwoID(teamTwoID).setTeamTwoName(teamTwoMotto); logMessage(pluginSettings.getVerboseLevel(), "debug", "Team One set to: %s", currentMatch.getTeamOneName().c_str()); logMessage(pluginSettings.getVerboseLevel(), "debug", "Team Two set to: %s", currentMatch.getTeamTwoName().c_str()); } } } } break; default: break; } }