*E@7_VBefGۿH-None GetValue addButton splitRegionH splitRegionVtrim addLabel setValues InternalTimeCore NexgenX108 hasRightSystemgetControllerColorlogAdminAction SetMaxLength addEditBox SetValuedivideRegionH addCheckBox Nexgen108split skipRegion selectRegionUWindowVBitsVClampUClampUBitsMipZero setContentUSizeVSizebMaskedPaletteNotifydivideRegionVaddContentPanel RegisterEngine saveSettingsshowMsgConsoleCommandUWindowSmallButton notifyEventFormat stringHashAddTextSetNumericOnlySetTextClosepanelIdentifier addNewLine setDisabled MaxColorplayerSelectedsignalConfigUpdateSetSkin LoadMapList fixStrLen addListBoxsetAppendsetPlayerOverlay doMapSwitchaddPluginConfigPanelcreatePanelRootRegion Initialize addComponent PreBeginPlayDeathMatchPlus addServercalcDynamicChecksum PanelHeightisNewChatMessageCaptionhandleNewChatMessage getXClient showRulesGetSelectedIndex SetGameSpeedannounceNewRemainingTimeSortcontainsProtectTag isNumericupdateChecksumRemovecreateWindowRootRegion mapSelectedaddMapCreated addPanelReplacenscLogAddBotsgetTimeInSeconds AddMessageforceClientViewRulessetAdminForcedViewMessagenotifyMapListPartRecievednotifyMapListAvailabledisableSpecialMatchControlsgetLongTimeDescriptionfixSpecatorViewPlayerNumBug ChangeNameadminForceClientViewRulessetServerRulesSettingsnotifyUpdateAvailablesetTagProtectionSettingssetRemainingTimesetTeamScoreLimitgetMessageupdateRemainingTime setTimeLimitsetScoreLimitnotifyClientSpamisSpamsetFullServerRedirSettingssetGeneralSettingsnexgenXConfigChangedreceiveMapListPartrequestMapListinstallVersion105clientInitializedloadMutatorList ProcessDatareconnectTextTickloadGameTypeListsplit2 addListComboupdateDynamicChecksums setGameInfocheckConfigUpdate ValidateMutate!initialConfigReplicationCompleteClientPlaySound TeamGamePlusCreateControlinstallVersion107installVersion106install getFloatbCanModifyHUDStatePanelClear serverfullcsmuted csnormal DestroyedctrlID pluginName pluginAuthorpluginVersiongetIntNexgenX getNextLineNexgenXClientbUnlitMutatorTeamMessageMutatorBroadcastMessageNexgenXConfigNexgenXConfigExt ScaleGlowloadFavouritesNexgen AmbientGlowStyleNexgenXConfigSys bAnimByOwnermodifyClientState ForceAddBot NexgenXLangAddItemNexgenXPlayerOverlaySetSelectedIndexNexgenXRCPFullServerRedirPhysicsNexgenXRCPMapSwitch GameEndedmodifyLoginRejectNexgenXRCPMatchControlbNetTemporaryaddController isValidLevel showPanel getItemByIDclientCreatedsetupControlPanel fixIntRangebTrailerSameRotationaddEditControlNexgenXRCPServerRulesTimerNexgenXRCPServerRulesViewNexgenXRCPSettings checkLogin SpectatorNexgenXRCPTagProtectionNexgenXServerFullDialogNexgenXTagRejectDialogIpDrv HTTPErrorhandleMsgCommand gameStarted UBrowserHTTPReceivedDataBrowseNexgenXUpdateCheckerplayerNameChanged NameText playerLeft playerJoinedNexgenXUpdateNotifyDialog getPanel getClientaddPlayerToListWAVupdatePlayerInfo removePlayerVersionMessage NexgenXUtil wrapLengthgetClientByNum fixByteRange showPopup RemoteRolebMeshEnviroMap playerEvent PlayerPawnPawn ServerTravelReceiveLocalizedMessagePostNetBeginPlay bOwnerNoSeeTeamSaySpectatorText versionNum CHSpectatorSay GetTeamName ReBalance DrawType tagMessageisReadyToInitialize PlayerNumBotpack MutatorName FirstMapRestartButtonUMenuLabelControlbBalanceTeams CountDownTournamentGameReplicationInfo AnnouncerTGRI(All)prepare GameTypeListUMenu NexgenCCbHiddenNewNameGeneralConfigtempA ScriptTextS ReturnValueMinutesHoursGRIMutator LevelInfo GameInfoPlayerReplicationInfoInfoReplicationInfoGameReplicationInfo ServerActorsLevelActorGoalTeamScoreNextMapMeshPlayerClientCountColorsNumBotsSoundTexture TimeLimitCmd FragLimitRole Palette11 Palette13TagClass Palette15 Palette17 Palette19PackageEffectsConst TimeMessage MinPlayers GameType MainWindowCodeServerUBrowserHTTPClientUpdateServerPortData ServerURLOutputCh WinWidth bCanDragItemsbBlinkNexgenControllerNexgenMainFrame bDisabledGetPlayerOwnerUWindowListBoxItemUWindowListBoxUWindowWindowUWindowButtonUWindowDialogControlUWindowCheckboxUWindowComboControlUWindowListControl UWindowListUWindowEditControl TextColor DrawScaleTeam GameNameTypeMapListFatness Receiver BorderSizeAmount versionCodeversionpNum buttonSpace buttonHeightitemID Checksum SelectedItemSender bCheckedBotDeaths PlayerIDRemainingTimeNewItem RotationbUseExternalConfig NexgenUtilNexgenSimplePlayerListBoxNexgenSimpleListItemNexgenSimpleListBoxNexgenRCPMatchControlNexgenPlayerDataNexgenPlayerListNexgenPlayerListBoxNexgenPopupDialog NexgenClientNexgenClientController NexgenConfigNexgenContentPanelNexgenMainPanel NexgenPlugin NexgenPanelNexgenDummyComponentNexgenEditControlNexgenGameInfo NexgenHUD TextBuffercontrol separatordynamicChecksumsdynamicChecksumModifiers updateCountslastInstalledVersionmatchControlPanelClass gameTypeInfo mutatorInfoactiveGameTypeactiveMutatorIndices configType remainingargs updateCount gameStatelngsConf clientListgInfplugins timerFreq mapCount bInvalid bRejected rejectTypepopupWindowClass popupArgs currClientpDatbWasForcedChangedstr1str2str3str4 bNoBroadcast bIsCommand senderPRI argumentsGFX mutedIcon mutedIcon2 solidIconcxcy Location nextClientgc bNetWait bHasAccount bSpectatorspawnProtectionTimeXtkDmgProtectionTimeXtkPushProtectionTimeXnscHUDnextDynamicUpdateCountnextDynamicChecksumbWaitingForNewConfigSSTR_OverrideClassreconnectCommandspectatorClasscreatorTeamNum mutators indexStr targetPlayermaxLenintVar lowerBound upperBoundbyteVarinvalidConfigMsg messageTxt mainPanel currRegion resetButton saveButtoninclMutatorListexclMutatorListoldItem mutatorIndexreconnectButton teamButtons pauseButton endButtonsendToURLButtonreconnectAsPlayerButtonreconnectAsSpecButtondisableTeamSwitchButtonurlInpallowTeamSwitchInpallowTeamBalanceInp lockTeamsInptournamentModeInpfavouritesListcwspectatorButton slotLabel displayTexthashObjectStrText Palette1ValueKey BaseMutator MapPrefixNextURL PawnList TimeSecondsbBeepOwner nextPawnReasonTargetRegionGameNextPRI xControlgeneralSettingsChecksumenableOverlaySkinenableMapSwitchenableStartAnnouncerenableAntiSpamenableClientIDAKALogcheckForUpdatesfullServerRedirectChecksumenableFullServerRedirectfullServerRedirectMsgredirectServerName redirectURLenableTagProtectiontagsToProtectenableServerRules serverRulesEVENT_NexgenXConfigChangedCT_GeneralSettingsCT_FullServerRedirectCT_TagProtectionSettingsCT_ServerRulesSettings StartTimelatestVersionbUpdateAvailableupdateServerHostupdateServerPath currLine alertSoundxConf mapSwitchTabplayerOverlaybSendingMapList bMapListSendlastMaplastCountDownbGameStartingAnnounced lastMessageslastMessageTimeStampslastSpamTimeStampminMessageIntervalspamNotifyDurationmaxMapListPartStringSizestartCountDownWaitmaxStringSizeSSTR_LastVersionNotifybFoundbMapListComplete bMapListFullScore bLastPart mapListPart FunctionmutatorClassesclientTravelURLserverTravelURL mapNameNoExtStructbRemoveOldName PlayerName NumPlayersredirectServerName1redirectServerName2redirectServerName3 redirectURL1 redirectURL2 redirectURL3 bTeamGame GameClass bAddBotsmulStrSecondsItempreviousTimeLimit bSelectedIndexPremainingTimeStrMsgtagsToProtect_0tagsToProtect_1tagsToProtect_2tagsToProtect_3tagsToProtect_4tagsToProtect_5URLlastNotifiedVersion bNetOwnerserverRules_0serverRules_1serverRules_2serverRules_3serverRules_4serverRules_5serverRules_6serverRules_7serverRules_8serverRules_9bGameRestartRequired StrProperty bAdminForced rulesViewTab ViewTargetxTarget logReasonxUpdate EventType lastMessagelastMessageTimeStamplastMessageSenderlastMessageWasSpam PA_Score PA_Deaths PA_StartTimeCMD_SmartCTFToggleStatsCMD_AKAClientIDLogxClientisChatMessagebSuppressMessageStructPropertybIsNewClassProperty NameProperty DeltaTimeObjectProperty currXClientFloatProperty protectedTagupdateCheckFailedMsgupdateAvailableMsgprotectedTagLoginRejectMsgadminMapSwitchMsgadminUpdateGeneralSettingsMsg adminFullServerRedirSettingsMsgadminAddBotsMsgadminRemoveBotsMsgadminChangeTimeLimitMsgadminChangeScoreLimitMsgadminChangeTeamScoreLimitMsgadminChangeGameSpeedMsgadminChangeTimeRemainingMsg$adminUpdateTagProtectionSettingsMsg"adminUpdateServerRulesSettingsMsgadminForceClientViewRulesMsggameRestartRequiredMsgtagNotAllowedMsgviewRulesClientMsgnoReasonGivenMsgmapSwitchTabTxtmapSwitchActionTxthideBadMapsTxtrecievingMapListTxtrecievingMapListProgressTxtsettingsPanelTitleenableOverlaySkinTxtenableMapSwitchTabTxtenableStartAnnouncerTxtenableAntiSpamTxtenableClientIDAKALogTxtcheckForUpdatesTxtfullServerRedirPanelTitleenableFullServerRedirTxtdefaultFullServerRedirMsgserverEntryTxturlTxtremainingTimeTxt setButtonTxt addBotsTxtremoveBotsTxttagProtectionPanelTitleenableTagProtectionTxtprotectedTagsTxtserverRulesPanelTitleenableServerRulesTxtserverRulesCaptionTxtantiSpamMutedStateserverRulesTabTxtserverRulesTabTitleserverRulesForcedTabTitleforceClientViewRulesTxtforceClientViewRulesReasonTxtMapNameoverlaySkinRedoverlaySkinBlueoverlaySkinGreenoverlaySkinGoldoverlaySkinSilveroverlaySkinARedoverlaySkinABlueoverlaySkinAGreenoverlaySkinAGoldoverlaySkinASilver bActivatedactivatedAmbientGlowactivatedFatnessbClientProtected timeLimitInpscoreLimitInpteamScoreLimitInp gameSpeedInpremainingTimeInp addBotsInpremoveBotsInpsetTimeLimitButtonsetScoreLimitButtonsetTeamScoreLimitButtonsetGameSpeedButtonsetRemainingTimeButtonaddBotsButtonremoveBotsButton PlayerListenableFullServerRedirectInpfullServerRedirectMsgInpredirectServerNameInpredirectURLInp switchButtonhideBadMapsInpbMapListAvailableSSTR_HideBadMaps bHideBadMaps BoolProperty IntPropertyHealth GameSpeedenableServerRulesInpserverRulesInprulesTitleLabelrulesshowRulesButtonshowReasonInpbShowAdminControls MutatorClassMapsenableOverlaySkinInpenableMapSwitchTabInpenableStartAnnouncerInpenableAntiSpamInpenableClientIDAKALogInpcheckForUpdatesInpenableTagProtectionInpprotectedTagsInpmaxTagsPerRownumRows nextVOffset numServers serverButton openCommandserver1server2server3 ByteProperty buttonText urlLabel tagLabel nameInputIcon versionLabel newVersionnewVersionStr stateTypetimeStr minutesStr secondsStr NexgenLang bIsNumeric currentCharh E _G ::$::$Ng+>9˃9݇9U.e9ˎg+g+jj9݇9U9s⥎rU>9sjrU>9ˎrU>9˃9݇9U݇9U݇9U3B݇9U3B݇9U3B݇9U3B݇9U3B݇9U3B݇9U3B݇9U3B݇9U3B݇9U3B݇9U2I݇9U9˝.e{V9jj9M9M9M9˃9˃9݇9U݇9U3B݇9U3B݇9U3B݇9U3B݇9U3B݇9U3B݇9U2I݇9U9˝.e{Vj9˃9˚E7 Y9˗> Y'n 69˃9˚-%n-%n-%n;(-%n-%n.e-%n-%n-%n.e-%n-%n.e-%n'n 6-%n2I՘-%nj9˃9˚-%n-%n;(-%nj9˃9˚-%n-%n-%n-%nL]}"#}"#jj@sE݇9Uj.e9˃9˗> Y9>&9˃9>&j9>&9>&9˗> Y9˃9˝.e9˃9˃9˝.e9˃9݇9U݇9U݇9U݇9U݇9U݇9U݇9U݇9U݇9U2I݇9U9˝.e{Vj9˃9݇9U݇9U݇9U݇9U݇9U݇9U݇9U2I݇9U9˝.e{Vj݇9U݇9U݇9U݇9U݇9U9݇9U@sEȃ9˃9˃9˗> Y9˗> Y@sEȃ9˃9˃9˧3B9˧3B9˧3B9˧j3B}`j}`j2IՃ9˃9{9{9{9{݇9U9˧9˗> Y9˗> Y9˃9݇9U9sj݇9U9sj9˃9˃9˃9˃9˃9 ( X]ClientExtensionRc zcD\ ::$݇9UYQZ2Ij2I2I ( w Q PnjU[ ( i[VE ]t2Iբ,݇9U_BZ9˃9˃9ˎg+g+_BZ݇9U9j݇9U݇9U݇9U݇9U݇9U9˃9˃9˃9˃9˟{Vj݇9U9˃9j.e9˃9ˎg+g+9˚ttt.e9ˎg+݇9U݇9U.e9˃9ˎg+g+݇9U݇9U9˝.e.e.e,݇9U3B=$:e݇9Ug+݇9Ug+g+g+ԝXԝXtԝX{#U{#U{#U.e9˃9ˎg+g+9݇9U.e9˃9ˎg+g+9˃9ˎg+g+9^S9˗> Y{#U9^S9˗> Y{#U9^S9˗> Y{#U.e{.e{9˃9ˎg+݇9Ug+9˗> Y{#U9^S9˗> Y{#U9˗> Y{#U9^S9˗> Y{#U9˗> Y{#U9^S9˗> Y{#U݇9U9˗> Y9˝.e݇9U݇9U3B݇9U݇9U3B݇9U݇9U3B݇9U݇9U9g+.e݇9U݇9U.ej݇9U.e݇9U ( o"lY]Nexgen extension packZ] Zeropoint[]1.08 build 10324@ @P|` F @@AF) @@Fb @@SLt u D.rU>g+; ^3Bt3Bg+j᱘)7Xg+݇9Ug+݇9U9˃9; 롃9˜7X; 롺᱘g+݇9U9ˎg+9˃9g+j4Lg+jg+jt4Lg+j4L4L  4]nexgenxserverrulesviewR @@ c@W' @VM@ZHg=$@VATDF` zA f @E@j @[adeS! @@MRV{  @[lPd~@o:@K D @Q @Y@Jj @ff @h @Ec| @UQv^JGz]y G tg}`j yJ_4 yJEyEEyEEyEEyEEyEg+ yJEyE_4 yJ yJy&. yJ yJ yJy&. yJ yJ yJK4螓EyE yJEyEEyE yJEyE yJ yJy&. yJEyE yJy&. yJ yJ yJ yJK4螓EyE yJEyEEyE yJEyE yJ yJy&. yJEyE yJy&. yJ7XÕ|.Xڃ9M|.Xڃ9M yJK4螓EyE9˟{Vg+jg+ yJK4螓EyE7XÙ yJ yJK4螙 yJg+j_43B9˧3B|.Xg+3Bg+g+g+ yJ9˧9˧3B9˧ yJK4螓EyEEyE yJK4螃9˧3B yJ yJK4螓EyEEyEEyEEyEEyE9˧9˧3B9˧3B_4_49˧9ˎg+g+jg+j4L4L4L4L9˟{V4L4L4L4L9˟{V4L4L9˟{V4L|.X_4|.Xڃ9M yJ  4] mapswitchIH pp@sEGɗ> Y{#U9˗> Y9˗> Y9˃9˃9˗> Y{#UԝXԝX ( klxS@s dtie$=h`eH@;XD@"HQK@qH@N@E@|@C@LV@est@h_@`@Q bR_BZ釅m3B3B3B3B2I՝.e2Ij3B3B2I՝.e3B2Ij OK( X0^BT]  @o@@P U @I@@@qZ@{@MMM}@\n@y^BR@CEKu @xlOuMvQfT._@@\^y_aZ@Cc@dUX@S@MRZ @9o@p@@d @IJLGJ,}g @@y@z@@{@t@p@@PbkGj3srSLhvAO@@W@@vWUD ]I a@+@ wij@k{c @k j q` w]@N@6@jl@H @@aG e _E7 Y{#U> Y> Y> Y᱘3Bt> Y{#Ut  L]43Failed to login: you tried to use a protected tag.q]gThis server has (clan) tag protection enabled, which means you can't use certain tags unless you have an account on the server. Please change your name and reconnect.u]+*The protected tag you tried to use is: %1T]Name:@] Reconnect@X@Z@#@I@Z { I2 []anŴ)> Y> Y> Y> Y> Y> Y3B᱘7X  L]"!Failed to login: server is full.@] Reconnectn] Spectatord Y H$\9ˍ)7Xg+|.Xڛttttttg+݇9Ug+݇9U|.Xg+݇9Utg+݇9U9ˎg+g+j9˟{V9˟{Vg+jg+jt  4]nexgenxtagprotectionsettingsJ$BV@]@`@b@f@|@^@@~Ec@d@\@@ @p k F E6ld)7Xg+|.Xڕ|.Xڕ|.Xڕ|.Xڕ|.Xڕ|.Xg+݇9Ug+݇9U|.Xg+݇9U|.Xg+݇9U|.Xg+݇9U|.Xg+݇9U|.Xg+݇9U|.Xg+݇9U9ˎg+g+j9˟{V9˟{Vg+jg+jg+jg+jg+jg+j  4]nexgenxsettingsJ$Bg@m@xnu X B(qh)7Xg+|.Xڛttttttttttg+݇9Ug+݇9U|.Xg+݇9Utg+݇9U9ˎg+g+j9˟{V9˟{Vg+jg+jt  4]nexgenxserverrulessettingsJ$@Crw GwqtWX?)7Xg+[[g+[[g+[[g+[[g+[[g+[[g+[[[[[[[[[[[[[[7XÜ7XÜ7XÜ7XÜ7XÜ7XÃ9˗> Y[[;([[;([[;([[9{9ˎg+4L4L4L4L9˟{V9˟{V9˟{V4L9˟{V4L9˟{V4L9˟{V4L9˟{V4L4L4L4L4L4L4L4L4L9˟{V4L9˟{V4L9˟{V4L9˟{V4Lg+j4L4L4L4L4L4L4L4Lg+j4Lg+j4Lg+j4Lg+j4Lg+j4L4L4L4L9˟{V4L9˟{V4L9˟{V4Lg+j4L4Lg+j4L4L4L9˟{V4L9˟{V4L9˟{V4L9˟{V[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[t; 롕|.Xڕ|.Xڕ|.Xڕ|.X_4|.Xڃ9˗> Y'n 6|.Xڃ9˗> Y'n 69˃9  i svm@w| Zr3zDg)7Xg+|.Xڛtttttttg+݇9Ug+݇9U|.Xg+݇9Utg+݇9Utg+݇9Utg+݇9U9ˎg+g+j9˟{V9˟{Vg+jg+j9˟{Vg+jg+jttt  4]#"nexgenxfullserverredirectsettingsJ$Cay@}@@@D@B@C@d @H@FGS@N@@L@U J@O@P@T@gJ @@U@VK @Z@~@Y@d@[@]@^@_@T@`@h@m@b@f@g@@i@@k@j@m@n@o@pt@y@vh@B@n@@W j{:݇9U ( a _ d}E݇9U ( gJ X W2s nź᱘3B  L]'&A new version of Nexgen is available.qm&dThe server is automatically checking for Nexgen updates and has found a new version. Visit www.unrealadmin.org for more information. You can turn automatic update checking off in the plugin configuration tab. This message will not be repeated until another new version of Nexgen is released.^]Latest Nexgen version: %1`"OQ "Remaining time"@ "set"A "Add bots"B "Remove bots"C! "NexgenX - Clan tag protection"D= "Only allow registered players to use protected clan tags."E "Protected tags:"F# "NexgenX - Server rules settings"G8 "Show a server rules tab in the Nexgen control panel."H "Rules to display:"I "Muted (spam)"J "Rules"K! "The rules of this server are:"L= "An administrator has forced you to view the server rules!"M "Show rules"N "Reason for showing rules:"Ogc??F,<F,<?% S?hour?& p s F%?%% p ,  p  and  p SFminute F& p s% z PF% ?% p  and  p Ssecond& p s  T "URL"?@qF@i>,-F w,*,a,*-F r,*-,a @   ,K U "Server %1"Wg "The server you have tried to enter has no more player slots available. You can try again in a few minutes or reconnect immediately as a spectator. If you wish to play immediately you can connect to one of the alternate servers."]/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenX * $VERSION 1.11 (22-6-2008 10:05) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Nexgen controller extension plugin. * **************************************************************************************************/ class NexgenX extends NexgenPlugin; var NexgenXLang lng; // Language instance to support localization. var NexgenXConfig xConf; // Plugin configuration. var NexgenXUpdateChecker xUpdate; // Nexgen update checker. var int versionNum; // Plugin version number. // Message control. var string lastMessage; // Last send chat message. var float lastMessageTimeStamp; // Time stamp of last send chat message. var PlayerPawn lastMessageSender; // Sender of the last message. var bool lastMessageWasSpam; // Whether the last send message was spam. // Extra player attributes. const PA_Score = "score"; // Score / frag count. const PA_Deaths = "deaths"; // Number of times the player died. const PA_StartTime = "starttime"; // Time at which the player joined the game. // Misc constants. const CMD_SmartCTFToggleStats = "smartctf stats"; const CMD_AKAClientIDLog = "aka info"; const separator = ","; /*************************************************************************************************** * * $DESCRIPTION Initializes the plugin. Note that if this function returns false the plugin will * be destroyed and is not to be used anywhere. * $RETURN True if the initialization succeeded, false if it failed. * $OVERRIDE * **************************************************************************************************/ function bool initialize() { local Actor a; // Load localization support. lng = spawn(class'NexgenXLang'); // Load settings. if (control.bUseExternalConfig) { xConf = spawn(class'NexgenXConfigExt', self); } else { xConf = spawn(class'NexgenXConfigSys', self); } xConf.install(); if (!xConf.validate()) { control.nscLog(lng.invalidConfigMsg); } xConf.initialize(); // Set panel classes. control.sConf.matchControlPanelClass = class'NexgenXRCPMatchControl'; // Load update checker. if (xConf.checkForUpdates) { xUpdate = spawn(class'NexgenXUpdateChecker', self); } return true; } /*************************************************************************************************** * * $DESCRIPTION Called when a new client has been created. Use this function to setup the new * client with your own extensions (in order to support the plugin). * $PARAM client The client that was just created. * $REQUIRE client != none * $OVERRIDE * **************************************************************************************************/ function clientCreated(NexgenClient client) { local NexgenXClient xClient; xClient = NexgenXClient(client.addController(class'NexgenXClient', self)); xClient.xConf = xConf; } /*************************************************************************************************** * * $DESCRIPTION Called whenever the login request of a player has been rejected and allows the * plugin to modify the behaviour. * $PARAM client The client that was denied access to the server. * $PARAM rejectType Reject type identification code. * $PARAM reason Reason why the player was rejected from the server. * $PARAM popupWindowClass Class name of the popup window that is to be shown at the client. * $PARAM popupArgs Optional arguments for the popup window. Note you may have to * explicitly reset them if you change the popupWindowClass. * $REQUIRE client != none * $OVERRIDE * **************************************************************************************************/ function modifyLoginReject(NexgenClient client, out name rejectType, out string reason, out string popupWindowClass, out string popupArgs[4]) { if (rejectType == control.RT_ServerFull && xConf.enableFullServerRedirect) { popupWindowClass = string(class'NexgenXServerFullDialog'); popupArgs[0] = xConf.fullServerRedirectMsg; popupArgs[1] = class'NexgenUtil'.static.replace(xConf.redirectServerName[0], separator, "") $ separator $ xConf.redirectURL[0]; popupArgs[2] = class'NexgenUtil'.static.replace(xConf.redirectServerName[1], separator, "") $ separator $ xConf.redirectURL[1]; popupArgs[3] = class'NexgenUtil'.static.replace(xConf.redirectServerName[2], separator, "") $ separator $ xConf.redirectURL[2]; } } /*************************************************************************************************** * * $DESCRIPTION Called whenever a player has joined the game (after its login has been accepted). * $PARAM client The player that has joined the game. * $REQUIRE client != none * $OVERRIDE * **************************************************************************************************/ function playerJoined(NexgenClient client) { local NexgenXClient xClient; // Spawn player overlay for the client. if (control.gInf.gameState == control.gInf.GS_Playing && !client.bSpectator) { xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); if (xConf.enableOverlaySkin) xClient.setPlayerOverlay(); } // Restore saved player data. client.player.playerReplicationInfo.score = client.pDat.getFloat(PA_Score, client.player.playerReplicationInfo.score); client.player.playerReplicationInfo.deaths = client.pDat.getFloat(PA_Deaths, client.player.playerReplicationInfo.deaths); client.player.playerReplicationInfo.startTime = client.pDat.getInt(PA_StartTime, client.player.playerReplicationInfo.startTime); // Make AKA log the client id. if (xConf.enableClientIDAKALog) { client.player.mutate(CMD_AKAClientIDLog @ client.playerID); } } /*************************************************************************************************** * * $DESCRIPTION Called if a player has left the server. * $PARAM client The player that has left the game. * $REQUIRE client != none * $OVERRIDE * **************************************************************************************************/ function playerLeft(NexgenClient client) { local NexgenXClient xClient; // Get extended client controller. xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); // Remove player overlay. xClient.setPlayerOverlay(true); // Store saved player data. client.pDat.set(PA_Score, client.player.playerReplicationInfo.score); client.pDat.set(PA_Deaths, client.player.playerReplicationInfo.deaths); client.pDat.set(PA_StartTime, client.player.playerReplicationInfo.startTime); } /*************************************************************************************************** * * $DESCRIPTION Called when the game has started. * $OVERRIDE * **************************************************************************************************/ function gameStarted() { local NexgenClient client; local NexgenXClient xClient; // Spawn player overlays for client that haven't received one yet. if (xConf.enableOverlaySkin) { for (client = control.clientList; client != none; client = client.nextClient) { xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); xClient.setPlayerOverlay(); } } } /*************************************************************************************************** * * $DESCRIPTION Called when the game has ended. * $OVERRIDE * **************************************************************************************************/ function gameEnded() { local NexgenClient client; local NexgenXClient xClient; // Destroy player overlays. for (client = control.clientList; client != none; client = client.nextClient) { xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); xClient.setPlayerOverlay(true); } // Fix infinite loop in viewPlayerNum() caused by spectators at the end of the match. fixSpecatorViewPlayerNumBug(); } /*************************************************************************************************** * * $DESCRIPTION Called to check if the specified message should be send to the given receiver. * $PARAM sender The actor that has send the message. * $PARAM receiver Pawn receiving the message. * $PARAM msg The message that is to be send. * $PARAM bBeep Whether or not to make a beep sound once received. * $PARAM type Type of the message that is to be send. * $RETURN True if the message should be send, false if it should be suppressed. * $OVERRIDE * **************************************************************************************************/ function bool mutatorBroadcastMessage(Actor sender, Pawn receiver, out coerce string msg, optional bool bBeep, out optional name type) { local PlayerReplicationInfo senderPRI; local bool isChatMessage; local bool bSuppressMessage; // Get sender player replication info. if (sender != none && sender.isA('Pawn')) { senderPRI = Pawn(sender).playerReplicationInfo; } // Check if the current message is a chat message. isChatMessage = senderPRI != none && sender.isA('Spectator') && left(msg, len(senderPRI.playerName) + 1) ~= (senderPRI.playerName $ ":"); // Handle new chat messages. if (isChatMessage && isNewChatMessage(PlayerPawn(sender), msg)) { handleNewChatMessage(PlayerPawn(sender), right(msg, len(msg) - len(senderPRI.playerName) - 1)); } // Suppress message in case of spam. bSuppressMessage = bSuppressMessage || isChatMessage && lastMessageWasSpam; // Indicate whether the message should be suppressed or not. return !bSuppressMessage; } /*************************************************************************************************** * * $DESCRIPTION Called to check if the specified team message should be send to the given * receiver. * is called if a message is send to player. * $PARAM sender The actor that has send the message. * $PARAM receiver Pawn receiving the message. * $PARAM pri Player replication info of the sending player. * $PARAM s The message that is to be send. * $PARAM type Type of the message that is to be send. * $PARAM bBeep Whether or not to make a beep sound once received. * $RETURN True if the message should be send, false if it should be suppressed. * $OVERRIDE * **************************************************************************************************/ function bool mutatorTeamMessage(Actor sender, Pawn receiver, PlayerReplicationInfo pri, coerce string s, name type, optional bool bBeep) { local bool isChatMessage; local bool bSuppressMessage; // Check if the current message is a chat message. isChatMessage = sender != none && sender.isA('PlayerPawn') && (type == 'Say' || type == 'TeamSay'); // Handle new chat messages. if (isChatMessage && isNewChatMessage(PlayerPawn(sender), s)) { handleNewChatMessage(PlayerPawn(sender), s); } // Suppress message in case of spam. bSuppressMessage = bSuppressMessage || isChatMessage && lastMessageWasSpam; // Indicate whether the message should be suppressed or not. return !bSuppressMessage; } /*************************************************************************************************** * * $DESCRIPTION Checks whether the specified message is a new message. * $PARAM sender PlayerPawn that has send the message in question. * $PARAM msg Message send by the player. * $RETURN True if this is a new chat message, false if not. * **************************************************************************************************/ function bool isNewChatMessage(PlayerPawn sender, string msg) { local bool bIsNew; // Check if this is a new message. bIsNew = lastMessage != msg || lastMessageTimeStamp != level.timeSeconds || lastMessageSender != sender; // Store message info if this is a new message. if (bIsNew) { lastMessage = msg; lastMessageTimeStamp = level.timeSeconds; lastMessageSender = sender; } // Return result. return bIsNew; } /*************************************************************************************************** * * $DESCRIPTION Chat message handler procedure. * $PARAM sender PlayerPawn that has send the message in question. * $PARAM msg Message send by the player. * **************************************************************************************************/ function handleNewChatMessage(PlayerPawn sender, string msg) { local NexgenXClient xClient; // Get extended client controller. xClient = getXClient(sender); // Stuff that needs the extended client controller. if (xClient != none) { // Spam detection. if (xConf.enableAntiSpam) { // Check if message is spam. lastMessageWasSpam = xClient.isSpam(msg); if (!lastMessageWasSpam) { // Store message for future spam detection. xClient.addMessage(msg); } else { // Notify client. xClient.notifyClientSpam(); } } else { lastMessageWasSpam = false; } } } /*************************************************************************************************** * * $DESCRIPTION Handles a potential command message. * $PARAM sender PlayerPawn that has send the message in question. * $PARAM msg Message send by the player, which could be a command. * $REQUIRE sender != none * $RETURN True if the specified message is a command, false if not. * $OVERRIDE * **************************************************************************************************/ function bool handleMsgCommand(PlayerPawn sender, string msg) { local string cmd; local bool bIsCommand; local NexgenXClient xClient; cmd = class'NexgenUtil'.static.trim(msg); bIsCommand = true; switch (cmd) { case "!stats": level.game.baseMutator.mutate(CMD_SmartCTFToggleStats, sender); break; case "!rules": if (xConf.enableServerRules) { xClient = getXClient(sender); if (xClient != none) { xClient.showRules(); } } break; // Not a command. default: bIsCommand = false; } return bIsCommand; } /*************************************************************************************************** * * $DESCRIPTION Notifies the clients that a certain part of the server configuration has changed. * $PARAM configType Type of settings that have been changed. * $ENSURE new.xConf.updateCount = old.xConf.updateCount + 1 * **************************************************************************************************/ function signalConfigUpdate(byte configType) { local NexgenClient client; local NexgenXClient xClient; local int index; // Set update counter. xConf.updateCounts[configType]++; // Update checksum. xConf.updateChecksum(configType); // Notify clients. for (client = control.clientList; client != none; client = client.nextClient) { xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); if (xClient != none) { xClient.nexgenXConfigChanged(configType, xConf.updateCounts[configType], xConf.dynamicChecksums[configType]); } } // Notify plugins. while (index < arrayCount(control.plugins) && control.plugins[index] != none) { control.plugins[index].notifyEvent(xConf.EVENT_NexgenXConfigChanged, string(configType)); index++; } } /*************************************************************************************************** * * $DESCRIPTION Locates the NexgenXClient instance for the given actor. * $PARAM a The actor for which the extended client handler instance is to be found. * $REQUIRE a != none * $RETURN The client handler for the given actor. * $ENSURE (!a.isA('PlayerPawn') ? result == none : true) && * imply(result != none, result.client.owner == a) * **************************************************************************************************/ function NexgenXClient getXClient(Actor a) { local NexgenClient client; client = control.getClient(a); if (client == none) { return none; } else { return NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); } } /*************************************************************************************************** * * $DESCRIPTION Fixes the bug in UT that cases the server to crash when a spectator does a * viewPlayerNum(-1) call when the game is ended. * **************************************************************************************************/ function fixSpecatorViewPlayerNumBug() { local Pawn p; for (p = level.pawnList; p != none; p = p.nextPawn) { if (p.isA('CHSpectator')) { CHSpectator(p).viewTarget = none; } } } /*************************************************************************************************** * * $DESCRIPTION Changes the remaining time for the current game at all connected clients. * $PARAM remainingTime The new remaining time. * **************************************************************************************************/ function announceNewRemainingTime(int remainingTime) { local NexgenClient currClient; local NexgenXClient currXClient; for (currClient = control.clientList; currClient != none; currClient = currClient.nextClient) { currXClient = NexgenXClient(currClient.getController(class'NexgenXClient'.default.ctrlID)); if (currXClient != none) { currXClient.updateRemainingTime(remainingTime); } } } /*************************************************************************************************** * * $DESCRIPTION Called when a client is attempting to login. This allows to plugin to accept or * reject the login request. If the function returns false the login request will be * rejected (player will be disconnected). Please make sure the reason parameter * is set in that case, as it will be written to the log. * $PARAM client Client that is requesting to login to the server. * $PARAM rejectType Reject type identification code. * $PARAM reason Message describing why the login is rejected. * $PARAM popupWindowClass Class name of the popup window that is to be shown at the client. * $PARAM popupArgs Optional arguments for the popup window. Note you may have to * explicitly reset them if you change the popupWindowClass. * $REQUIRE client != none * $RETURN True if the login request is accepted, false if it should be rejected. * $ENSURE result == false ? new.reason != "" : true * $OVERRIDE * **************************************************************************************************/ function bool checkLogin(NexgenClient client, out name rejectType, out string reason, out string popupWindowClass, out string popupArgs[4]) { local bool bRejected; local int index; local string playerName; local string tag; // Check if the client uses a protected tag and is not allowed to do so. if (xConf.enableTagProtection && !client.bHasAccount) { if (containsProtectTag(client.playerName, tag)) { bRejected = true; reason = lng.protectedTagLoginRejectMsg; popupWindowClass = string(class'NexgenXTagRejectDialog'); popupArgs[0] = tag; } } // Return result. return !bRejected; } /*************************************************************************************************** * * $DESCRIPTION Deals with a client that has changed his or her name. * $PARAM client The client that has changed name. * $PARAM oldName The old name of the player. * $PARAM bWasForcedChanged Whether the name change was forced by the controller. * $REQUIRE client != none * $OVERRIDE * **************************************************************************************************/ function playerNameChanged(NexgenClient client, string oldName, bool bWasForcedChanged) { local int index; local string playerName; local string tag; // Check if the client uses a protected tag and is not allowed to do so. if (xConf.enableTagProtection && !client.bHasAccount && !bWasForcedChanged) { if (containsProtectTag(client.playerName, tag)) { client.changeName(oldName); // Reset to old name. client.showMsg(client.lng.format(lng.tagNotAllowedMsg, tag)); } } } /*************************************************************************************************** * * $DESCRIPTION Checks whether the specified player name contains a protected tag. * $PARAM playerName The name of the player that is to be checked for protected tags. * $PARAM protectedTag The protected tag that was found in the name of the player. * $RETURN True if a protected tag was found in the players name, false if not. * **************************************************************************************************/ function bool containsProtectTag(string playerName, out string protectedTag) { local bool bFound; local int index; // Format player name. playerName = caps(playerName); // Check for each tag if the name contains the tag. while (!bFound && index < arrayCount(xConf.tagsToProtect)) { // Uses protected tag? if (xConf.tagsToProtect[index] != "" && instr(playerName, caps(xConf.tagsToProtect[index])) >= 0) { // Yes, protected tag is a substring of the players name. bFound = true; protectedTag = xConf.tagsToProtect[index]; } else { // Nope, check next protected tag. index++; } } // Retun result. return bFound; } /*************************************************************************************************** * * $DESCRIPTION Called whenever a client has finished its initialisation process. During this * process things such as the remote control window are created. So only after the * client is fully initialized all functions can be safely called. * $PARAM client The client that has finished initializing. * $REQUIRE client != none * $OVERRIDE * **************************************************************************************************/ function clientInitialized(NexgenClient client) { local NexgenXClient xClient; // Notify server admin of a Nexgen update if available. if (xConf.checkForUpdates && xUpdate != none && xUpdate.bUpdateAvailable && client.hasRight(client.R_ServerAdmin)) { xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); if (xClient != none) { xClient.notifyUpdateAvailable(xUpdate.latestVersion); } } // Show rules message. if (xConf.enableServerRules) { client.showMsg(lng.viewRulesClientMsg); } } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ X "Message"ZC "Enable player redirect to alternate servers when server is full""#s "!"""*7*"93s"@i+ "NexgenX - Full server redirect settings""#s "!"""*7*"&.u@"#s "!"""*7*"w@"#s "!"""*7*"cyH@"#s "!"""*MMM7*MMM"}|@"#` "!"""*#1"͍y~1@      %22+%A2   <5JC+% %  %%2CM[JJ;<%  %%         %% %<22%2ACMA2 %%% %+ 2JJ[MS;7 %%  %%25   %    %%%%     %+;22+#7MSSA7% %% %% %25FM;J72+   25*2+ %+  %% %%%     2CC79## 2M[[C72## % %% %  %++<275<  %C5MC2% %+  % %% %  %%%%%%+%%  %7MMMQ((# 7SgyJF7%% %% %+7++%+  +CCUM; % %%+%++2+  %%%%%%%+%% %%%% %    2S]iSYVA#(7[gySJC22+++ %+70   ;MUcJ;  %++2+%   %+5;;.5.*.2522222+%  +* #+ %Ci{{e^L((#7^kg[C72+%     %%  ;]coMC; %+22+%%+55CMMMMMSSSJJJC52.5  2+JPJCJ (;5%%A`^E(##F^}}kYF7%    %<<5%%+ 5c\PM %%  %+2+% % %55J]]]]]cZUc]ccicc]MC;+%*;M2SvoSS29MJF9VxV(#JYpwfO90%   +CMSMSC C{viU22%72%%%+2552+275;CS]cv{{{{voviSMSSMoiл{U%ASSQETpŽ-% ALfffE6(   %J`vvvlJ55+UəoCC2JCCCJJCCCJCCJMMMSt‰M-MUJF9EVyT# 9ETTD6( 27FMv±vM2%*UɻiM;SSJJMScccS.;MJMS»¿v9SJ;2%07Mol`}jT3#(D?-#   ;S{ivF$.o™i`ccSUU]icc]]SMSUoL555%%5S]2eG3## +66-#  %5Mllv2.**{iioicoo{{{oo]JJU{7%2%%2cUMV?#%  ((#%2C25;277CUM+$*ƒMoicco{oho{M%  2SUUf3+2+##+%%+7AMSM`lv2.ɉvMUUCJJI]ic]U]ca]J  5Ciif? 7%<7+ +2CC7FCM`ll{vi»{J 8iջ{]J;M;.55JIPJJJJM]ozS<# %+ 5MiipQMAFAM;7FFJS[[[[`[ci{»ջyll{viA# .c¤vJJ+5JC55;;C;;CCJ]ioomo{{ɻОv   +55;Uvor[`SlSMcCJM[S[`ci{{{iiv{v{{yvviv[[F% *cШv%<5+;CJJJJJC;88M]cc]]co{vovvv{{ovi{™l  %+5JCcv{v{{viY[QSivvvvl``vicUk][VSQLLLCLgkgv{voYYA *M‰cc%2%%%5CCJJJJMSSS]USMSUci]]Uciviiil{{il{c   5CC]{v{gFJJQSQJFAFJS`g`[c[SC>0#EQEEM`i{lYM2## $.Jv±vMS+#%% +55;JJJJMSSJJCJMMSSMMMS[][Sc{{viiU[JAFMS   25J;c{lv{l|lF2277<2+27Jkv{{vlk[MJJMMSYLS`[[A7A0 .S`ivvMS%0% %% %%2.5CJJJM5522;CJCJJJJJSSS]i{{{ii`S5+#  *2;MCcv[gl`lyl`7A+0++2222F[llg`^S``SSMMYMMF;A<+++ .;[g{UJM%0%%22% %+.2;C;++++.27<;;JMMMS[Y`[MS[[SFF<7+(6(%25MC``SVKMJ[`M+222+2++22AFJJ>9A7+777A922920%  *5CSvcUJCM%++%+22+% %%% %+225;C;CJJJCCC6(%2% + $$55]]UUIJCc\IaPPa]tPahiolgMJ2+%%%%%%+%%% %++220FU22% %  @.o{vcUο\httmmЮgM.*+22ELJQFJ;PPazaP8**$  *.Pڹȣt*.8Pto`C+ #(A339<+9+###((#69QQVLA9 # $7F`YF7##++27k!/DCB3x*\29k'/1III{02VD*a9>OKK-s+7(:~$3[.)RQP|.;j:;>,:`I1w5=/="/o?@\XT:,4:)5.sHE7A6*7eb]!1CK64@}KIl+9%5895BRN(8:oli"4PJ6>CI.>=%7VM;C-7;Z".EL\P8Anl4+6`TKR;D5.92.EMbX8B!9>-9qqJR=@f\":1=JSi_&4:59!PSob8<'6&sdTW&BF59uhYY).GG99}w[[xj--;;KK__pAA |oddȄt61RRxnGChh̆v)VV9kkы}J7[[SKfc֒CZ?ПieaQٖM{{nkܝbCj[⡔`!yonG禗{]t/boQbU{y7iiIɽ͵cǫ͵ȭ"#b "!"""*'$" O5v@      %22+%A2   <5JC+% %  %%2CM[JJ;<%  %%         %% %<22%2ACMA2 %%% %+ 2JJ[MS;7 %%  %%25   %    %%%%     %+;22+#7MSSA7% %% %% %25FM;J72+   25*2+ %+  %% %%%     2CC79## 2M[[C72## % %% %  %++<275<  %C5MC2% %+  % %% %  %%%%%%+%%  %7MMMQ((# 7SgyJF7%% %% %+7++%+  +CCUM; % %%+%++2+  %%%%%%%+%% %%%% %    2S]iSYVA#(7[gySJC22+++ %+70   ;MUcJ;  %++2+%   %+5;;.5.*.2522222+%  +* #+ %Ci{{e^L((#7^kg[C72+%     %%  ;]coMC; %+22+%%+55CMMMMMSSSJJJC52.5  2+JPJCJ (;5%%A`^E(##F^}}kYF7%    %<<5%%+ 5c\PM %%  %+2+% % %55J]]]]]cZUc]ccicc]MC;+%*;M2SvoSS29MJF9VxV(#JYpwfO90%   +CMSMSC C{viU22%72%%%+2552+275;CS]cv{{{{voviSMSSMoiл{U%ASSQETpŽ-% ALfffE6(   %J`vvvlJ55+UəoCC2JCCCJJCCCJCCJMMMSt‰M-MUJF9EVyT# 9ETTD6( 27FMv±vM2%*UɻiM;SSJJMScccS.;MJMS»¿v9SJ;2%07Mol`}jT3#(D?-#   ;S{ivF$.o™i`ccSUU]icc]]SMSUoL555%%5S]2eG3## +66-#  %5Mllv2.**{iioicoo{{{oo]JJU{7%2%%2cUMV?#%  ((#%2C25;277CUM+$*ƒMoicco{oho{M%  2SUUf3+2+##+%%+7AMSM`lv2.ɉvMUUCJJI]ic]U]ca]J  5Ciif? 7%<7+ +2CC7FCM`ll{vi»{J 8iջ{]J;M;.55JIPJJJJM]ozS<# %+ 5MiipQMAFAM;7FFJS[[[[`[ci{»ջyll{viA# .c¤vJJ+5JC55;;C;;CCJ]ioomo{{ɻОv   +55;Uvor[`SlSMcCJM[S[`ci{{{iiv{v{{yvviv[[F% *cШv%<5+;CJJJJJC;88M]cc]]co{vovvv{{ovi{™l  %+5JCcv{v{{viY[QSivvvvl``vicUk][VSQLLLCLgkgv{voYYA *M‰cc%2%%%5CCJJJJMSSS]USMSUci]]Uciviiil{{il{c   5CC]{v{gFJJQSQJFAFJS`g`[c[SC>0#EQEEM`i{lYM2## $.Jv±vMS+#%% +55;JJJJMSSJJCJMMSSMMMS[][Sc{{viiU[JAFMS   25J;c{lv{l|lF2277<2+27Jkv{{vlk[MJJMMSYLS`[[A7A0 .S`ivvMS%0% %% %%2.5CJJJM5522;CJCJJJJJSSS]i{{{ii`S5+#  *2;MCcv[gl`lyl`7A+0++2222F[llg`^S``SSMMYMMF;A<+++ .;[g{UJM%0%%22% %+.2;C;++++.27<;;JMMMS[Y`[MS[[SFF<7+(6(%25MC``SVKMJ[`M+222+2++22AFJJ>9A7+777A922920%  *5CSvcUJCM%++%+22+% %%% %+225;C;CJJJCCC6(%2% + $$55]]UUIJCc\IaPPa]tPahiolgMJ2+%%%%%%+%%% %++220FU22% %  @.o{vcUο\httmmЮgM.*+22ELJQFJ;PPazaP8**$  *.Pڹȣt*.8Pto`C+ #(A339<+9+###((#69QQVLA9 # $7F`YF7##++270#EQEEM`i{lYM2## $.Jv±vMS+#%% +55;JJJJMSSJJCJMMSSMMMS[][Sc{{viiU[JAFMS   25J;c{lv{l|lF2277<2+27Jkv{{vlk[MJJMMSYLS`[[A7A0 .S`ivvMS%0% %% %%2.5CJJJM5522;CJCJJJJJSSS]i{{{ii`S5+#  *2;MCcv[gl`lyl`7A+0++2222F[llg`^S``SSMMYMMF;A<+++ .;[g{UJM%0%%22% %+.2;C;++++.27<;;JMMMS[Y`[MS[[SFF<7+(6(%25MC``SVKMJ[`M+222+2++22AFJJ>9A7+777A922920%  *5CSvcUJCM%++%+22+% %%% %+225;C;CJJJCCC6(%2% + $$55]]UUIJCc\IaPPa]tPahiolgMJ2+%%%%%%+%%% %++220FU22% %  @.o{vcUο\httmmЮgM.*+22ELJQFJ;PPazaP8**$  *.Pڹȣt*.8Pto`C+ #(A339<+9+###((#69QQVLA9 # $7F`YF7##++272V;Da9KOKCCs+<QB~$}C=PRPH|.Dj:V@D:`FHw5K/D"Io?T\VVDH4I)GIsEN7TJ*]e`J!VCOP4O}IM+3L%ZST5SNO(]iokN"OJT6XCT.\Q%OMY;R-[M"\EPRY8nlX=S+TVbKZ;[S.C.aEZXZ82^!kU-wqeJ[=^\\"Y1hJa_Z&aY5/jPbb\8]'dfnTRdB\5hhpYV)dG\9zwAr[jjU-^;iKv_prdA1qoydtvN1qRsnŽ^C}hvx$qVk}}E7u[`KxcքD?К{e]Qى-{kܐCCc[!;}oGP]a/Q0#EQEEM`i{lYM2## $.Jv±vMS+#%% +55;JJJJMSSJJCJMMSSMMMS[][Sc{{viiU[JAFMS   25J;c{lv{l|lF2277<2+27Jkv{{vlk[MJJMMSYLS`[[A7A0 .S`ivvMS%0% %% %%2.5CJJJM5522;CJCJJJJJSSS]i{{{ii`S5+#  *2;MCcv[gl`lyl`7A+0++2222F[llg`^S``SSMMYMMF;A<+++ .;[g{UJM%0%%22% %+.2;C;++++.27<;;JMMMS[Y`[MS[[SFF<7+(6(%25MC``SVKMJ[`M+222+2++22AFJJ>9A7+777A922920%  *5CSvcUJCM%++%+22+% %%% %+225;C;CJJJCCC6(%2% + $$55]]UUIJCc\IaPPa]tPahiolgMJ2+%%%%%%+%%% %++220FU22% %  @.o{vcUο\httmmЮgM.*+22ELJQFJ;PPazaP8**$  *.Pڹȣt*.8Pto`C+ #(A339<+9+###((#69QQVLA9 # $7F`YF7##++27a6 F7$763l6U8d; y4_:$p:g> ::7]<N?%8j@%BEs? Y@ c@oCSD)AB;>xE bFoG|JUK.hJ#H wMHJCOgN,N uP^R16~R[SMS}U bW6WR RSLYi\3Z!wZ,[X ^kb5^%a] Kda.og7d#d_Oc n gsk;f4h&glsk/zo>n${l`qsiTo3r(~tArvt3xEwmz!x8}G$~J};z,"L@Ɉ0$YAOя'4ESƓ*RHVי:Ql̜,LYĘ< O^ۤ#ƜAӣ4ŠGb߮)wˤIת8f [˨Ok,ٰ@ædqϯR0tB̯by޻R9~Ҷl;["ݽpŽLoMe1Ŕvaˍ˝|eϟHۅԦxֳߵ"#h "!"""*"ry1)C@      %22+%A2   <5JC+% %  %%2CM[JJ;<%  %%         %% %<22%2ACMA2 %%% %+ 2JJ[MS;7 %%  %%25   %    %%%%     %+;22+#7MSSA7% %% %% %25FM;J72+   25*2+ %+  %% %%%     2CC79## 2M[[C72## % %% %  %++<275<  %C5MC2% %+  % %% %  %%%%%%+%%  %7MMMQ((# 7SgyJF7%% %% %+7++%+  +CCUM; % %%+%++2+  %%%%%%%+%% %%%% %    2S]iSYVA#(7[gySJC22+++ %+70   ;MUcJ;  %++2+%   %+5;;.5.*.2522222+%  +* #+ %Ci{{e^L((#7^kg[C72+%     %%  ;]coMC; %+22+%%+55CMMMMMSSSJJJC52.5  2+JPJCJ (;5%%A`^E(##F^}}kYF7%    %<<5%%+ 5c\PM %%  %+2+% % %55J]]]]]cZUc]ccicc]MC;+%*;M2SvoSS29MJF9VxV(#JYpwfO90%   +CMSMSC C{viU22%72%%%+2552+275;CS]cv{{{{voviSMSSMoiл{U%ASSQETpŽ-% ALfffE6(   %J`vvvlJ55+UəoCC2JCCCJJCCCJCCJMMMSt‰M-MUJF9EVyT# 9ETTD6( 27FMv±vM2%*UɻiM;SSJJMScccS.;MJMS»¿v9SJ;2%07Mol`}jT3#(D?-#   ;S{ivF$.o™i`ccSUU]icc]]SMSUoL555%%5S]2eG3## +66-#  %5Mllv2.**{iioicoo{{{oo]JJU{7%2%%2cUMV?#%  ((#%2C25;277CUM+$*ƒMoicco{oho{M%  2SUUf3+2+##+%%+7AMSM`lv2.ɉvMUUCJJI]ic]U]ca]J  5Ciif? 7%<7+ +2CC7FCM`ll{vi»{J 8iջ{]J;M;.55JIPJJJJM]ozS<# %+ 5MiipQMAFAM;7FFJS[[[[`[ci{»ջyll{viA# .c¤vJJ+5JC55;;C;;CCJ]ioomo{{ɻОv   +55;Uvor[`SlSMcCJM[S[`ci{{{iiv{v{{yvviv[[F% *cШv%<5+;CJJJJJC;88M]cc]]co{vovvv{{ovi{™l  %+5JCcv{v{{viY[QSivvvvl``vicUk][VSQLLLCLgkgv{voYYA *M‰cc%2%%%5CCJJJJMSSS]USMSUci]]Uciviiil{{il{c   5CC]{v{gFJJQSQJFAFJS`g`[c[SC>0#EQEEM`i{lYM2## $.Jv±vMS+#%% +55;JJJJMSSJJCJMMSSMMMS[][Sc{{viiU[JAFMS   25J;c{lv{l|lF2277<2+27Jkv{{vlk[MJJMMSYLS`[[A7A0 .S`ivvMS%0% %% %%2.5CJJJM5522;CJCJJJJJSSS]i{{{ii`S5+#  *2;MCcv[gl`lyl`7A+0++2222F[llg`^S``SSMMYMMF;A<+++ .;[g{UJM%0%%22% %+.2;C;++++.27<;;JMMMS[Y`[MS[[SFF<7+(6(%25MC``SVKMJ[`M+222+2++22AFJJ>9A7+777A922920%  *5CSvcUJCM%++%+22+% %%% %+225;C;CJJJCCC6(%2% + $$55]]UUIJCc\IaPPa]tPahiolgMJ2+%%%%%%+%%% %++220FU22% %  @.o{vcUο\httmmЮgM.*+22ELJQFJ;PPazaP8**$  *.Pڹȣt*.8Pto`C+ #(A339<+9+###((#69QQVLA9 # $7F`YF7##++27%1 has changed the game to %2.z s "Enable anti spam"t "Enable game start announcer"v/ "Enable map switch tab for match controllers"wuzW1hv\{h D h@hDE@ w-uwewd y% "Enable player overlay skin effect"x5C(h"::$-MGff-H[zAAb%5AHA$bH&3-c -B|$A-c'0z55$H$$bH&0}5},}$,(-B'05pp5,$H$$bH&lz-c5f-c-H(-Q'a( z{%0-H-Q -H'a?@' } "NexgenX - General settings"|sD#&2.s2/ ~{AU_]::$ w*-]:,XX]-M-h+&X X, $X:,j ,X]]-P-P' K  ' D "Receiving map list (%1)..."} -M( B~TF F-j{w.}'\ Map switch } game-)$\Rules  serverD J B l B z B \ B q  ,  .  X*C,@C,%,,.= & C,,,i%9i,i[C.Switch to %1 rii% Send to URL-Reconnect as player0Reconnect as spectator0(Dis)allow team switchD&B ',  B,$ Time limit% Score limit*Team score limit$ Game speed( Remaining time,,PSRMd[ set^ set_ seta setC set&, B, ' B, '$ Pause game" End game&Restart gameb"  Add botsTc%  Remove botsV&,0$Allow team switching0$Allow team balancing)$Lock the game+$Tournament modeP1'S1'R1'M1'T1'V1'P,S,R,M,d,T,V,d 5:00T 1V 1,''''''----8Ff  Kf EAvw*J @DF>Dk.Dwk*PSkSSkRSkM&SDB I "Receiving map list..."HkvB=-a a?@'q@@a  CfP6'S6'R6'M6'T6'V6'[-'^-'_-'a-'b-'c-' Fm$mEwm* :E,ma/!,.m-m b _JT c _JV [ sJP ^ tJS 6_ oJR `a QJM C nd  JFb::$-M' K "Hide incompatible maps"M "LastVersionNotify"L "Switch"R "Map switch"N ","O 255P 2S 40H$A.  C@A,)NexgenX - Full server redirect settings'$?,E A, 'HDC '%,,GSaveFResetH,j$AEnable player redirect to alternate servers when server is full'B@CD?,@@CD?,@@CD?,@ Message'RBBBBBB3%(3,,. Server %1S3&'3CURL'3A3C,3A,@3]R, W "(no reason given)"U 2.0Q<_ j--cRQ<%<,<C#<!<A#<<U [ 1.5Tl-r][|lnexgenx_config_changed:Ik& XA "To view the rules of this server use the !rules command."\F "Failed to change name, you are not allowed to use the %1 tag."V)wj-R%C&C,C%A&A,A Y~$G~Iw~* :I,~a/!,.~-~ sF G)  2 5.0]D "You have to restart the game in order to apply the changes!"^? "%1 has forced %2 to read the server rules. Reason: %3."_3 "%1 has modified the server rules settings."a5 "%1 has modified the tag protection settings."[jRIFFbpWAVEfmt "VDdata>p )hP+t SGU3f /oN.,cXz -O!V',.,K$P hv/FK8Ɵa Xq,I46-0Y&D_6-ppr2.GVJN;W+5a Xޮu(+(=J{]fWBδ֯@C*30 )'Xs < T<%#4C{HEDq@CG6D"7!pԿn0L (1p/2 2׎.ϟl\ 5r .e M*:mAv?2!B˹ɞύ+[h/EY\P8d> cGb+,5RHD5 T +ʩȎy"ο¿]'v%Y1(<1:B1" mD)uHЉɀo =.NCNPKAn3+u$L"x uO#200(M64JSl6Ei/UB _6?: SM 8]0 "+)"~(z )3*{{ %&#="('pGG@q3Oc|T$!%c 0\|)uZ <%]! 5(&&t W K3_@B3aAo , XގжV̦֕3qU`K.K)UΘA իӹ3dz>/85.$2Ce *b~߽ə߾zi7Bk?B?=x?A7%$_0ѧ2[["$" .;ƯR{OѸ6 H'X t&6XAa?2! wwzQ6K +4Kad\Bh#W1f7.y.C^OK5Qud?A8bӑڌJ"c6;>@5 (Ck[yJ]48 *FVZE+:/,)!3k77(+( .&$92]7őREV* { $1  !Dzʢؖ:# g N-9>L7+#sH {!())x5I'دDWy* $"rZ̨΍S r0R#7)#={ , 8 U)7q9.j D/kJsXӴR LίL :;"L&:-=B4A5m\0ˢ.f08DLI:$T + WB L;X| " m )D{|KlLڛzwnH/i6/*)  {/eύً 6iDHDY:/7O41R/(%dJ2)R&z ~(sŤ"?R* >  @&6@FoA2 ! Fcٔdk3QM^aS6, G'IWqSK@M̌AiX,PdGpy&:c@"#.8:50*}Ene  i޳PW6 "/HVQR+?-C$#'$&"B- 4%U,%+\H$.GƾGK*[vV\uc$ # hD0ПavE* T % >![3H%WYM6DM! :cH (0-+ :ڽ7cް+z]B_6 AQZvXM/Q6`= BR <+M@!D9##K g; > Zwf%'jD #|–K@B C!*Ȇ9&"(.#3>@7"Qs+M#V!gi@%:&3#6/%Qs l. {I m H0Ͳ0c-S>oTC #292S,n&!$Z|hq)!9rIRL:y W nFJm*G-/@JtA`4 &O4pL8Ј4Ta]]L46'4%"Xo"U .0\.#,{vüRƴ;ߚw 654 5_$& 9FͯӞܼ( ->{QSYVGU*i7m\ ^Ac %.:>c@2fo~!ж[=[f.z\7Wlb{=G6S 9#B3O_K9#j 2 ?X *&,&dChcX͇dڟi iI@МOc" #"M  (@01-#0n 'm,"2)xg%#rl4zޒ3 j>- K vMgɳ(w[@`u 9.Y5t/&g { nj "b13,*(.2~1(g,.0)% aYف!׼6ށĘ+?ʿo+.&S?n0E%05U;73 zdΎnԽ?p0^I2YRVD.9 % jG !*3.!ŦG6E#'O.'(>|G?3L L 3N9j,^$)JVZI?:1.|'S%y.5>Ay4,xWǸ́ϣMʴ)M@=_+D  x)жŭ׊eJ)j8JUSF.Y&5<5&% wQ֊ήY,Xi=ݞ:h#7 L*ߌA =X iKy/BMI;5) 3 k!06l1"/ ١א ~]tl"  UbM۪ `Z3OU @%319#w"F,~-#l38?"^/'1"ɛϻC  4$l Igr^Ԥ #=DOnRIA63.%8} ],D:z>2(|hGp2ĴВ$oVjґ~m!K&'!=u nD mDd ^[ 2 ;  Bķb4 9eL. $FGMf8 T6e-/VESK?,u  71& !58HEc2arzP0#p?׃#ȟs؈ xUfg{L0%;n;N/%<9.E$&+:$w5g s%B0K.!m sMƨÈƜNi cc!ˡ,RcgV"*&gcw!r,3}2'\37ߗ [(Vt"/@<A9J(5ݵ}G gyYüØl^?X pV,/ - rF[$+h'4|PK " 7><9.0~nQsG')2$K""Ce7`{ӲЙΟ(\:,.)y%e 6 } $s  |$m6PByD>.  ? 2jlOi-$Y E%x7K " =vטт 5 =3qCLuI8..$?a Dwa2JM9<"E7_G*١Af knSB`i^&u*;A;+ynL#K"V wq(>BYDu4ΨɮX$R_6-ˌ+`/ IOh,!2$%%)N1]8;6+8nB} /@OM=!ukK^'#RzfEoʍe Zs4%,b& +%9$;3O@=z*chC % 7/AO>, N3"$%S!Ӷ k Jdۭxۜˮj)&"^J *!m )8:c.F"s^! [JHAg0:>@C AICu9`)o 4f "&$- ey.G}l@ͣ@ޠwn۱'x *.,+h#P 9!9 *~W&4!A?,5i& % OlC:5mE+h lK|& ' JcG8 oDME O$9@JC{8.K)m$M5M#07i1#l C])%FFA4 D6֓Fx#:%A%+'25&8DF =e) M!')d$Mh .]% D߬>ЕD^ZwŠDžڥV v RX='/u1*)*2W782)$fr4#{u26-KS^Sc7FjY-:+Z0$,l͕õRòԖ6{]q#)m$/AJGd5z[e=J# 8?=2(SM$"bU B F%v¢)Jٔc!$" P|5n#% )d%0  %# 3Iͬ72,/f8>@_GMKB*B V6lR{a)I3i0 ק&]qڒiQo ) (,)k$A eHnAbF A +4:D?B3!L SfjZV\ÿZ';= z+($* /ٻؕ o&$@~ tM+36+42 01,",IB "$F FĢ0ZJr >[9|Pe  .7hq:P _"5B@5'u!b%@,[I/85(mI]fݝ{A^ٯsm & N}bwFgE1Ei/A74e.$"'/31%^VA|-P=ETC2ˬYmWh.<2' |h1.Lڊ] @" ) vLt3KSUsR:j;9pg R 9;DME2c? +Hyp)6'C/L}?}} ! 5 Fh  *#1e9-`  `"#n˘9 0!+=TNv][cO2tҶ;̨&U3)C:9(m\ߟZ٬#֣|$F Ac7n Tɷњi=, ,1߄ޝ ":mDAy4#YP$,P+! O  _#2#'(! k%̧*#ID'17( Y5+K@3\h9[@/M0J*UTX0D,'X?߶ݭ7:,SVVM*63L;gk֏ yegُ-xӹ8+ M2 %:QFB3* #nD4;"x8LtTVLf6Ar>^6ˢ F:Fl;*0U}l{uT=> $_#K :n K.+1# / ݎٸYm] z`8P?Z_WE/&q`> `s2, HYNoՓ%,%< Mou dolAW( `!$)E8gG;QD], bz/זE!$eAۍi̮[ 3vU3szi 'v Yy!)0Y3((/0&f Us E˗Ďˈ'bC-FBYvTR>ϭځp>vZ\rJs.BoJ>+"(`-B%L >( & (BĹpk(,f#44`ʿ\}˟avE`q aԵ _/, %2IF]SPAM(#Ko?]ُ/LTPL=. ˖;_vNK*Y@mJVmw9<e`{P/5HQI6]!9 a="3 Vڅ 3(3H;9I60'>G.߽+ *=JA7 բ՞rP&'~F '<%+%Q3n#,g.! ߽ڙYZB?XokP1mqE+ Mj HrSei״ ͸ɺҞBd&G$  8I2G iNT | 8 !0.E>IG:?" ~қrF['"$ :&©y%!;gC/L<  6bkG2 =&O%8,:8/UZ߿ lu #7& 8IkTm{a[p?o  @&i1:Ƽҙc +Q+4m7/#!#o,M1,}B%G wnz\. {D5]Ͻ2# % k.Ч؊$G'Ѡ\*>:1n )=J@=u*a AJNݲ w-72)R֮<ѩ!*K-k*W acƋɵ>L~U 1 *DO*RC<,hh 5+ ZD?&"ElC:q~ V >+ !*31^ I5I,Nܸ TU #C5Evǿ*ε3k.A+a(MjGbѾ2pܡԷՉIYP ;Z$4'7S- Ln !/83o&4. 2 0Frט'vYe3\ݳ8~ R#w &}%!c * e~z -(5MS!WS(7YߵCmކl %K/k,W +KٚK !LDr H ] a@ J $.:+b#Aj>(-1 6.7 eBZxݻ% jHt1J &" i Ϭź˩)b? $7?7I' o*R6)4U*5P  qk  % <?1H7κ5ƴc+y5O2)BVq:ކ/ki)-x˥ۏ #-}$ f 5+7:KG*@[5'9hm;wJ!*a -x` |q 1mY$g^I +n690#?IgmJP >I _ aVޥIk?vX?}ܚb ( n( e{Fx"Q44@]Bx<(E6W7ʳ{"3^0!E_wW/ $ 5ofBHdPbP 'T\"" 9/<>6h&w<!,N 5arl,YN l>n;W^,(52& {'20-$ "#!sS8'kQ'=@3?Y˼F>G3=@8%[u Oz ӛ!" )2) P5 )w5719%[ 8 <S*ډ&ԆݳW& V4 A 51  U m %-$Ѝ5WΛڹ Ik !1>@/5! b>hR iF &6A?3V Ɨy-|,P =W"n!UY_͋Ml(#! #1:8+"PG M@<  N:VnT 4=_E|9&A r>2֙ s';HKF)7MݣmAőΥBKP2(+9)j  j~%"$p rDL[%#'<&Gvmr ` JH^3&E94 ~#'d&^ J=CGV(nF M RjuzhRjR @9;Q&dT38,t ecrD@  ' G oZ1 W [uV[ v & F O Dr6 E/ dPjG$Nch j~r^P$rC.= ) Y6+cev^n = B   @>' "T!i  uKp$2Aix > 6wWI=%' 5T afOx Wwn rig}R(H  ' X d  d4_n^ AVeE H= zH .Qb,Rfk * 2 ).OQ`QX(a2@7nP9 \Md&} :  J ] @>(S% h , lNy jfXY e u& L G oV:8=fd d  _T>h2 A2HXyt 8 c( &  "53p'  VditVCR q   :w7;jV$@ `5J[} TdY% jZMC=$ ~ `pS? . wA- 1 L[fju  m  , * YMc5  0 a    % BH|\X- ~i?{ U3 B{QV?CAW,rC4 - S2P<h* U"w N AoZ'1i Kw1!B=[8~_ HWH =cS+X* LH Nj_ v9o^*jOfE[:7 5 A ES_&2e7 6U e +O5ILmRh`HJ}g{T <x v Z ,#1,=:vLtO( h4h6q  k"J;z`gj:mj W i&1yZtjq: j 6/!B'&z9B6 khA Cm IGhxu TI3Wy{Q[LUP ^  %m8_A?mrk { I*hcrf#2U1~)S-9Is^PE2|HvP[cl[klBqdm l7MmD}fXP@Gr3Vkj/(' 6y_H3m %0">ITzTi8E-3~P[>, xw :3 -]p(az63 TRazT\}Wv-:N <t@0>1dt/cCw`-v7$ \]^T'\l0R3'2Fw_)r{]Z)Z`xg&r eXx<=V)a6Pg'-vixWq@k4$v mJzn?':O uSri7t!:UJm./Fg 2,*s":x>[2[mat~SllP1&yD[y<[UB)S Dq;DXdBaE_H :eX4uw[ANm#i%?UGb+5z}>lj9 <&4BOGN^:VG0fnCw\N@Jw:rXo Wa.\*5py@|3rakt$\"ehSf)H[D`U?ezxjl#F/DWhOdwQpVhr>1)8Q t! 8ttOgZ xmh) <?@Y;8HPD \[BlgA()i|k;C(E!VW(dn lKq]rVK[tevCeW?{}[}ov,/6Zs;cG(6@ =Fpc]cUH)s-&%hr{'oLI9[<_'.J^+' NJ).HhDeC)U9,v}y&A A:MLAvaN= eqTA] a]n.ArXTLx7(,3g NJ9"bOuX.>T~=vV>`R%}64BN96Oj_=juy#{HvHZA9[z% *S=pKm?+i<$Erq! L*!J:McaFz 3u@- v W;0>zKQtyT]B}# c JB)S4S@fw]}3+tg+8"CR3 9 d%K'|H@K/yZJ,Y8l\/@g3vPiD}QAE~P[M):#aB\@M/=2m3p|de~T.P1JN~}&bmW? 3 qG(QFdt<&_Na5aQ&( ZRNt3,IU"+ #IoPeNw&?c#\r_?O-GiK-yK q*Nw28Sux^+vP(yK^uJAimSm-TzO?jik]9M{p u/e I93uykxd\m}R0gY#I*@@&cIVJ? S5sCn{d,AlwrR?. NT2t*u]"wz:z&&^20d9{ pb.bRDpL@@I-Y.^l_#h=Fy})4{kO+jZe1a"o[?/cg< og`Pe I+`;NyNTr,/:VoEF^i[|$=`k5*)3~Y]J/a@tVjn*n*F`^juM6)&?dWYhMEd]cpdC' W 0_k4%:x*7Pkad^"i{Ko}qH^QG6MZIr#sGf/jbwd0y7;dzVm x4Do8T^1QFs?XmAyd&o}P3RVD}wq'mHn )]M?$/% oNteK_{Z(wk#\mEi^)fKirj606;J`5.=I>4+3X6x'ukt\cP>#x$#b}t4*@S~g >bc<TFylHa{sz(.E`1pGyX-g0&  ^q$ ~? 4[7w_foeMrOn gFekrPP)m R :c}s~2_M@4) zLRsfr|$\r0s Hi_V^t |]M47T"D_W2n79v"?X+]f= ],Yq (n,dA" c6.De(\oupWA$$R2is|)v ,&~J)#Y!Vpkz4kvB/N94ksRLgPmG. mLB9Q;(oj[WKAKgMa31W'-+N9fu_cYO:3:@F8T&b59Np\$ S8j*:S`\RORT`keSD6 u<{hnwFQd^8 t 1_1VioT1!9[zTnVO.}mrvjQ9 xgv"KR1?w Tu}plo'TltU'#\.tF  8aP-<IMJMPNG8* u`G6wN/*IdiJ-3\# &Z+>DI:-1.$^=vPUY]`cZH1" UhMHLi<g kI* U* 1:AMSUG<+).3R 6Q`S6$/Sg>dadmomgecd]J9 2Qw)Hew}n\K<.}hVLC<5@N`kqwsts{EwoZPF7%qb[OMGMQb{,35?Qfx}tgec]SOA;0"|~|{%:Sdsusqouyo^OA3+$ +=Tcpwyqg_YVSOKD:.  *4<DILPX`cjklmlh`XPF>61*)&" %/7=BIMNONMLIFGFEDC?7/$  $'+/37:;?@A>:6.&'$#"!   !"##"###&''&"   c- "%1 has set the remaining time to %2."dRTe ~R:% CRON:O ON NO latest-versionfJNf gZ^g/BA new version of Nexgen is available. Check www.unrealadmin.org.-U'  g. "%1 has changed the game speed to %2%."ieP?# Ymeo  ^mK{oo zm  "HideBadMaps"e&.  X@C,A, 'A, '".= =$Hide incompatible maps'&FSwitchB$ A, B %,,$ Game type'4D A A,Mutators not used' . = (Mutators used' . = ='4'B~;=-|pHideBadMapstruetrue -' j3 "%1 has changed the team score limit to %2."fnBU n, "{n -nch hhS4oSSnn4q: kdL/rg^^ O.g/1Failed to check for updates, error returned: %1Sd l. "%1 has changed the score limit to %2."nF #Cg.Q130.89.163.70/nexgen_update.txt,P q- "%1 has changed the time limit to %2."h7~s_7,"{7 -7aTL.  ? LTL77 SW{W WVW7JVV |7L.  ? LVLVVW o 80p "/nexgen_update.txt"g "130.89.163.70"r/ "%1 has removed %2 bot%3 from the game."s+ "%1 has added %2 bot%3 to the game."t; "%1 has modified the full server redirect settings."w. "%1 has modified the NexgenX settings."m-;x"S"*Yk-TZReceiving map list... -4P-% --\Y YdYd-Z=--%-D-Z {d z-E2-Z%|-E}ddZ-E-"S x' "%1 has changed the game to %2."y! "Attempt to use protected tag."}D "A new version of Nexgen is available. Check www.unrealadmin.org."H `bg;F!:`:X`X'DB:`:W`W'D( uYG#F-r"* {ZZB>Y." ? YZ 3 "Failed to check for updates, error returned: %1"Y@A "NexgenX configuration file was corrupt and has been repaired."|e -T'; @ [d-T[."[C.Receiving map list (%1)...SD Sxy|DKI\:xv:xv\:xJU:xs@' A ($!9('or(  :',lw * -( *r(  :',w * -( * r(  :', w *.  ? . . w * -( -' W * S77r(  :', w *.  ? . . w * -( -' W *qr(F :',F-Ar(4 :'&=-;r(" :',Y7r(= :'&#>HideBadMapsT=-b; N r}hv]-U w[*[-Ur rJ{.r  w{*{l[f -)rN*/?To view the rules of this server use the !rules command. B GG $: ,;: s$: `: v# I : J: s@(--nexgenx_config_changedR   C ]ATW-:-Tr"*4P% :. w:*:%z]]S:]ppp], S::.:S7A."=4P] K bgY7Bb^b^'@>b]b]'@( L XFailed to change name, you are not allowed to use the %1 tag.b \ O( -f' ^ |8&S-J'-j'-h'-c(Qf/The server you have tried to enter has no more player slots available. You can try again in a few minutes or reconnect immediately as a spectator. If you wish to play immediately you can connect to one of the alternate servers.%!Server 1%unreal://127.0.0.1:7777/ e@_ PJ#go,i|$o,jO6o,kNbofhofhb ` F!f. b }V .:}u:}FI} 1#[.  -g GX-g C, 'A, 'A, 'B, C.= L Show rules1&S1:The rules of this server are:'$1&Reason for showing rules:'uu,dB,1&S1:The rules of this server are:'$1&1, w%Mw, wf1 'w8 i vE,v$*:v,Vvv ] la \Y8 Q\%O\, \f#2\\ me 8f ;9wu* w*L-r* g |fy.w*7zypjZ|nhzypl ]|8zyac\|n q G/bZ{Gm]tG&G}G,&,G&}Gm  Ah ~-^\|~nexgenx_config_changed:I}, p oF"P-bo-Toe-l'A/Attempt to use protected tag.BV U%Ce-l M |x "QN" J -J-|-j-y-h-w-f-v-j-s-U-rb29$<*$New settings have been saved.,%1 has modified the NexgenX settings. l B$BzvwB* :z,Ba/!,.B-B sLbv w* rB :z,8 s {RHa}wa*D.a  fwD*D r{aa t pIiV:pup p$A-JA-j&A-h,A-f,A-j,A-U, $A-c/Q%,/!%,/ H$A-b%E,/ $A-)%, /b  o xcm xyzmm;An administrator has forced you to view the server rules!S 2m z IhFaI_wI*HIa/!p.I*II v  3r bK@j. u w  2x  1y  0f "nexgenx_config_changed"~ uNCOG Yu*rG**M.G   cJn pwJX" J -c-pQn,%!m,&!g,,!c,%^,@&],@,V,@b29$<*$New settings have been saved.9%1 has modified the full server redirect settings. C O9q>K:O` VOewe*J.e  wJ*J5yO:O`:OFee?Il,wl@*l@--nexgenx_config_changedROl  {$ .  C@A, NexgenX - General settings'$?,E A, '{DC '%,,wSavevReset{%,D?,@,,@$ #Enable player overlay skin effect'B$ -Enable map switch tab for match controllers'C$ Enable game start announcer'E$ Enable anti spam'K$ Enable AKA client ID logging'O$ (Automatically check for Nexgen updates' z Na @- -JB- -jC- -hE- -fK- -jO- -U A h-`][|h nexgenx_config_changed:Id % D }M}b:z j-N'z m!statsIsmartctf stats} !rules-)MN}wM*MO -N(-N I eMS5lNewl*}-f-{l v~k-{l a~zlu-{( B )mk `x@-B-C-E-K-O- E q$^qwq* :,qa/!,.q-q sv w)  i(/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXUtil * $VERSION 1.01 (10-8-2008 11:12) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Utility class. Contains some usefull general purpose functions. * **************************************************************************************************/ class NexgenXUtil extends Object; /*************************************************************************************************** * * $DESCRIPTION Retrieves the number of seconds denoted by the specified string. * $PARAM timeStr The string that is to be converted. * $PARAM seconds The number of seconds that are represented by the specified string. * $RETURN True if the given string was valid, false if not. In case the result is false, the * value stored in seconds should be ignored. * **************************************************************************************************/ static function bool getTimeInSeconds(string timeStr, out int seconds) { local string minutesStr; local string secondsStr; local int index; // Remove spaces. timeStr = class'NexgenUtil'.static.trim(timeStr); // Check for empty string. if (timeStr == "") return false; // Get minutes and seconds strings. class'NexgenUtil'.static.split2(timeStr, minutesStr, secondsStr, ":"); // Check minutes and seconds strings. if (!isNumeric(minutesStr) || !isNumeric(secondsStr)) { return false; } // Return result seconds = int(minutesStr) * 60 + int(secondsStr); return true; } /*************************************************************************************************** * * $DESCRIPTION Checks wether the specified string does only contain numeric characters. * $PARAM str The string that is to be checked. * $RETURN True if the given string is numeric, false if it isn't. * **************************************************************************************************/ static function bool isNumeric(string str) { local int index; local bool bIsNumeric; local string currentChar; bIsNumeric = true; while (bIsNumeric && index < len(str)) { currentChar = mid(str, index, 1); if (currentChar < "0" || currentChar > "9") { bIsNumeric = false; } else { index++; } } return bIsNumeric; } PT BK7>2z-P{i@j wkBq-Pi@jkB-P S*/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXUpdateNotifyDialog * $VERSION 1.00 (22-6-2008 15:56) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Dialog to display if the player has entered an invalid password. * **************************************************************************************************/ class NexgenXUpdateNotifyDialog extends NexgenPopupDialog; var UMenuLabelControl versionLabel; // Slot label component. var localized string caption; // Caption to display on the dialog. var localized string message; // Dialog help / info / description message. var localized string versionMessage; // Message that tells the new Nexgen version. /*************************************************************************************************** * * $DESCRIPTION Creates the dialog. Calling this function will setup the static dialog contents. * $ENSURE reconnectButton != none && spectatorButton != none * $OVERRIDE * **************************************************************************************************/ function created() { local float cy; super.created(); // Add components. cy = borderSize; addText(caption, cy, F_Bold, TA_Center); addNewLine(cy); addText(message, cy, F_Normal, TA_Left); addNewLine(cy); versionLabel = addLabel(cy); } /*************************************************************************************************** * * $DESCRIPTION Sets the contents for this dialog. * $PARAM newVersion The new version of Nexgen that is available. * $PARAM str2 Not used. * $PARAM str3 Not used. * $PARAM str4 Not used. * $OVERRIDE * **************************************************************************************************/ function setContent(optional string newVersion, optional string str2, optional string str3, optional string str4) { local string newVersionStr; newVersionStr = left(newVersion, len(newVersion) - 2) $ "." $ right(newVersion, 2); versionLabel.setText(class'NexgenUtil'.static.format(versionMessage, newVersionStr)); } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ RK L% 6N N%l%.  a,,J?,?,?%aC@A,%NexgenX - Clan tag protection'$?,E A, 'NDC '%,,MSaveHResetNAW$%;Only allow registered players to use protected clan tags.'A%Protected tags:'a0%0a%,,00%d0,0.0., 0% M `5/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXUpdateChecker * $VERSION 1.00 (22-6-2008 15:18) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION The HTTP client used to check if there is a new version of Nexgen available. * **************************************************************************************************/ class NexgenXUpdateChecker extends UBrowserHTTPClient; var NexgenX xControl; // Extension controller. var int latestVersion; // The latest version of Nexgen that is available. var bool bUpdateAvailable; // Whether there is an update available. // Settings. const updateServerHost = "130.89.163.70"; const updateServerPath = "/nexgen_update.txt"; const updateServerPort = 80; /*************************************************************************************************** * * $DESCRIPTION Retrieves the affiliated server list. * **************************************************************************************************/ function preBeginPlay() { super.preBeginPlay(); xControl = NexgenX(owner); browse(updateServerHost, updateServerPath, updateServerPort); } /*************************************************************************************************** * * $DESCRIPTION Called when the HTTP request failed. * **************************************************************************************************/ function HTTPError(int code) { xControl.control.nscLog(class'NexgenUtil'.static.format(xControl.lng.updateCheckFailedMsg, code)); } /*************************************************************************************************** * * $DESCRIPTION Called when the HTTP request has been replied and the data has been received. * $PARAM data The data that has been received. * **************************************************************************************************/ function HTTPReceivedData(string data) { local string remaining; local string currLine; // Process data. remaining = data; do { currLine = class'NexgenUtil'.static.trim(class'NexgenUtil'.static.getNextLine(remaining)); if (currLine != "") { processData(currLine); } } until (remaining == ""); } /*************************************************************************************************** * * $DESCRIPTION Processes the specified string. * **************************************************************************************************/ function processData(string str) { local string key; local string value; // Check format if (instr(str, ":") > 0) { class'NexgenUtil'.static.split2(str, key, value, ":"); key = class'NexgenUtil'.static.trim(key); value = class'NexgenUtil'.static.trim(value); // Check key. switch (key) { // Latest Nexgen version. case "latest-version": latestVersion = int(value); if (latestVersion > class'NexgenUtil'.default.versionCode) { xControl.control.nscLog(xControl.lng.updateAvailableMsg); bUpdateAvailable = true; } break; } } } E/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXTagRejectDialog * $VERSION 1.00 (22-6-2008 11:50) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Dialog to display if the server is full. * **************************************************************************************************/ class NexgenXTagRejectDialog extends NexgenPopupDialog; var UWindowSmallButton reconnectButton; // Reconnect button component. var UMenuLabelControl tagLabel; // Tag label component. var UWindowEditControl nameInput; // Player name input field component. var localized string caption; // Caption to display on the dialog. var localized string message; // Dialog help / info / description message. var localized string tagMessage; // Message describing the rejected tag. var localized string nameText; // Label to display before the name field. var localized string reconnectText; // Text to display on the reconnect button. const reconnectCommand = "Reconnect"; // Console command for reconnecting. /*************************************************************************************************** * * $DESCRIPTION Creates the dialog. Calling this function will setup the static dialog contents. * $ENSURE reconnectButton != none && spectatorButton != none * $OVERRIDE * **************************************************************************************************/ function created() { local float cy; super.created(); // Add components. cy = borderSize; addText(caption, cy, F_Bold, TA_Center); addNewLine(cy); addText(message, cy, F_Normal, TA_Left); addNewLine(cy); tagLabel = addLabel(cy); nameInput = addEditControl(cy, nameText, 64.0); reconnectButton = addButton(reconnectText, 64.0); // Set component properties. nameInput.setMaxLength(24); } /*************************************************************************************************** * * $DESCRIPTION Sets the contents for this dialog. * $PARAM tag The tag that is protected. * $PARAM str2 Not used. * $PARAM str3 Not used. * $PARAM str4 Not used. * $OVERRIDE * **************************************************************************************************/ function setContent(optional string tag, optional string str2, optional string str3, optional string str4) { tagLabel.setText(class'NexgenUtil'.static.format(tagMessage, tag)); nameInput.setValue(getPlayerOwner().playerReplicationInfo.playerName); } /*************************************************************************************************** * * $DESCRIPTION Notifies the dialog of an event (caused by user interaction with the interface). * Checks if the reconnect or spectator buttons have been clicked and deals with it * accordingly. * $PARAM control The control object where the event was triggered. * $PARAM eventType Identifier for the type of event that has occurred. * $REQUIRE control != none * $OVERRIDE * **************************************************************************************************/ function notify(UWindowDialogControl control, byte eventType){ local string newName; super.notify(control, eventType); // Reconnect button. if (control == reconnectButton && eventType == DE_Click) { newName = class'NexgenUtil'.static.trim(nameInput.getValue()); // Check name. if (newName == "") { nameInput.setValue(getPlayerOwner().playerReplicationInfo.playerName); } else { // Update player name. getPlayerOwner().changeName(newName); getPlayerOwner().updateURL("Name", newName, true); // Reconnect. getplayerowner().consoleCommand(reconnectCommand); close(); } } } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ O sZH yW-%-bs%ws,s.#s%s/ a ia--Rwi*ia/!gK!q K!m-RK.iLM.iL-Q-Q-R-{-Q S T-k^\|T%nexgenx_config_changed:IR%, } Svn]  G(r%r,zzrJS,rK?'r'( rU )x%mW-%.&.,.,.,.,. X t$tQwt* :Q,ta/!,.t-t sH M)  Lh/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXServerFullDialog * $VERSION 1.00 (8-3-2008 15:57) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Dialog to display if the server is full. * **************************************************************************************************/ class NexgenXServerFullDialog extends NexgenPopupDialog; var UWindowSmallButton reconnectButton; // Reconnect button component. var UWindowSmallButton spectatorButton; // Spectator button component. var UMenuLabelControl slotLabel; // Slot label component. var localized string caption; // Caption to display on the dialog. var localized string reconnectText; // Text to display on the reconnect button. var localized string spectatorText; // Text to display on the spectator button. var float nextVOffset; // Next vertical offset in the dialog. var int numServers; // Number of servers to connect to. var UWindowSmallButton serverButton[3]; // Server button components. var string serverURL[3]; // Server URLs. const SSTR_OverrideClass = "OverrideClass"; // Override class setting string. const openCommand = "Open"; // Console command for opening an URL. const reconnectCommand = "Reconnect"; // Console command for reconnecting. const spectatorClass = "Botpack.CHSpectator"; // Override class to use for spectators. /*************************************************************************************************** * * $DESCRIPTION Creates the dialog. Calling this function will setup the static dialog contents. * $ENSURE reconnectButton != none && spectatorButton != none * $OVERRIDE * **************************************************************************************************/ function created() { local float cy; super.created(); // Add components. cy = borderSize; addText(caption, cy, F_Bold, TA_Center); nextVOffset = cy; spectatorButton = addButton(spectatorText, 64.0); reconnectButton = addButton(reconnectText, 64.0); } /*************************************************************************************************** * * $DESCRIPTION Sets the contents for this dialog. * $PARAM message Message to display on the dialog * $PARAM server1 Alternate server 1. * $PARAM server2 Alternate server 2. * $PARAM server3 Alternate server 3. * $OVERRIDE * **************************************************************************************************/ function setContent(optional string message, optional string server1, optional string server2, optional string server3) { local float cy; cy = nextVOffset; addNewLine(cy); addText(message, cy, F_Normal, TA_Left); if (server3 == "") addNewLine(cy); addServer(server1, cy); addServer(server2, cy); addServer(server3, cy); } /*************************************************************************************************** * * $DESCRIPTION Adds a new alternate server button to the dialog. * $PARAM server Server description string, composed of the server title and url, which are * separated by a comma. * $PARAM cy Vertical offset on the dialog where the server link is to be added. * $REQUIRE cy >= 0 * **************************************************************************************************/ function addServer(string server, out float cy) { local float cx, cw, ch; local string buttonText; local string url; local UMenuLabelControl urlLabel; if (server != "" && numServers < arrayCount(serverButton)) { class'NexgenUtil'.static.split(server, buttonText, url); if (buttonText != "" && url != "") { cx = borderSize; cw = 128; ch = buttonHeight; serverButton[numServers] = UWindowSmallButton(createControl(class'UWindowSmallButton', cx, cy, cw, ch)); cx += buttonSpace + cw; cw = winWidth - cx - borderSize; urlLabel = UMenuLabelControl(createControl(class'UMenuLabelControl', cx, cy + 2, cw, ch)); urlLabel.setText(url); cy += ch + buttonSpace; serverButton[numServers].setText(buttonText); serverURL[numServers] = url; numServers++; } } } /*************************************************************************************************** * * $DESCRIPTION Notifies the dialog of an event (caused by user interaction with the interface). * Checks if the reconnect or spectator buttons have been clicked and deals with it * accordingly. * $PARAM control The control object where the event was triggered. * $PARAM eventType Identifier for the type of event that has occurred. * $REQUIRE control != none * $OVERRIDE * **************************************************************************************************/ function notify(UWindowDialogControl control, byte eventType){ super.notify(control, eventType); if (control != none && control.isA('UWindowSmallButton') && eventType == DE_Click) { switch (control) { // Reconnect button. case reconnectButton: getplayerowner().consoleCommand(reconnectCommand); close(); break; // Spectator button. case spectatorButton: getplayerowner().updateURL(SSTR_OverrideClass, spectatorClass, true); getplayerowner().consoleCommand(reconnectCommand); close(); break; // Join server 1 button: case serverButton[0]: getplayerowner().consoleCommand(openCommand @ serverURL[0]); close(); break; // Join server 2 button: case serverButton[1]: getplayerowner().consoleCommand(openCommand @ serverURL[1]); close(); break; // Join server 3 button: case serverButton[2]: getplayerowner().consoleCommand(openCommand @ serverURL[2]); close(); break; } } } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ p[ \ WV Ya`#%T#,&#J#&J#K#&K##JY#K ec @bi&:w@*@a/!hp.@-Uwp*@a/!G0|e}p&pp:-UK.@eM.@e}e}p&-T-T-U-{-T _ uNc5 K ` 'q m wu vwnww*J.w  J@'wwh CY/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXRCPTagProtection * $VERSION 1.00 (22-6-2008 10:27) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Nexgen extension plugin settings control panel page. * **************************************************************************************************/ class NexgenXRCPTagProtection extends NexgenPanel; var NexgenXClient xClient; var UWindowCheckbox enableTagProtectionInp; var UWindowEditControl protectedTagsInp[6]; var UWindowSmallButton resetButton; var UWindowSmallButton saveButton; const maxTagsPerRow = 6; /*************************************************************************************************** * * $DESCRIPTION Creates the contents of the panel. * $OVERRIDE * **************************************************************************************************/ function setContent() { local int region; local int numRows; local int index; xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); // Compute number of rows. numRows = arrayCount(protectedTagsInp) / maxTagsPerRow; if (arrayCount(protectedTagsInp) % maxTagsPerRow > 0) { numRows++; } // Create layout & add components. createPanelRootRegion(); splitRegionH(12, defaultComponentDist); addLabel(xClient.lng.tagProtectionPanelTitle, true, TA_Center); splitRegionH(1, defaultComponentDist); addComponent(class'NexgenDummyComponent'); splitRegionH(20, defaultComponentDist, , true); region = currRegion; skipRegion(); splitRegionV(196, , , true); skipRegion(); divideRegionV(2, defaultComponentDist); saveButton = addButton(client.lng.saveTxt); resetButton = addButton(client.lng.resetTxt); selectRegion(region); selectRegion(splitRegionH(20)); enableTagProtectionInp = addCheckBox(TA_Left, xClient.lng.enableTagProtectionTxt, true); selectRegion(splitRegionH(20)); addLabel(xClient.lng.protectedTagsTxt, true); divideRegionH(numRows); for (index = 0; index < numRows; index++) { divideRegionV(maxTagsPerRow, defaultComponentDist); } for (index = 0; index < arrayCount(protectedTagsInp); index++) { protectedTagsInp[index] = addEditBox(); protectedTagsInp[index].setMaxLength(10); } // Configure components. setValues(); } /*************************************************************************************************** * * $DESCRIPTION Sets the values of all input components to the current settings. * **************************************************************************************************/ function setValues() { local int index; enableTagProtectionInp.bChecked = xClient.xConf.enableTagProtection; for (index = 0; index < arrayCount(protectedTagsInp); index++) { protectedTagsInp[index].setValue(xClient.xConf.tagsToProtect[index]); } } /*************************************************************************************************** * * $DESCRIPTION Called when a general event has occurred in the system. * $PARAM type The type of event that has occurred. * $PARAM argument Optional arguments providing details about the event. * **************************************************************************************************/ function notifyEvent(string type, optional string arguments) { if (type ~= xClient.xConf.EVENT_NexgenXConfigChanged && byte(arguments) == xClient.xConf.CT_TagProtectionSettings) { setValues(); } } /*************************************************************************************************** * * $DESCRIPTION Saves the current settings. * **************************************************************************************************/ function saveSettings() { xClient.setTagProtectionSettings(enableTagProtectionInp.bChecked, protectedTagsInp[0].getValue(), protectedTagsInp[1].getValue(), protectedTagsInp[2].getValue(), protectedTagsInp[3].getValue(), protectedTagsInp[4].getValue(), protectedTagsInp[5].getValue()); } /*************************************************************************************************** * * $DESCRIPTION Notifies the dialog of an event (caused by user interaction with the interface). * $PARAM control The control object where the event was triggered. * $PARAM eventType Identifier for the type of event that has occurred. * $REQUIRE control != none * $OVERRIDE * **************************************************************************************************/ function notify(UWindowDialogControl control, byte eventType) { super.notify(control, eventType); // Button pressed? if (control != none && eventType == DE_Click && control.isA('UWindowSmallButton') && !UWindowSmallButton(control).bDisabled) { switch (control) { case resetButton: setValues(); break; case saveButton: saveSettings(); break; } } } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ b ClRgC!Vq@C!UaMuted (spam)f%,E F G@' P "OverrideClass"f  "Open"g "Reconnect"h  "Botpack.CHSpectator"i \[-W\0W\&$I\OZ,@PX,@ cZ/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXRCPSettings * $VERSION 1.02 (12-4-2008 13:23) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Nexgen extension plugin settings control panel page. * **************************************************************************************************/ class NexgenXRCPSettings extends NexgenPanel; var NexgenXClient xClient; var UWindowCheckbox enableOverlaySkinInp; var UWindowCheckbox enableMapSwitchTabInp; var UWindowCheckbox enableStartAnnouncerInp; var UWindowCheckbox enableAntiSpamInp; var UWindowCheckbox enableClientIDAKALogInp; var UWindowCheckbox checkForUpdatesInp; var UWindowSmallButton resetButton; var UWindowSmallButton saveButton; /*************************************************************************************************** * * $DESCRIPTION Creates the contents of the panel. * $OVERRIDE * **************************************************************************************************/ function setContent() { local int region; xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); // Create layout & add components. createPanelRootRegion(); splitRegionH(12, defaultComponentDist); addLabel(xClient.lng.settingsPanelTitle, true, TA_Center); splitRegionH(1, defaultComponentDist); addComponent(class'NexgenDummyComponent'); splitRegionH(20, defaultComponentDist, , true); region = currRegion; skipRegion(); splitRegionV(196, , , true); skipRegion(); divideRegionV(2, defaultComponentDist); saveButton = addButton(client.lng.saveTxt); resetButton = addButton(client.lng.resetTxt); selectRegion(region); selectRegion(divideRegionV(2, 2 * defaultComponentDist)); divideRegionH(3); divideRegionH(3); enableOverlaySkinInp = addCheckBox(TA_Left, xClient.lng.enableOverlaySkinTxt, true); enableMapSwitchTabInp = addCheckBox(TA_Left, xClient.lng.enableMapSwitchTabTxt, true); enableStartAnnouncerInp = addCheckBox(TA_Left, xClient.lng.enableStartAnnouncerTxt, true); enableAntiSpamInp = addCheckBox(TA_Left, xClient.lng.enableAntiSpamTxt, true); enableClientIDAKALogInp = addCheckBox(TA_Left, xClient.lng.enableClientIDAKALogTxt, true); checkForUpdatesInp = addCheckBox(TA_Left, xClient.lng.checkForUpdatesTxt, true); // Configure components. setValues(); } /*************************************************************************************************** * * $DESCRIPTION Sets the values of all input components to the current settings. * **************************************************************************************************/ function setValues() { enableOverlaySkinInp.bChecked = xClient.xConf.enableOverlaySkin; enableMapSwitchTabInp.bChecked = xClient.xConf.enableMapSwitch; enableStartAnnouncerInp.bChecked = xClient.xConf.enableStartAnnouncer; enableAntiSpamInp.bChecked = xClient.xConf.enableAntiSpam; enableClientIDAKALogInp.bChecked = xClient.xConf.enableClientIDAKALog; checkForUpdatesInp.bChecked = xClient.xConf.checkForUpdates; } /*************************************************************************************************** * * $DESCRIPTION Called when a general event has occurred in the system. * $PARAM type The type of event that has occurred. * $PARAM argument Optional arguments providing details about the event. * **************************************************************************************************/ function notifyEvent(string type, optional string arguments) { if (type ~= xClient.xConf.EVENT_NexgenXConfigChanged && byte(arguments) == xClient.xConf.CT_GeneralSettings) { setValues(); } } /*************************************************************************************************** * * $DESCRIPTION Saves the current settings. * **************************************************************************************************/ function saveSettings() { xClient.setGeneralSettings(enableOverlaySkinInp.bChecked, enableMapSwitchTabInp.bChecked, enableStartAnnouncerInp.bChecked, enableAntiSpamInp.bChecked, enableClientIDAKALogInp.bChecked, checkForUpdatesInp.bChecked); } /*************************************************************************************************** * * $DESCRIPTION Notifies the dialog of an event (caused by user interaction with the interface). * $PARAM control The control object where the event was triggered. * $PARAM eventType Identifier for the type of event that has occurred. * $REQUIRE control != none * $OVERRIDE * **************************************************************************************************/ function notify(UWindowDialogControl control, byte eventType) { super.notify(control, eventType); // Button pressed? if (control != none && eventType == DE_Click && control.isA('UWindowSmallButton') && !UWindowSmallButton(control).bDisabled) { switch (control) { case resetButton: setValues(); break; case saveButton: saveSettings(); break; } } } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ j _I r6I560_6%$@z|56H`6Hb6H|6 n xN`-Jxwx*G.x  G@xx& o >UD.>  D@'>.>scoreU>>/>deathsU>>2>starttimeS> s V:,-A.  -JA@-Qscore.Qdeaths1\starttime-j Iaka info i@kl yHdYW{y u, y`ZW{` {ZyzC]uv.M y]z]yzzyt.M y]?,z]t 2Z]]uv 2`u^Zu v q vpk!T-ciV [%\Q&\pp ]%!,,%,\pp ]&!,,&,\pp ],!,,, Aw/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXRCPServerRulesView * $VERSION 1.01 (9-8-2008 12:59) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Nexgen map switch control panel page. * **************************************************************************************************/ class NexgenXRCPServerRulesView extends NexgenPanel; var NexgenXClient xClient; var UMenuLabelControl rulesTitleLabel; var UMenuLabelControl rules[10]; var NexgenPlayerListBox playerList; var UWindowSmallButton showRulesButton; var UWindowEditControl showReasonInp; /*************************************************************************************************** * * $DESCRIPTION Creates the contents of the panel. * $OVERRIDE * **************************************************************************************************/ function setContent() { local NexgenContentPanel p; local bool bShowAdminControls; local int index; xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); bShowAdminControls = client.hasRight(client.R_Moderate); // Create layout & add components. createWindowRootRegion(); if (bShowAdminControls) { splitRegionV(160, defaultComponentDist, , true); splitRegionH(16, defaultComponentDist, , true); splitRegionH(16, defaultComponentDist, , true); splitRegionH(32, defaultComponentDist); splitRegionV(140); playerList = NexgenPlayerListBox(addListBox(class'NexgenSimplePlayerListBox')); showRulesButton = addButton(xClient.lng.forceClientViewRulesTxt); p = addContentPanel(); rulesTitleLabel = p.addLabel(xClient.lng.serverRulesTabTitle, true, TA_Center); p = addContentPanel(); addLabel(xClient.lng.forceClientViewRulesReasonTxt, true); showReasonInp = addEditBox(); showReasonInp.setMaxLength(100); } else { splitRegionH(32, defaultComponentDist); p = addContentPanel(); rulesTitleLabel = p.addLabel(xClient.lng.serverRulesTabTitle, true, TA_Center); p = addContentPanel(); } // Create rules panel. p.divideRegionH(arrayCount(rules)); for (index = 0; index < arrayCount(rules); index++) { rules[index] = p.addLabel("", true); } // Configure components. setValues(); playerSelected(); } /*************************************************************************************************** * * $DESCRIPTION Sets the values of all input components to the current server settings. * **************************************************************************************************/ function setValues() { local int index; for (index = 0; index < arrayCount(rules); index++) { rules[index].setText(xClient.xConf.serverRules[index]); } } /*************************************************************************************************** * * $DESCRIPTION Called when a player was selected from the list. * **************************************************************************************************/ function playerSelected() { if (showReasonInp != none && playerList != none) { showRulesButton.bDisabled = playerList.selectedItem == none; } } /*************************************************************************************************** * * $DESCRIPTION Notifies the client of a player event. Additional arguments to the event should be * combined into one string which then can be send along with the playerEvent call. * $PARAM playerNum Player identification number. * $PARAM eventType Type of event that has occurred. * $PARAM args Optional arguments. * $REQUIRE playerNum >= 0 * **************************************************************************************************/ function playerEvent(int playerNum, string eventType, optional string args) { if (playerList != none) { // Player has joined the game? if (eventType == client.PE_PlayerJoined) { addPlayerToList(playerList, playerNum, args); } // Player has left the game? if (eventType == client.PE_PlayerLeft) { playerList.removePlayer(playerNum); playerSelected(); } // Attribute changed? if (eventType == client.PE_AttributeChanged) { updatePlayerInfo(playerList, playerNum, args); } } } /*************************************************************************************************** * * $DESCRIPTION Called when a general event has occurred in the system. * $PARAM type The type of event that has occurred. * $PARAM argument Optional arguments providing details about the event. * **************************************************************************************************/ function notifyEvent(string type, optional string arguments) { if (type ~= xClient.xConf.EVENT_NexgenXConfigChanged && byte(arguments) == xClient.xConf.CT_ServerRulesSettings) { setValues(); } } /*************************************************************************************************** * * $DESCRIPTION Notifies the dialog of an event (caused by user interaction with the interface). * $PARAM control The control object where the event was triggered. * $PARAM eventType Identifier for the type of event that has occurred. * $REQUIRE control != none * $OVERRIDE * **************************************************************************************************/ function notify(UWindowDialogControl control, byte eventType) { super.notify(control, eventType); // Button pressed? if (control != none && eventType == DE_Click && control.isA('UWindowSmallButton') && !UWindowSmallButton(control).bDisabled) { switch (control) { case showRulesButton: forceClientViewRules(); break; } } // Player selected? if (playerList != none && control == playerList && eventType == DE_Click) { playerSelected(); } } /*************************************************************************************************** * * $DESCRIPTION Forces the currently selected client to view the rules. * **************************************************************************************************/ function setAdminForcedViewMessage(optional string reason) { local string message; // Get message. message = class'NexgenUtil'.static.trim(reason); if (message == "") { message = xClient.lng.serverRulesForcedTabTitle; } // Set message. rulesTitleLabel.setText(message); } /*************************************************************************************************** * * $DESCRIPTION Forces the currently selected client to view the rules. * **************************************************************************************************/ function forceClientViewRules() { xClient.adminForceClientViewRules(NexgenPlayerList(playerList.selectedItem).pNum, class'NexgenUtil'.static.trim(showReasonInp.getValue())); } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ M[/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXRCPServerRules * $VERSION 1.00 (2-8-2008 20:49) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Nexgen extension plugin settings control panel page. * **************************************************************************************************/ class NexgenXRCPServerRules extends NexgenPanel; var NexgenXClient xClient; var UWindowCheckbox enableServerRulesInp; var UWindowEditControl serverRulesInp[10]; var UWindowSmallButton resetButton; var UWindowSmallButton saveButton; /*************************************************************************************************** * * $DESCRIPTION Creates the contents of the panel. * $OVERRIDE * **************************************************************************************************/ function setContent() { local int region; local int index; xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); // Create layout & add components. createPanelRootRegion(); splitRegionH(12, defaultComponentDist); addLabel(xClient.lng.serverRulesPanelTitle, true, TA_Center); splitRegionH(1, defaultComponentDist); addComponent(class'NexgenDummyComponent'); splitRegionH(20, defaultComponentDist, , true); region = currRegion; skipRegion(); splitRegionV(196, , , true); skipRegion(); divideRegionV(2, defaultComponentDist); saveButton = addButton(client.lng.saveTxt); resetButton = addButton(client.lng.resetTxt); selectRegion(region); selectRegion(splitRegionH(20)); enableServerRulesInp = addCheckBox(TA_Left, xClient.lng.enableServerRulesTxt, true); selectRegion(splitRegionH(20)); addLabel(xClient.lng.serverRulesCaptionTxt, true); divideRegionV(2, 2 * defaultComponentDist); divideRegionH(arrayCount(serverRulesInp) / 2); divideRegionH(arrayCount(serverRulesInp) / 2); for (index = 0; index < arrayCount(serverRulesInp); index++) { splitRegionV(15); } for (index = 0; index < arrayCount(serverRulesInp); index++) { addLabel(string(index + 1), true, TA_CENTER); serverRulesInp[index] = addEditBox(); serverRulesInp[index].setMaxLength(200); } // Configure components. setValues(); } /*************************************************************************************************** * * $DESCRIPTION Sets the values of all input components to the current settings. * **************************************************************************************************/ function setValues() { local int index; enableServerRulesInp.bChecked = xClient.xConf.enableServerRules; for (index = 0; index < arrayCount(serverRulesInp); index++) { serverRulesInp[index].setValue(xClient.xConf.serverRules[index]); } } /*************************************************************************************************** * * $DESCRIPTION Called when a general event has occurred in the system. * $PARAM type The type of event that has occurred. * $PARAM argument Optional arguments providing details about the event. * **************************************************************************************************/ function notifyEvent(string type, optional string arguments) { if (type ~= xClient.xConf.EVENT_NexgenXConfigChanged && byte(arguments) == xClient.xConf.CT_ServerRulesSettings) { setValues(); } } /*************************************************************************************************** * * $DESCRIPTION Saves the current settings. * **************************************************************************************************/ function saveSettings() { xClient.setServerRulesSettings(enableServerRulesInp.bChecked, serverRulesInp[0].getValue(), serverRulesInp[1].getValue(), serverRulesInp[2].getValue(), serverRulesInp[3].getValue(), serverRulesInp[4].getValue(), serverRulesInp[5].getValue(), serverRulesInp[6].getValue(), serverRulesInp[7].getValue(), serverRulesInp[8].getValue(), serverRulesInp[9].getValue()); } /*************************************************************************************************** * * $DESCRIPTION Notifies the dialog of an event (caused by user interaction with the interface). * $PARAM control The control object where the event was triggered. * $PARAM eventType Identifier for the type of event that has occurred. * $REQUIRE control != none * $OVERRIDE * **************************************************************************************************/ function notify(UWindowDialogControl control, byte eventType) { super.notify(control, eventType); // Button pressed? if (control != none && eventType == DE_Click && control.isA('UWindowSmallButton') && !UWindowSmallButton(control).bDisabled) { switch (control) { case resetButton: setValues(); break; case saveButton: saveSettings(); break; } } } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ } o}Y 6x.o y x Q/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXRCPMatchControl * $VERSION 1.04 (21-6-2008 15:51) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Nexgen match control panel page. * **************************************************************************************************/ class NexgenXRCPMatchControl extends NexgenRCPMatchControl; var NexgenXClient xClient; var NexgenEditControl timeLimitInp; var NexgenEditControl scoreLimitInp; var NexgenEditControl teamScoreLimitInp; var NexgenEditControl gameSpeedInp; var NexgenEditControl remainingTimeInp; var NexgenEditControl addBotsInp; var NexgenEditControl removeBotsInp; var UWindowSmallButton setTimeLimitButton; var UWindowSmallButton setScoreLimitButton; var UWindowSmallButton setTeamScoreLimitButton; var UWindowSmallButton setGameSpeedButton; var UWindowSmallButton setRemainingTimeButton; var UWindowSmallButton addBotsButton; var UWindowSmallButton removeBotsButton; /*************************************************************************************************** * * $DESCRIPTION Creates the contents of the panel. * $OVERRIDE * **************************************************************************************************/ function setContent() { local NexgenContentPanel p; local int index; xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); // Create layout & add components. createWindowRootRegion(); splitRegionH(170, defaultComponentDist); splitRegionV(192, defaultComponentDist); divideRegionV(3, defaultComponentDist); // Player list. playerList = NexgenPlayerListBox(addListBox(class'NexgenPlayerListBox')); // Player controls. p = addContentPanel(); p.splitRegionV(128, defaultComponentDist); p.divideRegionH(8); p.divideRegionH(8); for (index = 0; index < arrayCount(teamButtons); index++) { teamButtons[index] = p.addButton(client.lng.format(client.lng.switchToTeamTxt, client.lng.getTeamName(index))); } sendToURLButton = p.addButton(client.lng.sendToURLTxt); reconnectAsPlayerButton = p.addButton(client.lng.reconnectAsPlayerTxt); reconnectAsSpecButton = p.addButton(client.lng.reconnectAsSpecTxt); disableTeamSwitchButton = p.addButton(client.lng.disableTeamSwitchTxt); p.skipRegion(); p.skipRegion(); p.skipRegion(); favouritesList = p.addListCombo(); urlInp = p.addEditBox(); // Match controls 1. p = addContentPanel(); p.splitRegionV(80, , , true); p.divideRegionH(5); p.splitRegionV(40, defaultComponentDist); p.addLabel(client.lng.timeLimitTxt); p.addLabel(client.lng.scoreLimitTxt); p.addLabel(client.lng.teamScoreLimitTxt); p.addLabel(client.lng.gameSpeedTxt); p.addLabel(xClient.lng.remainingTimeTxt); p.divideRegionH(5); p.divideRegionH(5); timeLimitInp = p.addEditBox(); scoreLimitInp = p.addEditBox(); teamScoreLimitInp = p.addEditBox(); gameSpeedInp = p.addEditBox(); remainingTimeInp = p.addEditBox(); setTimeLimitButton = p.addButton(xClient.lng.setButtonTxt); setScoreLimitButton = p.addButton(xClient.lng.setButtonTxt); setTeamScoreLimitButton = p.addButton(xClient.lng.setButtonTxt); setGameSpeedButton = p.addButton(xClient.lng.setButtonTxt); setRemainingTimeButton = p.addButton(xClient.lng.setButtonTxt); // Match controls 2. p = addContentPanel(); p.divideRegionH(5); p.splitRegionV(40, defaultComponentDist, , true); p.splitRegionV(40, defaultComponentDist, , true); pauseButton = p.addButton(client.lng.pauseGameTxt); endButton = p.addButton(client.lng.endGameTxt); restartButton = p.addButton(client.lng.restartGameTxt); addBotsButton = p.addButton(xClient.lng.addBotsTxt); addBotsInp = p.addEditBox(); removeBotsButton = p.addButton(xClient.lng.removeBotsTxt); removeBotsInp = p.addEditBox(); // Match controls 3. p = addContentPanel(); p.divideRegionH(5); allowTeamSwitchInp = p.addCheckBox(TA_Left, client.lng.allowTeamSwitchTxt); allowTeamBalanceInp = p.addCheckBox(TA_Left, client.lng.allowTeamBalanceTxt); lockTeamsInp = p.addCheckBox(TA_Left, client.lng.lockTeamsTxt); tournamentModeInp = p.addCheckBox(TA_Left, client.lng.tournamentModeTxt); // Configure components. timeLimitInp.setNumericOnly(true); scoreLimitInp.setNumericOnly(true); teamScoreLimitInp.setNumericOnly(true); gameSpeedInp.setNumericOnly(true); addBotsInp.setNumericOnly(true); removeBotsInp.setNumericOnly(true); timeLimitInp.setMaxLength(3); scoreLimitInp.setMaxLength(5); teamScoreLimitInp.setMaxLength(5); gameSpeedInp.setMaxLength(3); remainingTimeInp.setMaxLength(5); addBotsInp.setMaxLength(2); removeBotsInp.setMaxLength(2); remainingTimeInp.setValue("5:00"); addBotsInp.setValue("1"); removeBotsInp.setValue("1"); urlInp.setMaxLength(128); playerList.register(self); allowTeamSwitchInp.register(self); allowTeamBalanceInp.register(self); lockTeamsInp.register(self); tournamentModeInp.register(self); favouritesList.register(self); allowTeamSwitchInp.bDisabled = !client.player.gameReplicationInfo.bTeamGame; allowTeamBalanceInp.bDisabled = !client.player.gameReplicationInfo.bTeamGame; playerSelected(); setValues(); setGameInfo(); loadFavourites(); if (!client.hasRight(client.R_MatchSet)) { disableSpecialMatchControls(); } } /*************************************************************************************************** * * $DESCRIPTION Sets the values of the game info labels. * **************************************************************************************************/ function setGameInfo() { local GameReplicationInfo GRI; local TournamentGameReplicationInfo TGRI; GRI = client.player.gameReplicationInfo; TGRI = TournamentGameReplicationInfo(GRI); if (TGRI != none) { timeLimitInp.setValue(string(TGRI.timeLimit)); scoreLimitInp.setValue(string(TGRI.fragLimit)); teamScoreLimitInp.setValue(string(TGRI.goalTeamScore)); } gameSpeedInp.setValue(string(int(100.0 * client.gInf.gameSpeed))); } /*************************************************************************************************** * * $DESCRIPTION Disables the special match controls, which are only available to certain admins. * **************************************************************************************************/ function disableSpecialMatchControls() { timeLimitInp.setDisabled(true); scoreLimitInp.setDisabled(true); teamScoreLimitInp.setDisabled(true); gameSpeedInp.setDisabled(true); addBotsInp.setDisabled(true); removeBotsInp.setDisabled(true); setTimeLimitButton.bDisabled = true; setScoreLimitButton.bDisabled = true; setTeamScoreLimitButton.bDisabled = true; setGameSpeedButton.bDisabled = true; addBotsButton.bDisabled = true; removeBotsButton.bDisabled = true; } /*************************************************************************************************** * * $DESCRIPTION Notifies the dialog of an event (caused by user interaction with the interface). * $PARAM control The control object where the event was triggered. * $PARAM eventType Identifier for the type of event that has occurred. * $REQUIRE control != none * $OVERRIDE * **************************************************************************************************/ function notify(UWindowDialogControl control, byte eventType) { super.notify(control, eventType); // Button pressed? if (control != none && eventType == DE_Click && control.isA('UWindowSmallButton') && !UWindowSmallButton(control).bDisabled) { switch (control) { case addBotsButton: xClient.addBots(int(addBotsInp.getValue())); break; case removeBotsButton: xClient.addBots(-int(removeBotsInp.getValue())); break; case setTimeLimitButton: xClient.setTimeLimit(int(timeLimitInp.getValue())); break; case setScoreLimitButton: xClient.setScoreLimit(int(scoreLimitInp.getValue())); break; case setTeamScoreLimitButton: xClient.setTeamScoreLimit(int(teamScoreLimitInp.getValue())); break; case setGameSpeedButton: xClient.setGameSpeed(int(gameSpeedInp.getValue())); break; case setRemainingTimeButton: xClient.setRemainingTime(remainingTimeInp.getValue()); break; } } } x/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXRCPMapSwitch * $VERSION 1.03 (21-6-2008 16:59) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Nexgen map switch control panel page. * **************************************************************************************************/ class NexgenXRCPMapSwitch extends NexgenPanel; var NexgenXClient xClient; var UWindowSmallButton switchButton; var NexgenSimpleListBox mapList; var NexgenSimpleListBox inclMutatorList; var NexgenSimpleListBox exclMutatorList; var UWindowComboControl gameTypeList; var UWindowCheckbox hideBadMapsInp; var bool bMapListAvailable; const SSTR_HideBadMaps = "HideBadMaps"; /*************************************************************************************************** * * $DESCRIPTION Creates the contents of the panel. * $OVERRIDE * **************************************************************************************************/ function setContent() { local NexgenContentPanel p; xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); // Create layout & add components. createWindowRootRegion(); splitRegionV(192, defaultComponentDist); splitRegionH(20, defaultComponentDist, , true); splitRegionH(20, defaultComponentDist, , true); mapList = NexgenSimpleListBox(addListBox(class'NexgenSimpleListBox')); hideBadMapsInp = addCheckBox(TA_Left, xClient.lng.hideBadMapsTxt, true); p = addContentPanel(); switchButton = addButton(xClient.lng.mapSwitchActionTxt, 96, AL_Right); p.splitRegionH(20, defaultComponentDist); p.splitRegionV(96); p.divideRegionV(2, defaultComponentDist); p.addLabel(client.lng.gameTypeTxt, true); gameTypeList = p.addListCombo(); p.splitRegionH(16); p.splitRegionH(16); p.addLabel(client.lng.exclMutatorsTxt, true); exclMutatorList = NexgenSimpleListBox(p.addListBox(class'NexgenSimpleListBox')); p.addLabel(client.lng.inclMutatorsTxt, true); inclMutatorList = NexgenSimpleListBox(p.addListBox(class'NexgenSimpleListBox')); // Configure components. hideBadMapsInp.register(self); gameTypeList.register(self); loadGameTypeList(); loadMutatorList(); loadMapList(); hideBadMapsInp.bChecked = client.gc.get(SSTR_HideBadMaps, "true") ~= "true"; inclMutatorList.bCanDrag = true; } /*************************************************************************************************** * * $DESCRIPTION Loads the game type list. * **************************************************************************************************/ function loadGameTypeList() { local int index; local string gameClass; local string mapPrefix; local string gameName; // Load available game types. while (index < arrayCount(client.sConf.gameTypeInfo) && client.sConf.gameTypeInfo[index] != "") { class'NexgenUtil'.static.split(client.sConf.gameTypeInfo[index], gameClass, mapPrefix); class'NexgenUtil'.static.split(mapPrefix, mapPrefix, gameName); gameTypeList.addItem(gameName, string(index)); index++; } // Select current game type. gameTypeList.setSelectedIndex(client.sConf.activeGameType); } /*************************************************************************************************** * * $DESCRIPTION Loads the mutator list. * **************************************************************************************************/ function loadMutatorList() { local int index; local NexgenSimpleListItem oldItem; local NexgenSimpleListItem newItem; local string mutatorClass; local string mutatorName; local string remaining; local string mutatorIndex; // Load available mutators. while (index < arrayCount(client.sConf.mutatorInfo) && client.sConf.mutatorInfo[index] != "") { class'NexgenUtil'.static.split(client.sConf.mutatorInfo[index], mutatorClass, mutatorName); newItem = NexgenSimpleListItem(exclMutatorList.items.append(class'NexgenSimpleListItem')); newItem.displayText = mutatorName; newItem.itemID = index; index++; } exclMutatorList.items.sort(); // Load used mutators. remaining = client.sConf.activeMutatorIndices; while (remaining != "") { class'NexgenUtil'.static.split(remaining, mutatorIndex, remaining); index = int(mutatorIndex); oldItem = exclMutatorList.getItemByID(index); newItem = NexgenSimpleListItem(inclMutatorList.items.append(class'NexgenSimpleListItem')); newItem.displayText = oldItem.displayText; newItem.itemID = oldItem.itemID; oldItem.remove(); } } /*************************************************************************************************** * * $DESCRIPTION Loads the map list. * **************************************************************************************************/ function loadMapList() { local int index; local bool bHideBadMaps; local string gameClass; local string mapPrefix; local string remaining; // Clear the map list. mapList.items.clear(); mapList.selectedItem = none; mapSelected(); // Check if the map list is available. if (!bMapListAvailable) { addMap(xClient.lng.recievingMapListTxt); return; } // Get map prefix. index = gameTypeList.getSelectedIndex(); if (index >= 0) { class'NexgenUtil'.static.split(client.sConf.gameTypeInfo[index], gameClass, remaining); class'NexgenUtil'.static.split(remaining, mapPrefix, remaining); } else { mapPrefix = ""; } // Load the map list. bHideBadMaps = hideBadMapsInp.bChecked; index = 0; while (index < xClient.mapCount && (!bHideBadMaps || mapPrefix != "")) { // Add map? if (class'NexgenUtil'.static.isValidLevel(xClient.maps[index]) && (!bHideBadMaps || left(xClient.maps[index], len(mapPrefix)) ~= mapPrefix)) { addMap(xClient.maps[index]); } // Continue with next map. index++; } mapList.sort(); } /*************************************************************************************************** * * $DESCRIPTION Called when a map was selected from the map list. * **************************************************************************************************/ function mapSelected() { switchButton.bDisabled = mapList.selectedItem == none; } /*************************************************************************************************** * * $DESCRIPTION Adds a new map to the map list. * $PARAM mapName Name of the map that is to be added. * $REQUIRE mapName != "" * **************************************************************************************************/ function string addMap(string mapName) { local NexgenSimpleListItem item; item = NexgenSimpleListItem(mapList.items.append(class'NexgenSimpleListItem')); item.displayText = mapName; } /*************************************************************************************************** * * $DESCRIPTION Called when the client has received the map list from the server. * **************************************************************************************************/ function notifyMapListAvailable() { bMapListAvailable = true; loadMapList(); } /*************************************************************************************************** * * $DESCRIPTION Called when the client has received a part of the map list. * **************************************************************************************************/ function notifyMapListPartRecieved() { local NexgenSimpleListItem item; if (!bMapListAvailable) { item = NexgenSimpleListItem(mapList.items.next); item.displayText = client.lng.format(xClient.lng.recievingMapListProgressTxt, xClient.mapCount); } } /*************************************************************************************************** * * $DESCRIPTION Notifies the dialog of an event (caused by user interaction with the interface). * $PARAM control The control object where the event was triggered. * $PARAM eventType Identifier for the type of event that has occurred. * $REQUIRE control != none * $OVERRIDE * **************************************************************************************************/ function notify(UWindowDialogControl control, byte eventType) { local NexgenSimpleListItem newItem; super.notify(control, eventType); // Mutator selected? if (control == inclMutatorList && eventType == DE_Click) { if (exclMutatorList.selectedItem != none) { exclMutatorList.selectedItem.bSelected = false; exclMutatorList.selectedItem = none; } } else if (control == exclMutatorList && eventType == DE_Click) { if (inclMutatorList.selectedItem != none) { inclMutatorList.selectedItem.bSelected = false; inclMutatorList.selectedItem = none; } } // Mutator double clicked? if (control == inclMutatorList && eventType == DE_DoubleClick && inclMutatorList.selectedItem != none) { newItem = NexgenSimpleListItem(exclMutatorList.items.append(class'NexgenSimpleListItem')); newItem.displayText = NexgenSimpleListItem(inclMutatorList.selectedItem).displayText; newItem.itemID = NexgenSimpleListItem(inclMutatorList.selectedItem).itemID; if (exclMutatorList.selectedItem != none) { exclMutatorList.selectedItem.bSelected = false; } exclMutatorList.selectedItem = newItem; newItem.bSelected = true; inclMutatorList.selectedItem.remove(); inclMutatorList.selectedItem = none; exclMutatorList.sort(); } else if (control == exclMutatorList && eventType == DE_DoubleClick && exclMutatorList.selectedItem != none) { newItem = NexgenSimpleListItem(inclMutatorList.items.append(class'NexgenSimpleListItem')); newItem.displayText = NexgenSimpleListItem(exclMutatorList.selectedItem).displayText; newItem.itemID = NexgenSimpleListItem(exclMutatorList.selectedItem).itemID; if (inclMutatorList.selectedItem != none) { inclMutatorList.selectedItem.bSelected = false; } inclMutatorList.selectedItem = newItem; newItem.bSelected = true; exclMutatorList.selectedItem.remove(); exclMutatorList.selectedItem = none; } // Switch map button clicked? if (control == switchButton && eventType == DE_Click && !switchButton.bDisabled) { doMapSwitch(); } // Game type selected? if (control == gameTypeList && eventType == DE_Change) { if (hideBadMapsInp.bChecked) { loadMapList(); } } // Map selected? if (control == mapList && eventType == DE_Click) { mapSelected(); } // Hide bad maps checkbox changed? if (control == hideBadMapsInp && eventType == DE_Change) { // Save setting. client.gc.set(SSTR_HideBadMaps, string(hideBadMapsInp.bChecked)); client.gc.saveConfig(); // Reload map list. loadMapList(); } } /*************************************************************************************************** * * $DESCRIPTION Performs the map switch with the currently selected map, mutators and game type. * **************************************************************************************************/ function doMapSwitch() { local string mutators; local NexgenSimpleListItem item; // Check if a map and game type have been selected. if (!bMapListAvailable ||mapList.selectedItem == none || gameTypeList.getSelectedIndex() < 0) { return; } // Get mutators. for (item = NexgenSimpleListItem(inclMutatorList.items); item != none; item = NexgenSimpleListItem(item.next)) { if (item.itemID >= 0) { if (mutators == "") { mutators = string(item.itemID); } else { mutators = mutators $ separator $ " " $ item.itemID; } } } // Send the map switch request to the server. xClient.doMapSwitch(NexgenSimpleListItem(mapList.selectedItem).displayText, gameTypeList.getSelectedIndex(), mutators); } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ x r Y$EsYsqwY*Ya/!, :s,Y tP+Reconnect3q O(b"OverrideClassBotpack.CHSpectator'+Reconnect3q %v+Open%^3q 9&v+Open&^3q n,v+Open,^3q  Lb/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXRCPFullServerRedir * $VERSION 1.01 (14-3-2008 21:15) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Nexgen extension plugin settings control panel page. * **************************************************************************************************/ class NexgenXRCPFullServerRedir extends NexgenPanel; var NexgenXClient xClient; var UWindowSmallButton resetButton; var UWindowSmallButton saveButton; var UWindowCheckbox enableFullServerRedirectInp; var UWindowEditControl fullServerRedirectMsgInp; var UWindowEditControl redirectServerNameInp[3]; var UWindowEditControl redirectURLInp[3]; /*************************************************************************************************** * * $DESCRIPTION Creates the contents of the panel. * $OVERRIDE * **************************************************************************************************/ function setContent() { local int region; local int index; xClient = NexgenXClient(client.getController(class'NexgenXClient'.default.ctrlID)); // Create layout & add components. createPanelRootRegion(); splitRegionH(12, defaultComponentDist); addLabel(xClient.lng.fullServerRedirPanelTitle, true, TA_Center); splitRegionH(1, defaultComponentDist); addComponent(class'NexgenDummyComponent'); splitRegionH(20, defaultComponentDist, , true); region = currRegion; skipRegion(); splitRegionV(196, , , true); skipRegion(); divideRegionV(2, defaultComponentDist); saveButton = addButton(client.lng.saveTxt); resetButton = addButton(client.lng.resetTxt); selectRegion(region); selectRegion(divideRegionH(5)); enableFullServerRedirectInp = addCheckBox(TA_Left, xClient.lng.enableFullServerRedirTxt, true); splitRegionV(64); splitRegionV(192, 2 * defaultComponentDist); splitRegionV(192, 2 * defaultComponentDist); splitRegionV(192, 2 * defaultComponentDist); addLabel(xClient.lng.messageTxt, true); fullServerRedirectMsgInp = addEditBox(); splitRegionV(64); splitRegionV(64); splitRegionV(64); splitRegionV(64); splitRegionV(64); splitRegionV(64); for (index = 0; index < arrayCount(redirectServerNameInp); index++) { addLabel(client.lng.format(xClient.lng.serverEntryTxt, index + 1), true); redirectServerNameInp[index] = addEditBox(); addLabel(xClient.lng.urlTxt, true); redirectURLInp[index] = addEditBox(); redirectServerNameInp[index].setMaxLength(24); redirectURLInp[index].setMaxLength(64); } // Configure components. fullServerRedirectMsgInp.setMaxLength(250); setValues(); } /*************************************************************************************************** * * $DESCRIPTION Sets the values of all input components to the current settings. * **************************************************************************************************/ function setValues() { local int index; enableFullServerRedirectInp.bChecked = xClient.xConf.enableFullServerRedirect; fullServerRedirectMsgInp.setValue(xClient.xConf.fullServerRedirectMsg); for (index = 0; index < arrayCount(redirectServerNameInp); index++) { redirectServerNameInp[index].setValue(xClient.xConf.redirectServerName[index]); redirectURLInp[index].setValue(xClient.xConf.redirectURL[index]); } } /*************************************************************************************************** * * $DESCRIPTION Called when a general event has occurred in the system. * $PARAM type The type of event that has occurred. * $PARAM argument Optional arguments providing details about the event. * **************************************************************************************************/ function notifyEvent(string type, optional string arguments) { if (type ~= xClient.xConf.EVENT_NexgenXConfigChanged && byte(arguments) == xClient.xConf.CT_FullServerRedirect) { setValues(); } } /*************************************************************************************************** * * $DESCRIPTION Saves the current settings. * **************************************************************************************************/ function saveSettings() { xClient.setFullServerRedirSettings(enableFullServerRedirectInp.bChecked, fullServerRedirectMsgInp.getValue(), redirectServerNameInp[0].getValue(), redirectServerNameInp[1].getValue(), redirectServerNameInp[2].getValue(), redirectURLInp[0].getValue(), redirectURLInp[1].getValue(), redirectURLInp[2].getValue()); } /*************************************************************************************************** * * $DESCRIPTION Notifies the dialog of an event (caused by user interaction with the interface). * $PARAM control The control object where the event was triggered. * $PARAM eventType Identifier for the type of event that has occurred. * $REQUIRE control != none * $OVERRIDE * **************************************************************************************************/ function notify(UWindowDialogControl control, byte eventType) { super.notify(control, eventType); // Button pressed? if (control != none && eventType == DE_Click && control.isA('UWindowSmallButton') && !UWindowSmallButton(control).bDisabled) { switch (control) { case resetButton: setValues(); break; case saveButton: saveSettings(); break; } } } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ ~ z D24 /a 2-a }Aa {PHN^/?NexgenX configuration file was corrupt and has been repaired.D t-U[a _'   ","@ "aka info"A  "smartctf stats"B "starttime"C "deaths"/ "score"e IkUJINOP-T J QjNH8 G-) X aQ_rX* e.X  re* e O'gzgd(no reason given)dg=%1 has forced %2 to read the server rules. Reason: %3.Xd ' r "Reconnect"F 8[&808&$580@8%$58q8A8HBrS,@, EQ/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXPlayerOverlay * $VERSION 1.00 (23-11-2007 19:01) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Player overlay skin effect. * **************************************************************************************************/ class NexgenXPlayerOverlay extends Effects; #exec TEXTURE IMPORT NAME=overlaySkinRed FILE=Resources\RedSkin.pcx GROUP="GFX" FLAGS=2 MIPS=OFF #exec TEXTURE IMPORT NAME=overlaySkinBlue FILE=Resources\BlueSkin.pcx GROUP="GFX" FLAGS=2 MIPS=OFF #exec TEXTURE IMPORT NAME=overlaySkinGreen FILE=Resources\GreenSkin.pcx GROUP="GFX" FLAGS=2 MIPS=OFF #exec TEXTURE IMPORT NAME=overlaySkinGold FILE=Resources\GoldSkin.pcx GROUP="GFX" FLAGS=2 MIPS=OFF #exec TEXTURE IMPORT NAME=overlaySkinSilver FILE=Resources\SilverSkin.pcx GROUP="GFX" FLAGS=2 MIPS=OFF #exec TEXTURE IMPORT NAME=overlaySkinARed FILE=Resources\RedSkinA.pcx GROUP="GFX" FLAGS=2 MIPS=OFF #exec TEXTURE IMPORT NAME=overlaySkinABlue FILE=Resources\BlueSkinA.pcx GROUP="GFX" FLAGS=2 MIPS=OFF #exec TEXTURE IMPORT NAME=overlaySkinAGreen FILE=Resources\GreenSkinA.pcx GROUP="GFX" FLAGS=2 MIPS=OFF #exec TEXTURE IMPORT NAME=overlaySkinAGold FILE=Resources\GoldSkinA.pcx GROUP="GFX" FLAGS=2 MIPS=OFF #exec TEXTURE IMPORT NAME=overlaySkinASilver FILE=Resources\SilverSkinA.pcx GROUP="GFX" FLAGS=2 MIPS=OFF var NexgenClient client; // The NexgenClient instance of the player. var bool bActivated; // Whether the overlay skin is activated. var int teamNum; // Current team number of the player owning this instance. const activatedAmbientGlow = 64; // AmbientGlow when activated. const activatedFatness = 145; // Fatness when activated. /*************************************************************************************************** * * $DESCRIPTION Initializes the player overlay skin. * $OVERRIDE * **************************************************************************************************/ function preBeginPlay() { if (PlayerPawn(owner) == none) { destroy(); return; } mesh = owner.mesh; drawScale = owner.drawscale; setSkin(); } /*************************************************************************************************** * * $DESCRIPTION Global world tick. * $PARAM deltaTime Time elapsed since last tick. * $OVERRIDE * **************************************************************************************************/ function tick(float deltaTime) { local bool bClientProtected; // Hide / show player overlay skin? if (!bHidden && client.player.health <= 0) { // Hide overlay skin. bHidden = true; } if (bHidden && client.player.health > 0) { // Show overlay skin. bHidden = false; } // Activate / deactivate player overlay skin? bClientProtected = client.spawnProtectionTimeX > 0 || client.tkDmgProtectionTimeX > 0 || client.tkPushProtectionTimeX > 0; if (!bActivated && bClientProtected) { // Activate overlay skin. ambientGlow = activatedAmbientGlow; fatness = activatedFatness; bActivated = true; setSkin(); } if (bActivated && !bClientProtected) { // Deactivate overlay skin. ambientGlow = default.ambientGlow; fatness = default.fatness; bActivated = false; setSkin(); } // Team changed? if (owner != none && PlayerPawn(owner).playerReplicationInfo.team != teamNum) { setSkin(); } } /*************************************************************************************************** * * $DESCRIPTION Updates the skin. * $ENSURE teamNum == PlayerPawn(owner).playerReplicationInfo.team * **************************************************************************************************/ function setSkin() { teamNum = PlayerPawn(owner).playerReplicationInfo.team; if (bActivated) { // Activated overlay skins. switch (teamNum) { case 0: texture = Texture'overlaySkinARed'; break; case 1: texture = Texture'overlaySkinABlue'; break; case 2: texture = Texture'overlaySkinAGreen'; break; case 3: texture = Texture'overlaySkinAGold'; break; default: texture = Texture'overlaySkinASilver'; } } else { // Normal overlay skins. switch (teamNum) { case 0: texture = Texture'overlaySkinRed'; break; case 1: texture = Texture'overlaySkinBlue'; break; case 2: texture = Texture'overlaySkinGreen'; break; case 3: texture = Texture'overlaySkinGold'; break; default: texture = Texture'overlaySkinSilver'; } } } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ G XE Qq2 .DX O WO`9-)U.X rU*U.$\Rules  server-WU cV{  L @M @@I N$YKNLrNr :L,S zS iSb"NameS'+Reconnect3 R Ok4m" J -Z-)-O-)-O% h& g, f, b, `, _, ^, ], [,  Yb29$<*$New settings have been saved.-ZQ*BYou have to restart the game in order to apply the changes!1%1 has modified the server rules settings. D WNnjw,*,a,*h::$Jw*a*hw*a* rZ/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXLang * $VERSION 1.06 (9-8-2008 13:02) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Localization support class. * **************************************************************************************************/ class NexgenXLang extends Info; const invalidConfigMsg = "NexgenX configuration file was corrupt and has been repaired."; const updateCheckFailedMsg = "Failed to check for updates, error returned: %1"; const updateAvailableMsg = "A new version of Nexgen is available. Check www.unrealadmin.org."; const protectedTagLoginRejectMsg = "Attempt to use protected tag."; const adminMapSwitchMsg = "%1 has changed the game to %2."; const adminUpdateGeneralSettingsMsg = "%1 has modified the NexgenX settings."; const adminFullServerRedirSettingsMsg = "%1 has modified the full server redirect settings."; const adminAddBotsMsg = "%1 has added %2 bot%3 to the game."; const adminRemoveBotsMsg = "%1 has removed %2 bot%3 from the game."; const adminChangeTimeLimitMsg = "%1 has changed the time limit to %2."; const adminChangeScoreLimitMsg = "%1 has changed the score limit to %2."; const adminChangeTeamScoreLimitMsg = "%1 has changed the team score limit to %2."; const adminChangeGameSpeedMsg = "%1 has changed the game speed to %2%."; const adminChangeTimeRemainingMsg = "%1 has set the remaining time to %2."; const adminUpdateTagProtectionSettingsMsg = "%1 has modified the tag protection settings."; const adminUpdateServerRulesSettingsMsg = "%1 has modified the server rules settings."; const adminForceClientViewRulesMsg = "%1 has forced %2 to read the server rules. Reason: %3."; const gameRestartRequiredMsg = "You have to restart the game in order to apply the changes!"; const tagNotAllowedMsg = "Failed to change name, you are not allowed to use the %1 tag."; const viewRulesClientMsg = "To view the rules of this server use the !rules command."; const noReasonGivenMsg = "(no reason given)"; const mapSwitchTabTxt = "Map switch"; const mapSwitchActionTxt = "Switch"; const hideBadMapsTxt = "Hide incompatible maps"; const recievingMapListTxt = "Receiving map list..."; const recievingMapListProgressTxt = "Receiving map list (%1)..."; const settingsPanelTitle = "NexgenX - General settings"; const enableOverlaySkinTxt = "Enable player overlay skin effect"; const enableMapSwitchTabTxt = "Enable map switch tab for match controllers"; const enableStartAnnouncerTxt = "Enable game start announcer"; const enableAntiSpamTxt = "Enable anti spam"; const enableClientIDAKALogTxt = "Enable AKA client ID logging"; const checkForUpdatesTxt = "Automatically check for Nexgen updates"; const fullServerRedirPanelTitle = "NexgenX - Full server redirect settings"; const enableFullServerRedirTxt = "Enable player redirect to alternate servers when server is full"; const messageTxt = "Message"; const defaultFullServerRedirMsg = "The server you have tried to enter has no more player slots available. You can try again in a few minutes or reconnect immediately as a spectator. If you wish to play immediately you can connect to one of the alternate servers."; const serverEntryTxt = "Server %1"; const urlTxt = "URL"; const remainingTimeTxt = "Remaining time"; const setButtonTxt = "set"; const addBotsTxt = "Add bots"; const removeBotsTxt = "Remove bots"; const tagProtectionPanelTitle = "NexgenX - Clan tag protection"; const enableTagProtectionTxt = "Only allow registered players to use protected clan tags."; const protectedTagsTxt = "Protected tags:"; const serverRulesPanelTitle = "NexgenX - Server rules settings"; const enableServerRulesTxt = "Show a server rules tab in the Nexgen control panel."; const serverRulesCaptionTxt = "Rules to display:"; const antiSpamMutedState = "Muted (spam)"; const serverRulesTabTxt = "Rules"; const serverRulesTabTitle = "The rules of this server are:"; const serverRulesForcedTabTitle = "An administrator has forced you to view the server rules!"; const forceClientViewRulesTxt = "Show rules"; const forceClientViewRulesReasonTxt = "Reason for showing rules:"; /*************************************************************************************************** * * $DESCRIPTION Get a textual description of the specified time. * $PARAM seconds The number of seconds. * $RETURN A textual description of the specified amount of time. * **************************************************************************************************/ function string getLongTimeDescription(int seconds) { local int hours; local int minutes; local string output; // Split number of seconds in hours, minutes and seconds. hours = seconds / 3600; seconds = seconds - hours * 3600; minutes = seconds / 60; seconds = seconds - minutes * 60; // Add hours. if (hours != 0) { output = hours @ "hour"; if (hours != 1) output = output $ "s"; } // Add minutes. if (minutes != 0) { if (hours != 0) { if (seconds != 0) { output = output $ ", "; } else { output = output $ " and "; } } output = output $ minutes @ "minute"; if (minutes != 1) output = output $ "s"; } // Add seconds. if (seconds != 0 || output == "") { if (minutes != 0 || hours != 0) { output = output $ " and "; } output = output $ seconds @ "second"; if (seconds != 1) output = output $ "s"; } // Return result. return output; } S ilMJpLastVersionNotify0iM>LastVersionNotifySibcV Si U qm" J -b-q% p& o, n, m, j, ib29$<*$New settings have been saved.3%1 has modified the tag protection settings. P W_r[/ K W% -lW%-l9%9Wm9Na/!GE./a0 A>wE*EE&EE&Aa9=9W>10a/!L.-.s-lW&Ps)%1 has added %2 bot%3 to the game.SWPY9&Ps-%1 has removed %2 bot%3 from the game.S9P Y wnjOc Fa/!G E`w; B.B% ;;B,<B;B;2 R;+%1 has set the remaining time to %2. g; KN[ `N0rN&$5N0tN%$5NKN P /*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXConfigSys * $VERSION 1.00 (9-3-2008 22:19) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION NexgenX configuration container/replication class for configurations stored in the * servers configuration file. * **************************************************************************************************/ class NexgenXConfigSys extends NexgenXConfig config(system); V k;R|ppk}k,.k,K2 .y| b zQJ" K Q?zBbb,%1 has changed the game speed to %2%.SD?,d [ @\ @|@T rt:xC Ka/!G I.Ir.IrIb,%1 has changed the score limit to %2.Sr Q`KQ Q(zQ( CQnp:mUnUp(|Jn,<Jp'  G /*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXConfigExt * $VERSION 1.00 (9-3-2008 22:20) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION NexgenX configuration container/replication class for external stored * configuration file (Nexgen.ini) * **************************************************************************************************/ class NexgenXConfigExt extends NexgenXConfig config(Nexgen); ] &sWX{C Ka/!G .|&.&b|% &%&,<|% &%%\&|&,<&|,<2R+%1 has changed the time limit to %2.S& nf to"C Ka/!L L.L?t.LtLb1%1 has changed the team score limit to %2.St _/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXConfig * $VERSION 1.05 (4-8-2008 17:17) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION NexgenX configuration container/replication class. This class contains the * settings for the extension plugin. * **************************************************************************************************/ class NexgenXConfig extends ReplicationInfo; var NexgenX xControl; // NexgenX plugin. // Special settings. var config int lastInstalledVersion; // Last installed version of the plugin. // General settings. var int generalSettingsChecksum; // Checksum for the general settings variables. var config bool enableOverlaySkin; // Enable the player overlay skin effect. var config bool enableMapSwitch; // Whether map switch is available. var config bool enableStartAnnouncer; // Play a voice announcer when the game starts. var config bool enableAntiSpam; // Enable message spam detection. var config bool enableClientIDAKALog; // Enable AKA player ID logging. var config bool checkForUpdates; // Automatically check if there is a new version // of Nexgen available. // Full server redirect settings. var int fullServerRedirectChecksum; // Check for the full server redirect variables. var config bool enableFullServerRedirect; // Whether full server redirect is enabled. var config string fullServerRedirectMsg; // Message to display when the server is full. var config string redirectServerName[3]; // Names of the alternate servers. var config string redirectURL[3]; // Redirect URL for the servers. // Clan tag protection. var config bool enableTagProtection; // Whether the clan tag protection should be used. var config string tagsToProtect[6]; // The tags that are protected. // Server rules. var config bool enableServerRules; // Display server rules? var config string serverRules[10]; // The rules of the server. // Data transfer control. var int dynamicChecksums[4]; // Checksum for the dynamic replicated variables. var int dynamicChecksumModifiers[4]; // Dynamic data checksum salt. var int updateCounts[4]; // How many times the settings have been updated // during the current game. Used to detect setting // changes clientside. // Events. const EVENT_NexgenXConfigChanged = "nexgenx_config_changed"; // Config types. const CT_GeneralSettings = 0; // General settings config type. const CT_FullServerRedirect = 1; // Full server redirect settings config type. const CT_TagProtectionSettings = 2; // Clan tag protection settings config type. const CT_ServerRulesSettings = 3; // Server rules settings config type. /*************************************************************************************************** * * $DESCRIPTION Replication block. * **************************************************************************************************/ replication { reliable if (role == ROLE_Authority) // General settings. enableOverlaySkin, enableMapSwitch, enableStartAnnouncer, enableAntiSpam, enableClientIDAKALog, checkForUpdates, // Full server redirect settings. enableFullServerRedirect, fullServerRedirectMsg, redirectServerName, redirectURL, // Clan tag protection. enableTagProtection, tagsToProtect, // Server rules. enableServerRules, serverRules, // Data transfer control. dynamicChecksums, dynamicChecksumModifiers, updateCounts; } /*************************************************************************************************** * * $DESCRIPTION Calculates a checksum of the replicated dynamic variables. * $PARAM configType The configuration type for which the checksum is to be calculated. * $REQUIRE configType == CT_GeneralSettings || * configType == CT_FullServerRedirect || * configType == CT_TagProtectionSettings * $RETURN The checksum of the replicated variables. * **************************************************************************************************/ simulated function int calcDynamicChecksum(byte configType) { local int checksum; local int index; checksum += dynamicChecksumModifiers[configType]; switch (configType) { case CT_GeneralSettings: // General settings config type. checksum += int(enableOverlaySkin) | int(enableMapSwitch) << 1 | int(enableStartAnnouncer) << 2 | int(enableAntiSpam) << 3 | int(enableClientIDAKALog) << 4 | int(checkForUpdates) << 5; break; case CT_FullServerRedirect: // Full server redirect settings config type. checksum += int(enableFullServerRedirect) + stringHash(fullServerRedirectMsg); for (index = 0; index < arrayCount(redirectServerName); index++) { checksum += stringHash(redirectServerName[index]); } for (index = 0; index < arrayCount(redirectURL); index++) { checksum += stringHash(redirectURL[index]); } break; case CT_TagProtectionSettings: // Clan tag protection settings config type. checksum += int(enableTagProtection); for (index = 0; index < arrayCount(tagsToProtect); index++) { checksum += stringHash(tagsToProtect[index]); } break; case CT_ServerRulesSettings: // Server rules settings config type. checksum += int(enableServerRules); for (index = 0; index < arrayCount(serverRules); index++) { checksum += stringHash(serverRules[index]); } } return checksum; } /*************************************************************************************************** * * $DESCRIPTION Gives the integer hash value of a string. * $PARAM str The string that is to be hashed. * $RETURN The hash value of the given string. * **************************************************************************************************/ static function int stringHash(coerce string str) { local int hash; if (str != "") { hash = 29789 * asc(left(str, 1)) + 953 * asc(mid(str, len(str) / 2, 1)) + 31 * asc(right(str, 1)) + len(str); } return hash; } /*************************************************************************************************** * * $DESCRIPTION Updates the checksums for the dynamic replication info. * $ENSURE foreach(type => dynamicChecksum in dynamicChecksums) * dynamicChecksum == calcDynamicChecksum(type) * **************************************************************************************************/ function updateDynamicChecksums() { local byte index; for (index = 0; index < arrayCount(dynamicChecksums); index++) { updateChecksum(index); } } /*************************************************************************************************** * * $DESCRIPTION Updates the checksums for the current replication info. * $PARAM configType The configuration type for which the checksum is to be calculated. * $ENSURE dynamicChecksums[configType] == calcDynamicChecksum(configType) * **************************************************************************************************/ function updateChecksum(byte configType) { dynamicChecksumModifiers[configType] = rand(maxInt); dynamicChecksums[configType] = calcDynamicChecksum(configType); } /*************************************************************************************************** * * $DESCRIPTION Loads the plugins configuration. * $OVERRIDE * **************************************************************************************************/ function preBeginPlay() { xControl = NexgenX(owner); } /*************************************************************************************************** * * $DESCRIPTION Automatically installs the extension plugin. * $ENSURE lastInstalledVersion >= xControl.versionNum * **************************************************************************************************/ function install() { if (lastInstalledVersion < 105) installVersion105(); if (lastInstalledVersion < 106) installVersion106(); if (lastInstalledVersion < 107) installVersion107(); //if (lastInstalledVersion < 108) installVersion108(); //if (lastInstalledVersion < 109) installVersion109(); // etc. if (lastInstalledVersion < xControl.versionNum) { lastInstalledVersion = xControl.versionNum; } saveConfig(); } /*************************************************************************************************** * * $DESCRIPTION Automatically installs version 105 of the Nexgen extension plugin. * **************************************************************************************************/ function installVersion105() { enableOverlaySkin = true; enableMapSwitch = true; enableStartAnnouncer = true; enableFullServerRedirect = false; fullServerRedirectMsg = xControl.lng.defaultFullServerRedirMsg; redirectServerName[0] = "Server 1"; redirectURL[0] = "unreal://127.0.0.1:7777/"; } /*************************************************************************************************** * * $DESCRIPTION Automatically installs version 106 of the Nexgen extension plugin. * **************************************************************************************************/ function installVersion106() { enableAntiSpam = true; } /*************************************************************************************************** * * $DESCRIPTION Automatically installs version 107 of the Nexgen extension plugin. * **************************************************************************************************/ function installVersion107() { checkForUpdates = true; } /*************************************************************************************************** * * $DESCRIPTION Validates the configuration. Problems with the Nexgen extension plugin * configuration will be automatically repaired. * $RETURN True if the configuration was valid, false if there were one or more configuration * corruptions. * $ENSURE imply(old.validate(), new.validate()) * **************************************************************************************************/ function bool validate() { local bool bInvalid; local int index; bInvalid = bInvalid || fixStrLen(fullServerRedirectMsg, 250); for (index = 0; index < arrayCount(redirectServerName); index++) { bInvalid = bInvalid || fixStrLen(redirectServerName[index], 24); } for (index = 0; index < arrayCount(redirectURL); index++) { bInvalid = bInvalid || fixStrLen(redirectURL[index], 64); } for (index = 0; index < arrayCount(tagsToProtect); index++) { bInvalid = bInvalid || fixStrLen(tagsToProtect[index], 10); } if (bInvalid) { saveConfig(); } return !bInvalid; } /*************************************************************************************************** * * $DESCRIPTION Initializes the configuration. * **************************************************************************************************/ function initialize() { local int index; // Last thing to do is to make sure all the checksums are up to date. updateDynamicChecksums(); for (index = 0; index < arrayCount(dynamicChecksums); index++) { updateCounts[index] = 1; } } /*************************************************************************************************** * * $DESCRIPTION Fixes the length of a string. This function makes sure the length of a given * string doesn't exceed the specified maximum length. * $PARAM str The string of which the length has to be checked. * $PARAM maxLen The maximum length of the string. * $REQUIRE maxLen >= 0 * $RETURN True if the length of the string was changed, false otherwise. * $ENSURE len(new.str) <= maxLen * **************************************************************************************************/ function bool fixStrLen(out string str, int maxLen) { if (len(str) > maxLen) { str = left(str, maxLen); return true; } else { return false; } } /*************************************************************************************************** * * $DESCRIPTION Fixes the value of a given integer variable. Calling this function will ensure * that the value of the variable will be in the specified domain. * $PARAM intVar The integer variable whose value is to be checked. * $PARAM lowerBound Lower bound on the range of the variable. * $PARAM upperBound Upperbound bound on the range of the variable. * $RETURN True if value of the integer variable was changed, false otherwise. * $ENSURE lowerBound <= intVar && intVar <= upperBound * **************************************************************************************************/ function bool fixIntRange(out int intVar, int lowerBound, int upperBound) { if (intVar < lowerBound) { intVar = lowerBound; return true; } else if (intVar > upperBound) { intVar = upperBound; return true; } else { return false; } } /*************************************************************************************************** * * $DESCRIPTION Fixes the value of a given byte variable. Calling this function will ensure * that the value of the variable will be in the specified domain. * $PARAM byteVar The byte variable whose value is to be checked. * $PARAM lowerBound Lower bound on the range of the variable. * $PARAM upperBound Upperbound bound on the range of the variable. * $RETURN True if value of the byte variable was changed, false otherwise. * $ENSURE lowerBound <= byteVar && byteVar <= upperBound * **************************************************************************************************/ function bool fixByteRange(out byte byteVar, byte lowerBound, byte upperBound) { if (byteVar < lowerBound) { byteVar = lowerBound; return true; } else if (byteVar > upperBound) { byteVar = upperBound; return true; } else { return false; } } ^ xU?> q-G'h-Gu}xHxu&^sH0 tH9-G(eu-G  ` ~rECw*~ ul/*************************************************************************************************** * * NSC. Nexgen Server Controller by Zeropoint. * * $CLASS NexgenXClient * $VERSION 1.16 (9-8-2008 13:36) * $AUTHOR Daan 'Defrost' Scheerens initial version * $CONTACT d.scheerens@gmail.com * $DESCRIPTION Extension pack client controller class. This class is the base of the clientside * support for the extension plugin. * **************************************************************************************************/ class NexgenXClient extends NexgenClientController; #exec OBJ LOAD FILE=Announcer #exec AUDIO IMPORT NAME=alertSound FILE=Resources\klax1.wav var NexgenX xControl; // Extension controller. var NexgenXLang lng; // Language instance to support localization. var NexgenXConfig xConf; // Plugin configuration. var NexgenXRCPMapSwitch mapSwitchTab; // Map switch control panel tab. var NexgenXPlayerOverlay playerOverlay; // Player overlay skin. var bool bNetWait; // Client is waiting for initial replication. // Map list control. var bool bSendingMapList; // Whether the server is currently sending the map list. var bool bMapListSend; // Whether the map list has been sended to the client. var string firstMap; // Filename of the first map on the server. var string lastMap; // Filename of the last map send to the client. var string maps[1024]; // Maps available on the server. var int mapCount; // Number of maps available. // Dynamic control info. var int lastCountDown; // Last known value of gInf.countDown. var bool bGameStartingAnnounced; // Has the game starting state been announced yet? // Config replication control. var int nextDynamicUpdateCount[4]; // Last received config update count per config type. var int nextDynamicChecksum[4]; // Checksum to wait for. var byte bWaitingForNewConfig[4]; // Whether the client is waiting for the configuration. // Anti spam control. var string lastMessages[3]; // Last chat messages send by the player. var float lastMessageTimeStamps[3]; // Time stamp of the last send chat messages. var float lastSpamTimeStamp; // Last time this player has spammed. // Controller settings. const timerFreq = 5.0; // Timer tick frequency. const minMessageInterval = 1.5; // Minimum time between duplicate chat messages. const spamNotifyDuration = 2.0; // How long will the spam notification be visible? const maxMapListPartStringSize = 40; // Maximum size of the map list parts send to the client. const startCountDownWait = 2; // Second to wait before starting the count down announcer. // General constants. const maxStringSize = 255; // Maximum size of strings replicated over the net. const separator = ","; // Character used to seperate elements in a list. // Client side settings. const SSTR_LastVersionNotify = "LastVersionNotify"; // Last Nexgen update the client was notified of. /*************************************************************************************************** * * $DESCRIPTION Replication block. * **************************************************************************************************/ replication { reliable if (role == ROLE_Authority) // Replicate to client... // Variables. xConf, // Functions. receiveMapListPart, nexgenXConfigChanged, notifyClientSpam, updateRemainingTime, notifyUpdateAvailable, showRules; reliable if (role == ROLE_SimulatedProxy) // Replicate to server... // Variables. // Functions. requestMapList, doMapSwitch, setGeneralSettings, setFullServerRedirSettings, addBots, setScoreLimit, setTimeLimit, setTeamScoreLimit, setGameSpeed, setRemainingTime, setTagProtectionSettings, setServerRulesSettings, adminForceClientViewRules; } /*************************************************************************************************** * * $DESCRIPTION Initializes the client controller. * $OVERRIDE * **************************************************************************************************/ simulated function preBeginPlay() { super.preBeginPlay(); // Execute client side actions. if (role == ROLE_SimulatedProxy) { // Wait for initial replication to complete. bNetWait = true; } } /*************************************************************************************************** * * $DESCRIPTION Initializes the client controller. * $OVERRIDE * **************************************************************************************************/ simulated event postNetBeginPlay() { if (bNetOwner) { super.postNetBeginPlay(); // Load localization support. lng = spawn(class'NexgenXLang'); // Enable timer. setTimer(1.0 / timerFreq, true); // Make sure the HUD won't show a muted icon just after we joined the game. lastSpamTimeStamp = -spamNotifyDuration; } else { destroy(); } } /*************************************************************************************************** * * $DESCRIPTION Checks whether the client is ready to initialize. * $RETURN True if the client is ready to initialize, false if not. * $OVERRIDE * **************************************************************************************************/ simulated function bool isReadyToInitialize() { return (client != none && initialConfigReplicationComplete()); } /*************************************************************************************************** * * $DESCRIPTION Modifies the setup of the Nexgen remote control panel. * $OVERRIDE * **************************************************************************************************/ simulated function setupControlPanel() { // Add control panel tabs. if (client.hasRight(client.R_MatchAdmin) && xConf.enableMapSwitch) { requestMapList(); mapSwitchTab = NexgenXRCPMapSwitch(client.mainWindow.mainPanel.addPanel(lng.mapSwitchTabTxt, class'NexgenXRCPMapSwitch', , "game")); } if (xConf.enableServerRules) { client.mainWindow.mainPanel.addPanel(lng.serverRulesTabTxt, class'NexgenXRCPServerRulesView', , "server"); } if (client.hasRight(client.R_ServerAdmin)) { client.addPluginConfigPanel(class'NexgenXRCPSettings'); client.addPluginConfigPanel(class'NexgenXRCPFullServerRedir'); client.addPluginConfigPanel(class'NexgenXRCPTagProtection'); client.addPluginConfigPanel(class'NexgenXRCPServerRules'); } } /*************************************************************************************************** * * $DESCRIPTION Called when the NexgenClient has received its initial replication info is has * been initialized. At this point it's safe to use all functions of the client. * $OVERRIDE * **************************************************************************************************/ simulated function clientInitialized() { bNetWait = false; } /*************************************************************************************************** * * $DESCRIPTION Time critical event detection loop. * $OVERRIDE * **************************************************************************************************/ simulated function tick(float deltaTime) { // Client side actions. if (role == ROLE_SimulatedProxy && client != none && !client.bNetWait) { // Game starting count down ticked? if (client.gInf.gameState == client.gInf.GS_Starting && lastCountDown != client.gInf.countDown) { lastCountDown = client.gInf.countDown; // Play countdown announcer sound? if (!bNetWait && xConf.enableStartAnnouncer) { if (1 <= lastCountDown && lastCountDown <= 10 && lastCountDown <= client.sConf.startTime - startCountDownWait) { //ChallengeHUD(client.player.myHUD).tellTime(16 - lastCountDown); client.player.receiveLocalizedMessage(class'Botpack.TimeMessage', 16 - lastCountDown); } else if (!bGameStartingAnnounced) { bGameStartingAnnounced = true; client.player.clientPlaySound(sound'Announcer.Prepare', , true); } } } } } /*************************************************************************************************** * * $DESCRIPTION Initializes the client controller. This function is automatically called after * the critical variables have been set, such as the client variable. * $PARAM creator The Actor that has added the controller to the client. * $OVERRIDE * **************************************************************************************************/ function initialize(optional Actor creator) { xControl = NexgenX(creator); lng = xControl.lng; } /*************************************************************************************************** * * $DESCRIPTION Called by the client when it wants to receive the list of maps that are available * on the server. * $ENSURE bSendingMapList || bMapListSend * **************************************************************************************************/ function requestMapList() { // Check if map list is already being send or has already been send. if (bSendingMapList || bMapListSend) { // It is and there's no need to send things again. return; } // Start sending the map list to the client. bSendingMapList = true; setTimer(1.0 / timerFreq, true); } /*************************************************************************************************** * * $DESCRIPTION Timer tick function. On the server side the timer tick is responsible for sending * the map list to the client if bSendingMapList is set to true. * **************************************************************************************************/ simulated function timer() { local string mapList; local string nextMap; local bool bMapListComplete; local bool bMapListFull; // Client side actions. if (role == ROLE_SimulatedProxy) { // Check for config updates. if (!bNetWait) { checkConfigUpdate(); } // Server side actions. } else { // Send next part of the map list. if (bSendingMapList) { // Just starting to send the map list? if (firstMap == "") { // First map hasn't been determined yet, so yes. firstMap = getMapName("", "", 0); mapList = firstMap; lastMap = firstMap; } // Get next map to send. nextMap = getMapName("", lastMap, 1); // Continue adding maps the map list till the string get too large. while (!bMapListComplete && !bMapListFull) { if (nextMap ~= firstMap) { // Back at the first map, so we're done. bMapListComplete = true; } else if (mapList == "") { // Map list is empty, so we can safely add the next map. mapList = nextMap; lastMap = nextMap; nextMap = getMapName("", lastMap, 1); } else if (len(mapList) + len(separator) + len(nextMap) > maxMapListPartStringSize) { // Can't add the next map without exceeding the maximum string size. bMapListFull = true; } else { // There's still enough space to add the next map. mapList = mapList $ separator $ nextMap; lastMap = nextMap; nextMap = getMapName("", lastMap, 1); } } // Send the map list. receiveMapListPart(bMapListComplete, mapList); // Check if sending has been completed. if (bMapListComplete) { bSendingMapList = false; bMapListSend = true; setTimer(0.0, false); } } } } /*************************************************************************************************** * * $DESCRIPTION Called on the client when a new part of the map list has been received. * $PARAM bLastPart Indicates whether this is the last part of the map list. * $PARAM mapListPart String containing a part of the map list. * **************************************************************************************************/ simulated function receiveMapListPart(bool bLastPart, string mapListPart) { local string remaining; local string mapName; remaining = mapListPart; while (remaining != "" && mapCount < arrayCount(maps)) { class'NexgenUtil'.static.split(remaining, mapName, remaining); maps[mapCount++] = mapName; } if (bLastPart) { mapSwitchTab.notifyMapListAvailable(); } else { mapSwitchTab.notifyMapListPartRecieved(); } } /*************************************************************************************************** * * $DESCRIPTION Causes the server to load the specified map with the given game type and mutators. * $PARAM mapName File name of the map that is to be loaded. * $PARAM gameType The game type to use when the new map is loaded. * $PARAM mutators List of mutators that are to be loaded. * **************************************************************************************************/ function doMapSwitch(string mapName, byte gameType, string mutators) { local string remaining; local string indexStr; local int index; local string mutatorClass; local string mutatorClasses; local string temp; local string gameClass; local string clientTravelURL; local string serverTravelURL; local string mapNameNoExt; local string serverActors; // Preliminary checks. if (!client.hasRight(client.R_MatchAdmin)) { return; } // Get game type. if (0 <= gameType && gameType < arrayCount(client.sConf.gameTypeInfo)) { class'NexgenUtil'.static.split(client.sConf.gameTypeInfo[gameType], gameClass, temp); } else { gameClass = ""; } // Get server actor list. serverActors = caps(consoleCommand("get Engine.GameEngine ServerActors")); // Get mutator classes. remaining = mutators; while (remaining != "") { class'NexgenUtil'.static.split(remaining, indexStr, remaining); index = int(indexStr); if (0 <= index && index < arrayCount(client.sConf.mutatorInfo)) { class'NexgenUtil'.static.split(client.sConf.mutatorInfo[index], mutatorClass, temp); // Only add mutator class if not already in the server actor list. if (instr(serverActors, "\"" $ caps(mutatorClass) $ "\"") < 0) { if (mutatorClasses == "") { mutatorClasses = mutatorClass; } else { mutatorClasses = mutatorClasses $ separator $ mutatorClass; } } } } // Assemble URL & set server travel. clientTravelURL = mapName $ "?game=" $ gameClass; serverTravelURL = mapName $ "?game=" $ gameClass $ "?mutator=" $ mutatorClasses; level.serverTravel(clientTravelURL, false); level.nextURL = serverTravelURL; // Now make the server use the 'real' travel url. // Log action. mapNameNoExt = left(mapName, instr(mapName, ".")); logAdminAction(lng.adminMapSwitchMsg, mapNameNoExt); } /*************************************************************************************************** * * $DESCRIPTION Adds or removes the player overlay skin for this client. * $PARAM bRemove Whether the overlay skin is to be removed. * $ENSURE bRemove ? new.playerOverlay == none : new.playerOverlay != none * **************************************************************************************************/ function setPlayerOverlay(optional bool bRemove) { // Remove overlay skin? if (bRemove && playerOverlay != none) { // Yes. playerOverlay.destroy(); playerOverlay = none; } else if (!bRemove && playerOverlay == none && !client.bSpectator) { // No, add overlay skin. playerOverlay = spawn(class'NexgenXPlayerOverlay', client.player, , client.player.location, client.player.rotation); playerOverlay.client = client; } } /*************************************************************************************************** * * $DESCRIPTION Notifies the client that the server configuration has been updated. The new * settings might not yet have been replicated, so the client has to wait for the * replication to complete. Once the replication is completed an event will be * triggered to signal the GUI and other client controllers that the new settings * are available, see checkConfigUpdate(). Note this function is similar to the * configChanged() function in NexgenClient. * $PARAM configType Type of settings that have been changed. * $PARAM updateCount Config update number for the new settings. * $PARAM checksum Checksum of the new settings. * $REQUIRE 0 <= configType && configType < arrayCount(configChecksum) && updateCount >= 0 * **************************************************************************************************/ simulated function nexgenXConfigChanged(byte configType, int updateCount, int checksum) { if (updateCount > nextDynamicUpdateCount[configType]) { nextDynamicUpdateCount[configType] = updateCount; nextDynamicChecksum[configType] = checksum; bWaitingForNewConfig[configType] = byte(true); } } /*************************************************************************************************** * * $DESCRIPTION Checks whether some of the configuration was updated and if the new configuration * has been replicated yet to the client. If this is the case an event will be * signalled on the client to notify the system that the new configuration is * available. * **************************************************************************************************/ simulated function checkConfigUpdate() { local byte type; // Server configuration. for (type = 0; type < arrayCount(nextDynamicChecksum); type++) { if (bool(bWaitingForNewConfig[type]) && xConf.updateCounts[type] >= nextDynamicUpdateCount[type] && xConf.calcDynamicChecksum(type) == nextDynamicChecksum[type]) { bWaitingForNewConfig[type] = byte(false); // Signal event GUI. client.notifyEvent(xConf.EVENT_NexgenXConfigChanged, string(type)); } } } /*************************************************************************************************** * * $DESCRIPTION Checks whether the initial replication of the configuration has completed. * $RETURN True if the initial data of the xConf instance has been recieved, false if not. * **************************************************************************************************/ simulated function bool initialConfigReplicationComplete() { local int index; // Check if configuration instance has been spawned (via replication). if (xConf == none) { return false; } // Check dynamic replication data. for (index = 0; index < arrayCount(nextDynamicChecksum); index++) { if (xConf.updateCounts[index] <= 0 || xConf.dynamicChecksums[index] != xConf.calcDynamicChecksum(index)) { return false; } } // All checks passed, initial replication complete! return true; } /*************************************************************************************************** * * $DESCRIPTION Changes the general Nexgen extension plugin settings. * $PARAM enableOverlaySkin Whether the player overlay skin effect is enabled. * $PARAM enableMapSwitch Whether the map switch tab is enabled. * $PARAM enableStartAnnouncer Whether the game starting voice announcer is enabled. * $PARAM enableAntiSpam Whether prevent players from message spamming. * $PARAM enableClientIDAKALog Whether to log the client ID's to AKA. * $PARAM checkForUpdates Whether to check for new versions of Nexgen. * **************************************************************************************************/ function setGeneralSettings(bool enableOverlaySkin, bool enableMapSwitch, bool enableStartAnnouncer, bool enableAntiSpam, bool enableClientIDAKALog, bool checkForUpdates) { // Check rights. if (!client.hasRight(client.R_ServerAdmin)) { return; } // Save settings. xConf.enableOverlaySkin = enableOverlaySkin; xConf.enableMapSwitch = enableMapSwitch; xConf.enableStartAnnouncer = enableStartAnnouncer; xConf.enableAntiSpam = enableAntiSpam; xConf.enableClientIDAKALog = enableClientIDAKALog; xConf.checkForUpdates = checkForUpdates; xConf.saveConfig(); // Notify system. xControl.signalConfigUpdate(xConf.CT_GeneralSettings); // Log action. client.showMsg(control.lng.settingsSavedMsg); logAdminAction(lng.adminUpdateGeneralSettingsMsg); } /*************************************************************************************************** * * $DESCRIPTION Changes the full server redirect settings. * $PARAM enableFullServerRedirect Whether full server redirect is enabled. * $PARAM fullServerRedirectMsg Message to display when the server is full. * $PARAM redirectServerName1 First redirect server name. * $PARAM redirectServerName2 Second redirect server name. * $PARAM redirectServerName3 Third redirect server name. * $PARAM redirectURL1 First redirect server address/URL. * $PARAM redirectURL2 Second redirect server address/URL. * $PARAM redirectURL3 Third redirect server address/URL. * **************************************************************************************************/ function setFullServerRedirSettings(bool enableFullServerRedirect, string fullServerRedirectMsg, string redirectServerName1, string redirectServerName2, string redirectServerName3, string redirectURL1, string redirectURL2, string redirectURL3) { // Check rights. if (!client.hasRight(client.R_ServerAdmin)) { return; } // Save settings. xConf.enableFullServerRedirect = enableFullServerRedirect; xConf.fullServerRedirectMsg = left(fullServerRedirectMsg, 250); xConf.redirectServerName[0] = left(redirectServerName1, 24); xConf.redirectServerName[1] = left(redirectServerName2, 24); xConf.redirectServerName[2] = left(redirectServerName3, 24); xConf.redirectURL[0] = left(redirectURL1, 64); xConf.redirectURL[1] = left(redirectURL2, 64); xConf.redirectURL[2] = left(redirectURL3, 64); xConf.saveConfig(); // Notify system. xControl.signalConfigUpdate(xConf.CT_FullServerRedirect); // Log action. client.showMsg(control.lng.settingsSavedMsg); logAdminAction(lng.adminFullServerRedirSettingsMsg); } /*************************************************************************************************** * * $DESCRIPTION Checks whether the specified message should be considered spam by this player. * $PARAM msg The message that the player tried to send. * $RETURN True whether the specified message is spam, false if not. * **************************************************************************************************/ function bool isSpam(string msg) { local int index; // Moderators can say whatever they want. if (client.hasRight(client.R_Moderate)) return false; // Check if we already said this message in the last x seconds. for (index = 0; index < arrayCount(lastMessages); index++) { if (lastMessages[index] == msg && (client.control.timeSeconds - lastMessageTimeStamps[index]) <= minMessageInterval) { return true; } } // No matching rules found, so message isn't spam. return false; } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ function addMessage(string msg) { local int index; // Shift old messages up in the list. for (index = 0; index < arrayCount(lastMessages) - 1; index++) { lastMessages[index] = lastMessages[index + 1]; lastMessageTimeStamps[index] = lastMessageTimeStamps[index + 1]; } // Store new message at the back of the list. lastMessages[index] = msg; lastMessageTimeStamps[index] = client.control.timeSeconds; } /*************************************************************************************************** * * $DESCRIPTION Called when this client is spamming. * **************************************************************************************************/ simulated function notifyClientSpam() { client.player.clientPlaySound(sound'alertSound', , true); lastSpamTimeStamp = client.timeSeconds; } /*************************************************************************************************** * * $DESCRIPTION Modifies the client state panel on the Nexgen HUD. * $PARAM stateType State type identifier. * $PARAM text Text to display on the state panel. * $PARAM textColor Color of the text to display. * $PARAM icon State icon. The icon is displayed in front of the text. * $PARAM solidIcon Solid version of the icon (masked, no transparency). * $PARAM bBlink Whether the text on the panel should blink. * $OVERRIDE * **************************************************************************************************/ simulated function modifyClientState(out name stateType, out string text, out Color textColor, out Texture icon, out Texture solidIcon, out byte bBlink) { if (stateType == client.nscHUD.CS_Normal && (client.timeSeconds - lastSpamTimeStamp) <= spamNotifyDuration) { stateType = client.nscHUD.CS_Muted; text = lng.antiSpamMutedState; textColor = client.nscHUD.colors[client.nscHUD.C_RED]; icon = Texture'mutedIcon'; solidIcon = Texture'mutedIcon2'; bBlink = byte(true); } } /*************************************************************************************************** * * $DESCRIPTION Wrapper function for NexgenController.logAdminAction(). * $PARAM msg Message that describes the action performed by the administrator. * $PARAM str1 Message specific content. * $PARAM str2 Message specific content. * $PARAM str3 Message specific content. * $PARAM bNoBroadcast Whether not to broadcast this administrator action. * **************************************************************************************************/ function logAdminAction(string msg, optional coerce string str1, optional coerce string str2, optional coerce string str3, optional bool bNoBroadcast) { control.logAdminAction(client, msg, client.playerName, str1, str2, str3, client.player.playerReplicationInfo, bNoBroadcast); } /*************************************************************************************************** * * $DESCRIPTION Called when an instance of this class is destroyed. Automatically cleans up any * remaining objects. * $OVERRIDE * **************************************************************************************************/ simulated function destroyed() { // Destroy player overlay. if (playerOverlay != none) { playerOverlay.destroy(); playerOverlay = none; } // Client side only. if (role == ROLE_SimulatedProxy) { // Destroy localization support. if (xConf != none) { xConf.destroy(); xConf = none; } // Destroy localization support. if (lng != none) { lng.destroy(); lng = none; } } } /*************************************************************************************************** * * $DESCRIPTION Adds bots to the current game. A negative amount indicates that bots should be * removed. * $PARAM amount The amount of bots to add or remove * **************************************************************************************************/ function addBots(int amount) { local bool bAddBots; local int count; local Bot bot; local string mulStr; local DeathMatchPlus game; // Preliminary checks. if (!client.hasRight(client.R_MatchSet) || amount == 0) { return; } // Perform action. bAddBots = amount > 0; if (bAddBots) { // Add bots to the game. for (count = 0; count < amount; count++) { level.game.forceAddBot(); } } else { // Get DeathMatchPlus game. if (level.game.isA('DeathMatchPlus')) { game = DeathMatchPlus(level.game); } // Destroy some bots. foreach allActors(class 'Bot', bot) { if (game != none) { game.minPlayers = max(game.minPlayers - 1, game.numPlayers + game.numBots - 1); } bot.destroy(); count++; if (count >= -amount) { break; } } // Rebalance game if necessary. if (level.game.isA('TeamGamePlus') && TeamGamePlus(level.game).bBalanceTeams) { TeamGamePlus(level.game).reBalance(); } } // Log action. if (bAddBots) { if (amount != 1) mulStr = "s"; logAdminAction(lng.adminAddBotsMsg, amount, mulStr); } else { if (count != 1) mulStr = "s"; logAdminAction(lng.adminRemoveBotsMsg, count, mulStr); } } /*************************************************************************************************** * * $DESCRIPTION Changes the score limit for the current game. * $PARAM amount The new score limit. * **************************************************************************************************/ function setScoreLimit(int amount) { local DeathMatchPlus game; // Preliminary checks. if (!client.hasRight(client.R_MatchSet) || !level.game.isA('DeathMatchPlus')) { return; } // Get DeathMatchPlus game. game = DeathMatchPlus(level.game); // Change frag limit. game.fragLimit = amount; TournamentGameReplicationInfo(game.gameReplicationInfo).fragLimit = amount; game.saveConfig(); // Log action. logAdminAction(lng.adminChangeScoreLimitMsg, amount); } /*************************************************************************************************** * * $DESCRIPTION Changes the time limit for the current game. * $PARAM amount The new time limit. * **************************************************************************************************/ function setTimeLimit(int amount) { local DeathMatchPlus game; local int previousTimeLimit; // Preliminary checks. if (!client.hasRight(client.R_MatchSet) || !level.game.isA('DeathMatchPlus')) { return; } // Get DeathMatchPlus game. game = DeathMatchPlus(level.game); // Change time limit. previousTimeLimit = game.timeLimit; game.timeLimit = amount; TournamentGameReplicationInfo(game.gameReplicationInfo).timeLimit = amount; game.saveConfig(); // Update remaining time. if (previousTimeLimit == 0 && amount > 0) { game.remainingTime = amount * control.secondsPerMinute; } else if (previousTimeLimit > 0 && amount == 0) { game.remainingTime = 0; } else if (amount < previousTimeLimit) { game.remainingTime = min(game.remainingTime, amount * control.secondsPerMinute); } else { game.remainingTime = game.remainingTime + (amount - previousTimeLimit) * control.secondsPerMinute; } game.gameReplicationInfo.remainingTime = game.remainingTime; xControl.announceNewRemainingTime(game.remainingTime); // Log action. logAdminAction(lng.adminChangeTimeLimitMsg, amount); } /*************************************************************************************************** * * $DESCRIPTION Changes the value of the remaining time at the client. * $PARAM remainingTime The new remaining time. * **************************************************************************************************/ simulated function updateRemainingTime(int remainingTime) { if (client.player.gameReplicationInfo != none) { client.player.gameReplicationInfo.remainingTime = remainingTime; } } /*************************************************************************************************** * * $DESCRIPTION Changes the team score limit for the current game. * $PARAM amount The new team score limit. * **************************************************************************************************/ function setTeamScoreLimit(int amount) { local TeamGamePlus game; // Preliminary checks. if (!client.hasRight(client.R_MatchSet) || !level.game.isA('TeamGamePlus')) { return; } // Get TeamGamePlus game. game = TeamGamePlus(level.game); // Change frag limit. game.goalTeamScore = amount; TournamentGameReplicationInfo(game.gameReplicationInfo).goalTeamScore = amount; game.saveConfig(); // Log action. logAdminAction(lng.adminChangeTeamScoreLimitMsg, amount); } /*************************************************************************************************** * * $DESCRIPTION Changes the game speed for the current game. * $PARAM gameSpeed The new game speed limit. * **************************************************************************************************/ function setGameSpeed(int gameSpeed) { // Preliminary checks. if (!client.hasRight(client.R_MatchSet)) { return; } // Change the game speed. level.game.setGameSpeed(gameSpeed / 100.0); level.game.saveConfig(); level.game.gameReplicationInfo.saveConfig(); // Log action. logAdminAction(lng.adminChangeGameSpeedMsg, int(level.game.gameSpeed * 100)); } /*************************************************************************************************** * * $DESCRIPTION Changes the remaining time for the current game. * $PARAM remainingTimeStr The new remaining time. * **************************************************************************************************/ function setRemainingTime(string remainingTimeStr) { local DeathMatchPlus game; local int remainingTime; // Preliminary checks. if (!client.hasRight(client.R_MatchAdmin) || !level.game.isA('DeathMatchPlus') || !class'NexgenXUtil'.static.getTimeInSeconds(remainingTimeStr, remainingTime)) { return; } // Get DeathMatchPlus game. game = DeathMatchPlus(level.game); // Check if there is a time limit. if (game.timeLimit <= 0) { return; } // Update time limit. remainingTime = min(remainingTime, game.timeLimit * control.secondsPerMinute); game.remainingTime = remainingTime; game.gameReplicationInfo.remainingTime = remainingTime; xControl.announceNewRemainingTime(remainingTime); // Log action. logAdminAction(lng.adminChangeTimeRemainingMsg, lng.getLongTimeDescription(remainingTime)); } /*************************************************************************************************** * * $DESCRIPTION Changes the tag protection settings. Note that we can't use an array for the list * of tags to protect, because this will give unexpected behaviour when the function * call is replicated. * $PARAM enableTagProtection Whether tag protection should be used or not. * $PARAM tagsToProtect_0 Tag to protect. * $PARAM tagsToProtect_1 Tag to protect. * $PARAM tagsToProtect_2 Tag to protect. * $PARAM tagsToProtect_3 Tag to protect. * $PARAM tagsToProtect_4 Tag to protect. * $PARAM tagsToProtect_5 Tag to protect. * **************************************************************************************************/ function setTagProtectionSettings(bool enableTagProtection, string tagsToProtect_0, string tagsToProtect_1, string tagsToProtect_2, string tagsToProtect_3, string tagsToProtect_4, string tagsToProtect_5) { // Check rights. if (!client.hasRight(client.R_ServerAdmin)) { return; } // Save settings. xConf.enableTagProtection = enableTagProtection; xConf.tagsToProtect[0] = class'NexgenUtil'.static.trim(tagsToProtect_0); xConf.tagsToProtect[1] = class'NexgenUtil'.static.trim(tagsToProtect_1); xConf.tagsToProtect[2] = class'NexgenUtil'.static.trim(tagsToProtect_2); xConf.tagsToProtect[3] = class'NexgenUtil'.static.trim(tagsToProtect_3); xConf.tagsToProtect[4] = class'NexgenUtil'.static.trim(tagsToProtect_4); xConf.tagsToProtect[5] = class'NexgenUtil'.static.trim(tagsToProtect_5); xConf.saveConfig(); // Notify system. xControl.signalConfigUpdate(xConf.CT_TagProtectionSettings); // Log action. client.showMsg(control.lng.settingsSavedMsg); logAdminAction(lng.adminUpdateTagProtectionSettingsMsg); } /*************************************************************************************************** * * $DESCRIPTION Notifies the client that there is an update for Nexgen available * $PARAM version The latest version of Nexgen that is available. * **************************************************************************************************/ simulated function notifyUpdateAvailable(int version) { local int lastNotifiedVersion; lastNotifiedVersion = int(client.gc.get(SSTR_LastVersionNotify, "0")); // Check if the client should be notified of this update. if (version > lastNotifiedVersion) { client.gc.set(SSTR_LastVersionNotify, string(version)); client.gc.saveConfig(); client.showPopup(string(class'NexgenXUpdateNotifyDialog'), string(version)); } } /*************************************************************************************************** * * $DESCRIPTION Changes the server rules settings. * $PARAM enableServerRules Whether the server rules should be displayed * $PARAM serverRules_0 Server rule. * $PARAM serverRules_1 Server rule. * $PARAM serverRules_2 Server rule. * $PARAM serverRules_3 Server rule. * $PARAM serverRules_4 Server rule. * $PARAM serverRules_5 Server rule. * $PARAM serverRules_6 Server rule. * $PARAM serverRules_7 Server rule. * $PARAM serverRules_8 Server rule. * $PARAM serverRules_9 Server rule. * **************************************************************************************************/ function setServerRulesSettings(bool enableServerRules, string serverRules_0, string serverRules_1, string serverRules_2, string serverRules_3, string serverRules_4, string serverRules_5, string serverRules_6, string serverRules_7, string serverRules_8, string serverRules_9) { local bool bGameRestartRequired; // Check rights. if (!client.hasRight(client.R_ServerAdmin)) { return; } // Check if the game has to be restarted in order to apply the changes. bGameRestartRequired = (xConf.enableServerRules != enableServerRules); // Save settings. xConf.enableServerRules = enableServerRules; xConf.serverRules[0] = class'NexgenUtil'.static.trim(serverRules_0); xConf.serverRules[1] = class'NexgenUtil'.static.trim(serverRules_1); xConf.serverRules[2] = class'NexgenUtil'.static.trim(serverRules_2); xConf.serverRules[3] = class'NexgenUtil'.static.trim(serverRules_3); xConf.serverRules[4] = class'NexgenUtil'.static.trim(serverRules_4); xConf.serverRules[5] = class'NexgenUtil'.static.trim(serverRules_5); xConf.serverRules[6] = class'NexgenUtil'.static.trim(serverRules_6); xConf.serverRules[7] = class'NexgenUtil'.static.trim(serverRules_7); xConf.serverRules[8] = class'NexgenUtil'.static.trim(serverRules_8); xConf.serverRules[9] = class'NexgenUtil'.static.trim(serverRules_9); xConf.saveConfig(); // Notify system. xControl.signalConfigUpdate(xConf.CT_ServerRulesSettings); // Notify client. client.showMsg(control.lng.settingsSavedMsg); if (bGameRestartRequired) { client.showMsg(lng.gameRestartRequiredMsg); } // Log action. logAdminAction(lng.adminUpdateServerRulesSettingsMsg); } /*************************************************************************************************** * * $DESCRIPTION Shows the server rules at the client. * **************************************************************************************************/ simulated function showRules(optional bool bAdminForced, optional string reason) { local NexgenXRCPServerRulesView rulesViewTab; if (xConf.enableServerRules) { // Get rules view tab. rulesViewTab = NexgenXRCPServerRulesView(client.mainWindow.mainPanel.getPanel(class'NexgenXRCPServerRulesView'.default.panelIdentifier)); if (rulesViewTab == none) { rulesViewTab = NexgenXRCPServerRulesView(client.mainWindow.mainPanel.addPanel(lng.serverRulesTabTxt, class'NexgenXRCPServerRulesView', , "server")); } // Set force message. if (bAdminForced) { rulesViewTab.setAdminForcedViewMessage(reason); } // Show the rules view tab. client.showPanel(class'NexgenXRCPServerRulesView'.default.panelIdentifier); } } /*************************************************************************************************** * * $DESCRIPTION Forces the client with the specified player code to view the server rules. * $PARAM targetPlayer Player code of the player that should view the server rules. * $PARAM reason Reason of the admin to make the player view the rules. * **************************************************************************************************/ function adminForceClientViewRules(int targetPlayer, optional string reason) { local NexgenClient target; local NexgenXClient xTarget; local string logReason; // Check rights. if (!client.hasRight(client.R_Moderate) || !xConf.enableServerRules) { return; } // Get target client. target = control.getClientByNum(targetPlayer); if (target == none) return; xTarget = NexgenXClient(target.getController(class'NexgenXClient'.default.ctrlID)); if (xTarget == none) return; // Show rules at target client. xTarget.showRules(true, reason); // Log action. if (reason == "") { logReason = lng.noReasonGivenMsg; } else { logReason = reason; } logAdminAction(lng.adminForceClientViewRulesMsg, target.playerName, logReason, , true); } /*************************************************************************************************** * * $DESCRIPTION Default properties block. * **************************************************************************************************/ G q q mv q( q m^ mw mn mw mm ms m[ m| mm qx my w ` mX mo mW mM w ` mg mG mp mS mQ m, mD m~ mB mU w R m{ mI mq w c mu mx mh w Z w _ W e mf mT mu w w mA m W F mK mL ^ X w U w B my qE m| me mJ mX mH n$ m mL nG w S ^ d mP w e X a w B w B mO X i w r mt mN mE u i nF mr n[ w _ w X mI w q W E m# n qF ^ v y Z m@ w U mu n- w X ^ v w w mz X L w T w p qO X f n$ W G ^ I w R w x m} w K mz X i u h u X X P y g ms ^ J w ] n w \ mf y k W s w ` mp X f y p mW X u X ~ w [ w U ^ 4 X Y mV w x n$ y p w V w ^ W ~ X \ mr w _ y _ X h u Q w B nk w M y p nA u T w ^ W t qi y S nC n r b W R ^ h w l X ^ nW X w ^ n w o w s y Z nf mn mR nV y @ W A w T nL s nP y u nU u P mr q@ n} y w w a r k ^ L X c X h r o y v W r w S mq w W w X w Y w Z y \ W } qCB t H X \ nS y Z w { w V w U md u K nD n~ y ` W l n} nM na nb nu nN nv nF(e`j(e`k nv nl n} nD mt(d0C_P1\cGlWsnZCR ]G jWx]nF}P t~ A}O Mlo Zto hqF  vwBq\ PJ^`mzo {HISF  W&G  c}o pF~o MM [SY jDDvCj zqb GB  SFV `Em}W {F  H] T\o a[ oCe  {CB HIUqo cOF  qY}5F  L\k YR gF  taG @z NF  [}DgW un A-F  Mn Za fGC  si @F  L}S X`fP tdAzQ  OoB\zP jMF  xw DO Qig ]\ jsG  w|D`S-jatB on }~MIt WDetA st@ AtD OA]tE l[ z] GXBTo b{  oeF  |GA HNF  TZ``Fnp^|GJCX5m g~`tBzQ~_F  n}zA Io  VBc(F  qG ~gKBYF  gF  sB[o  M[p Z`h`vm Da Qi  ^D  jtGvB}Uy KpCYz \w iRF  vX Bc  O}R  \C  iZ vw C_ P` ]wjr x"j E"k QA  ^  kzO xH F}T  R`  ^-Qk-N yuFBTP  bd o] ~ J[} WRec:HHm  VHE bi otC |I  JzWLF  eN qd~@Lp  [~F  hrq tN @@ MF  Yb  fE`siCA D`  QbF  ^aF  kBMwhe  Eoe  REo  _hw l`M y~  FNh Rld _Nv mle zlf Hpx  Vlg cDqz` @D  MvY~o glh u_ Co  Qf ^li ks  yq  Ep  Q] ^q  lp  xq[  E\j  RKg _5N l5V  xtF En Sn _tG ltH zv  HtI UtK ctL  qc  ~b JQ Xt e(m r] zN L|  Z@  g$N s@  @$U MA  Ya f[ r{[ MF  Zy gXtg BY Or [q h}  up AJ NB [p  hftj CtJ OQ]e  kzMxzNFv Te  `z m{ ze HQ  VBbI p^ }[ J"g W(U d-y pR }-R I:GU:Fc<C  q]  ~AC  JBP WHG dHF qKD ~qMKqN YZl fOv rXe  ~ml K^  Waa  do qf  ~g  Kh XmZ fie shO m`KqMYUx gUSue  Cw  PE]lMllN zo  Gy Tg av nt  zdFI  Te  aI  no  {dH~  Vo  c_|pt lo  x\ME[n  So  `V mM z\N Gv T[ba[Soe  }h JI  VV cJXp}} H[L T[@ aI  n[n zIAGHtH}| |}{ Iq Vr  ch ps  }}z Jh WdcRq}y @V M\ ZI  g[ tEI A}x J}D W`d}C rBVnA Un@ awEnzKsn An~ Nrt [n} hr@ upi un| Blh OlV [UL hUq umt Bm\ Om] \Uu iz vlDC RUT _I  lTh yZu EZ` RTV _a lb yc FC SNz  `U@ me yBb Et Q_  ^l k\  x<p  E[  R5 _Z  lY  yX  FW  S-b  `V  m( z)x G$| SU  `T  mS  zO  GN  Sh `V lM  yL  FK  SJ  `G mL z Gq Tl am nH  {A H^ UZ  ajXmB  EdYRi kWqw` ha  b Kc \d &pe BVf Xg (ph =Xi Uj ok Dl &Rm Bxn zo "Mgso_  bN n@_z^ Y] mkL4iXJA\ IQq RZ[ 0lr R\s Rnt R@u RRv LdjCp w Ls kC x LB nCN y SQ oCdz LgpCsZ /v|  e}  nFMxA]Ev  bY %o:OTAjcX MW $fV 4JzB~U *@Cdj{GNT #UD2xv  jAfvS #\}$~FctxiN av.mtFe[R @kR^tfgpt$}WF4TQ HggP AO PC cf mewd z{ HN Cc ]z`gb Gz-fQM GwL L~z)DJz$@NW NK JWJ DaI 8eH :]VtWG 2K}F 3|P[o}U J}|]E 8Y}BnQL{D 3zFTmC 2A}~Fs{ yTBS]B 4sA 0g@ @W 3W};\J:N f~ ,r} &^| JDbRN}Y3`}ZDS{ 8W<N OIF\}e&b}dIHySQ}$l dHN P}q\GgM}AbtNVKN dNN p<=}DBzJx|TPtqfDZv jSN wqmCHpq-goZF  VMN cq)fpq$@VN#VSRyO#K|Ynmv GPjTF'~V>eJcE>mmF  kmN xTEiN Y8EffEk/mpqN ]m[ i-gvFY]x]v$YSRtlIs`cPShdcOGbLON[McLkKsNRRB d{ qw^~9I\lM eN rl~l-f}MycM@\l)b\l$@~EL4t(~N rKrL4^*qN Oq \yi\l w\^~Y\L4k5jUL4JFU\n_a\M\-givDPN T\)va\$@W[L4WhWN nV {q H[cUavcYYbnguAUunV\L4NYDltR[|F[q  \[}i[~{[[UWlL4nZl[^ZNvxUMnVC{t ~`K[HEYvj^L4LwHqL4X[T}?ltL4]kK H}L4DUN Y [$Df zL4Wbj DkA!C l!n v!m G!l ^!k p!j  !PL!j^\!U}z!U[{L!L4PQG!URW"Ozi"b c"c p"d }"U$}I"kpF"Wiv"L4}Z_"l`\"mg|"_fc#nRI#[X[#L4[ s#WN#QDe#b i#c v#d C#tHP#E`X#L4R W#s]i#N F#oOS#L4kb#F  M%EUuY%rON%N ]%L4xj%zNb*ip*