From 92c70eab08f4be6802768df3d4bf1ed9e1e275f0 Mon Sep 17 00:00:00 2001 From: chacha <15073640+cclecle@users.noreply.github.com> Date: Tue, 27 Jan 2026 00:46:55 +0000 Subject: [PATCH] version 126 => integrate with UT v469e --- Classes/DummyArenaMutator.uc | 28 + Classes/NIUTConfigDialog.uc | 748 ++++++++++++++ Classes/NIUTConfigMenu.uc | 10 + Classes/NIUTConfigMenuItem.uc | 20 + Classes/NIUTMutator.uc | 1717 +++++++++++++++++++++++++++++++ System/NIUT.ini | 2 +- System/Niut.int | 2 +- System/{niut125.u => niut126.u} | Bin 138163 -> 140580 bytes make.bat | 6 + make.ini | 31 + 10 files changed, 2562 insertions(+), 2 deletions(-) create mode 100644 Classes/DummyArenaMutator.uc create mode 100644 Classes/NIUTConfigDialog.uc create mode 100644 Classes/NIUTConfigMenu.uc create mode 100644 Classes/NIUTConfigMenuItem.uc create mode 100644 Classes/NIUTMutator.uc rename System/{niut125.u => niut126.u} (61%) create mode 100644 make.bat create mode 100644 make.ini diff --git a/Classes/DummyArenaMutator.uc b/Classes/DummyArenaMutator.uc new file mode 100644 index 0000000..42289b0 --- /dev/null +++ b/Classes/DummyArenaMutator.uc @@ -0,0 +1,28 @@ +//============================================================================= +// DummyArenaMutator. +//============================================================================= + +class DummyArenaMutator extends Arena; + +/*============================================================================= +Used for no other purpose than to put an Arena mutator into the chain so ammo +will stay in LastManStanding NIUT games with weapons being cycled and no auto +incrementing of ammo. If any other arena mutator is used, this should *not* +be used (only one arena mutator at a time can be loaded). +=============================================================================*/ + +function bool AlwaysKeep(Actor Other) +{ + if ( NextMutator != None ) + return ( NextMutator.AlwaysKeep(Other) ); + return false; +} + +function bool CheckReplacement(Actor Other, out byte bSuperRelevant) +{ + return true; +} + +defaultproperties +{ +} diff --git a/Classes/NIUTConfigDialog.uc b/Classes/NIUTConfigDialog.uc new file mode 100644 index 0000000..fb49b30 --- /dev/null +++ b/Classes/NIUTConfigDialog.uc @@ -0,0 +1,748 @@ +//============================================================================ +// NIUTConfigDialog. +//============================================================================= +class NIUTConfigDialog expands UWindowDialogClientWindow; + +var UWindowSmallCloseButton CloseButton; +var UWindowSmallButton DefaultsButton; + +const AmmoTableHOffset = 120; +const AmmoTableSize = 48; +const EditControlVerticalSpacing = 18; + +const PowerUpsTableOffset = 120; +const PowerUpsTableSize = 80; + +const TablesVOffset = 8; + +// NIUT main options +var UWindowCheckBox + CycleWeaponsCheckBox, + RandomWeaponsCheckBox, + UseAllWeaponsCheckBox; + +var UWindowLabelControl + TimeBetweenWeaponSwitchesMinLC, + TimeBetweenWeaponSwitchesMaxLC, + TimeBetweenAmmoIncrementsLC, + TimeBetweenHealthIncrementsLC, + HealthIncrementAmountLC, + StartHealthLC, + MaxHealthLC; + +var UWindowEditControl + TimeBetweenAmmoIncrementsEC, + TimeBetweenWeaponSwitchesMinEC, + TimeBetweenWeaponSwitchesMaxEC, + TimeBetweenHealthIncrementsEC, + HealthIncrementAmountEC, + StartHealthEC, + MaxHealthEC; + +// weapons +var UWindowCheckBox + UseBioRifleCheckBox, + UseChainSawCheckBox, + UseEnforcerCheckBox, + UseFlakCannonCheckBox, + UseImpactHammerCheckBox, + UseMiniGunCheckBox, + UsePulseGunCheckBox, + UseRipperCheckBox, + UseRocketLauncherCheckBox, + UseRedeemerCheckBox, + UseShockRifleCheckBox, + UseSniperRifleCheckBox, + UseSuperShockRifleCheckBox, + UseUnrealIASMDCheckBox, + UseUnrealIAutoMagCheckBox, + UseUnrealIDispersionPistolCheckBox, + UseUnrealIFlakCannonCheckBox, + UseUnrealIEightballCheckBox, + UseUnrealIGESBioRifleCheckBox, + UseUnrealIMinigunCheckBox, + UseUnrealIRazorjackCheckBox, + UseUnrealIRifleCheckBox, + UseUnrealIStingerCheckBox; + +// ammo labels +var UWindowLabelControl + InitialAmmoLC, + MaxAmmoLC, + RateAmmoLC, + BioAmmoLC, + GunAmmoLC, + FlakAmmoLC, + PulseAmmoLC, + RedeemerAmmoLC, + RifleAmmoLC, + RipperAmmoLC, + RocketAmmoLC, + ShockAmmoLC, + StingerAmmoLC; + +// ammo edits - disabled if cycling weapons and not incrementing ammo +var UWindowEditControl + InitialBioAmmoEC, RateBioAmmoPerSecEC, MaxBioAmmoEC, + InitialGunAmmoEC, RateGunAmmoPerSecEC, MaxGunAmmoEC, + InitialFlakAmmoEC, RateFlakAmmoPerSecEC, MaxFlakAmmoEC, + InitialPulseAmmoEC, RatePulseAmmoPerSecEC, MaxPulseAmmoEC, + InitialRedeemerAmmoEC, RateRedeemerAmmoPerSecEC, MaxRedeemerAmmoEC, + InitialRifleAmmoEC, RateRifleAmmoPerSecEC, MaxRifleAmmoEC, + InitialRipperAmmoEC, RateRipperAmmoPerSecEC, MaxRipperAmmoEC, + InitialRocketAmmoEC, RateRocketAmmoPerSecEC, MaxRocketAmmoEC, + InitialShockAmmoEC, RateShockAmmoPerSecEC, MaxShockAmmoEC, + InitialStingerAmmoEC, RateStingerAmmoPerSecEC, MaxStingerAmmoEC; + +// power ups +var UWindowLabelControl + PowerUpDelayMinLC, PowerUpDelayMaxLC, PowerUpDurationMinLC, PowerUpDurationMaxLC, + DamageAmplifierLC, JumpbootsLC, InvisibilityLC; + +var UWindowEditControl + InvisibilityDelayMinEC, InvisibilityDelayMaxEC, InvisibilityDurationMinEC, InvisibilityDurationMaxEC, + DamageAmplifierDelayMinEC, DamageAmplifierDelayMaxEC, DamageAmplifierDurationMinEC, DamageAmplifierDurationMaxEC, + JumpBootsDelayMinEC, JumpBootsDelayMaxEC, JumpBootsDurationMinEC, JumpBootsDurationMaxEC; + +var class UMutator; + +// used to vertically position the components +var int SpacingOffset; +var int HOffset, VOffset; + +//----------------------------------------------------------------------------- + +function AddCheckBox( out int HorzOffset, int HorzInc, out int VertOffset, int VertInc, out UWindowCheckBox CB, string LabelText, string HelpText, bool bChecked ) +{ + CB = UWindowCheckBox( CreateControl(class'UWindowCheckBox', HorzOffset, VertOffset, (WinWidth/4)-16, 16) ); + CB.SetText( LabelText ); + CB.SetHelpText( HelpText ); + CB.SetFont(F_Normal); + CB.bChecked = bChecked; + CB.Align = TA_Left; + CB.Register(self); + HorzOffset += HorzInc; + VertOffset += VertInc; +} + +//----------------------------------------------------------------------------- + +function AddLabelControl( out int HorzOffset, int HorzInc, out int VertOffset, int VertInc, int Width, out UWindowLabelControl LC, string LabelText, string HelpText ) +{ + LC = UWindowLabelControl( CreateControl(class'UWindowLabelControl', HorzOffset, VertOffset, Width, 16) ); + LC.SetText( LabelText ); + LC.SetHelpText( HelpText ); + LC.SetFont(F_Normal); + LC.Align = TA_Left; + LC.Register(self); + HorzOffset += HorzInc; + VertOffset += VertInc; +} + +//----------------------------------------------------------------------------- + +function AddIntEditControl( out int HorzOffset, int HorzInc, out int VertOffset, int VertInc, int Width, out UWindowEditControl EC, string LabelText, string HelpText, int Val, optional int MaxLen ) +{ + EC = UWindowEditControl(CreateControl(class'UWindowEditControl', HorzOffset, VertOffset, Width, 16)); + EC.SetText( LabelText ); + EC.SetHelpText( HelpText ); + EC.SetFont(F_Normal); + EC.SetNumericOnly(True); + + if( MaxLen != 0 ) + EC.SetMaxLength( MaxLen ); + else + EC.SetMaxLength(3); + + EC.Align = TA_Right; + EC.EditBox.Offset = 0; + EC.EditBoxWidth = WinWidth/22; + EC.SetValue(string(Val)); + EC.Register(self); + HorzOffset += HorzInc; + VertOffset += VertInc; +} + +//----------------------------------------------------------------------------- + +function AddFltEditControl( out int HorzOffset, int HorzInc, out int VertOffset, int VertInc, int Width, out UWindowEditControl EC, string LabelText, string HelpText, float Val ) +{ + EC = UWindowEditControl(CreateControl(class'UWindowEditControl', HorzOffset, VertOffset, Width, 16)); + EC.SetText( LabelText ); + EC.SetHelpText( HelpText ); + EC.SetFont(F_Normal); + EC.SetNumericOnly(True); + EC.SetNumericFloat(True); + EC.SetMaxLength(8); + EC.Align = TA_Right; + EC.EditBox.Offset = 0; + EC.EditBoxWidth = WinWidth/11; + EC.SetValue(string(Val)); + EC.Register(self); + HorzOffset += HorzInc; + VertOffset += VertInc; +} + +//----------------------------------------------------------------------------- + +function Created() +{ + Super.Created(); + + // close button + CloseButton = UWindowSmallCloseButton(CreateWindow(class'UWindowSmallCloseButton', WinWidth-48, WinHeight-19, 48, 16)); + + // defaults button + DefaultsButton = UWindowSmallButton(CreateControl(class'UWindowSmallButton', WinWidth-96-8, WinHeight-19, 48, 16)); + DefaultsButton.SetText( "Defaults" ); + DefaultsButton.SetHelpText( "Restore default settings." ); + + // main options + HOffset = 8; + VOffset = 8; + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, CycleWeaponsCheckBox, "Cycle Weapons:", "If checked, specified weapons are cycled, otherwise everyone has all specified weapons at all times (and ammo is given out automatically).", UMutator.default.bCycleWeapons ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, RandomWeaponsCheckBox, "Random Weapons:", "If checked and cycling weapons, weapons are selected randomly, otherwise weapons are selected in order.", UMutator.default.bRandomWeapons ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseAllWeaponsCheckBox, "Use All Weapons:", "If checked and cycling weapons randomly, each weapon will be used once each time through the list.", UMutator.default.bUseAllWeapons ); + + HOffset = 168; + VOffset = 8; + AddLabelControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/3, TimeBetweenWeaponSwitchesMinLC, "Min Time Between Weapon Switches:", "Minimum time (seconds) server waits between weapon switches (when cycling weapons)." ); + AddLabelControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/3, TimeBetweenWeaponSwitchesMaxLC, "Max Time Between Weapon Switches:", "Maximum time (seconds) server waits between weapon switches (when cycling weapons)." ); + AddLabelControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/3, TimeBetweenAmmoIncrementsLC, "Time Between Ammo Increments:", "Time (seconds) between ammo increments. Use 0.0 to disable (pickups become ammo). If set to 0.0 and weapons not cycled will default to 1.0." ); + AddLabelControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/3, TimeBetweenHealthIncrementsLC, "Time Between Health Increments:", "Time (seconds) server waits between health increments." ); + AddLabelControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/3, HealthIncrementAmountLC, "Health Increment Amount:", "Amount of health server will give to everyone when it is time to give out health." ); + AddLabelControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/3, StartHealthLC, "Initial Health:", "Health that everyone starts out with (if 0, uses default for pawns)." ); + AddLabelControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/3, MaxHealthLC, "Maximum Incremented Health:", "Maximum that health can be incremented to by server (if 0, uses default for pawns). Health vials still increment to 199." ); + + HOffset = 360; + VOffset = 8; + AddFltEditControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/11, TimeBetweenWeaponSwitchesMinEC, "", "Minimum time (seconds) server waits between weapon switches (when cycling weapons).", UMutator.default.TimeBetweenWeaponSwitchesMin ); + AddFltEditControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/11, TimeBetweenWeaponSwitchesMaxEC, "", "Maximum time (seconds) server waits between weapon switches (when cycling weapons).", UMutator.default.TimeBetweenWeaponSwitchesMax ); + AddFltEditControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/11, TimeBetweenAmmoIncrementsEC, "", "Time (seconds) server waits between giving out ammo to everyone (if 0.0, pickups become ammo for the current weapon).", UMutator.default.TimeBetweenAmmoIncrements ); + AddFltEditControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/11, TimeBetweenHealthIncrementsEC, "", "Time (seconds) server waits between giving out health to everyone.", UMutator.default.TimeBetweenHealthIncrements ); + AddIntEditControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/22, HealthIncrementAmountEC, "", "Amount of health server will give to everyone when it is time to give out health.", UMutator.default.HealthIncrementAmount ); + AddIntEditControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/22, StartHealthEC, "", "Health that everyone starts out with (if 0, uses default for pawns).", UMutator.default.StartHealth, 4 ); + AddIntEditControl( HOffset, 0, VOffset, EditControlVerticalSpacing, WinWidth/22, MaxHealthEC, "", "Maximum that health can be incremented to by server (if 0, uses default for pawns). Health vials still increment to 199.", UMutator.default.MaxHealth, 4 ); + + // ammo + HOffset = 8 + AmmoTableHOffset; + VOffset += TablesVOffset; + AddLabelControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/20, InitialAmmoLC, "Initial", "Amount of ammo that the weapon starts out with." ); + AddLabelControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/20, MaxAmmoLC, "Max", "Maximum amount of ammo for the weapon (0 = default)." ); + AddLabelControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/20, RateAmmoLC, "Rate", "Rate (amount per second) at which the weapon's ammo increments (if not cycling weapons or if AmmoIncrementRate is set)." ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, BioAmmoLC, "Bio Rifle Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialBioAmmoEC, "", "", UMutator.default.InitialBioAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxBioAmmoEC, "", "", UMutator.default.MaxBioAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RateBioAmmoPerSecEC, "", "", UMutator.default.RateBioAmmoPerSec ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, GunAmmoLC, "Gun Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialGunAmmoEC, "", "", UMutator.default.InitialGunAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxGunAmmoEC, "", "", UMutator.default.MaxGunAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RateGunAmmoPerSecEC, "", "", UMutator.default.RateGunAmmoPerSec ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, FlakAmmoLC, "Flak Cannon Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialFlakAmmoEC, "", "", UMutator.default.InitialFlakAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxFlakAmmoEC, "", "", UMutator.default.MaxFlakAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RateFlakAmmoPerSecEC, "", "", UMutator.default.RateFlakAmmoPerSec ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, PulseAmmoLC, "Pulse Gun Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialPulseAmmoEC, "", "", UMutator.default.InitialPulseAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxPulseAmmoEC, "", "", UMutator.default.MaxPulseAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RatePulseAmmoPerSecEC, "", "", UMutator.default.RatePulseAmmoPerSec ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, RedeemerAmmoLC, "Redeemer Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialRedeemerAmmoEC, "", "", UMutator.default.InitialRedeemerAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxRedeemerAmmoEC, "", "", UMutator.default.MaxRedeemerAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RateRedeemerAmmoPerSecEC, "", "", UMutator.default.RateRedeemerAmmoPerSec ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, RifleAmmoLC, "Rifle Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialRifleAmmoEC, "", "", UMutator.default.InitialRifleAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxRifleAmmoEC, "", "", UMutator.default.MaxRifleAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RateRifleAmmoPerSecEC, "", "", UMutator.default.RateRifleAmmoPerSec ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, RipperAmmoLC, "Ripper Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialRipperAmmoEC, "", "", UMutator.default.InitialRipperAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxRipperAmmoEC, "", "", UMutator.default.MaxRipperAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RateRipperAmmoPerSecEC, "", "", UMutator.default.RateRipperAmmoPerSec ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, RocketAmmoLC, "Rocket Launcher Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialRocketAmmoEC, "", "", UMutator.default.InitialRocketAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxRocketAmmoEC, "", "", UMutator.default.MaxRocketAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RateRocketAmmoPerSecEC, "", "", UMutator.default.RateRocketAmmoPerSec ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, ShockAmmoLC, "Shock Rifle Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialShockAmmoEC, "", "", UMutator.default.InitialShockAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxShockAmmoEC, "", "", UMutator.default.MaxShockAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RateShockAmmoPerSecEC, "", "", UMutator.default.RateShockAmmoPerSec ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, AmmoTableHOffset, VOffset, 0, WinWidth/5, StingerAmmoLC, "Stinger Ammo:", "" ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, InitialStingerAmmoEC, "", "", UMutator.default.InitialStingerAmmo ); + AddIntEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/22, MaxStingerAmmoEC, "", "", UMutator.default.MaxStingerAmmo ); + AddFltEditControl( HOffset, AmmoTableSize, VOffset, 0, WinWidth/11, RateStingerAmmoPerSecEC, "", "", UMutator.default.RateStingerAmmoPerSec ); + + // power-ups + HOffset = 8 + PowerUpsTableOffset; + VOffset += TablesVOffset; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/10, PowerUpDelayMinLC, "Min Delay", "Min time (seconds) before power up is given to everyone (0.0 disables power up)." ); + AddLabelControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/10, PowerUpDelayMaxLC, "Max Delay", "Max time (seconds) before power up is given to everyone (if enabled)." ); + AddLabelControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/10, PowerUpDurationMinLC, "Min Duration", "Min duration (seconds) of power up (if enabled)." ); + AddLabelControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/10, PowerUpDurationMaxLC, "Max Duration", "Max duration (seconds) of power up (if enabled)." ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, PowerUpsTableOffset, VOffset, 0, WinWidth/5, DamageAmplifierLC, "Damage Amplifier:", "" ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, DamageAmplifierDelayMinEC, "", "", UMutator.default.DamageAmplifierDelayMin ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, DamageAmplifierDelayMaxEC, "", "", UMutator.default.DamageAmplifierDelayMax ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, DamageAmplifierDurationMinEC, "", "", UMutator.default.DamageAmplifierDurationMin ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, DamageAmplifierDurationMaxEC, "", "", UMutator.default.DamageAmplifierDurationMax ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, PowerUpsTableOffset, VOffset, 0, WinWidth/5, JumpBootsLC, "JumpBoots:", "" ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, JumpBootsDelayMinEC, "", "", UMutator.default.JumpBootsDelayMin ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, JumpBootsDelayMaxEC, "", "", UMutator.default.JumpBootsDelayMax ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, JumpBootsDurationMinEC, "", "", UMutator.default.JumpBootsDurationMin ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, JumpBootsDurationMaxEC, "", "", UMutator.default.JumpBootsDurationMax ); + + HOffset = 8; + VOffset += EditControlVerticalSpacing; + AddLabelControl( HOffset, PowerUpsTableOffset, VOffset, 0, WinWidth/5, InvisibilityLC, "Invisibility:", "" ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, InvisibilityDelayMinEC, "", "", UMutator.default.InvisibilityDelayMin ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, InvisibilityDelayMaxEC, "", "", UMutator.default.InvisibilityDelayMax ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, InvisibilityDurationMinEC, "", "", UMutator.default.InvisibilityDurationMin ); + AddFltEditControl( HOffset, PowerUpsTableSize, VOffset, 0, WinWidth/11, InvisibilityDurationMaxEC, "", "", UMutator.default.InvisibilityDurationMax ); + + // weapons + HOffset = (3*WinWidth/4) + 8; + VOffset = 8; + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseBioRifleCheckBox, "Bio Rifle", "If checked Bio Rifle will be used.", UMutator.default.bUseBioRifle ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseChainSawCheckBox, "Chainsaw", "If checked Chainsaw will be used.", UMutator.default.bUseChainSaw ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseEnforcerCheckBox, "Enforcer", "If checked Enforcer will be used.", UMutator.default.bUseEnforcer ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseFlakCannonCheckBox, "Flak Cannon", "If checked Flak Cannon will be used.", UMutator.default.bUseFlakCannon ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseImpactHammerCheckBox, "Impact Hammer", "If checked Impact Hammer will be used.", UMutator.default.bUseImpactHammer ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseMiniGunCheckBox, "Minigun", "If checked Minigun will be used.", UMutator.default.bUseMiniGun ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UsePulseGunCheckBox, "Pulse Gun", "If checked Pulse Gun will be used.", UMutator.default.bUsePulseGun ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseRedeemerCheckBox, "Redeemer", "If checked Redeemer will be used.", UMutator.default.bUseRedeemer ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseRipperCheckBox, "Ripper", "If checked Ripper will be used.", UMutator.default.bUseRipper ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseRocketLauncherCheckBox, "Rocket Launcher", "If checked Rocket Launcher will be used.", UMutator.default.bUseRocketLauncher ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseShockRifleCheckBox, "Shock Rifle", "If checked Shock Rifle will be used.", UMutator.default.bUseShockRifle ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseSniperRifleCheckBox, "Sniper Rifle", "If checked Sniper Rifle will be used.", UMutator.default.bUseSniperRifle ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseSuperShockRifleCheckBox, "Super Shock Rifle", "If checked Super Shock Rifle will be used.", UMutator.default.bUseSuperShockRifle ); + + VOffset += SpacingOffset; + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIASMDCheckBox, "UnrealI ASMD*", "If checked UnrealI ASMD will be used (*only works in singleplayer games).", UMutator.default.bUseUnrealIASMD ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIAutoMagCheckBox, "UnrealI Auto Mag*", "If checked UnrealI Auto Mag will be used (*only works in singleplayer games).", UMutator.default.bUseUnrealIAutoMag ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIDispersionPistolCheckBox,"UnrealI Dispersion Pistol*", "If checked UnrealI Dispersion Pistol will be used (*only works in singleplayer games).",UMutator.default.bUseUnrealIDispersionPistol ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIEightballCheckBox, "UnrealI Eightball*", "If checked UnrealI Eightball will be used (*only works in singleplayer games).", UMutator.default.bUseUnrealIEightball ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIFlakCannonCheckBox, "UnrealI Flak Cannon*", "If checked UnrealI Flak Cannon will be used (*only works in singleplayer games).", UMutator.default.bUseUnrealIFlakCannon ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIGESBioRifleCheckBox, "UnrealI GES Bio Rifle*", "If checked UnrealI GES Bio Rifle will be used (*only works in singleplayer games).", UMutator.default.bUseUnrealIGESBioRifle ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIMinigunCheckBox, "UnrealI Minigun*", "If checked UnrealI Minigun will be used (*only works in singleplayer games).", UMutator.default.bUseUnrealIMinigun ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIRazorjackCheckBox, "UnrealI Razorjack*", "If checked UnrealI Razorjack be used (*only works in singleplayer games).", UMutator.default.bUseUnrealIRazorjack ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIRifleCheckBox, "UnrealI Rifle*", "If checked UnrealI Rifle will be used (*only works in singleplayer games).", UMutator.default.bUseUnrealIRifle ); + AddCheckBox( HOffset, 0, VOffset, SpacingOffset, UseUnrealIStingerCheckBox, "UnrealI Stinger*", "If checked UnrealI Stinger will be used (*only works in singleplayer games).", UMutator.default.bUseUnrealIStinger ); +} + +//----------------------------------------------------------------------------- + +function Paint(Canvas C, float X, float Y) +{ + local Texture T; + Super.Paint(C, X, Y); + T = GetLookAndFeelTexture(); +} + +//----------------------------------------------------------------------------- + +function Close(optional bool bByParent) +{ + // save NIUTMutator config + UMutator.default.bCycleWeapons = CycleWeaponsCheckBox.bChecked; + UMutator.default.bRandomWeapons = RandomWeaponsCheckBox.bChecked; + UMutator.default.bUseAllWeapons = UseAllWeaponsCheckBox.bChecked; + + UMutator.default.TimeBetweenWeaponSwitchesMin = RangeFloat( float(TimeBetweenWeaponSwitchesMinEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.TimeBetweenWeaponSwitchesMax = RangeFloat( float(TimeBetweenWeaponSwitchesMaxEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.TimeBetweenAmmoIncrements = RangeFloat( float(TimeBetweenAmmoIncrementsEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.TimeBetweenHealthIncrements = RangeFloat( float(TimeBetweenHealthIncrementsEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.HealthIncrementAmount = RoundRangeInt( float(HealthIncrementAmountEC.EditBox.Value), 0, 999 ); + UMutator.default.StartHealth = RoundRangeInt( float(StartHealthEC.EditBox.Value), 0, 9999 ); + UMutator.default.MaxHealth = RoundRangeInt( float(MaxHealthEC.EditBox.Value), 0, 9999 ); + + UMutator.default.InitialBioAmmo = RoundRangeInt( float(InitialBioAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxBioAmmo = RoundRangeInt( float(MaxBioAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RateBioAmmoPerSec = RangeFloat( float(RateBioAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.InitialGunAmmo = RoundRangeInt( float(InitialGunAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxGunAmmo = RoundRangeInt( float(MaxGunAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RateGunAmmoPerSec = RangeFloat( float(RateGunAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.InitialFlakAmmo = RoundRangeInt( float(InitialFlakAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxFlakAmmo = RoundRangeInt( float(MaxFlakAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RateFlakAmmoPerSec = RangeFloat( float(RateFlakAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.InitialPulseAmmo = RoundRangeInt( float(InitialPulseAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxPulseAmmo = RoundRangeInt( float(MaxPulseAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RatePulseAmmoPerSec = RangeFloat( float(RatePulseAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.InitialRedeemerAmmo = RoundRangeInt( float(InitialRedeemerAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxRedeemerAmmo = RoundRangeInt( float(MaxRedeemerAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RateRedeemerAmmoPerSec = RangeFloat( float(RateRedeemerAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.InitialRifleAmmo = RoundRangeInt( float(InitialRifleAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxRifleAmmo = RoundRangeInt( float(MaxRifleAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RateRifleAmmoPerSec = RangeFloat( float(RateRifleAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.InitialRipperAmmo = RoundRangeInt( float(InitialRipperAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxRipperAmmo = RoundRangeInt( float(MaxRipperAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RateRipperAmmoPerSec = RangeFloat( float(RateRipperAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.InitialRocketAmmo = RoundRangeInt( float(InitialRocketAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxRocketAmmo = RoundRangeInt( float(MaxRocketAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RateRocketAmmoPerSec = RangeFloat( float(RateRocketAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.InitialShockAmmo = RoundRangeInt( float(InitialShockAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxShockAmmo = RoundRangeInt( float(MaxShockAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RateShockAmmoPerSec = RangeFloat( float(RateShockAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.InitialStingerAmmo = RoundRangeInt( float(InitialStingerAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.MaxStingerAmmo = RoundRangeInt( float(MaxStingerAmmoEC.EditBox.Value), 0, 999 ); + UMutator.default.RateStingerAmmoPerSec = RangeFloat( float(RateStingerAmmoPerSecEC.EditBox.Value), 0.0, 100.0 ); + + UMutator.default.bUseBioRifle = UseBioRifleCheckBox.bChecked; + UMutator.default.bUseChainSaw = UseChainSawCheckBox.bChecked; + UMutator.default.bUseEnforcer = UseEnforcerCheckBox.bChecked; + UMutator.default.bUseFlakCannon = UseFlakCannonCheckBox.bChecked; + UMutator.default.bUseImpactHammer = UseImpactHammerCheckBox.bChecked; + UMutator.default.bUseMiniGun = UseMiniGunCheckBox.bChecked; + UMutator.default.bUsePulseGun = UsePulseGunCheckBox.bChecked; + UMutator.default.bUseRedeemer = UseRedeemerCheckBox.bChecked; + UMutator.default.bUseRipper = UseRipperCheckBox.bChecked; + UMutator.default.bUseRocketLauncher = UseRocketLauncherCheckBox.bChecked; + UMutator.default.bUseShockRifle = UseShockRifleCheckBox.bChecked; + UMutator.default.bUseSniperRifle = UseSniperRifleCheckBox.bChecked; + UMutator.default.bUseSuperShockRifle = UseSuperShockRifleCheckBox.bChecked; + UMutator.default.bUseUnrealIASMD = UseUnrealIASMDCheckBox.bChecked; + UMutator.default.bUseUnrealIAutoMag = UseUnrealIAutoMagCheckBox.bChecked; + UMutator.default.bUseUnrealIDispersionPistol = UseUnrealIDispersionPistolCheckBox.bChecked; + UMutator.default.bUseUnrealIEightball = UseUnrealIEightballCheckBox.bChecked; + UMutator.default.bUseUnrealIFlakCannon = UseUnrealIFlakCannonCheckBox.bChecked; + UMutator.default.bUseUnrealIGESBioRifle = UseUnrealIGESBioRifleCheckBox.bChecked; + UMutator.default.bUseUnrealIMinigun = UseUnrealIMinigunCheckBox.bChecked; + UMutator.default.bUseUnrealIRazorjack = UseUnrealIRazorjackCheckBox.bChecked; + UMutator.default.bUseUnrealIRifle = UseUnrealIRifleCheckBox.bChecked; + UMutator.default.bUseUnrealIStinger = UseUnrealIStingerCheckBox.bChecked; + + UMutator.default.DamageAmplifierDelayMin = RangeFloat(float(DamageAmplifierDelayMinEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.DamageAmplifierDelayMax = RangeFloat(float(DamageAmplifierDelayMaxEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.DamageAmplifierDurationMin = RangeFloat(float(DamageAmplifierDurationMinEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.DamageAmplifierDurationMax = RangeFloat(float(DamageAmplifierDurationMaxEC.EditBox.Value), 0.0, 999.0 ); + + UMutator.default.JumpBootsDelayMin = RangeFloat(float(JumpBootsDelayMinEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.JumpBootsDelayMax = RangeFloat(float(JumpBootsDelayMaxEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.JumpBootsDurationMin = RangeFloat(float(JumpBootsDurationMinEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.JumpBootsDurationMax = RangeFloat(float(JumpBootsDurationMaxEC.EditBox.Value), 0.0, 999.0 ); + + UMutator.default.InvisibilityDelayMin = RangeFloat(float(InvisibilityDelayMinEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.InvisibilityDelayMax = RangeFloat(float(InvisibilityDelayMaxEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.InvisibilityDurationMin = RangeFloat(float(InvisibilityDurationMinEC.EditBox.Value), 0.0, 999.0 ); + UMutator.default.InvisibilityDurationMax = RangeFloat(float(InvisibilityDurationMaxEC.EditBox.Value), 0.0, 999.0 ); + + UMutator.static.StaticSaveConfig(); + + Super.Close(bByParent); +} + +//----------------------------------------------------------------------------- + +function RestoreDefaults() +{ + // restore default NIUTMutator config -- can't figure out a way to get at class defaults + // so far before these are overridden by values in the config file (no can do?). + + CycleWeaponsCheckBox.bChecked = true; + RandomWeaponsCheckBox.bChecked = true; + UseAllWeaponsCheckBox.bChecked = true; + + TimeBetweenWeaponSwitchesMinEC.SetValue( "75.000000" ); + TimeBetweenWeaponSwitchesMaxEC.SetValue( "75.000000" ); + TimeBetweenAmmoIncrementsEC.SetValue( "0.000000" ); + TimeBetweenHealthIncrementsEC.SetValue( "1.000000" ); + HealthIncrementAmountEC.SetValue( "5" ); + StartHealthEC.SetValue( "0" ); + MaxHealthEC.SetValue( "0" ); + + InitialBioAmmoEC.SetValue( "50" ); + MaxBioAmmoEC.SetValue( "100" ); + RateBioAmmoPerSecEC.SetValue( "0.250000" ); + + InitialGunAmmoEC.SetValue( "100" ); + MaxGunAmmoEC.SetValue( "199" ); + RateGunAmmoPerSecEC.SetValue( "5.000000" ); + + InitialFlakAmmoEC.SetValue( "12" ); + MaxFlakAmmoEC.SetValue( "50" ); + RateFlakAmmoPerSecEC.SetValue( "0.200000" ); + + InitialPulseAmmoEC.SetValue( "50" ); + MaxPulseAmmoEC.SetValue( "199" ); + RatePulseAmmoPerSecEC.SetValue( "2.000000" ); + + InitialRedeemerAmmoEC.SetValue( "0" ); + MaxRedeemerAmmoEC.SetValue( "1" ); + RateRedeemerAmmoPerSecEC.SetValue( "0.050000" ); + + InitialRifleAmmoEC.SetValue( "12" ); + MaxRifleAmmoEC.SetValue( "50" ); + RateRifleAmmoPerSecEC.SetValue( "0.500000" ); + + InitialRipperAmmoEC.SetValue( "25" ); + MaxRipperAmmoEC.SetValue( "75" ); + RateRipperAmmoPerSecEC.SetValue( "1.500000" ); + + InitialRocketAmmoEC.SetValue( "12" ); + MaxRocketAmmoEC.SetValue( "48" ); + RateRocketAmmoPerSecEC.SetValue( "0.250000" ); + + InitialShockAmmoEC.SetValue( "12" ); + MaxShockAmmoEC.SetValue( "50" ); + RateShockAmmoPerSecEC.SetValue( "0.670000" ); + + InitialStingerAmmoEC.SetValue( "50" ); + MaxStingerAmmoEC.SetValue( "200" ); + RateStingerAmmoPerSecEC.SetValue( "5.000000" ); + + UseBioRifleCheckBox.bChecked = false; + UseChainSawCheckBox.bChecked = false; + UseEnforcerCheckBox.bChecked = false; + UseFlakCannonCheckBox.bChecked = false; + UseImpactHammerCheckBox.bChecked = false; + UseMiniGunCheckBox.bChecked = true; + UsePulseGunCheckBox.bChecked = false; + UseRedeemerCheckBox.bChecked = false; + UseRipperCheckBox.bChecked = true; + UseRocketLauncherCheckBox.bChecked = true; + UseShockRifleCheckBox.bChecked = false; + UseSniperRifleCheckBox.bChecked = true; + UseSuperShockRifleCheckBox.bChecked = false; + UseUnrealIASMDCheckBox.bChecked = false; + UseUnrealIAutoMagCheckBox.bChecked = false; + UseUnrealIDispersionPistolCheckBox.bChecked = false; + UseUnrealIEightballCheckBox.bChecked = false; + UseUnrealIFlakCannonCheckBox.bChecked = false; + UseUnrealIGESBioRifleCheckBox.bChecked = false; + UseUnrealIMinigunCheckBox.bChecked = false; + UseUnrealIRazorjackCheckBox.bChecked = false; + UseUnrealIRifleCheckBox.bChecked = false; + UseUnrealIStingerCheckBox.bChecked = false; + + DamageAmplifierDelayMinEC.SetValue( "240.000000" ); + DamageAmplifierDelayMaxEC.SetValue( "240.000000" ); + DamageAmplifierDurationMinEC.SetValue( "30.000000" ); + DamageAmplifierDurationMaxEC.SetValue( "30.000000" ); + + JumpBootsDelayMinEC.SetValue( "0.000000" ); + JumpBootsDelayMaxEC.SetValue( "0.000000" ); + JumpBootsDurationMinEC.SetValue( "15.000000" ); + JumpBootsDurationMaxEC.SetValue( "15.000000" ); + + InvisibilityDelayMinEC.SetValue( "0.000000" ); + InvisibilityDelayMaxEC.SetValue( "0.000000" ); + InvisibilityDurationMinEC.SetValue( "30.000000" ); + InvisibilityDurationMaxEC.SetValue( "30.000000" ); +} + +//----------------------------------------------------------------------------- + +function int RangeInt(int Num, int Min, int Max) +{ + if (Num > Max) + return Max; + else if (Num < Min) + return Min; + else + return Num; +} + +//----------------------------------------------------------------------------- + +function float RangeFloat( float Num, float Min, float Max) +{ + if (Num > Max) + return Max; + else if (Num < Min) + return Min; + else return + Num; +} + +//----------------------------------------------------------------------------- + +function int RoundRangeInt(float Num, int Min, int Max) +{ + return RangeInt( int(Num + 0.5), Min, Max ); +} + +//----------------------------------------------------------------------------- + +function Notify(UWindowDialogControl C, byte E) +{ + Super.Notify(C, E); + + if(E == DE_MouseMove) + { + if(UMenuRootWindow(Root) != None) + if(UMenuRootWindow(Root).StatusBar != None) + UMenuRootWindow(Root).StatusBar.SetHelp(C.HelpText); + } + + if(E == DE_MouseLeave) + { + if(UMenuRootWindow(Root) != None) + if(UMenuRootWindow(Root).StatusBar != None) + UMenuRootWindow(Root).StatusBar.SetHelp(""); + } + + if( E == DE_Click ) + { + switch( C ) + { + case DefaultsButton: + RestoreDefaults(); + break; + } + } +} + +defaultproperties +{ + CloseButton=None + DefaultsButton=None + CycleWeaponsCheckBox=None + RandomWeaponsCheckBox=None + UseAllWeaponsCheckBox=None + TimeBetweenWeaponSwitchesMinLC=None + TimeBetweenWeaponSwitchesMaxLC=None + TimeBetweenAmmoIncrementsLC=None + TimeBetweenHealthIncrementsLC=None + HealthIncrementAmountLC=None + StartHealthLC=None + MaxHealthLC=None + TimeBetweenAmmoIncrementsEC=None + TimeBetweenWeaponSwitchesMinEC=None + TimeBetweenWeaponSwitchesMaxEC=None + TimeBetweenHealthIncrementsEC=None + HealthIncrementAmountEC=None + StartHealthEC=None + MaxHealthEC=None + UseBioRifleCheckBox=None + UseChainSawCheckBox=None + UseEnforcerCheckBox=None + UseFlakCannonCheckBox=None + UseImpactHammerCheckBox=None + UseMiniGunCheckBox=None + UsePulseGunCheckBox=None + UseRipperCheckBox=None + UseRocketLauncherCheckBox=None + UseRedeemerCheckBox=None + UseShockRifleCheckBox=None + UseSniperRifleCheckBox=None + UseSuperShockRifleCheckBox=None + UseUnrealIASMDCheckBox=None + UseUnrealIAutoMagCheckBox=None + UseUnrealIDispersionPistolCheckBox=None + UseUnrealIFlakCannonCheckBox=None + UseUnrealIEightballCheckBox=None + UseUnrealIGESBioRifleCheckBox=None + UseUnrealIMinigunCheckBox=None + UseUnrealIRazorjackCheckBox=None + UseUnrealIRifleCheckBox=None + UseUnrealIStingerCheckBox=None + InitialAmmoLC=None + MaxAmmoLC=None + RateAmmoLC=None + BioAmmoLC=None + GunAmmoLC=None + FlakAmmoLC=None + PulseAmmoLC=None + RedeemerAmmoLC=None + RifleAmmoLC=None + RipperAmmoLC=None + RocketAmmoLC=None + ShockAmmoLC=None + StingerAmmoLC=None + InitialBioAmmoEC=None + RateBioAmmoPerSecEC=None + MaxBioAmmoEC=None + InitialGunAmmoEC=None + RateGunAmmoPerSecEC=None + MaxGunAmmoEC=None + InitialFlakAmmoEC=None + RateFlakAmmoPerSecEC=None + MaxFlakAmmoEC=None + InitialPulseAmmoEC=None + RatePulseAmmoPerSecEC=None + MaxPulseAmmoEC=None + InitialRedeemerAmmoEC=None + RateRedeemerAmmoPerSecEC=None + MaxRedeemerAmmoEC=None + InitialRifleAmmoEC=None + RateRifleAmmoPerSecEC=None + MaxRifleAmmoEC=None + InitialRipperAmmoEC=None + RateRipperAmmoPerSecEC=None + MaxRipperAmmoEC=None + InitialRocketAmmoEC=None + RateRocketAmmoPerSecEC=None + MaxRocketAmmoEC=None + InitialShockAmmoEC=None + RateShockAmmoPerSecEC=None + MaxShockAmmoEC=None + InitialStingerAmmoEC=None + RateStingerAmmoPerSecEC=None + MaxStingerAmmoEC=None + PowerUpDelayMinLC=None + PowerUpDelayMaxLC=None + PowerUpDurationMinLC=None + PowerUpDurationMaxLC=None + DamageAmplifierLC=None + JumpbootsLC=None + InvisibilityLC=None + InvisibilityDelayMinEC=None + InvisibilityDelayMaxEC=None + InvisibilityDurationMinEC=None + InvisibilityDurationMaxEC=None + DamageAmplifierDelayMinEC=None + DamageAmplifierDelayMaxEC=None + DamageAmplifierDurationMinEC=None + DamageAmplifierDurationMaxEC=None + JumpBootsDelayMinEC=None + JumpBootsDelayMaxEC=None + JumpBootsDurationMinEC=None + JumpBootsDurationMaxEC=None + UMutator=None + SpacingOffset=16 + HOffset=0 + VOffset=0 +} diff --git a/Classes/NIUTConfigMenu.uc b/Classes/NIUTConfigMenu.uc new file mode 100644 index 0000000..f100d48 --- /dev/null +++ b/Classes/NIUTConfigMenu.uc @@ -0,0 +1,10 @@ +//============================================================================= +// NIUTConfigMenu. +//============================================================================= +class NIUTConfigMenu expands UWindowFramedWindow; + +defaultproperties +{ + ClientClass=None + WindowTitle="NIUT126 Mutator Options (see www.planetunreal.com/niu and/or niut.txt for more information)" +} diff --git a/Classes/NIUTConfigMenuItem.uc b/Classes/NIUTConfigMenuItem.uc new file mode 100644 index 0000000..6549819 --- /dev/null +++ b/Classes/NIUTConfigMenuItem.uc @@ -0,0 +1,20 @@ +//============================================================================= +// NIUTConfigMenuItem. +//============================================================================= +class NIUTConfigMenuItem expands UMenuModMenuItem; + +// assumes 640x480 resolution for now -- only alternative is to go to property pages +const SizeX = 624; +const SizeY = 448; + +// Called when the menu item is chosen +function Execute() +{ + MenuItem.Owner.Root.CreateWindow(class'NIUTConfigMenu', (MenuItem.Owner.Root.WinWidth/2 - (SizeX/2)), (MenuItem.Owner.Root.WinHeight/2 - (SizeY/2)), SizeX, SizeY); +} + +defaultproperties +{ + MenuCaption="NIUT126 Mutator Options" + MenuHelp="Configure the NIUT126 Mutator options." +} diff --git a/Classes/NIUTMutator.uc b/Classes/NIUTMutator.uc new file mode 100644 index 0000000..1e8181f --- /dev/null +++ b/Classes/NIUTMutator.uc @@ -0,0 +1,1717 @@ +//============================================================================= +// NIUTMutator. +//============================================================================= + +class NIUTMutator extends Mutator config(NIUT); + +/*============================================================================= +Mutator for NIUT (No Item Unreal Tournament). + +=============================================================================== + +Author: Mike Fox (a.k.a. ArtfulDodger) +Contact: mfox@legendent.com +URL: www.planetunreal.com/niu + +=============================================================================== +tbd: + +Check zone before healing (shouldn't heal if drowning, in lava etc.). +=============================================================================== +Version: 1.26 - chacha +Created: 27/01/26 + ++Integrate with 469e ++Code cleaning + +=============================================================================== +Version: 1.25 - chacha +Created: 26/08/25 + ++Fix random no weapon when join (ugly workaound... I'd like to rewrite this mod) ++Code cleaning + +=============================================================================== +Version: 1.24 +Created: 02/05/00 + ++Made NIUT work better with other mutators. + + +Derive from Mutator instead of Arena so it can be used with other Arena + mutators (e.g. grapple hook mod). This messes up Last Man Standing a bit + because it only keeps ammo in the level if there is an Arena mutator + being used. The work-around is to either have ammo auto-increment or use + any arena mutator (e.g. the grappling hook mod) to force the ammo to + stay (I don't think there is another way -- the LastManStanding Game + type should really be a bit more mutator friendly). I've also created a + dummy arena mutator (DummyArenaMutator) for this purpose. + + +The good news is that LastManStanding now works with exactly the + specified weapons, so you can have a Redeemer + super shock rifle + Last Man Standing match. About the only thing that doesn't work is + the fact that the weapons are always given their full complement of + ammo initially instead of the InitialSettings that NIUT specifies. There + doesn't seem to be an easy workaround to this and I don't think its a + big deal, so I probably won't look into it. + + + +NIUT no longer strips anything but "known" weapons from pawns so it doesn't + interfere with stuff that other mutators want to give them. Each time a + pawn (player / bot) joins the game or respawns, any "known" weapons in the + pawn's inventory at that point are removed. This is also done when cycling + weapons and when the current weapon changes. The list of "known" weapons includes + all the UT and Unreal I weapons currently. If someone adds a new weapon + (e.g. the BattleAxe) and gives this to players, it will *not* be filtered + out by default. To have the new weapon behave just like other weapons add + it to the ExtraWeaponClassStrings list. This means that a grapple (for + example) which has a class derived from weapon should not be affected by + having the NIUT mutator loaded. + + +CheckReplacement also only strips out known weapons (unless bForceWeaponSpawn + is set internally. + ++Fix for conflict between Low Gravity and NIUT mutators (Low Gravity was + forcing jumpboots to be stripped out even if NIUT was set up to use these). + Solution: have AlwaysKeep() return true for jumpboots. + ++Fix for accessed None warnings in RateSelf (give ammo before putting into + Pawn's inventory etc.). + +=============================================================================== +Version: 1.23 +Created: 01/28/00 + ++Added UI support for specifying NIUT settings through Mod menu. + ++bAllWeapons -> !bCycleWeapons + ++WeaponClassStrings -> ExtraWeaponClassStrings (support for new weapons not + already in UT). + ++Can specify max ammo that any weapon can carry (e.g. limit Redeemer to only + carrying 1 warhead at a time). + ++Added MaxHealth option for auto-incremented health (5000 with Redeemer is fun). + ++Added StartHealth option to control health that pawns start with. + +=============================================================================== +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 bCycleWeapons is false 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. + +=============================================================================*/ + +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 bCycleWeapons; // (true): false ==> players get all weapons in weapons list with auto-incrementing ammo + +// weapons +var() config bool bUseChainSaw; // (false) +var() config bool bUseEnforcer; // (false) +var() config bool bUseImpactHammer; // (false) +var() config bool bUseMiniGun; // (false) +var() config bool bUsePulseGun; // (false) +var() config bool bUseRipper; // (false) +var() config bool bUseShockRifle; // (false) +var() config bool bUseSniperRifle; // (false) +var() config bool bUseSuperShockRifle; // (false) +var() config bool bUseBioRifle; // (false) +var() config bool bUseRocketLauncher; // (false) +var() config bool bUseFlakCannon; // (false) +var() config bool bUseRedeemer; // (false) +var() config bool bUseUnrealIFlakCannon; // (false) +var() config bool bUseUnrealIGESBioRifle; // (false) +var() config bool bUseUnrealIMinigun; // (false) +var() config bool bUseUnrealIRazorjack; // (false) +var() config bool bUseUnrealIRifle; // (false) +var() config bool bUseUnrealIASMD; // (false) +var() config bool bUseUnrealIAutoMag; // (false) +var() config bool bUseUnrealIDispersionPistol; // (false) +var() config bool bUseUnrealIEightball; // (false) +var() config bool bUseUnrealIStinger; // (false) +var() config string ExtraWeaponClassStrings[32]; // list of weapons to use (for adding weapons not in UT / Unreal I) + +var() config float TimeRecheck; // (2): weapon check ugly workaround to force player to have a weapon +var() config float TimeBetweenWeaponSwitchesMin; // (45): min secs between weapon switches +var() config float TimeBetweenWeaponSwitchesMax; // (45): max secs between weapon switches +var() config float TimeBetweenAmmoIncrements; // (0.0): >0.0 ==> auto-increment ammo at this rate +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 int StartHealth; // (100): health that pawns start out with +var() config int MaxHealth; // (100): max that health can be auto-incremented to +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 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 InitialRipperAmmo; +var() config int InitialBioAmmo; +var() config int InitialGunAmmo; +var() config int InitialStingerAmmo; +var() config int InitialOtherAmmo; + +// 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 RateRipperAmmoPerSec; +var() config float RateBioAmmoPerSec; +var() config float RateGunAmmoPerSec; +var() config float RateStingerAmmoPerSec; +var() config float RateOtherAmmoPerSec; + +// ammo incrementing (number of TimeBetweenAmmoIncrements before ammo is incremented by 1) +var() config int MaxRedeemerAmmo; +var() config int MaxRocketAmmo; +var() config int MaxFlakAmmo; +var() config int MaxShockAmmo; +var() config int MaxRifleAmmo; +var() config int MaxPulseAmmo; +var() config int MaxRipperAmmo; +var() config int MaxBioAmmo; +var() config int MaxGunAmmo; +var() config int MaxStingerAmmo; +var() config int MaxOtherAmmo; + +var int NumWeapons; // number of weapons in ExtraWeaponClassStrings list +var string FilteredWeaponClassStrings[64]; // filtered list of weapons to use +var Class CurrentWeaponClass; // current weapon class +var int CurrentWeaponIndex; // index into FilteredWeaponClassStrings for current weapon +var int NumUsedWeapons; // number of weapons used so far (used with bUseAllWeapons) +var byte UsedWeapons[64]; // 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 NextTimeRecheck; // when to recheck player's weapon + +var float CountRedeemerAmmo; +var float CountRocketAmmo; +var float CountFlakAmmo; +var float CountShockAmmo; +var float CountRifleAmmo; +var float CountPulseAmmo; +var float CountRipperAmmo; +var float CountBioAmmo; +var float CountGunAmmo; +var float CountStingerAmmo; +var float CountOtherAmmo; + +// utility variables +var bool bDidTick; // set after first tick occurs +var bool bForceWeaponSpawn; // set to force CheckReplacement to return true for weapons + + +const LOTSATIME = 99999.0; + +//----------------------------------------------------------------------------- + +function MaybeAddWeapon( bool bUse, string WeaponClassString, out int NumWeapons ) +{ + if( bUse ) + { + if( DynamicLoadObject( WeaponClassString, class'Class' ) != None ) + { + FilteredWeaponClassStrings[ NumWeapons ] = WeaponClassString; + NumWeapons++; + } + else + { + warn( Self $ ": WeaponClassString is invalid in MaybeAddWeapon: " $ WeaponClassString ); + } + } +} + +//----------------------------------------------------------------------------- +// 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; + + // standard weapons + MaybeAddWeapon( bUseChainSaw, "Botpack.ChainSaw", NumWeapons ); + MaybeAddWeapon( bUseEnforcer, "Botpack.Enforcer", NumWeapons ); + MaybeAddWeapon( bUseImpactHammer, "Botpack.ImpactHammer", NumWeapons ); + MaybeAddWeapon( bUseMiniGun, "Botpack.MiniGun2", NumWeapons ); + MaybeAddWeapon( bUsePulseGun, "Botpack.PulseGun", NumWeapons ); + MaybeAddWeapon( bUseRipper, "Botpack.Ripper", NumWeapons ); + MaybeAddWeapon( bUseShockRifle, "Botpack.ShockRifle", NumWeapons ); + MaybeAddWeapon( bUseSniperRifle, "Botpack.SniperRifle", NumWeapons ); + MaybeAddWeapon( bUseSuperShockRifle, "Botpack.SuperShockRifle", NumWeapons ); + MaybeAddWeapon( bUseBioRifle, "Botpack.UT_BioRifle", NumWeapons ); + MaybeAddWeapon( bUseRocketLauncher, "Botpack.UT_Eightball", NumWeapons ); + MaybeAddWeapon( bUseFlakCannon, "Botpack.UT_FlakCannon", NumWeapons ); + MaybeAddWeapon( bUseRedeemer, "Botpack.WarheadLauncher", NumWeapons ); + MaybeAddWeapon( bUseUnrealIFlakCannon, "UnrealI.FlakCannon", NumWeapons ); + MaybeAddWeapon( bUseUnrealIGESBioRifle, "UnrealI.GESBioRifle", NumWeapons ); + MaybeAddWeapon( bUseUnrealIMinigun, "UnrealI.Minigun", NumWeapons ); + MaybeAddWeapon( bUseUnrealIRazorjack, "UnrealI.Razorjack", NumWeapons ); + MaybeAddWeapon( bUseUnrealIRifle, "UnrealI.Rifle", NumWeapons ); + MaybeAddWeapon( bUseUnrealIASMD, "UnrealShare.ASMD", NumWeapons ); + MaybeAddWeapon( bUseUnrealIAutoMag, "UnrealShare.AutoMag", NumWeapons ); + MaybeAddWeapon( bUseUnrealIDispersionPistol,"UnrealShare.DispersionPistol", NumWeapons ); + MaybeAddWeapon( bUseUnrealIEightball, "UnrealShare.Eightball", NumWeapons ); + MaybeAddWeapon( bUseUnrealIStinger, "UnrealShare.Stinger", NumWeapons ); + + // weapons specified through ExtraWeaponClassStrings + for( i=0; i 0.0 ) + { + CountRedeemerAmmo = 0.0; + CountRocketAmmo = 0.0; + CountFlakAmmo = 0.0; + CountShockAmmo = 0.0; + CountRifleAmmo = 0.0; + CountRipperAmmo = 0.0; + CountBioAmmo = 0.0; + CountGunAmmo = 0.0; + CountStingerAmmo = 0.0; + CountPulseAmmo = 0.0; + CountOtherAmmo = 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(); + + if( MaxHealth <= 0) + { + MaxHealth = class'Pawn'.default.Health; + } + + if( StartHealth <= 0) + { + StartHealth = class'Pawn'.default.Health; + } +} + +//----------------------------------------------------------------------------- +// Perform weapon switching etc. when the time is right. + +function Tick( float DeltaTime ) +{ + local Pawn P; + local Inventory Inv; + local bool bWeaponFound; + + //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; + NextTimeRecheck = Level.TimeSeconds + TimeRecheck; + } + else if (!DeathMatchPlus(Level.Game).bRequireReady) + { + 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( bCycleWeapons && Level.TimeSeconds >= NextChooseWeaponTime ) + { + // time to change everybody's weapon + ChooseWeapon(); + for( P=Level.PawnList; P != None; P=P.NextPawn ) + { + if(P.IsInState('Dying') || P.Health <= 0) + continue; + SetInventory( P ); + } + + NumWarnings = 0; + NextChooseWeaponTime = Level.TimeSeconds + RandRange(TimeBetweenWeaponSwitchesMin, TimeBetweenWeaponSwitchesMax); + NextTimeRecheck = Level.TimeSeconds + TimeRecheck; + } + // ugly safety workaround + else if(bCycleWeapons && Level.TimeSeconds >= NextTimeRecheck) + { + for( P=Level.PawnList; P != None; P=P.NextPawn ) + { + if(P.IsInState('Dying') || P.Health <= 0) + continue; + bWeaponFound = false; + for( Inv=P.Inventory; Inv!=None; Inv=Inv.Inventory ) + { + if( Inv.IsA( 'Weapon' ) && FilterWeapon( Weapon(Inv) ) ) + { + bWeaponFound = true; + break; + } + } + if(!bWeaponFound && (CurrentWeaponClass != None)) + { + log("NIUT: ! BUG DETECTED ! Player without weapon, fixing that ... (" $ P $")"); + //GiveWeaponTo( P, CurrentWeaponClass ); + SetInventory( P ); + } + } + NextTimeRecheck = Level.TimeSeconds + TimeRecheck; + } + // increment health + if( (HealthIncrementAmount >= 1) && (Level.TimeSeconds >= NextIncrementHealthTime) ) + { + for( P=Level.PawnList; P != None; P=P.NextPawn ) + { + if(P.IsInState('Dying') || P.Health <= 0) + continue; + if( (P.Health > 0) && (P.Health < MaxHealth) ) + { + P.Health += Min( HealthIncrementAmount, MaxHealth - P.Health ); + + // play sound only if we won't spam the weapons switch warning (not playing if NumWarnings is 0 + 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 ) + { + if(P.IsInState('Dying') || P.Health <= 0) + continue; + GiveInvisibilityTo( P ); + + // play sound only if we won't spam the weapons switch warning (not playing if NumWarnings is 0 + // sound always plays in singleplayer? + 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 ) + { + if(P.IsInState('Dying') || P.Health <= 0) + continue; + GiveDamageAmplifierTo( P ); + + // play sound only if we won't spam the weapons switch warning (not playing if NumWarnings is 0 + // sound always plays in singleplayer? + 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 ) + { + if(P.IsInState('Dying') || P.Health <= 0) + continue; + GiveJumpBootsTo( P ); + + // play sound only if we won't spam the weapons switch warning (not playing if NumWarnings is 0 + // sound always plays in singleplayer? + 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; + } + } + else + { + NextTimeRecheck = Level.TimeSeconds + TimeRecheck; + } +} + +//----------------------------------------------------------------------------- +// 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() +{ + + 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 $ ": ExtraWeaponsClassStrings contain no valid weapon(s)!" ); + } + + log( "NIUT: " $ Level.TimeSeconds $ " (" $ Level.Game.NumPlayers $ ") -- selected: " $ CurrentWeaponClass $"("$CurrentWeaponIndex$")"); + + TransformPickups(); + + NextChooseWeaponTime = Level.TimeSeconds + RandRange( TimeBetweenWeaponSwitchesMin, TimeBetweenWeaponSwitchesMax ); +} + +//----------------------------------------------------------------------------- +// Give W Amount units of ammo, increasing ammo's MaxAmmo if necessary and make +// sure the weapon doesn't end up with *more* than Amount units of ammo. + +function GiveAmmo( Weapon W, Pawn Other, int Amount, int Max ) +{ + if ( W.AmmoName != None ) + { + 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'); + } + + if( Max > 0 ) + { + // might override temporary MaxAmmo set above to give initial amount + W.AmmoType.MaxAmmo = Max; + } + } + + // make sure weapon doesn't have *more* than the specified amount. + if( W.AmmoType!=None && W.AmmoType.AmmoAmount > Amount ) + { + W.AmmoType.AmmoAmount = Amount; + } +} + +//----------------------------------------------------------------------------- + +function GiveWeaponTo( Pawn P, Class WeaponClass ) +{ + local Weapon newWeapon; + bForceWeaponSpawn = true; + + newWeapon = Spawn(WeaponClass); + if( newWeapon != None ) + { + newWeapon.Instigator = P; + newWeapon.BecomeItem(); + + if( newWeapon.IsA( 'ut_eightball' ) || newWeapon.IsA( 'Eightball' )) + { + GiveAmmo( newWeapon, P, InitialRocketAmmo, MaxRocketAmmo ); + } + else if( newWeapon.IsA( 'WarheadLauncher' ) ) + { + GiveAmmo( newWeapon, P, InitialRedeemerAmmo, MaxRedeemerAmmo ); + } + else if( newWeapon.IsA( 'ut_flakcannon' ) || newWeapon.IsA( 'FlakCannon' )) + { + GiveAmmo( newWeapon, P, InitialFlakAmmo, MaxFlakAmmo ); + } + else if( newWeapon.IsA( 'shockrifle' ) || newWeapon.IsA( 'ASMD') ) + { + GiveAmmo( newWeapon, P, InitialShockAmmo, MaxShockAmmo ); + } + else if( newWeapon.IsA( 'sniperrifle' ) || newWeapon.IsA( 'Rifle' )) + { + GiveAmmo( newWeapon, P, InitialRifleAmmo, MaxRifleAmmo ); + } + else if( newWeapon.IsA( 'PulseGun' ) ) + { + GiveAmmo( newWeapon, P, InitialPulseAmmo, MaxPulseAmmo ); + } + else if( newWeapon.IsA( 'ripper' ) || newWeapon.IsA( 'razorjack' ) ) + { + GiveAmmo( newWeapon, P, InitialRipperAmmo, MaxRipperAmmo ); + } + else if( newWeapon.IsA( 'minigun2' ) || newWeapon.IsA( 'enforcer' ) || newWeapon.IsA( 'AutoMag' ) || newWeapon.IsA( 'Minigun' ) ) + { + GiveAmmo( newWeapon, P, InitialGunAmmo, MaxGunAmmo ); + } + else if( newWeapon.IsA( 'ut_biorifle' ) || newWeapon.IsA( 'gesbiorifle' ) ) + { + GiveAmmo( newWeapon, P, InitialBioAmmo, MaxBioAmmo ); + } + else if( newWeapon.IsA( 'stinger' ) ) + { + GiveAmmo( newWeapon, P, InitialStingerAmmo, MaxStingerAmmo ); + } + else + { + // not one of the standard UT or Unreal I weapons -- handle all of these + // using "other" initial, max ammo etc. which might not be right... + GiveAmmo( newWeapon, P, InitialOtherAmmo, MaxOtherAmmo ); + } + + // make sure weapon can't be tossed + newWeapon.bCanThrow = false; + P.AddInventory(newWeapon); + newWeapon.SetSwitchPriority(P); + newWeapon.WeaponSet(P); +// mdf-tbd: might be bad to do this... +// newWeapon.BringUp(); + } + bForceWeaponSpawn = false; +} + +//----------------------------------------------------------------------------- +// Only filter weapons that we know about (including weapons added to the +// ExtraWeaponClassStrings so we don't remove anything that shouldn't be such +// as the CGrapple mutator classes. + +function bool FilterWeapon( Weapon W ) +{ + local int i; + local Class C; + + // standard UT and Unreal I weapons + if( W.IsA( 'UT_Eightball' ) || + W.IsA( 'UT_FlakCannon' ) || + W.IsA( 'Enforcer' ) || + W.IsA( 'MiniGun2' ) || + W.IsA( 'PulseGun' ) || + W.IsA( 'Ripper' ) || + W.IsA( 'ShockRifle' ) || + W.IsA( 'SniperRifle' ) || + W.IsA( 'SuperShockRifle' ) || + W.IsA( 'UT_BioRifle' ) || + W.IsA( 'WarheadLauncher' ) || + W.IsA( 'ImpactHammer' ) || + W.IsA( 'ChainSaw' ) || + W.IsA( 'FlakCannon' ) || + W.IsA( 'GESBioRifle' ) || + W.IsA( 'Minigun' ) || + W.IsA( 'Razorjack' ) || + W.IsA( 'Rifle' ) || + W.IsA( 'ASMD' ) || + W.IsA( 'AutoMag' ) || + W.IsA( 'DispersionPistol' ) || + W.IsA( 'Eightball' ) || + W.IsA( 'Stinger' ) ) + { + return true; + } + + // check any weapons specified through ExtraWeaponClassStrings + for( i=0; i( 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); + CountRipperAmmo += (RateRipperAmmoPerSec * TimeBetweenAmmoIncrements); + CountBioAmmo += (RateBioAmmoPerSec * TimeBetweenAmmoIncrements); + CountStingerAmmo += (RateStingerAmmoPerSec * TimeBetweenAmmoIncrements); + CountOtherAmmo += (RateOtherAmmoPerSec * 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), CountRipperAmmo ); + } + else if( Inv.IsA( 'BioAmmo' ) || Inv.IsA( 'Sludge' ) ) + { + AdjustAmmo( Ammo(Inv), CountBioAmmo ); + } + else if( Inv.IsA( 'StingerAmmo' ) ) + { + AdjustAmmo( Ammo(Inv), CountStingerAmmo ); + } + else + { + // unknown ammo type + AdjustAmmo( Ammo(Inv), CountOtherAmmo ); + } + } + } + + 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(CountRipperAmmo) ) + CountRipperAmmo = 0.0; + if( MoreOrLessInt(CountBioAmmo) ) + CountBioAmmo = 0.0; + if( MoreOrLessInt(CountStingerAmmo) ) + CountStingerAmmo = 0.0; + if( MoreOrLessInt(CountOtherAmmo) ) + CountOtherAmmo = 0.0; +} + +//----------------------------------------------------------------------------- + +function GiveInvisibilityTo( Pawn P ) +{ + local UT_Invisibility Invisibility; + + Invisibility = Spawn( class'UT_Invisibility' ); + if( Invisibility != None ) + { + Invisibility.Charge = 99999; + Invisibility.Touch( P ); + Invisibility.Destroy(); + } +} + +//----------------------------------------------------------------------------- + +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; + + DamageAmplifier = Spawn( class'UDamage' ); + if( DamageAmplifier != None ) + { + DamageAmplifier.Charge = 99999; + DamageAmplifier.Touch( P ); + DamageAmplifier.Destroy(); + } +} + +//----------------------------------------------------------------------------- + +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; + + JumpBoots = Spawn( class'ut_jumpboots' ); + if( JumpBoots != None ) + { + JumpBoots.Charge = 99999; + JumpBoots.Touch( P ); + JumpBoots.Destroy(); + } +} + +//----------------------------------------------------------------------------- + +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 ); + } + + if( StartHealth != 0 ) + { + Other.Health = StartHealth; + } +} + +//----------------------------------------------------------------------------- +// 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 ( Other.IsA('UT_Jumpboots') ) + { + bRetVal = true; + } + else if ( NextMutator != None ) + { + bRetVal = NextMutator.AlwaysKeep(Other); + } + + return bRetVal; +} + +//----------------------------------------------------------------------------- +// Only really here to support LastManStanding which Almost 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( bForceWeaponSpawn ) + { + bSuperRelevant = 1; + } + else if( Other.Owner != None && Other.IsA('Weapon') && FilterWeapon(Weapon(Other)) ) + { + // 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( CurrentWeaponClass!= None && !ClassIsChildOf(Other.Class,CurrentWeaponClass) ) + { + ReplaceWith(Other, string(CurrentWeaponClass)); + } + bRetVal = false; + } + + return bRetVal; +} + +//----------------------------------------------------------------------------- +// No weapon by default -- this mutator hands out all weapons. + +function Class MyDefaultWeapon() +{ + return None; +} + +//----------------------------------------------------------------------------- + +defaultproperties +{ + bRandomWeapons=False + bUseAllWeapons=True + bCycleWeapons=True + bUseChainSaw=True + bUseEnforcer=True + bUseImpactHammer=True + bUseMiniGun=True + bUsePulseGun=False + bUseRipper=True + bUseShockRifle=True + bUseSniperRifle=True + bUseSuperShockRifle=True + bUseBioRifle=True + bUseRocketLauncher=True + bUseFlakCannon=True + bUseRedeemer=False + bUseUnrealIFlakCannon=False + bUseUnrealIGESBioRifle=False + bUseUnrealIMinigun=False + bUseUnrealIRazorjack=False + bUseUnrealIRifle=False + bUseUnrealIASMD=False + bUseUnrealIAutoMag=False + bUseUnrealIDispersionPistol=False + bUseUnrealIEightball=False + bUseUnrealIStinger=False + ExtraWeaponClassStrings(0)="" + ExtraWeaponClassStrings(1)="" + ExtraWeaponClassStrings(2)="" + ExtraWeaponClassStrings(3)="" + ExtraWeaponClassStrings(4)="" + ExtraWeaponClassStrings(5)="" + ExtraWeaponClassStrings(6)="" + ExtraWeaponClassStrings(7)="" + ExtraWeaponClassStrings(8)="" + ExtraWeaponClassStrings(9)="" + ExtraWeaponClassStrings(10)="" + ExtraWeaponClassStrings(11)="" + ExtraWeaponClassStrings(12)="" + ExtraWeaponClassStrings(13)="" + ExtraWeaponClassStrings(14)="" + ExtraWeaponClassStrings(15)="" + ExtraWeaponClassStrings(16)="" + ExtraWeaponClassStrings(17)="" + ExtraWeaponClassStrings(18)="" + ExtraWeaponClassStrings(19)="" + ExtraWeaponClassStrings(20)="" + ExtraWeaponClassStrings(21)="" + ExtraWeaponClassStrings(22)="" + ExtraWeaponClassStrings(23)="" + ExtraWeaponClassStrings(24)="" + ExtraWeaponClassStrings(25)="" + ExtraWeaponClassStrings(26)="" + ExtraWeaponClassStrings(27)="" + ExtraWeaponClassStrings(28)="" + ExtraWeaponClassStrings(29)="" + ExtraWeaponClassStrings(30)="" + ExtraWeaponClassStrings(31)="" + TimeRecheck=2.000000 + TimeBetweenWeaponSwitchesMin=50.000000 + TimeBetweenWeaponSwitchesMax=70.000000 + TimeBetweenAmmoIncrements=0.000000 + WarningSound=Sound'Botpack.Pickups.UTSuperHeal' + WarningSoundRepeats=3 + HealthIncrementSound=None + HealthIncrementAmount=5 + StartHealth=100 + MaxHealth=200 + TimeBetweenHealthIncrements=1.000000 + InvisibilityDelayMin=0.000000 + InvisibilityDelayMax=0.000000 + InvisibilityDurationMin=10.000000 + InvisibilityDurationMax=10.000000 + DamageAmplifierDelayMin=45.000000 + DamageAmplifierDelayMax=45.000000 + DamageAmplifierDurationMin=45.000000 + DamageAmplifierDurationMax=45.000000 + JumpBootsDelayMin=0.000000 + JumpBootsDelayMax=0.000000 + JumpBootsDurationMin=15.000000 + JumpBootsDurationMax=15.000000 + InitialRedeemerAmmo=0 + InitialRocketAmmo=12 + InitialFlakAmmo=12 + InitialShockAmmo=12 + InitialRifleAmmo=12 + InitialPulseAmmo=50 + InitialRipperAmmo=25 + InitialBioAmmo=50 + InitialGunAmmo=100 + InitialStingerAmmo=50 + InitialOtherAmmo=50 + RateRedeemerAmmoPerSec=0.050000 + RateRocketAmmoPerSec=0.000000 + RateFlakAmmoPerSec=0.200000 + RateShockAmmoPerSec=0.670000 + RateRifleAmmoPerSec=0.500000 + RatePulseAmmoPerSec=2.000000 + RateRipperAmmoPerSec=1.500000 + RateBioAmmoPerSec=0.250000 + RateGunAmmoPerSec=0.000000 + RateStingerAmmoPerSec=5.000000 + RateOtherAmmoPerSec=5.000000 + MaxRedeemerAmmo=1 + MaxRocketAmmo=48 + MaxFlakAmmo=50 + MaxShockAmmo=50 + MaxRifleAmmo=50 + MaxPulseAmmo=199 + MaxRipperAmmo=75 + MaxBioAmmo=100 + MaxGunAmmo=199 + MaxStingerAmmo=200 + MaxOtherAmmo=200 + NumWeapons=0 + FilteredWeaponClassStrings(0)="" + FilteredWeaponClassStrings(1)="" + FilteredWeaponClassStrings(2)="" + FilteredWeaponClassStrings(3)="" + FilteredWeaponClassStrings(4)="" + FilteredWeaponClassStrings(5)="" + FilteredWeaponClassStrings(6)="" + FilteredWeaponClassStrings(7)="" + FilteredWeaponClassStrings(8)="" + FilteredWeaponClassStrings(9)="" + FilteredWeaponClassStrings(10)="" + FilteredWeaponClassStrings(11)="" + FilteredWeaponClassStrings(12)="" + FilteredWeaponClassStrings(13)="" + FilteredWeaponClassStrings(14)="" + FilteredWeaponClassStrings(15)="" + FilteredWeaponClassStrings(16)="" + FilteredWeaponClassStrings(17)="" + FilteredWeaponClassStrings(18)="" + FilteredWeaponClassStrings(19)="" + FilteredWeaponClassStrings(20)="" + FilteredWeaponClassStrings(21)="" + FilteredWeaponClassStrings(22)="" + FilteredWeaponClassStrings(23)="" + FilteredWeaponClassStrings(24)="" + FilteredWeaponClassStrings(25)="" + FilteredWeaponClassStrings(26)="" + FilteredWeaponClassStrings(27)="" + FilteredWeaponClassStrings(28)="" + FilteredWeaponClassStrings(29)="" + FilteredWeaponClassStrings(30)="" + FilteredWeaponClassStrings(31)="" + FilteredWeaponClassStrings(32)="" + FilteredWeaponClassStrings(33)="" + FilteredWeaponClassStrings(34)="" + FilteredWeaponClassStrings(35)="" + FilteredWeaponClassStrings(36)="" + FilteredWeaponClassStrings(37)="" + FilteredWeaponClassStrings(38)="" + FilteredWeaponClassStrings(39)="" + FilteredWeaponClassStrings(40)="" + FilteredWeaponClassStrings(41)="" + FilteredWeaponClassStrings(42)="" + FilteredWeaponClassStrings(43)="" + FilteredWeaponClassStrings(44)="" + FilteredWeaponClassStrings(45)="" + FilteredWeaponClassStrings(46)="" + FilteredWeaponClassStrings(47)="" + FilteredWeaponClassStrings(48)="" + FilteredWeaponClassStrings(49)="" + FilteredWeaponClassStrings(50)="" + FilteredWeaponClassStrings(51)="" + FilteredWeaponClassStrings(52)="" + FilteredWeaponClassStrings(53)="" + FilteredWeaponClassStrings(54)="" + FilteredWeaponClassStrings(55)="" + FilteredWeaponClassStrings(56)="" + FilteredWeaponClassStrings(57)="" + FilteredWeaponClassStrings(58)="" + FilteredWeaponClassStrings(59)="" + FilteredWeaponClassStrings(60)="" + FilteredWeaponClassStrings(61)="" + FilteredWeaponClassStrings(62)="" + FilteredWeaponClassStrings(63)="" + CurrentWeaponClass=None + CurrentWeaponIndex=0 + NumUsedWeapons=0 + UsedWeapons(0)=0 + UsedWeapons(1)=0 + UsedWeapons(2)=0 + UsedWeapons(3)=0 + UsedWeapons(4)=0 + UsedWeapons(5)=0 + UsedWeapons(6)=0 + UsedWeapons(7)=0 + UsedWeapons(8)=0 + UsedWeapons(9)=0 + UsedWeapons(10)=0 + UsedWeapons(11)=0 + UsedWeapons(12)=0 + UsedWeapons(13)=0 + UsedWeapons(14)=0 + UsedWeapons(15)=0 + UsedWeapons(16)=0 + UsedWeapons(17)=0 + UsedWeapons(18)=0 + UsedWeapons(19)=0 + UsedWeapons(20)=0 + UsedWeapons(21)=0 + UsedWeapons(22)=0 + UsedWeapons(23)=0 + UsedWeapons(24)=0 + UsedWeapons(25)=0 + UsedWeapons(26)=0 + UsedWeapons(27)=0 + UsedWeapons(28)=0 + UsedWeapons(29)=0 + UsedWeapons(30)=0 + UsedWeapons(31)=0 + UsedWeapons(32)=0 + UsedWeapons(33)=0 + UsedWeapons(34)=0 + UsedWeapons(35)=0 + UsedWeapons(36)=0 + UsedWeapons(37)=0 + UsedWeapons(38)=0 + UsedWeapons(39)=0 + UsedWeapons(40)=0 + UsedWeapons(41)=0 + UsedWeapons(42)=0 + UsedWeapons(43)=0 + UsedWeapons(44)=0 + UsedWeapons(45)=0 + UsedWeapons(46)=0 + UsedWeapons(47)=0 + UsedWeapons(48)=0 + UsedWeapons(49)=0 + UsedWeapons(50)=0 + UsedWeapons(51)=0 + UsedWeapons(52)=0 + UsedWeapons(53)=0 + UsedWeapons(54)=0 + UsedWeapons(55)=0 + UsedWeapons(56)=0 + UsedWeapons(57)=0 + UsedWeapons(58)=0 + UsedWeapons(59)=0 + UsedWeapons(60)=0 + UsedWeapons(61)=0 + UsedWeapons(62)=0 + UsedWeapons(63)=0 + NumWarnings=0 + NextChooseWeaponTime=0.000000 + ChooseWeaponWarningTime=0.000000 + NextIncrementHealthTime=0.000000 + NextInvisibilityTime=0.000000 + NextKillInvisibilityTime=0.000000 + NextDamageAmplifierTime=0.000000 + NextKillDamageAmplifierTime=0.000000 + NextJumpBootsTime=0.000000 + NextKillJumpBootsTime=0.000000 + NextAmmoIncrementTime=0.000000 + NextTimeRecheck=2.000000 + CountRedeemerAmmo=0.000000 + CountRocketAmmo=0.000000 + CountFlakAmmo=0.000000 + CountShockAmmo=0.000000 + CountRifleAmmo=0.000000 + CountPulseAmmo=0.000000 + CountRipperAmmo=0.000000 + CountBioAmmo=0.000000 + CountGunAmmo=0.000000 + CountStingerAmmo=0.000000 + CountOtherAmmo=0.000000 + bDidTick=False + bForceWeaponSpawn=False +} diff --git a/System/NIUT.ini b/System/NIUT.ini index 7c7c06c..75d30cc 100644 --- a/System/NIUT.ini +++ b/System/NIUT.ini @@ -1,4 +1,4 @@ -[NIUT125.NIUTMutator] +[NIUT126.NIUTMutator] bRandomWeapons=True bUseAllWeapons=True bCycleWeapons=False diff --git a/System/Niut.int b/System/Niut.int index 7c89a36..ddf81c5 100644 --- a/System/Niut.int +++ b/System/Niut.int @@ -1,5 +1,5 @@ [Public] -Object=(Name=NIUT125.NIUTMutator,Class=Class,MetaClass=Engine.Mutator,Description="NIUT125, NIUT V1.25: Server controls weapons, gives out ammo and/or turns pickups into ammo or health vials (www.planetunreal.com/niu).") +Object=(Name=NIUT126.NIUTMutator,Class=Class,MetaClass=Engine.Mutator,Description="NIUT126, NIUT V1.26: Server controls weapons, gives out ammo and/or turns pickups into ammo or health vials (www.planetunreal.com/niu).") Object=(Name=NIUT125.NIUTConfigMenuItem,Class=Class,MetaClass=UMenu.UMenuModMenuItem) Object=(Name=NIUT125.DummyArenaMutator,Class=Class,MetaClass=Engine.Mutator,Description="DAM, DummyArena: use with some game types (e.g. LastManStanding) to force ammo to stay etc.") diff --git a/System/niut125.u b/System/niut126.u similarity index 61% rename from System/niut125.u rename to System/niut126.u index eb952273d6eb0fc29ab554b454acbb086287264f..dc31a34fb2ecda183d6747dabf4b0bfa507b76c6 100644 GIT binary patch delta 32744 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 delta 30369 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