[Setup] Product=NIUT Version=121 Archive=NIUT.umod SrcPath=. MasterPath=.. Requires=UnrealTournament400Requirement Group=SetupGroup Group=NIUTGroup [UnrealTournament400Requirement] Product=UnrealTournament Version=400 [SetupGroup] Copy=(Src=System\Manifest.ini,Master=System\Manifest.ini,Size=417,Flags=3) Copy=(Src=System\Manifest.int,Master=System\Manifest.int,Size=421,Flags=3) [NIUTGroup] File=(Src=Help\niut.txt,Size=8435) File=(Src=System\NIUT.u,Size=51630) File=(Src=System\Niut.int,Size=351) File=(Src=System\Niut.ini,Size=2357) [Setup] LocalProduct=NIUT ReadMe=Help\niut.txt SetupWindowTitle=NIUT121 AutoplayWindowTitle=NIUT Options ProductURL=www.planetunreal.com/niu VersionURL=www.planetunreal.com/niu Developer=ArtulDodger DeveloperURL=www.planetunreal.com/niu [UnrealTournament400Requirement] LocalProduct=UnrealTournament ProductURL=www.epicgames.com VersionURL=www.epicgames.com Developer=Epic DeveloperURL=www.epicgames.com ------------------------------------------------------------------------------- NIUT 1.21 Mutator for UT (No Item Unreal Tournament) ------------------------------------------------------------------------------- Version: 1.21 Created: 01/07/00 Author: Mike Fox (a.k.a. ArtfulDodger) Contact: mfox@legendent.com URL: www.planetunreal.com/niu ------------------------------------------------------------------------------- Overview -------- Everyone plays with the same weapon(s) and has more or less the same items at all times. This makes the game play focus on combat skills, rather than item gathering and controlling. Most matchups are very even and the winner is be the one who makes the best use of the current weapon / items. If you are killed, it *won't* be because the other guy has a better weapon or the power armor etc. . ------------------------------------------------------------------------------- Features -------- Everyone plays with the same weapon(s) at all times. Weapon changes every X seconds. Weapon is chosen from a configurable list of weapons and this *should* work with any Weapon-derived classes, even non-UT weapons (including the Unreal weapons, although this hasn't been tested yet). Weapons are selected randomly or sequentially. If weapons are selected randomly can optionally force all weapons to be used at least once before restarting the selection process. Replaces all pickup items in the level with ammo for the current weapon. If the current weapon doesn't require ammo, uses health vials. Flags, runes etc. and the translocator aren't affected. Plays a warning sound just before weapon is changed. To have some weapons used more frequently that others, just put these in WeaponClassStrings more than once (see below). Can optionally have the server increment everyone's health automatically. Can optionally have server give everyone jumpboots, invisibility and/or the damage amplifier at random times and for random durations. Can optionally use NIUT to give everyone all specified weapons (ammo increments automatically and pickups become health vials). Can optionally have server automatically increment ammo for current weapon (pickups become health vials). Can control rate at which ammo is given out and the amount of ammo that weapons start out with (e.g. 99 Redeemer warheads ). Should work with most other mutators, including the Fatboy mutator. Tested and should work with all UT gametypes (CTF, Domination, Assault, Last Man Standing). Tested and works with the UT bots. ------------------------------------------------------------------------------- Installation ------------ After installing NIUT, you should end up with the following files in your UT system folder: niut.ini NIUT configuration file niut.int mutator information niut.u NIUT mutator code and in your UT help folder: niut.txt this file Fire up UT and start a practice session or multiplayer game. Click on the mutators button and make sure the NIUT mutator is included (in the right-hand pane) along with any other mutators that you want to use. NIUT should work with any of the game types available in the full version of Unreal Tournament. ------------------------------------------------------------------------------- Configuration ------------- Specify the weapons that you want to have available by editing the WeaponClassStrings settings in niut.ini. By default (bAllWeapons=false), weapons will be cycled, that is, everyone might play with the rocket launcher for a while, then the sniper rifle etc. The weapons are switched every TimeBetweenWeaponSwitchesMin..TimeBetweenWeaponSwitchesMax seconds. I recommend keeping the weapon switch time at 75.0 seconds or greater, and/ limiting how long a particular level is played to 30 mins or less. It seems that Unreal Tournament servers can become unstable (more likely to crash) if many objects are destroyed/created during a game. Since most of what NIUT does involves destroying and creating objects every time the weapon changes, following these guidelines may make NIUT servers less likely to crash. If bRandomWeapons is true, the next weapon to use is chosen randomly, otherwise they are cycled in order. If bUseAllWeapons is set (and bRandomWeapons is true), all weapons will be used at least once each time through the list of weapons. To have all weapons available, pickups are health vials and ammo regenerates automatically, make sure you set bAllWeapons=true in niut.ini. +If bAllWeapons is false (weapons cycle), you can still have ammo regenerate automatically (and pickups become health vials) by setting TimeBetweenAmmoIncrements=1.0 (there's really no need to use any other value). Ammo will be incremented automatically (depending on the RateXXXAmmoPerSec values. e.g. RateRedeemerAmmoPerSec=0.050000 means that this will be incremented (by 1) every 20 seconds, RateGunAmmoPerSec=5.000000 means you get 5 bullets per second. Pickups will become health vials. Leaving this off means that pickups will become ammo for the current weapon (if applicable). If you specify non-UnrealTournament weapons in the niut.ini file (e.g. weapons from Unreal I), these will only work in non-networked games. From what I can tell, the firing of non-UT weapons isn't replicated from clients to the server, so these weapons never (or rarely) fire. Ideally, you should use a batch file like sloop.bat (available at www.planetunreal.com/niu) to run the server so that if the server does crash, the batch file will make it start back up again. Other settings in niut.ini WarningSound: controls the switch warning sound WarningSoundRepeats: controls number of times to play warning sound TimeBetweenHealthIncrements: seconds between health increments (0 disables) HealthIncrementAmount: amount to increment health by HealthIncrementSound: sound to play when incrementing health // min/max delay between giving invisibility to all players (0.0 ==> not used) InvisibilityDelayMin=45.0 InvisibilityDelayMax=75.0 // min/max duration for invisibility InvisibilityDurationMin=15.0 InvisibilityDurationMax=15.0 // min/max delay between giving damage amplifier to all players (0.0 ==> not used) DamageAmplifierDelayMin=30.0 DamageAmplifierDelayMax=45.0 // min/max duration for damage amplifier DamageAmplifierDurationMin=15.0 DamageAmplifierDurationMax=15.0 // min/max delay between giving jump boots to all players (0.0 ==> not used) JumpBootsDelayMin=30 JumpBootsDelayMax=60 // min/max duration for jump boots JumpBootsDurationMin=20.0 JumpBootsDurationMax=20.0 Weapon Types ------------ Here's a list of weapon types available in the full version of UT which can go in the WeaponClassStrings in niut.ini. UT weapons ---------- Botpack.ChainSaw Botpack.Enforcer Botpack.ImpactHammer Botpack.MiniGun2 Botpack.PulseGun Botpack.Ripper Botpack.ShockRifle Botpack.SniperRifle Botpack.SuperShockRifle Botpack.UT_BioRifle Botpack.UT_Eightball Botpack.UT_FlakCannon Botpack.WarheadLauncher Unreal I weapons ---------------- (Unreal I weapons only work in standalone games -- do not use on servers) UnrealI.FlakCannon UnrealI.GESBioRifle UnrealI.Minigun UnrealI.Razorjack UnrealI.Rifle UnrealShare.ASMD UnrealShare.AutoMag UnrealShare.DispersionPistol UnrealShare.Eightball UnrealShare.Stinger ------------------------------------------------------------------------------- History ------- 1.21: Better, more flexible way to specify how quickly ammo regenerates. Can also specify how much ammo weapons should start out with. 1.20: Option to have all specified weapons available at all times (ammo increments automatically for all weapons). This can be used to have Redeemer only or Sniper Rifle + Redeemer games for example. Additionally, weapons can be cycled as usual with an option to have ammo increment automatically ("classic" No Item mode like NIQ for Q2). Couple of optimizations. 1.10: Fix for translocator being stripped out of games where it is specified. 1.00: Initial version for full release of UT including support for random jumpboots, invisibility and power amplifiers (to all players at once). *D@pKؾ"eBZNone NIUTMutator GiveAmmoMoreOrLessInt AdjustAmmo ReplaceWithSetInventoryResetUsedWeaponsGiveJumpBootsToGiveDamageAmplifierToTransformPickupsGiveInvisibilityToTouchUsedUpGiveWeaponTo RifleRound RazorjackTranslocatorChooseWeaponRemoveAllDamageAmplifiersRemoveAllJumpBootsIncrementAllAmmoAutoMagRemoveAllInvisibilityNIUT WarHeadAmmo HealthVialFlakBox RazorAmmoWeaponSludgeRifle GESBioRifle ShellBox StingerAmmo RocketCan ASMDAmmoWeaponPowerUpStingerAmmoASMD AlwaysKeep Eightball BecomeItemAddInventoryMinigunModifyPlayer FlakCannonTick WeaponSetIdle2SetSwitchPriorityBringUpMyDefaultWeapon PlayerPawnDeleteInventoryCheckReplacementAddAmmoPreBeginPlayFindInventoryTypeBroadcastMessageBotpackCoreUT_Jumpboots ResetOwnerJumpBootsDurationMinInitialShockAmmoInitialBladeAmmoInitialRifleAmmoInitialGunAmmoInitialStingerAmmoInitialBioAmmoInitialPulseAmmoInitialFlakAmmoRateBioAmmoPerSecRateRedeemerAmmoPerSecJumpBootsDurationMaxInvisibilityDurationMaxDamageAmplifierDelayMaxDamageAmplifierDelayMinWarningSoundRepeatsbRandomWeaponsTimeBetweenWeaponSwitchesMaxbUseAllWeaponsTimeBetweenWeaponSwitchesMinDamageAmplifierDurationMinRateRocketAmmoPerSecPAmmoUDamageRateShockAmmoPerSecHealthIncrementAmountDispersionPistol EnforcerUT_invisibility ShockRifle UT_BioRifleRateBladeAmmoPerSec Minigun2UT_FlakCannonRateFlakAmmoPerSecRatePulseAmmoPerSecUT_EightballInitialRocketAmmo SniperRifle PulseGun ShockCoreripper FlakAmmoInvisibilityDurationMinWarheadLauncherInitialRedeemerAmmoTimeBetweenHealthIncrementsEngineTournamentWeaponClipWarningSound BladeHopper MiniammoTournamentAmmoBioAmmoRateStingerAmmoPerSecDamageAmplifierDurationMax SearchLight RifleAmmo RocketPack BulletBoxRateGunAmmoPerSecRateRifleAmmoPerSec LevelInfo UnrealShare ReturnValue ItemName JumpBootsMutator GameInfo WeaponClassObjectPickupsDynamicLoadObjectInvisibilityVapour TextBuffer ScriptTextLeveli RandRangeValName Ammocount UTSuperHealActorW nextPawn NumPlayersClassPropertyNamePropertyObjectPropertyFloatPropertyBoolProperty IntPropertyBytePropertyPawnSoundClassPackageConst DrawTypeSuperShockRiflePickupGetSoundDurationHealth Inventory bCanThrow FunctionArenaMaxAmmoOwnerP AmmoAmountAmountExpireMessage Instigator AmmoType AmmoNameDeActivateSoundActivateSoundChargebRetVal WeaponNamebSuperRelevant NextMutatorInvDefaultWeapon PawnListNetMode TimeSeconds NewWeaponGameOther DeltaTime StrPropertyWeaponClassStrings bAllWeaponsJumpBootsDelayMinJumpBootsDelayMaxTimeBetweenAmmoIncrementsInvisibilityDelayMaxInvisibilityDelayMinHealthIncrementSound NumWeaponsFilteredWeaponClassStringsCurrentWeaponClassCurrentWeaponIndexNumUsedWeapons UsedWeapons NumWarningsNextChooseWeaponTimeChooseWeaponWarningTimeNextIncrementHealthTimeNextInvisibilityTimeNextKillInvisibilityTimeNextDamageAmplifierTimeNextKillDamageAmplifierTimeNextJumpBootsTimeNextKillJumpBootsTime bDidTick bAllowSpawn LOTSATIMEPPDamageAmplifierNextAmmoIncrementTime WeaponIndexAInvCountRedeemerAmmoCountRocketAmmoCountFlakAmmoCountShockAmmoCountRifleAmmoCountPulseAmmoCountBladeAmmoCountBioAmmoCountGunAmmoCountStingerAmmoF&J?@7_B.9 @" )=%E!IA@F@4@G @@C@@@<Z#@ ;O@D@>@\@k@-@N@h@K]@1i@R@^@,@0M@[@b@L@Q@X@U@c@ @Ge@d@V@*@+W@J@a@2@j@T@:@Y@g@S@uP sOpT-'0a 00  P0a-( | 7H3/a0 r*-'|a/!Botpack.HealthVialar a/!%UnrealShare.WeaponPowerUpaer * !r ba/!Botpack.HealthViala V a101r /a0 0/r*a/!$.&10 }( ckiI(DI?i(((( rX<-'a_2w*+ ,4 3 1a/!ea/!*R!a/!mM!?a/!ba/!/[!a/!^a/!(e!a/!ga/!j!a/!hg!1a/!ja/!T!a/!aa/!\a/!a/!-i!a/!_a/! L!a/!&Y! -(-( {x/a0 lw*  %w.*a A@10 w88,U-6'$-Z$-6'8a/!8a/!{8-6(-6 A z'Ur *  .B; w *    9 a B,  +L    q!2 E:* %%, {/ow/ * / ppppV: WeaponsClassStrings[S] is invalid: /*!!Server is running NIUT. See www.planetunreal.com/niu for more infoppNIUT: S  weapons %NIUT warning: No weapons specified in NIUT.ini (in the UT system folder)%Botpack.UT_Eightball &-:4%? h#!%);"  4=w-*=- o3`F3w*a/!a/!za/!]a/!Xa/!?3 7a)-:.%&.  . 3 .DDw *3  n3e#b!J]XUc%Va)WQ&w&*&vw*_a/!'Ra/!|a/!#.!_a/!ka/!._a/!.#_a/!a/!}._Da/!!a/!u._pa/!W._a/!$a/!i.%_a/!a/!t._6a/!wa/!.)__a/!".&&##!! #<%%Un)) z't/a0 'uw'*  %w.'*'a  A'10z &;<w*%%>%w@*  %w.*a@s;OX,w* ::$  %w.*a  AOGN^,F*"xw* a::$  %w.*a  A"OG\d"*A2 w*::$  %w.*a  AV OGkSz 2C99 xK hsT-'1a 11  K1a-( v`OwT-'+a ++  `+a-( y5MG75%.5 5<$57% tH'c!H?DH? #< p$.zzw* .$$D $^ $x$ @HyE_Ա(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(Ƀ(ɖ1p1pɫɫɫ(ɓɫɫɫɫɫzczczc(ɐzczczczczczczcq;q;q;(ɔq;q;q;q; ǢʈooMMMMMMMMMMMMMMMMMMMMoڇڇڇڇڇoMMMMMMoMMro'ro'oro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'ro'oro'ro'ro'ڇro'ڇro'ڇro'ro'oro'ro'ڇro'ڇro'ڇro'ڇro'ڇ Ǣʄ Ǣʮ`'X ǢʇMMMMMro'ro'ڇMMMMro'ڇro'MMMMڇ Ǣʄ Ǣʄ Ǣʄ Ǣʄ Ǣʄ Ǣʈoo?Mo Ǣʄ Ǣʈoo Ǣʄ Ǣʄ Ǣʈooooooooo Ǣʄ Ǣʄ Ǣʈo Ǣʈoq;o Ǣʄ Ǣʄ Ǣʄ Ǣʄ Ǣʄ Ǣʈo Ǣʈozco Ǣʄ Ǣʄ Ǣʄ Ǣʄ Ǣʄ Ǣʈo Ǣʈoɫo Ǣʄ Ǣʄ Ǣʄ Ǣʄ Ǣʄ Ǣ=p>QST$BR$BsP"Z"o$?l$pAM$pAO$BN$BU$pAy$pAA$pAL$pAK$L=V$>c$L>Y$+?$?d$@`$?J$?~$@x$@n"f" I" B" D" H"dC"G"2E"dF"ddx//============================================================================= // NIUTMutator. //============================================================================= class NIUTMutator expands Arena config(NIUT); /*============================================================================= Mutator for NIUT (No Item Unreal Tournament). =============================================================================== Version: 1.21 Created: 01/04/00 +Made it possible to specify how much ammo should be given per second (ammo is still incremented on each TimeBetweenAmmoIncrements). +Added InitialAmmoXXX settings to specify how much ammo weapons should have when given to players (bots). Setting this to 0 means that the weapon will have no ammo (and won't be available until ammo is found/given to the player). +Can actually give more ammo to a weapon that it normally allows (e.g. can start out with redeemers with 99 warheads) and this becomes the new maximum for the weapon. +Tweaked default ammo rates for all weapons. =============================================================================== Version: 1.20 Created: 12/21/99 +If bAllWeapons flag is true players get all weapons specified in niut.ini and ammo auto-increments -- pickups are health vials. +If TimeBetweenAmmoIncrements is > 0.0, ammo auto-increments by 1 unit every N seconds where N is determined by settings in niut.ini. Pickups are health vials. +Several optimizations (replace ForEach AllActors with, e.g. iterating PawnList where possible. =============================================================================== Version: 1.11 Created: 12/09/99 +Fix for translocator getting stripped out in games where it should be kept. =============================================================================== Version: 1.10 Created: 12/08/99 +Fix for Redeemer ammo not working. TBD: how will UT release handle this -- currently ammo class has no mesh and gives 0 ammo. Change was to make ammo a sprite and to give it 1 charge (update -- will stick with this approach for NIUT 1.10). +Change to support UnrealI and UnrealShare weapons and WeaponPowerUp (UT normally replaces these with UT equivalents or filters them out). +When dispersion pistol is in use, all pickups in the level are turned into powerups so you can upgrade the pistol. +Don't allow jumpboots, invisibility, damage amplifier to run out before their time is up (probably no one will even notice this change). +Added logging in PreBeginPlay (number of weapons) and log info if no weapons found. +Added logging each time the weapon is changed, including the number of (real) players in the game. +Default to just 1 weapon in slot 0 of the WeaponClassStrings -- rocket launcher so that you don't have to override a pile of unused slots if you have < N weapons. +Default time between weapon switches is now 75 secs. Might help to avoid server crashes which can occur when many objects created and destroyed before a level ends. +Don't zap searchlights (darkmatch support). +Only play sounds through playerpawns (not bots). +Weapon switch sound shouldn't get overridden as much now. =============================================================================== Version: 1.00 Created: 11/05/99 +Weapon changes every MinTimeBetweenWeaponSwitches..MaxTimeBetweenWeaponSwitches secs instead of every TimeBetweenWeaponSwitches secs. +Server automatically increments health of all players by HealthIncrementRate units per second. +Option to randomly give everyone jump boots, invisibility, power amplifier. =============================================================================== Version: 0.99 Created: 11/01/99 +Everyone plays with the same weapon at all times. +Current weapon is chosen from a configurable list of weapons and should support any Weapon-derived classes, even non-UT weapons. +Current weapon changes every TimeBetweenWeaponSwitches. +Weapons are selected randomly/sequentially (bRandomWeapons=true/false). +If weapons are selected randomly can force all weapons to be used at least once before restarting the selection process (bUseAllWeapons=true). +Replaces all pickup items in the level with ammo for the current weapon. If the current weapon doesn't require ammo, uses health vials. Flags, runes etc. and the translocator aren't affected. +Plays a warning sound just before weapon is changed (WarningSound). +To have some weapons used more frequently that others, just put them in WeaponClassStrings more than once. =============================================================================== Notes: +Doesn't work with double enforcers special case -- single only +Unreal I weapons don't fire for clients so can only be used against bots in a standalone (non-server) game. =============================================================================== Author: Mike Fox (a.k.a. ArtfulDodger) Contact: mfox@legendent.com URL: www.planetunreal.com/niu =============================================================================*/ var() config string WeaponClassStrings[32]; // list of weapons to use var() config bool bRandomWeapons; // (true): true ==> weapons selected randomly, false ==> weapons cycled sequentially var() config bool bUseAllWeapons; // (true): true ==> if bWeaponsRandom is true, all weapons used once per cycle var() config bool bAllWeapons; // (false): true ==> players get all weapons in weapons list with auto-incrementing ammo var() config float TimeBetweenAmmoIncrements; // (0.0): >0.0 ==> auto-increment ammo at this rate var() config float TimeBetweenWeaponSwitchesMin; // (45): min secs between weapon switches var() config float TimeBetweenWeaponSwitchesMax; // (45): max secs between weapon switches var() config Sound WarningSound; // (UTSuperHeal): sound to use for "about to switch" warning var() config int WarningSoundRepeats; // (3): # times to repeat WarningSound var() config Sound HealthIncrementSound; // (None): sound to play when incrementing player's health var() config int HealthIncrementAmount; // (0): rate at which health of players is incremented var() config float TimeBetweenHealthIncrements; // (5): secs between health updates if HealthIncrementRate >= 1 var() config float InvisibilityDelayMin; // (0.0): min time to wait before giving everyone invisibility var() config float InvisibilityDelayMax; // (0.0): max time to wait before giving everyone invisibility var() config float InvisibilityDurationMin; // (0.0): min time to wait before giving everyone invisibility var() config float InvisibilityDurationMax; // (0.0): max time to wait before giving everyone invisibility var() config float DamageAmplifierDelayMin; // (0.0): min time to wait before giving everyone damage amplifier var() config float DamageAmplifierDelayMax; // (0.0): max time to wait before giving everyone damage amplifier var() config float DamageAmplifierDurationMin; // (0.0): min time to wait before giving everyone damage amplifier var() config float DamageAmplifierDurationMax; // (0.0): max time to wait before giving everyone damage amplifier var() config float JumpBootsDelayMin; // (0.0): min time to wait before giving everyone jump boots var() config float JumpBootsDelayMax; // (0.0): max time to wait before giving everyone jump boots var() config float JumpBootsDurationMin; // (0.0): min time to wait before giving everyone jump boots var() config float JumpBootsDurationMax; // (0.0): max time to wait before giving everyone jump boots // ammo incrementing (number of TimeBetweenAmmoIncrements before ammo is incremented by 1) var() config float RateRedeemerAmmoPerSec; var() config float RateRocketAmmoPerSec; var() config float RateFlakAmmoPerSec; var() config float RateShockAmmoPerSec; var() config float RateRifleAmmoPerSec; var() config float RatePulseAmmoPerSec; var() config float RateBladeAmmoPerSec; var() config float RateBioAmmoPerSec; var() config float RateGunAmmoPerSec; var() config float RateStingerAmmoPerSec; // ammo incrementing (number of TimeBetweenAmmoIncrements before ammo is incremented by 1) var() config int InitialRedeemerAmmo; var() config int InitialRocketAmmo; var() config int InitialFlakAmmo; var() config int InitialShockAmmo; var() config int InitialRifleAmmo; var() config int InitialPulseAmmo; var() config int InitialBladeAmmo; var() config int InitialBioAmmo; var() config int InitialGunAmmo; var() config int InitialStingerAmmo; var int NumWeapons; // number of weapons in WeaponClassStrings list var string FilteredWeaponClassStrings[32]; // filtered list of weapons to use var Class CurrentWeaponClass; // current weapon class var int CurrentWeaponIndex; // index int WeaponClassStrings for current weapon var int NumUsedWeapons; // number of weapons used so far (used with bUseAllWeapons) var byte UsedWeapons[32]; // list of weapons used so far (used with bUseAllWeapons) var int NumWarnings; // did "about to switch" warning var float NextChooseWeaponTime; // when to switch again var float ChooseWeaponWarningTime; // secs before weapon switch to warn clients var float NextIncrementHealthTime; // when to do another pass through player health values var float NextInvisibilityTime; // when to give everyone invisibility var float NextKillInvisibilityTime; // when to remove invisibility from everyone (also indicates everyone is invisible) var float NextDamageAmplifierTime; // when to give everyone damage amplifier var float NextKillDamageAmplifierTime; // when to remove damage amplifier from everyone (also indicates everyone has damage amplifier) var float NextJumpBootsTime; // when to give everyone jump boots var float NextKillJumpBootsTime; // when to remove jump boots (also indicates everyone has jump boots) var float NextAmmoIncrementTime; // when to increment ammo var float CountRedeemerAmmo; var float CountRocketAmmo; var float CountFlakAmmo; var float CountShockAmmo; var float CountRifleAmmo; var float CountPulseAmmo; var float CountBladeAmmo; var float CountBioAmmo; var float CountGunAmmo; var float CountStingerAmmo; // utility variables var bool bDidTick; // set after first tick occurs var bool bAllowSpawn; // set to force CheckReplacement to return true const LOTSATIME = 99999.0; //============================================================================= // Prepare list of weapon classes to use, initialize stuff. The first tick that // this mutator receives will select the first weapon to use and give it to // all players. function PreBeginPlay() { local int i; Super.PreBeginPlay(); // determine how many valid weapons we have NumWeapons=0; for( i=0; i 0.0 ) { CountRedeemerAmmo = 0.0; CountRocketAmmo = 0.0; CountFlakAmmo = 0.0; CountShockAmmo = 0.0; CountRifleAmmo = 0.0; CountBladeAmmo = 0.0; CountBioAmmo = 0.0; CountGunAmmo = 0.0; CountStingerAmmo = 0.0; CountPulseAmmo = 0.0; } NextChooseWeaponTime = 0.0; NextIncrementHealthTime = 0.0; NextInvisibilityTime = 0.0; NextKillInvisibilityTime = 0.0; NextDamageAmplifierTime = 0.0; NextKillDamageAmplifierTime = 0.0; NextJumpBootsTime = 0.0; NextKillJumpBootsTime = 0.0; NumWarnings = WarningSoundRepeats; ChooseWeaponWarningTime = 0.0; if( WarningSound != None ) { ChooseWeaponWarningTime = GetSoundDuration( WarningSound ); } CurrentWeaponIndex = -1; ResetUsedWeapons(); } //============================================================================= // Perform weapon switching etc. when the time is right. function Tick( float DeltaTime ) { local Pawn P; local PlayerPawn PP; local Inventory Inv; Super.Tick( DeltaTime ); // setup if( !bDidTick ) { if( InvisibilityDelayMin > 0.0 ) { NextInvisibilityTime = Level.TimeSeconds + RandRange(InvisibilityDelayMin, InvisibilityDelayMax); } if( DamageAmplifierDelayMin > 0.0 ) { NextDamageAmplifierTime = Level.TimeSeconds + RandRange(DamageAmplifierDelayMin, DamageAmplifierDelayMax); } if( JumpBootsDelayMin > 0.0 ) { NextJumpBootsTime = Level.TimeSeconds + RandRange(JumpBootsDelayMin, JumpBootsDelayMax); } if( TimeBetweenAmmoIncrements > 0.0 ) { NextAmmoIncrementTime = Level.TimeSeconds + TimeBetweenAmmoIncrements; } bDidTick = true; } else { // weapon switch warning if( (NumWarnings < WarningSoundRepeats) && (Level.TimeSeconds >= (NextChooseWeaponTime - (WarningSoundRepeats-NumWarnings)*ChooseWeaponWarningTime )) ) { // warn that we are about to switch the weapon if( WarningSound != None ) { for( P=Level.PawnList; P != None; P=P.NextPawn ) { if( P.IsA( 'PlayerPawn' ) ) { PlayerPawn(P).PlaySound( WarningSound,, 8 ); } } } NumWarnings++; } } // weapon switch if( !bAllWeapons && Level.TimeSeconds >= NextChooseWeaponTime ) { // time to change everybody's weapon ChooseWeapon(); for( P=Level.PawnList; P != None; P=P.NextPawn ) { SetInventory( P ); } NumWarnings = 0; NextChooseWeaponTime = Level.TimeSeconds + RandRange(TimeBetweenWeaponSwitchesMin, TimeBetweenWeaponSwitchesMax); } // increment health if( (HealthIncrementAmount >= 1) && (Level.TimeSeconds >= NextIncrementHealthTime) ) { for( P=Level.PawnList; P != None; P=P.NextPawn ) { if( (P.Health > 0) && (P.Health < P.default.Health) ) { P.Health += Min( HealthIncrementAmount, P.default.Health - P.Health ); if( HealthIncrementSound != None && (NumWarnings == 0) && (PlayerPawn(P) != None) ) { P.PlaySound( HealthIncrementSound ); } } } NextIncrementHealthTime = Level.TimeSeconds + TimeBetweenHealthIncrements; } // invisibility if( (InvisibilityDelayMin > 0.0) && (Level.TimeSeconds >= NextInvisibilityTime) ) { for( P=Level.PawnList; P != None; P=P.NextPawn ) { GiveInvisibilityTo( P ); if( Level.NetMode != NM_Standalone && (NumWarnings == 0) && (PlayerPawn(P) != None) ) { P.PlaySound( class'UT_invisibility'.default.ActivateSound,, 8 ); } } NextInvisibilityTime = Level.TimeSeconds + LOTSATIME; NextKillInvisibilityTime = Level.TimeSeconds + RandRange(InvisibilityDurationMin, InvisibilityDurationMax); } if( (NextKillInvisibilityTime > 0.0) && (Level.TimeSeconds >= NextKillInvisibilityTime) ) { RemoveAllInvisibility(); NextKillInvisibilityTime = 0.0; NextInvisibilityTime = Level.TimeSeconds + RandRange(InvisibilityDelayMin, InvisibilityDelayMax); } // damage amplifier if( (DamageAmplifierDelayMin > 0.0) && (Level.TimeSeconds >= NextDamageAmplifierTime) ) { for( P=Level.PawnList; P != None; P=P.NextPawn ) { GiveDamageAmplifierTo( P ); if( Level.NetMode != NM_Standalone && (NumWarnings == 0) && (PlayerPawn(P) != None) ) { P.PlaySound( class'UDamage'.default.ActivateSound,, 8 ); } } NextDamageAmplifierTime = Level.TimeSeconds + LOTSATIME; NextKillDamageAmplifierTime = Level.TimeSeconds + RandRange(DamageAmplifierDurationMin, DamageAmplifierDurationMax); } if( (NextKillDamageAmplifierTime > 0.0) && (Level.TimeSeconds >= NextKillDamageAmplifierTime) ) { RemoveAllDamageAmplifiers(); NextKillDamageAmplifierTime = 0.0; NextDamageAmplifierTime = Level.TimeSeconds + RandRange(DamageAmplifierDelayMin, DamageAmplifierDelayMax); } // jump boots if( (JumpBootsDelayMin > 0.0) && (Level.TimeSeconds >= NextJumpBootsTime) ) { for( P=Level.PawnList; P != None; P=P.NextPawn ) { GiveJumpBootsTo( P ); if( Level.NetMode != NM_Standalone && (NumWarnings == 0) && (PlayerPawn(P) != None) ) { P.PlaySound( class'ut_jumpboots'.default.ActivateSound,, 8 ); } } NextJumpBootsTime = Level.TimeSeconds + LOTSATIME; NextKillJumpBootsTime = Level.TimeSeconds + RandRange(JumpBootsDurationMin, JumpBootsDurationMax); } if( (NextKillJumpBootsTime > 0.0) && (Level.TimeSeconds >= NextKillJumpBootsTime) ) { RemoveAllJumpBoots(); NextKillJumpBootsTime = 0.0; NextJumpBootsTime = Level.TimeSeconds + RandRange(JumpBootsDelayMin, JumpBootsDelayMax); } // ammo if( (TimeBetweenAmmoIncrements > 0.0) && (Level.TimeSeconds >= NextAmmoIncrementTime) ) { IncrementAllAmmo(); NextAmmoIncrementTime = Level.TimeSeconds + TimeBetweenAmmoIncrements; } } //============================================================================= // Clear used weapon list used to make sure all weapons are used at least once // when bUseAllWeapons is set. function ResetUsedWeapons() { local int i; for( i=0; i 0.0 ) { // replace pickups with health vials -- weapon ammo will be incremented if( !Inv.IsA( 'HealthVial' ) ) { ReplaceWith( Inv, "Botpack.HealthVial" ); Inv.Destroy(); } } else if( CurrentWeaponClass == Class'DispersionPistol' ) { // put powerups in level for dispersion pistol if( !Inv.IsA( 'WeaponPowerUp' ) ) { ReplaceWith( Inv, "UnrealShare.WeaponPowerUp" ); Inv.Destroy(); } } else if( (CurrentWeaponClass.default.AmmoName == None) || (CurrentWeaponClass.default.AmmoName.Name == '') || (CurrentWeaponClass == Class'SuperShockRifle') ) { // replace with vials of health -- keeps bot destination code happy if( !Inv.IsA( 'HealthVial' ) ) { ReplaceWith( Inv, "Botpack.HealthVial" ); Inv.Destroy(); } } else { if( Inv.Class.Name != CurrentWeaponClass.default.AmmoName.Name ) { ReplaceWith( Inv, string(CurrentWeaponClass.default.AmmoName) ); Inv.Destroy(); } } } } if( CurrentWeaponClass == Class'WarheadLauncher' ) { // UT400 WarheadAmmo currently has no mesh/texture and 0 ammo foreach AllActors( class'Inventory', Inv ) { if( Inv.Owner == None && Inv.IsA( 'WarheadAmmo') ) { Inv.DrawType = DT_Sprite; Ammo(Inv).AmmoAmount = 1; } } } } //============================================================================= // Select the next weapon to use and replace all pickup items in the level with // ammo for this weapon, or health vials if the weapon doesn't require ammo. function ChooseWeapon() { local int i; local Inventory Inv; if( CurrentWeaponIndex == -1 ) { CurrentWeaponIndex = 0; } if( NumWeapons >= 1) { if( NumUsedWeapons == NumWeapons ) { ResetUsedWeapons(); } if( bRandomWeapons ) { CurrentWeaponIndex = Rand( NumWeapons ); if( bUseAllWeapons ) { while( UsedWeapons[CurrentWeaponIndex] != 0 ) { CurrentWeaponIndex++; if( CurrentWeaponIndex >= NumWeapons ) { CurrentWeaponIndex=0; } } } NumUsedWeapons++; UsedWeapons[CurrentWeaponIndex] = 1; } CurrentWeaponClass = class( DynamicLoadObject( FilteredWeaponClassStrings[CurrentWeaponIndex], class'Class' ) ); if( CurrentWeaponClass == None ) { warn( Self $ ": CurrentDefaultWeapon is None!" ); } if( !bRandomWeapons ) { CurrentWeaponIndex++; if( CurrentWeaponIndex >= NumWeapons ) { CurrentWeaponIndex=0; } } } else { warn( Self $ ": WeaponsClassStrings contain no valid weapon(s)!" ); } log( "NIUT: " $ Level.TimeSeconds $ " (" $ Level.Game.NumPlayers $ ") -- selected: " $ CurrentWeaponClass ); TransformPickups(); NextChooseWeaponTime = Level.TimeSeconds + RandRange( TimeBetweenWeaponSwitchesMin, TimeBetweenWeaponSwitchesMax ); } //============================================================================= // Gives ammo for weapon W to Other, increasing ammo's MaxAmmo if necessary. function GiveAmmo( Weapon W, Pawn Other, int Amount ) { if ( W.AmmoName == None ) return; W.AmmoType = Ammo(Other.FindInventoryType(W.AmmoName)); if ( W.AmmoType != None ) { if( W.AmmoType.MaxAmmo < Amount ) { W.AmmoType.MaxAmmo = Amount; } W.AmmoType.AddAmmo(Amount); } else { W.AmmoType = Spawn(W.AmmoName); // Create ammo type required Other.AddInventory(W.AmmoType); // and add to player's inventory W.AmmoType.BecomeItem(); if( W.AmmoType.MaxAmmo < Amount ) { W.AmmoType.MaxAmmo = Amount; } W.AmmoType.AmmoAmount = Amount; W.AmmoType.GotoState('Idle2'); } } //============================================================================= function GiveWeaponTo( Pawn P, Class WeaponClass ) { local Weapon newWeapon; bAllowSpawn = true; newWeapon = Spawn(WeaponClass); if( newWeapon != None ) { newWeapon.Instigator = P; newWeapon.BecomeItem(); P.AddInventory(newWeapon); newWeapon.BringUp(); newWeapon.SetSwitchPriority(P); newWeapon.WeaponSet(P); if( newWeapon.IsA( 'ut_eightball' ) || newWeapon.IsA( 'Eightball' )) { GiveAmmo( newWeapon, P, InitialRocketAmmo ); } else if( newWeapon.IsA( 'WarheadLauncher' ) ) { GiveAmmo( newWeapon, P, InitialRedeemerAmmo ); } else if( newWeapon.IsA( 'ut_flakcannon' ) || newWeapon.IsA( 'FlakCannon' )) { GiveAmmo( newWeapon, P, InitialFlakAmmo ); } else if( newWeapon.IsA( 'shockrifle' ) || newWeapon.IsA( 'ASMD') ) { GiveAmmo( newWeapon, P, InitialShockAmmo ); } else if( newWeapon.IsA( 'sniperrifle' ) || newWeapon.IsA( 'Rifle' )) { GiveAmmo( newWeapon, P, InitialRifleAmmo ); } else if( newWeapon.IsA( 'PulseGun' ) ) { GiveAmmo( newWeapon, P, InitialPulseAmmo ); } else if( newWeapon.IsA( 'ripper' ) || newWeapon.IsA( 'razorjack' ) ) { GiveAmmo( newWeapon, P, InitialBladeAmmo ); } else if( newWeapon.IsA( 'minigun2' ) || newWeapon.IsA( 'enforcer' ) || newWeapon.IsA( 'AutoMag' ) || newWeapon.IsA( 'Minigun' ) ) { GiveAmmo( newWeapon, P, InitialGunAmmo ); } else if( newWeapon.IsA( 'ut_biorifle' ) || newWeapon.IsA( 'gesbiorifle' ) ) { GiveAmmo( newWeapon, P, InitialBioAmmo ); } else if( newWeapon.IsA( 'stinger' ) ) { GiveAmmo( newWeapon, P, InitialStingerAmmo ); } else { newWeapon.GiveAmmo( P ); } // make sure weapon can't be tossed newWeapon.bCanThrow = false; } bAllowSpawn = false; } //============================================================================= // Set the given Pawn's weapon to the current one. Get rid of all inventory // before doing this. function SetInventory( Pawn P ) { local Inventory Inv; local int WeaponIndex; // zap any current inventory for( Inv=P.Inventory; Inv!=None; Inv=Inv.Inventory ) { if( !Inv.IsA( 'Translocator' ) && !Inv.IsA( 'SearchLight') && !Inv.IsA( 'UT_invisibility' ) && !Inv.IsA( 'UDamage' ) && !Inv.IsA( 'ut_jumpboots') ) { P.DeleteInventory( Inv ); Inv.Destroy(); } } if( bAllWeapons ) { for( WeaponIndex=0; WeaponIndex( DynamicLoadObject( FilteredWeaponClassStrings[WeaponIndex], class'Class' ) ); GiveWeaponTo( P, CurrentWeaponClass ); } } else if( CurrentWeaponClass!=None ) { GiveWeaponTo( P, CurrentWeaponClass ); } } //============================================================================= function bool MoreOrLessInt( float Val ) { return( abs(Val - int(Val+0.5)) < 0.010 ); } //============================================================================= function AdjustAmmo( Ammo AInv, float AmmoCount ) { if( MoreOrLessInt(AmmoCount) ) { AInv.AmmoAmount += int(AmmoCount+0.5); if( AInv.AmmoAmount > AInv.MaxAmmo ) { AInv.AmmoAmount = AInv.MaxAmmo; } } } //============================================================================= function IncrementAllAmmo() { local Inventory Inv; local Pawn P; CountRedeemerAmmo += (RateRedeemerAmmoPerSec * TimeBetweenAmmoIncrements); CountRocketAmmo += (RateRocketAmmoPerSec * TimeBetweenAmmoIncrements); CountFlakAmmo += (RateFlakAmmoPerSec * TimeBetweenAmmoIncrements); CountRifleAmmo += (RateRifleAmmoPerSec * TimeBetweenAmmoIncrements); CountGunAmmo += (RateGunAmmoPerSec * TimeBetweenAmmoIncrements); CountPulseAmmo += (RatePulseAmmoPerSec * TimeBetweenAmmoIncrements); CountShockAmmo += (RateShockAmmoPerSec * TimeBetweenAmmoIncrements); CountBladeAmmo += (RateBladeAmmoPerSec * TimeBetweenAmmoIncrements); CountBioAmmo += (RateBioAmmoPerSec * TimeBetweenAmmoIncrements); CountStingerAmmo += (RateStingerAmmoPerSec * TimeBetweenAmmoIncrements); for( P=Level.PawnList; P != None; P=P.NextPawn ) for( Inv=P.Inventory; Inv!=None; Inv=Inv.Inventory ) { if( Inv.IsA( 'Ammo' ) ) { if( Inv.IsA( 'RocketPack' ) || Inv.IsA( 'RocketCan' ) ) { AdjustAmmo( Ammo(Inv), CountRocketAmmo ); } else if( Inv.IsA( 'FlakAmmo' ) || Inv.IsA( 'FlakBox' ) ) { AdjustAmmo( Ammo(Inv), CountFlakAmmo ); } else if( Inv.IsA( 'WarHeadAmmo' ) ) { AdjustAmmo( Ammo(Inv), CountRedeemerAmmo ); } else if( Inv.IsA( 'RifleRound' ) || Inv.IsA( 'BulletBox' ) ) { AdjustAmmo( Ammo(Inv), CountRifleAmmo ); } else if( Inv.IsA( 'ShellBox' ) || Inv.IsA( 'Miniammo' ) ) { AdjustAmmo( Ammo(Inv), CountGunAmmo ); } else if( Inv.IsA( 'PAmmo' ) ) { AdjustAmmo( Ammo(Inv), CountPulseAmmo ); } else if( Inv.IsA( 'ASMDAmmo' ) || Inv.IsA( 'ShockCore' ) ) { AdjustAmmo( Ammo(Inv), CountShockAmmo ); } else if( Inv.IsA( 'RazorAmmo' ) || Inv.IsA( 'BladeHopper' ) ) { AdjustAmmo( Ammo(Inv), CountBladeAmmo ); } else if( Inv.IsA( 'BioAmmo' ) || Inv.IsA( 'Sludge' ) ) { AdjustAmmo( Ammo(Inv), CountBioAmmo ); } else if( Inv.IsA( 'StingerAmmo' ) ) { AdjustAmmo( Ammo(Inv), CountStingerAmmo ); } } } if( MoreOrLessInt(CountRedeemerAmmo) ) CountRedeemerAmmo = 0.0; if( MoreOrLessInt(CountRocketAmmo) ) CountRocketAmmo = 0.0; if( MoreOrLessInt(CountFlakAmmo) ) CountFlakAmmo = 0.0; if( MoreOrLessInt(CountRifleAmmo) ) CountRifleAmmo = 0.0; if( MoreOrLessInt(CountGunAmmo) ) CountGunAmmo = 0.0; if( MoreOrLessInt(CountPulseAmmo) ) CountPulseAmmo = 0.0; if( MoreOrLessInt(CountShockAmmo) ) CountShockAmmo = 0.0; if( MoreOrLessInt(CountBladeAmmo) ) CountBladeAmmo = 0.0; if( MoreOrLessInt(CountBioAmmo) ) CountBioAmmo = 0.0; if( MoreOrLessInt(CountStingerAmmo) ) CountStingerAmmo = 0.0; } //============================================================================= function GiveInvisibilityTo( Pawn P ) { local UT_Invisibility Invisibility; bAllowSpawn = true; Invisibility = Spawn( class'UT_Invisibility' ); Invisibility.Charge = 99999; Invisibility.Touch( P ); Invisibility.Destroy(); bAllowSpawn = false; } //============================================================================= function RemoveAllInvisibility() { local UT_Invisibility Invisibility; foreach AllActors( class'UT_invisibility', Invisibility ) { if( Invisibility.Owner != None && (NumWarnings == 0) && (PlayerPawn(Invisibility.Owner) != None) ) { Invisibility.Owner.PlaySound( Sound'Botpack.ASMD.Vapour',, 8 ); } Invisibility.UsedUp(); } } //============================================================================= function GiveDamageAmplifierTo( Pawn P ) { local UDamage DamageAmplifier; bAllowSpawn = true; DamageAmplifier = Spawn( class'UDamage' ); DamageAmplifier.Charge = 99999; DamageAmplifier.Touch( P ); DamageAmplifier.Destroy(); bAllowSpawn = false; } //============================================================================= function RemoveAllDamageAmplifiers() { local UDamage DamageAmplifier; foreach AllActors( class'UDamage', DamageAmplifier ) { if( DamageAmplifier.Owner != None && (NumWarnings == 0) && (PlayerPawn(DamageAmplifier.Owner) != None) ) { DamageAmplifier.Owner.PlaySound( class'UDamage'.default.DeActivateSound,, 8 ); } DamageAmplifier.UsedUp(); } // UT gold might add ExpireMessage? if( class'UDamage'.default.ExpireMessage == "" ) { BroadcastMessage( class'UDamage'.default.ItemName $ " has expired." ); // not localized... } } //============================================================================= function GiveJumpBootsTo( Pawn P ) { local ut_jumpboots JumpBoots; bAllowSpawn = true; JumpBoots = Spawn( class'ut_jumpboots' ); JumpBoots.Charge = 99999; JumpBoots.Touch( P ); JumpBoots.Destroy(); bAllowSpawn = false; } //============================================================================= function RemoveAllJumpBoots() { local ut_jumpboots JumpBoots; foreach AllActors( class'ut_jumpboots', JumpBoots ) { if( JumpBoots.Owner != None && (NumWarnings == 0) && (PlayerPawn(JumpBoots.Owner) != None) ) { JumpBoots.Owner.PlaySound( Sound'Botpack.ASMD.Vapour',, 8 ); } JumpBoots.ResetOwner(); JumpBoots.UsedUp(); } } //============================================================================= // Make sure everyone is using the correct weapon, ammo no matter when they // join the game or respawn. function ModifyPlayer( Pawn Other ) { if ( NextMutator != None ) { NextMutator.ModifyPlayer(Other); } SetInventory( Other ); if( NextKillInvisibilityTime > 0.0 ) { GiveInvisibilityTo( Other ); } if( NextKillDamageAmplifierTime > 0.0 ) { GiveDamageAmplifierTo( Other ); } if( NextKillJumpBootsTime > 0.0 ) { GiveJumpBootsTo( Other ); } } //============================================================================= // Return true for any non-UT weapons and ammo (otherwise DMMutator will swap // these with UT equivalents). function bool AlwaysKeep( Actor Other ) { local bool bRetVal; bRetVal = false; if( Other.IsA('Weapon') && !Other.IsA('TournamentWeapon') ) { if( Other.IsA('Stinger') || Other.IsA('Rifle') || Other.IsA('Razorjack') || Other.IsA('Minigun') || Other.IsA('AutoMag') || Other.IsA('Eightball') || Other.IsA('FlakCannon') || Other.IsA('ASMD') || Other.IsA('GesBioRifle') || Other.IsA('DispersionPistol') ) { bRetVal = true; } } else if ( Other.IsA('Ammo') && !Other.IsA('TournamentAmmo') ) { if( Other.IsA('ASMDAmmo') || Other.IsA('RocketCan') || Other.IsA('StingerAmmo') || Other.IsA('RazorAmmo') || Other.IsA('RifleRound') || Other.IsA('RifleAmmo') || Other.IsA('FlakBox') || Other.IsA('Clip') || Other.IsA('ShellBox') || Other.IsA('Sludge') ) { bRetVal = true; } } else if ( Other.IsA('WeaponPowerUp') ) { bRetVal = true; } else if ( NextMutator != None ) { bRetVal = NextMutator.AlwaysKeep(Other); } return bRetVal; } //============================================================================= // Anything gets through at this point, although in some cases these will be // replaced with other actors with the first tick. function bool CheckReplacement( Actor Other, out byte bSuperRelevant ) { local bool bRetVal; bRetVal = true; if( bAllowSpawn ) { bSuperRelevant = 1; bRetVal = true; } else if( Other.IsA('Weapon') && !Other.IsA('Translocator') ) { // Filter weapons by replacing them with the current weapon (if set) or by // removing them since some games (e.g. Last Man Standing) try to give // players weapons sometime after players join the game. if( CurrentWeaponIndex != -1 && FilteredWeaponClassStrings[CurrentWeaponIndex] != "" ) { ReplaceWith(Other, FilteredWeaponClassStrings[CurrentWeaponIndex]); bRetVal = false; } } return bRetVal; } //============================================================================= // No weapon by default -- this mutator hands out all weapons. function Class MyDefaultWeapon() { return None; } mB:RO% &67 -G -h:<% %U7<$  r *pV: CurrentDefaultWeapon is None!-G %SpV: WeaponsClassStrings contain no valid weapon(s)!pppppNIUT: U (S) -- selected: V  ?D D/ 99999.0C6qI5Fd* >dp>d>>cV>c@>c>d=>ck>ca>c]>c'>\O>c\>]C>cm>c_>cc>cX>cH>c?>c]>\v>cE>\p>mQ>c^>c6>\X>Zw>\A>cn>_o>_j>_r>\~>\k>[S>`B>mJ>cZ>\y>_z>m0>m:pbL>d(>cF>cH>c`>cb>ch>^l>mi>HC>\u>Z@>m.>_Y>`f>\E>c[>cM>cm>m5>ce>Ht>m)>m8>cg>Zc>[w>[|>dI>dApbU>\xyqEFoDSFu`FwFmFm{FM HGT TGoq`GrWnGS|GQ JHW VHtbHb oHsP {H` GIrs SIR _Iw{ kI\ wIpDCJ^ PJo \JX hJq tJk @K[ LKrXKm eKxKqKn ~K_ JLj VL] bLi nL~FzLl GMuqSMve`MnhmMp {MOGN{DTNOaNsnNtg {NIGOlKTOzeaOKnOtq{OPHP|P UPq{ aPU mPqFyPf GQJ SQZ _QVkQY xQZDRTQRP^RNkRrFxRLESR RSa ^SNjSQwS}RDTnT QTV]TzqjTGwTnDUlQUo ^UlqjUxwUfDVLQVC^V~kVYxVJEWRWF _Wq}kWIyWUFXcSXM `XoGlX{qzX`GYKTYdaYy nYBzYyG GZHSZS `ZElZDyZAF[ RS[ je\`Ocsod|bm8C^oMaq:j nunXs Fey)d^rB0^t RRRd