*E PsVPH ?sF0vc None PickupPlusEnhancedWeaponEnhancedItemsCoreEnhancedProjectile ReplaceWithEnginePlayerShellEffectSystemMultiPickupPlusBeginUpdateAppearanceClientMessageBotpackHoldablePowerup SelectNextIdleFindInventoryType TimedPowerupBotDesireability AdvancedHandlePickupQueryReceiveLocalizedMessagePickupInventoryErrorBotEnhancedMutator Activated BeginState LogPickupUWindowAddDamageActorRemoveDamageActorTickChooseNextItemUsedUp PreBeginPlayAddItem UseHoldable ClassIsA TakeDamageLogItemActivate Vanishing ActivateLogItemDeactivate EnhancedAmmo OtherIsA EndStateDamageIsTypeOfCompact SetKillType DestroyMe AlwaysKeepRestoreKillTypeFormingVisibleDeathMatchPlusDamageProtectionFactor SplashDamage NextItemRegenSuggestionPreRenderOverlaysForReturnMessageActorModifySubMunitionChooseGetIdealFatnessAdjustSplashDamageTypeClientPlaySoundPrioritizeArmorEnhancedArenaPickupFunction UpdateFlash PlayerPawn BeforePaint RecommendUseSpawnMIConverter DeActivated Destroyed LabelList RemoveItemTimer AliasNamesAlwaysKeepInMPP CheckMPPSpawnEIChallengeHUD UnitDisplay UnitRatio UnitFullNamePostBeginPlay DirectHit TimedOutSpawnExplosionEffectsCreatedDrowned AddMutatorDoActiveAction SetRespawn ShowShell GetMaxOffsetShowMe Explosion EIDMMutatorMaxDesireability PlayerSphere GiveAmmoSpawnSubMunition GetCharge ItemPickedUpCheckReplacementDeleteInventory PickupShellPostRenderOverlaysForArmorPrioritybAllowOnlyOnceArmorAbsorbDamage FireFunction RespawnTimeChargeSuicideStringSuicideFString BecomePickupReplaceDMMutatorHeadHitStringDirectHitString SpawnedItem DrawTypeSetSwitchPriority RemoteRoleSplashHitString AllowPickupStaticGetItemNameRenderOverlays PostRenderHeadSuicideString LoadItemMinGlowStopEmulationGiveToMaxGlowNotifyMutatorsMutate SetFlashTimeProjectileFireAdjustLocation OwnerJumpedDeactivateActionHeadSuicideFStringIsSplashDamage GoodUsageUseAmmoWeapon TraceFireHeadShotHeightHeadShotDamageFactor ValidTouch PlayRecoilHeadDamageType CreateShell SleepingSplashDamageTypeOldRenderOverlaysMutatorTakeDamage bActivatableTrigger LoadSettingsEstimatedHitNormalSpawnedEIChallengeHUDParseKillMessage GetInfoOnPlayerJumpZScalingPlaySpawnEffectGetSuicideString GetStringCheckLocation SpawnCopyArmorImpactEffect MIConverter TimedActionActivateAction DecapitatedReady AmbientGlowbAutoActivateRegisterHUDMutator!MutatorBroadcastLocalizedMessage PrevItemAbsorptionPriorityArmorAbsorption HideWindow ShowWindowCloseUp DeSelect M_ActivatedSetHelpGetDesiredDimensions M_SelectedbUnlitBlowUp EIEffectsNoAlwaysAutoActivate FireEffect ProtectNoneM_DeactivatedbDisplayableInvPushStationaryPawn DeathMessageLODBias CorrodedSwitchPrioritySetOwnerDisplay WeaponSetIdle2HealthPhysics RateSelfSelect GetHumanNameClientAltFireSetWeaponStayClearBurned AddInventorybNetTemporaryPickupMessage DownWeaponChangedWeaponbHiddenAltFire ActivateItemCollisionHeightRegisterDamageMutator ScaleGlow DrawScale ItemNameCollisionRadiusFire SectionName PickupQuerySpawnNotificationAmmoClientReceive ClientFireStyleExplode NormalFirePawnMeshTextureBringUpSetHandTouch BecomeItem AltFiringHitWall GetOffsetbAlwaysRelevant SuperHealth bOwnerNoSeebUseVortexSphere SizeAdjust MaxOffset MinOffsetMaxSizebMeshEnviroMapEndSizeSVANISH_GrowFadeSVANISH_ShrinkFade StartSizeSVANISH_ShrinkSVANISH_Instant SVANISH_Fade SGLOW_Blink SGLOW_DarkenSGLOW_RestoreSuggestedRegeneration SVIS_Restore SVIS_Collaps SVIS_ExpandSFORM_GrowLightUpSFORM_LightUp SVIS_PulseRotationFromVector LifeSpanModeSpawnDamageScalingbKeepDamageScaling PlayerShellbTrailerSameRotationEnhancedDeathMessageEIUseHoldableReplaceWithItemReplaceWithItemAsMPPEWindowEditControlMultiPickupBaseClass GetDMMutator KeepClassesMegaSpeedFactorEWindowComboControlbReplaceInvisibilitybReplaceShieldbeltbReplaceAmplifierbReplaceArmorbReplaceHealth bReplaceAmmobReplaceWeaponsbSetMegaSpeedbKeepStationaryPawnsUTMenu AnyClassIsAMinSize bAnimByOwnerbEmulateWhenCoopModebAllowItemRotationUMenubAutoUseHoldablesbMoreUsageChecks JumpBootsYPosFlakBoxFirstPickupPlus RazorAmmoPlayGlobalSoundNextPickupPlusFrozen RifleRoundResetSpeedFactorSetSpeedFactor InvisibilityResetOwnerSpeedSetOwnerSpeed SetOwnerMassResetOwnerMassUnRegisterAsAffectorRegisterAsAffectorRifleMinigun FlakCannon UsedUnit GESBioRifle ShellBox TorchFlame PickupSoundActivateSoundClipbEnhancedStatusDollbAllowSameClassPickupWeaponPowerUp EightballStinger NaliFruitAddToOwnerSpeedAddToJumpZFactorSetEffectTexture ShieldBelt SGLOW_Steady SVIS_NoneSGLOW_LightUpSFORM_InstantEIDeathMessageSpawnNotify SFORM_GrowEnhancedKeyBindingsJumpbootsDummyEWindowPulldownMenuItemShieldBeltDummyThighPadsDummy FiredFromMySpawnNotifyClassEnhancedDeathMessageClassEWindowDialogClientWindowReplaceWithMPP ConvertToMPPEIDeathMessageMutatorEWindowPageWindowEWindowPulldownMenuEWindowRightClickMenubSetAutoActivatebRandomChoosingDefaultDurationTournamentPickupTournamentAmmo FinalCount MaxRangeTournamentHealthProjectileNameTournamentWeaponbDeactivateCountFinalCountIntervalTimingInterval FullChargeEstimatedPawnHitpointsSludge FlashShellExpireMessageResetDamageFactorSetDamageFactor RifleAmmo AddMenuItemConvertDistance Razorjack DecimalChar RocketCan KevlarSuit StingerAmmo ReplaceText DeniedRadiusArmor ASMDAmmo BandagesAddToBuoyancyFactorAddToDamageFactorRegisterMessageMutatorAddToMassFactorbDrawShieldOverWeapon AmplifierASMDAddToSpeedFactorDispersionPistol MultiItemAutoMagNotify LifeSpawn LMouseDown SetControls FindItemInItem LMouseUpAppendFocusOtherWindow SetCaptionDisableCoopMode RMouseDown ReplaceItem RMouseUpParentPageClass ListClassUnRegisterFromWeaponsbAllowItemFallCalcZoomedFireOffsetEWindowCheckbox SpeedScale GiveWeapon IsAffectorOfHoldableUseMessageUseMessageClassUWindowDialogClientWindow UWindowListUWindowRootWindowUWindowComboControlUWindowListControlUWindowPulldownMenuItemUWindowSmallCloseButtonPulldown_HBorderUWindowCheckboxUWindowEditControlaClassOther DeltaTimeUWindowDialogControlUWindowWindowhandUWindowPulldownMenuUWindowMenuBarItemAmountGetPlayerOwnerbTemp Accuracy ItemHeight bNetOwnerFlashSFlashYFlashO ViewTarget WinHeight WinWidthWinTop bByOwnerbSetFlashTimebDrawMuzzleFlashHMaxHMaxWPulldown_VBorderPulldown_TextBorderItemTopPulldown_ItemHeight damageScale SelectedItemProjectileClassAltProjectileClass WeaponName bInstantHit RelatedPRI_2DirCalcDrawOffset DifficultyPKiller EyeHeightkUWindowLookAndFeel actualDamageNextMessageMutatorMessageMutator Receiver Momentum bHUDMutatorNextHUDMutatorClipXReplaceWithSetAcceptsFocus CreateWindowRemoveAmpersandAltProjectileSpeedWallItemMessageClass FullNameExplosionDecal ExploWallOutbWindowVisible AmmoAmountProtectionType2 duration bSleepTouch bHeldItemMomentumTransferMaxAmmo NumCopiesbCanHaveMultipleCopiesNewItem ParentWindow HelpTextAlign ParentMenuWinLeft Distance aClassNameVictim bPlayerOwnerUMenuStatusBarUMenuPageWindow MFTexture bTransientItemsVBorder StatusBar FlashLength HandednessFlashC DefaultFOV EditBoxWidthHBorderBaseEyeHeight AmmoStringUT_ShieldBelt UT_Jumpboots ChallengeHUD bMuzzleFlash FlashTime ThighPads MaxWidthCurItemCaptionMaleSuicideMessage TextBorderFemaleSuicideMessageDoubleSwitchPriorityRangeTournamentGameInfo DMMutatorDeathMessagePlusPickupMessagePlus DoubleNamebNovice bRatedGame bNoviceModeRootOutputValueYLFontsbCanClientFire bIsSlave bBringUpMaster ShockRWM IdealFatness ItemClassbHelp bDeleteMebSuperRelevantAutoSwitchPriority MyDamageType BobDamping ViewRotationDamageScalingSetPostHGraphic FireOffset NextMutatorNetModebCoopWeaponMode FiringSpeed bRapidFire bWeaponStay bHideWeaponVictimsSubMenubAltInstantHit AirSpeedbSplashDamagebAltWarnTargettW AmmoType bPointing TimeSecondsOptionalObject LookAndFeel InsertAfter bIsPlayerPickupAmmoCount AmmoNamePendingWeapon ArmorDamage FirstArmorNumber CloseButton MuzzleScalebFound LastItem bIsFemalebIsPawn bSplashHit bHeadHitbDamageTriggeredWeaponPrioritybHighDetailModeCopyMaxSpeedFactorMinSpeedFactor bDropEffects PawnOwner WeaponBobGlobalRespawnSoundGlobalPickupSoundDeniedAnnounce ShellEffectPickupShellEffect ShellType ShellSkinbShellAlwaysOnbMakesInvisiblePickupShellSkinPickupShellType BlinkIcon DrawOffsetSenderdesire AlreadyHasDesiredAirControlbWeaponSpeedUp bPawnSpeedUpbPawnDamageUpIndexPickupMessageClassbPawnMassAffectbIsSpecialArmor bAltChargebIsChestArmorbIsThighArmorbIsShieldArmor bIsBeltArmorbIsGlovesArmorbIsBootsArmorbIsChestSpecialbIsThighSpecialbIsShieldSpecialbIsGlovesSpecialbIsBeltSpecial bIsJumpBoots AltChargeProtectedDamageFactorbDeniedAnnounce RespawnSound ReplaceTagDeActivateSound NextAffectorAffectedWeaponbFireEffectLastbRenderOverlays HitLocation bIsAnArmor bDebugMode AccelRate RotationRate LightType NewWeaponProtectionType1bFindIdenticalNoneNone TextSizebRotatingPickup InfoType OtherInfotmp bMegaSpeedNewUnitOldUnitbNoUnit bLongName DistanceText bNoChange interval numitems AffectorsMassNetUpdateFrequency AnimTime MultiSkinsEffectsbActivenewDamageFactorDamageInvnewMassFactor DesiredClass instigatedBy newFactor HUDMutator RotationnewSpeedFactorEW markedItembCollideWorld DamageType TestTypeCountertempFactor DamageFactor myMarker HitPointsClipY GlobalSoundbDontPlayInSlotA PlayerOwnerXCEM logOwner PrevOwnerNextDamageMutator bKillsOwner bMultiUsebInstantAutoUseProjectileSpeedUseMeUMenuRootWindowUseText ReUseText InitializedEZYUrgent TestClassW PriorityName Remaining WeaponClassSN FinalCounterbPreFinalCount DesiredFOV bAddChargebDeactivatedUseChargePitchRolljiSamePriorityLike MenuMeshMenuViewScale MenuRotation WeaponString SlaveWeapon MasterWeaponbCustomDrawSlaveDoublePriorityNameArena ScriptTextSG ReturnValueDynamicLoadObjectMaxMutatorHeadShotMessagebCanHeadShootbConstantSplashDamageFatnessOffset LevelInfo GameInfo ProjectileInventorySpotSplashMomentumSplashRangeModifierMomentumModifierExplosionEffectClassSubMunitionCountSubMunitionClassDeathMessageActorClassbDrawingWeapon bJumpMatch bOverrideHUDPlayerReplicationInfo CurLocation HitLevelExtendHN ColliderStatLogDecal bSpecialHitmomentumScale ScaledRadius SavedSStringSavedFSString SavedDString SpawnNotify InventoryCanvasFontLevel bFoundDouble MaxNumItemsTextImportedFromMI ReplacedItemLocationOffsetInitRespawnTime RejectChanceMyGamebEmulateMultiItemDeathMessageClassbNoMutatorCheck AffectorbForceItemRotation DesiredNamebForceItemFall bNoEmulation bStarted bNotifiedCurTime CurItemIndexPrevItemIndex CheckCounter CreatedByMoverbCorrectLocationActorUTExtraKeyBindingsLookFor bSubClassesbCheckReplaced bFoundItembIdenticalClassesPlayerViewOffsetNewItemOffset NewInitTime NewChance NDuration NewDuration NewItemClass MenuName ItemIndex bWasEmptyLodMesh bHurtEntry InitTimeChance AlwaysAddPlayerCount ClassNameSoundMessageRoleNewRot WorldLog LocalLogDamageMutator BaseMutator HitActor bBehindViewbReplaceJumpBootsdistposDefaultWeapon DrawIcon PawnListTagEventClassMyChallengeHUDbPendingHUDRegistration FovAngleParentbAlwaysCreateMPP LocationPackage PrevMutatorBaseNextMutatorNewBaseMutatorInput bWarnTarget MPPClass OtherClass DamageName DamageRadiusMPP AirControl DamageActor bHeadShotbUseMeInsteadJumpZ RelatedPRI_1MySpawnNotifyConst NewActorSwitchiSwitch SelectedNonebUsedHoldableHitType TempString TextBufferbFemale PlayerSelect MyTargetbKeepLightEffectsOwnerbLifeSpanMode bNoLifeSpanLoc GroundSpeed WaterSpeed AnimRate NewDirection OldRotator NewRotatorbHitLevelOnly bDestroyMeObject FormTime VanishTime VisibleTime GlowTimeEnum FunctionCurGlow GlowRate EFormAnim nextPawn bNetInitialFatnessmyHUD FormAnim EVisibleAnim Instigator TouchingbQuietbIsSuperWeaponNext VisibleAnim EGlowAnimGameWalkBob IdenticalTo PlayerName bIsSpectator GlowAnim EVanishAnim VelocityItemMEIDMM NewLocation VanishAnim bIdleLightCurSize LocalMessage HitNormalGetNextIntDesc CurOffset DesiredType BuoyancyState NewFlashTimeRotatorVectorStructName StrPropertyStructPropertyClassProperty NamePropertyDamageProjectileClassMaxDamageFactor bAutoSizebOpenedToLeftbLoadedMinDamageFactorObjectPropertybDeactivatablePageClassNamePageProperties AltValueFloatProperty BoolProperty IntProperty MutateString BytePropertybNeverAutoActivateNoneNonebMIConverterSpawnedRecursionCountE5sP::$-7IXu6tttГГГtГԝXГtГГГГԝXГГГԝXԝXГԝXԝXГԝXe[tt& & ttГe[e[e[& & tttГtt^ԝXttԝXԝXttttttttttГГГГГ> Y> Y{#U> Ye[e[e[e[e[e[e[ԝXԝXe[e[e[tt> Y> Y> YԝX> YtttГГГГГГГГГГtГГГГГГГГtttt-%nttt-%ntttttttttttt-%nttt-%nttttttttttttttttttXu6&̻&̻&̻&̻&̻&̻&̻&̻&̻ttttt& & ttԝXГ& & ГtГtГГГГГ> Y> Y{#U> YГГ& & ГtГtГГГГГ> Y> Y{#U> YГ55ҥ=$:e=$:e=$:e~qԝXГԝXГҥҥ[$?a$?a$?`$?]$?Z$?V$C[^ZW$?W0BW5 BWFVAV-UUVmVydVftX] Unreal UnitsXMetersXYardsXFeetQ].S"xcMB] activated.E= selected.L] deactivated.GGiGB]g(,::$-::$-~7P&̻> Y> Y> Y> Y> Y> Y> Y> Y> Y> Y> Y> Y> Y> Y> Y> Y> YԝXѸBt_GɃԝXԝXԝXtL]tԝXԝXԝXԝXtԝXԝXtttX'X'ԝXԝXԝXtL]ԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝX55ѸBtѸBt> Y> Y> Y> YtxxxxxxxxxxxxxxԝXtx> Y> Y5I=$:e=$:eҥ=$:e> Y> Y5I=$:e=$:eҥ=$:ettԝXttttҥҥ=$:e=$:e=$:ey$?A]bullet|]%k killed %o with the %w.A]%k killed %o with the %w.{]%k put a %p in %o's head.w] killed his own dumb self.x] killed her own dumb self.F] put a %p in his own head.S] put a %p in her own head.$@FY$R?Z$?]u`;P]%k was to heavy for %o.GGdC|ҥ=$:e=$:e> Y> Y5I=$:e=$:e=$:e=$:e> Y5I> Y> Y5I> Y5I=$:e> Y5I> Y> Y5I=$:e=$:e=$:e=$:e> Y5I> Y> Y5I> Y5I=$:e> Y5IГГГГГГГГГҗOГГГГГГГГГГГГГГГГГГГГГГГГГГГГГГГГГEڄГГГГEڄГГГГҗOEڄГГГГГEڄГEڄГГEEEEڄГГГГEڄГГГГEڄГEڄГEڄГEڄГEڅtX'X'X'X'X'X'X'tX'> YX'tX'tttX'xWoʍ[,ԍԝXԝXoʃԝXԝX[,ԃԝX=$:e=$:e=$:e=$:e=$:e=$:e{m=$:e=$:e=$:e=$:e=$:e555I5I=$:e=$:e=$:e=$:e=$:e=$:e=$:e=$:eҥҥ=$:e=$:e=$:e=$:e=$:e=$:eg]EnhancedItems.MultiPickupPlusGx\a!::$::$-"77oʭ__GɃԝXԝXԝXԝXtL]ttԝXԝXԝXԝXtԝXԝXttԝXԝXԝXtL]ԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝX55yrүԝXmmmttҥҥo|]%k killed %o with the %w.A]%k killed %o with the %w.{]%k put a bullet in %o's head.w] killed his own dumb self.x] killed her own dumb self.F]  put a bullet in his own head.S]  put a bullet in her own head.Y$R?Z$?]u`;_^$?Gmy C ::$ !%6VEڄГҗOГГГГГԝXҗOГГГГГГГГГГГГГГГГX'ГГГ=$:e=$:eҥ=$:e=$:eYӡ=$:e=$:e=$:e=$:eҥ=$:eYӡ=$:eГEEڊX'X'X'X'ГГГҥ{$Azyzvg$?eB@~m$ Ah$ AGGGGbG*! G GXGGI GG]GRLw)d}2նmxo xK4螠;aG;aG;aGEf$.'l.'l.'lնmնmնmo d}2նmնmնmնmo նmնmo o d}2d}2;aGd}2d}2K4螠;aG;aG;aGq DԌԌԌԌ tqGGFGGvGJGGXGGGG-{}U  e[{qCtԝX> Y> Y DaSaX @Q$?~uGGGeVu5ҥ=$:emmZ%ՆZ%ՆmZ%ՆqV pZrGGGG~ GGHGGAGeGG9GGrGGeGGE  GGG}GG`@GGGlGGRGGcKDX[-$$w.*-J'[稨! NextPickupPlus:Wis not owned by a PawnLTwL*x-$-Jr.L*ppFound an un-owned item (WL) in inventory chain ofW!wL稨ItemWLin same inventory chain likeWis owned byWLinstead ofW!La/!.L=rL-$O-J稨Wloops to itself in inventory chain ofWafterSxsteps!稨Wloops to itself afterSxsteps and has no owner!*==x;-$-JInfinite recursion in inventory chain ofW!;Infinite recursion in inventory chain ofW!*LLf* GNGGp GGGfGG_GeGG[GGgGGo!GGv GbGG(QA=rQ*;-$FirstPickupPlus: No pawn specified.*rQ*-$稨FirstPickupPlus:WQhas no inventory.*sQws*uP-$wsQ稨ItemWsin inventory chain ofWQis owned byWs!rsa/!.su-$Infinite recursion in inventory chain ofWQ!*ss*  GB GTK 7/7I>ttt7I>& & ԝXԝXԝXtГГ7I>7I>tГԝX~qttt7I>& & ГГ~q}}q u$pBg$?B E L GGGGGGt  GGGGGDGGD GGdGGGTGGGGGT GGNGGJGGkGGa GGGGnGGNGGxGG]GGLGGPGGJ@GG| GGE GGHGmGGJGGTGGRGGPGGHGGGGGGfG@GGGGGGG~GGGGKGGZ !GEGGtGGgGGHGGhGGK@GGo GGDGGOGG@GGlBU%(UB~UQ|ZppZUP UU}Q~UQZpZU-Y BZZ  GGGGGBGuGGUGGGG! Sk  ::$7:w3!ԝXԝX& & e[ԝXԝXԝXГw3!& & ГtГtГГГГГtw3!w3!w3!w3!& & e[~$@F$4BE$?D"Cu$Bg$ @GG|GGGGRGGr GGiGGGUwc69~qҥ> YГГ7I>Г> Y> Y> Y> Y> Y> Y=$:eГГГ^ГГtГГГГtttГГtttttГttГttttt=$:ettГГ7I>Г=$:e|rGG`@GGGG GGmGGmGGzGGLGGn@GG}GGa GGGGB@GGoGGuGGEGG@GGAGGGGCGGGGz!GOGGZ@GGGGGGXGGGJlhZ%ՆmԝXԝXoʃԝX[,ԃԝX{qCԝXҥԝX G_y.3[,L#!55ҥҥ U:=GGSGGUGGuGGZ@GG\GGEGGNGGGGDG_ G GSGGGGGhGGGG,GGdGGZGGMGG+GGGwGGG3 GRGGGG8GGsGGVGGeGQK(CN+{NnNFrK* z(s|VKn|WK'wK*|WKY'wK*|WKU' w[K*|W[KF';wK*|WK`'c{n`n '|w`*aK`(  G1Ay f<{m!J-%nԝXtttttԝXԝX-%n-%nГ-%nԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝX^ԝXԝXԝX-%nԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝX=$:e=$:e=$:e ytsrqpomlnj$33?GGvGGGZGkGGQGGGGGGD@GGY GG GGpGGs@GGFGG<GGHGGGGGGGGGGG@GGGGPGG@GGRGGuZC3rlwl*Fla/!Id.lI-b zrd*daZdaZd DZ 'll G~ GGGGY@GGtGGFGGD!G@GGwGGGh GGGGGgGGcG@ ] 3g74.,w@*@ ?-] -O  G?GGGGGtGGyGG|GGh GGmGGGGfGGgGGGG{GGr G\GG`!GGGGpH 3$.,w_*_ ?-H -G  GGGBGGv V/./rV* T!G T!G(EVa/T'tVa/!.VYTVa/!.VUTVa/!..[VFTVa/!.V`T(  G]GGK GGlGGGGG{GAGB GGUGG~GGGGfGOGGcGmGGGGhGGIGGOGGR GGmGGGGo6u)hrf-t-~w*.w*. r*. !<.%%**a @S.Sa.-f/a8 [e w[w[*[-[ DH10ff-G-rd.dd.dw*."w*.`r*. !.%%**a @S.Saf.-f/a8 [eedw[w[*[-[ DH10'ur*(  Gj@GGWGGiGGUGGEGGHG~GGG G}GGH @GCGQ\ F$YӡԱГГEEEEEEEEEEEEڃԝXԝXԝXX'X'X'ѸBԝXѸBѸB=$:eҥҥҥ i]Botpack.TranslocatorGGu GGm GGtGc GGGG_GGKGQ_K B -d -d('r.* _?I5.wI*wII-I-d_I[II(H._> A GGGYGGGQGGrG]GGLGG[ !GGGGNGGI%JQ& -? -?('r.* %.kw.  *%.@@5.w*w--?%c(.%wa/!9%.w.  *%?%.5.Yw*Aw--?a%%a(.%%?a/!9.-%ff?5.Hw*0w--?%g(..%> @..%> @..%> @..% G@GGE GN GGpGGv GGRGGxGGJGGGUGGJGGGG@@NfH{qCG55 GGY GGf@GGVGGpGGk@GGG\KN8 rK* ?rKK>>*m.Kwm*rm>m>>>*m.m>XD* G]GGlGtGG@GGt6%w_*_! GGx e G\, -c -c(L.e DrL*r.* P?E5.wE*wEE-E-cPEaEE(eLYLYP> @*wLD*ILD GF@GGSGBGGhGG~GGmGGEGGP @GGMGGWGGhGGK @GjGGOGGGGoGGb GGaGcG`@GWGGIGGI GGcGHGGgGgGG\GeGaG_GGGGGCGG\G_GGLGGvGGlGPHlq D;aGd}2d}2d}2նmնmնmնmնmնmնmնmd}2d}2նm GGYGGS@GGWGGGGRGGWGGbGGQGGxajaEra*(M%[M!ErM *QQrM a- pInItem: FoundVM insideWas #SMEM[QQ-paM aC- ppInItem: FoundVM (subclass ofWa) insideWas #SMEM[MoE']r**(]ra*-o- 稨InItem:Wreplaced aV*E']]-p-oa*aP- pInItem:Wreplaced aV*(subclass ofVa)E'( GpGGGGhGGaGGP GGGGg G}GNGGh G|GNGYGGQGGQ @FGGGZ GGGhGGa@GGGG@G~ GGGGGGGGzGG\GGCGGV GGTGGGGGGg GGhGGGG[GGGG Gqk GGGGGJGGb6m4w@*@! G]GGGGG@GG)GGvGG[GGGGZ sP*" #*9zFFW}F r}* {FW稨pW:Fis not a valid MultiPickupPlus subclass, using default.}W xr}*稨pW:Wis not a valid MultiPickupPlus subclass, using class'MultiPickupPlus'.}EnhancedItems.MultiPickupPlus w}*#a} կ}#? aw*#Qw#*#*w#*::::$#-`'::$#-U(b- "26# %6# %#-K(#-K "-- "#-Z "-4- "###*#~#pppW: Error: Couldn't spawn MultiPickupPlus (F)* GwGGGwg G^ GWGGZ GGtGGGGaf GGGGGpNvb&::$d amK@w*4ZwH*H4 GuGGw GGF GG}GZGGGP K AGBGQ GtGG}GG^GG^GG[GGDGGK"KR6J-m #r.* -?'".kw.  *".@@5.w*--?"c(."na/!9".w.  *"?".5.Cw*+--?a""a(.""?a/!9.-"ff?5.%w* --?"g(.."> @.."> @.."> @.." GS GGMoM8G -\ -\('r.* o?+5.w+*w++-+-\o+l++(H..oo?+5.qw+*Yw++-+-\o+D++(..o GsGGauL#D-K #r.* -\'u?85.w8*8-8-\u8l88(L..uu?85.[w8*C8-8-\u8D88(..u GgGGnGG`GGi^L?-a #r.* -d'^?W5.wW*W-W-d^W[WW(L.^> A G|GG@GGjGGGGA GGGGpGGTGGXGGUGGjGGkGGxGGhG]@GG@GGcGbGGq GGp GGbGGwGGj@GW @G\ GGzai2~-a!G a!G(/%/!Zr/ */ a- pFindItem: FoundV/ insideWas #S/~/-kva/ !/ Ua9a/ !/ `a- ppFindItem: FoundV/ (identical toWa) insideWas #S/~//4~'.-\  r**(.da*T- 稨FindItem:Wreplaced aV*~'..-k^a* *Ua-a* *`a!- pFindItem:Wreplaced aV*(identical toWa)~'( GnGGu@GGsGGoGGrGR Gj GG>GDGGGGGxGyGzGEGh GG}GJ G{GGB GAG^ GQ@GGFGC GGgGGy.GGGG]l (JA yl F   GTGGFdR a!q!7 GJGG[G +P\/:a:$ ?%aD-qq!Ga GLG$@GGO GG GG` GGwGGGGIX7qB d-( H:b:$ 2?%a2q!8 GTG` GbGGGK o:  GUGU GT~8hUvavvArq!+ GXGAGGnGG_GS GD  GQ @GGk] bDDDD G@ GSGGVGGGGSGG GGlGG GGEGGGGa GGqGGGc GGxGGGjGGT@GG\Gm GGuG}GYGG.GGI GGZGG[GO  GGG`GZ"-r*q! a  a+  D  GB!GEGGP@G: GGGS H GGGi GGPGGH=G^ GGu '$tS.aQ`Trk* {z.  z{z.k%**w**.w**.+-^ q!QK- %Q$ GzGGGGY @GGzGGYGGZ GGT GGoGGX GGyGG}GGiGGGGoGO GG\ G[ GGGGc GGlGGl GGP `,^d q!v GPGGjGGf GGGG@GGuGGi GGGGGGAGGGGsGFc|q z =7I>7I> $CGGp GGn GGu  GK G_ GGo GGmsHZ(-Is A.sErA*r.* W?-c'O5.wO*O-O-cWOaOO(nAYAYW> @&wAD*x AD Gi @GGd GGfs /z. ws n   Gz GGAGG]@DGy GG" w*4 GgGG~ @GG@@ Mی GGVGG G\@GGH GGAGB @GGPGO ,CCw.*.-- -i w.* {. pq!M G{GGq@GM @G}-cb Gr,m-Rw**.w**.{--i. pq! GGDGN @GS @GT @aWb2_V |W^M> Y> Y> Yoʒ> YoʍoʍoʍoʍoʍoʍoʍoʍГS=эS=эoʍoʍoʍoʍoʍГoʍ{#U{#U{#U{#U{#U{#U{#U GGU @Gw GGaGGfGPGYGGb GGJ GGM$l1mw.*-(.<r..<r..*w*-.w*-.Hw*.%**mm{.  aa G|@GGDG~GGfGGSKu;f/a0 Kc)g KBKbKa/!rKIK10 GJGG` GGd X{= rX*(rC*CA.XwA*rAC-$wXCDAffectingWXC'A.A>8( G~N%- "-[ -(NwN*iNa/!c-r'NN?-rppW: AddingWa ~...-NU G}GGEGG_ GGF GGxGGm GGeGGo GGGGA@GG^GGr @GGs GGGGGGGG{ hGGGhG} GGFGGvGf POQMLGGG@ GGpGGGGq4 -q'a G{GGE GGGGG GG[GGI GGQ@GGK GGMGGM GGR @GO @Gn pAL2a=L27!%q!# G<G^@GnGV @GT @GP @Gd GG@GGGGGJ@GGGGGG\ GGS GGw GGzGGGGmGGb GGGGGGg dfSRTGk e[XWVGsGGyGGoGG2giZYGB GGn GGo GGp GGLGGA GGi GGC GG~GGl GGt GGiGGxGGz GGGGk GG{ GG| GG} GG@ GGc GG^GG^ C ( yC D   GD GGF @GG` @GGkGGbGGy Gp @GGL GGU @G~ @GGy GGeGGl GGVGGEGGGGCGGc J%6L -NU- rz*JwJ*Ja/!uz.J JJSza  GVA o$-($ GGGGdGGGGFGGL I%sM- r@*IwI*lIa/!u@.I II;@a  GZ | / w| z   Ge ] SoF iC|VC rCC|VC'F%F, |VCFI'Fp( GCGGCGwGGG;GGx Gv@_(jpr@ nB-H r@@annw@*@-@ GGGn HTX~Hz ;';%};H,zr;HP *H P;;${Hl;H &zHz ;';%:;H,7r;HP *H P;;z{Hl;H &( G[  (g y y   Gi@G_ GGGQT1o/1SaRI-Aa[a GC m M MGuGGw [-(w*w.*ww*-.w*-.w*a::$ma Gq OmMhu%Uu, K{uI B OuI'uOO  GGGf t w(4Y.sլY9Y ::$.::$::$sY#?,sY#?GY 6Gff> ?6Y sGs G} k56ka/!cLyka/ww.k*.k.k'ka/.k.k'w* 5k( Gp GD]/wD* -BDff-~ wT* -BTw.*w.*F.wF*Fa/!-n.F >G-nFFJ.wJ*iJ-B -nJ >G-nJ.J>%-naG8w.*w.*F.8wF*!Fa/!.F >GFFJ.wJ*zJ-B J pGJ.J>HwD* -BD DG GYGsGGG{Gj |zReplacing BaseMutator...a/!9(r |w|*r|v|||wv*vR|a {w|*|R|a|BaseMutator now isVBaseMutator still isV Go 0T$ Gs Gz@G{ Ru>  G| st  GZts  GB HL:::$ $-Q /a0 QTSQa/!r-Q'0 10pV: Spawning the MIConverter...HMIConverter.MIConverter 'wH* waH*pV: MIConverter spawned.-Q' Gi efA0\?%I'I\C\?%HNHg -f OaeIHII(jrOVOIOaeIHII'jwO*VOIV*# GIGG~ I?_A30(wF*wF*F Gfe;z6 - -'Nw*OEE?&J YOEb'-z/a8 .Oezyw.W. eE?W-R E?W}WEe?E.O?Bw*m?&MmmeXr.JWW}mR |mw*w*j-rJ-76e6J wJ/a/!.-Ryexb('R.-b(-z.|)DeD. ի?..WծeemPWRU.-fyz!N.p)%. ի?..WծeemPW!GyRC..|)DeD. ի?..WծeemPWR10f-( GGGA L ZB r{* _r |j?-r{-76L 6{ w{/a/!.-[yjxb-s'[b-s-p !w*m?&,m{|)DjD{ ի?{{_ծjjmP_[f GE GH {p.wG Arp*Gp1pz{pzp1{ G_ h$'O.a![ - a(R-(Tdw*w.*w*-.w*-.w*a,::$ma GGGb @GT rLK ::$ $-R /a0 YTSYa/!r-R'0 10pV: Spawning the MIConverter...rMIConverter.MIConverter 'wr* war*pV: MIConverter spawned.-R' GK ,' GyRz#WE 7wR W**CaW}wC*CC JRC-'C iRC RC URC$Ra/!IC|.RCq!}-` Rq!cR*RCR{C G@U jG[@G@ j 5-Q ao'S?DSD1?&-( GC xCGz GH tUf t/a0 W('Wa/!h0 10tEIChallengeHUD.EIChallengeHUD 'rwt*at Gd H,ma ' GJ tt4?'RptqntZ Jwq*q &Vpq GO nNuaw*Nrrr/a0 @r@@10/a0 n4rnn\rnnrnnrnn10 GGG~0Rw* Gd {v|GRGGO w g51?%1z -B1zS?DSD1?&ao'-'t Gb T }3S(ea?( GGH j-OX7!G/a0 H 6H d*10Vw* GL[ SE=)( GYGGR M 3-+wz*z z -M -y  GGGI / w @   GGGk GGN |\yH::$Hw@*a@ |$rZ#Z#?wA*aA |PZ GQ d#gCT%!-:-D I]w*&-w**o!%q!Ja=T?T??%pppppW: CheckCounter =STItem[S] =V RejectChance[S] =UvG-Pe3e3-E !?v -: !A! %%r *2!% !Aq!S-P -:63?%a ?,?,Pa3?,?,r?% -:ard @-P'J r*- -Pw*-aa P8r* !Am::$ -Uo$::$-`o$--K--Za/!W.-(-PGw*aa lw.* -:w.K*.S.K-P'q!} A GGGGGG\ 6Vwz*z! Gr 0a" -N--- r*-N(M.wM*qMM-N(-]'nDM::$ n,-'-N(-]rM*. #_-N :%-- w*0 D--'$\:%~n%00?,??0L60?,??0!00?,??0?n60?,??00$00$pp-N-(a  g. n%6g66g6na+g-N0a( Gf m n `)"wD*DLL-~ wT*Ttr* w*i. V&q!w-'-'tm - ?%.\Y-X O- GSGGg h f +"wD*DLL-~ wT*Ttr* w*i. V&q!-'-'\h - ?%.\Y-X O- Ge u hFa/!f.{r za/!f.{* GyGGa W jLJy& rC* T%~TyYaC W PX Y@YT! G`GGr [5;?.`*w`*`a/!.` S[- 稨W`wants to keepV[inW'`a/!F.Y` S[- 稨W`wants to keepV[inW'``( GQ{z 1osT1SQ-H 1?,Sa1?%?G ?E ?%a-Aa$a G&GGGGMZL@<-P-u  -P'ZwZ*Za/! wZ~.ZTZa/!F wZ~.YZTZZ; GM L K;v{w.*{a/! ~-s{UL ^ J -S h-\ 'y-w'a #<('( GGGx t ` S GGG@z W GMer1S/rr-Mrra/! Mr GFm4y i$-h --.-.L.L.L.LS.rS*i$a/!V?'s--::$S?=<a/!B'-sa/!Wa/!^Botpack.PulseGuna/!PBotpack.SniperRifleEa/!PBotpack.Ripperya/!QBotpack.Minigun2a/!dBotpack.Enforcera/!]Botpack.UT_Eightballa/!RBotpack.UT_FlakCannonTa/!`Botpack.ShockRiflea/!TBotpack.UT_BioRiflea/!bBotpack.ImpactHammeri$'(a/!}'-j a/!r9a/!XBotpack.ShockCoreoa/!RBotpack.RocketPacka/!TBotpack.PAmmoa/!BBotpack.BladeHopper a/!FBotpack.RifleShellBa/!MBotpack.BulletBoxva/!@Botpack.FlakAmmoa/!YBotpack.EClipa/!UBotpack.MiniAmmoa/!HBotpack.BioAmmoi$'(O-~a/!.-'ea/!|'{a/!@'-m a/!~-Botpack.UT_JumpBoots -p a/!_Botpack.UDamage P-va/!SBotpack.ThighPads -oa/!CBotpack.HealthPack -va/!WBotpack.Armor2 -oa/!YBotpack.HealthVial d-oa/!Wa/!_Botpack.MedBox -n a/!cBotpack.UT_ShieldBelt -o a/!IBotpack.UT_Invisibility  -sa/!\i$'( GZ{ "]D75::$ --wy GGGz s>BF( GxLS*GL-~ 4a/!IY` w*%wr.}wD* }!G?A< GdGGGG| ApF GBGGGG@V EG!w* EV  GGGDGGJk5$E!-{ka/!O'Aw* 5k( GGGv GGGG~c_8+ca/!I-~(ca6c GLGG` GGPQP:^dD:Qh%6dQ dQpd GGGGGrtGn9Ot 'yzVONone稨pW: Loading failed!tis not a valid inventory class!*O GwVCXj~V.PjVV}Vj&j~V.V  GX@GGGGdKg1tKwK*tKa/!h}.ZKrr}^*-v }^ KKw~*}a~w}*}^ GT T%@1\ GUr zEr w2ry w%|*yt F%|Q& :%h% :%i%Q2Q% :%h% :%i%Q2Q& :%h%Q2 Q% :%h%Q22Q% :%i%Qsw*)zr i yQ| } Fu' G@GGW@GGj@GGMD EV rE-t-R-B1.wEz]1zw*E.w*E.5rE*. E!h.%E%**EaE @S.ESEa'r*( E G`GGGG_0U'$%wH*Ha GGG{HPcawV*HaV awH*HHq!o G{GGnGGLYn[-L- -L'_i GbOb!8w*$bOnLJS Cna/!-stnwt*ta/!.7tKCOLJ'ttk GM[/M-.M-.M%B.M$p.M!G/a0 vvdMM10'( Gi]Z 9GGGfGGzSN-$z GGgB' GM I '  .a`Trk* {@.  @{@.k&**w**.w**.$ GcT<29rT*TT wT*TTTTrT*TT G^6q6r^*6A6a/!.6@^.q6a/!.6_^.6a/!..[6y^.6a/!H.{6\^.6a/!.6z^..6a/!.6`^6  GGGkl{D/wl*xl'flwf*`rtxtfff'Cwt*lt<l GzdG4x\!G \!Gydwy*ya/!.y\\wyyayy4d-dQ-?I-\M-rd%-f/a8 ge~wgdwg*g-g DH10 Gqbv"^ w*d GkyINuGbEw*1-c NyEvy GXmq8z=m-g&nuDC EvvPm-g&nuDC E( GMGG GGwSGcDlXS Sw *J -W!G W!G W!Kr. *0 W Ww. *. :WXX?%XX a/!. k%. -fX. k ,d %X  ,d  ( Sw *! -{w. *x. -f %X?,d  % %X?,d   X  GGGl}Mh }|}UseHoldabletf}wt*fta/!.7t'-U'tt+-Ufgtf|}SelectNext<fwt*rf*f  SW|}SelectPrev{fWwt*rf*f  S{w*M}f GIGGQ X lT$a]q!# GGWGGP Qr om-Ua/!8-w-w(' mK!G%* (-oa=( GPGmZGa/!.G-+.G-.G- -$稨Reset bAutoActivate inVGtoT.G-.G-.G-' GGGE^ ~R( w* ^  GGG=n2Wrl* =& wl*rl*=Dzl|rD*zD==&&==&, ==%&  = ==%,= %9rz*zz^rl*rl*iDzl &QmlD-~Q%o%QpDQ  oQ%oDQ 稨Unexpected message parameters: Switch =S=OptionalObject =VlPRI1:TwD*PRI2:Twz*  GC|:Rd_[|!G |!K*1W|W1W|WY Z '( GGGFBkc-rd GGGY QsO*-:e3q!#Rr*H-:q!lOq!#a!_--*a*-:q!lq!#e?a?( GbJ1Ma$|BSplashDamageTJ}|BAllEnviromental1JW!R1JW!_1JW!E}J}B(|JB'|J}BB'(  GGGf =3-Ua/!-oa=(-w( GGGqGG^GGQ XT?(( GccPg0c% c,mcpW.RemoveItem: Tried to remove the ReplacedItem value.ppW.RemoveItem: Parameter has to be >= 0 and <S,(isSc)(wc *5c (Y- ppppRemoveItem: Removing item #Sc(Vc ) fromW(S!items)c *2cq!#! ' Gg Ji><-t+w>*>J:-t GAGG__&!')3l-:e]?&p>elz_|_None~_.- AddItem: Nothing to add._(%w *q|V _+- ppAddItem: _already inWas #S. Applying new values.pZrXvp3e',(!! G_w *pZrXvp3eh$- 稨pAddItem: AddedV as item #StoW(nowS!items)'!( GGGsGGDRpa; GGGGGTGGlxs@x]kC][rxkQrkCU,XU&{{rxCU,>] U%w]*w]q*x]qU>>w]*w]^*x]^U  GUGG] GG@GGGG_ XO6{-BX 4rX* rXD JwD*BD>XXDX G[GG_A%dW C?d  GW GGKXU5 RXwR*Ra/!.7R-r-.7RK!G%*X (RRX G@GGGG^N nsCAwT*-N %7TzA7T@  GW  B>6w*- W  GfGGTGGN@GG@GGj GGk@Gc@GvvO#V]]%,)s%s]&\R%vR&`s&`qvs&`w%NppSDv~ SD?Dv?, ?w?, ?ww%NU?Dv?, ?w?, ?wNSDv*-V-A Ns&B TN-VNs&I TN !GGGm@GGnJ eq3LynJ Dwy*y&L ~ } | { y GrA GGGqGG#GG` GGtGGwFjf2w(*( jF|FCurrentDamageFactor-ds?%?[^|FCurrentOwnerSpeedFactor-??%?g^%|FCurrentJumpZFactor-??%?c^b|FCurrentAirControl-?a^|FCurrentWeaponSpeedFactor-c?%?a^ |FCurrentOwnerMassFactor-\?%?D^^|FCurrentOwnerBuoyancyFactor-\R?%?l Gy6[w`*`! Gl q @"vK Gza 3-+w`*` l -a -c  Gh YUkt/a0 o('oa/!h0 10YEIChallengeHUD.EIChallengeHUD 'rwY*aY G\GG@{\{w\*2S*Y-i { \I \ss{a/I \\\*  GGG{ k ( yk i   GGGN@GGdGCGDGEGFGGGHGiN /k wN M   Gs uUM -k  -r GGGGGJL (pt yL K   Go d5"  #*lI wl*&al    կl #?  )w * &w&*&  *YYw&*&-'& w&*: : : :$-g': :$-N(Q -  "26  %6  %-](-]  " - -  "-h  " -4 -  "f:&:$ -N&o$:&:$-g&o$&--]&--h& & &* GS GGGGNgulj-x ::$Kw.*e.jjw*e GRT[U G@GGSV]k-_-_-_LowL*XLa/!f-_''LL/-_(-_'( GLGGIGUJ \U)iPJ 6i6I i  GLGGOy=-w(w.*.w*9w9*r999Yr9*w9Gh.G -$w*pRegisterHUDMutator: RegisteredW, NextHUDMutator isW -$RegisterHUDMutator: RegisteredWv-'/a0 w*9}w9*fr9}99@w9*r91Gh.G -$w*pRegisterHUDMutator: RegisteredW, NextHUDMutator isW -$RegisterHUDMutator: RegisteredWv-'10--w'u!" GiGGWGX`e7"`#`::$O[?%;`jjjwj*Z`j@ %j`\@ \`\G`a G\G^G_G]\@r::$jw.A*.A-A*)D?!Gb?e\\ G[GGD GaG f+!%H#s0sHUD#R`RDhaG MRss-}F -}rhw.h*bhMwh*bhMb*# Gh r%x-U ~-s Gi@Gh 0.3Gi 2.5Gl 0.3G GGsGG 10.0GoM GG0i Grnl GGdq?#0(wh*wh*h GGGwQ w*Q GjGGGGGGG@;& - -'m[zw*S-xm[e?&uzm[?&u@#@t'-j/a8 )m@w)g) @L?ggwgLN?L)m?f-xBe?&w*B?&BBN-S N?-x w*Ner)~V?%VggwBV?B-_~-76@6~ n~/a/!.-gxNqt('g)-t(-j)|)DN) ի?))gծNNB\gg)-GF}!N)p)%) ի?))gծNNB\g!GgC))|)DN) ի?))gծNNB\gg10G-( GuG  GGGxGG}y* GGG{GG@|q% GGGNGGDv EA2w*NEv _ [ 9N*N GGGvx ZiS4c-|#L|?BL?i?:x:$6L?%6L>6L@-_x-76x 6x nx/a/!.-uxiqt('Xut(-w -x w*ie-xhe?&w*h?&hx|)Dix ի?xxLծiih\LuG GsGGG} p}  GGG|u p,&np%p|p&|pip&iphp&hp %|u %i=A-l %h=A-B  GOj  $ w* j ( GGGHGGIGGBLC:} GMGGGGKE\B;::$Nwc*ac EP^$x^#^#?w*a EP^ Ge se  GQN4* GWb.| GNF j)={& r`* J%J{ua` F PE }wu*u@uJ! G^k0\-(k%Zk,Pwk*ka/!x-'k GOGGGGUGGgV+P GRY@e> GGGX[G> b? GGGZs vE?es C  G} @CNw.@*6[!GXAX[%,2.@X=-i'}!G!.@}A-l'H-i:,2l.@!G!.@!G.@X,2&P.@.@XXP-l }!GX}A,2y.@!G!.@!G.@X,2&P.@.@XXP Gy-' GGG_GG 20GD q 3j-+w\*\ @ -q -A  GC S_PaalaSKq! G@GFq!#q%nq,&q|q&|qiq&iqhq&hq,&|*,&i$,&h$ GGGb6w\*\! Gj`q& GGGMGGlU E)A2w*MEU T Z 9M*M GGGnkqB GGGpmG GGGwV  $ w* V ( GGGee_sQ---i {. pow*q* GqGGIYoS-'-K-q6r*)w.*.%4a/!I--r.*.--?%-d ::$$-?%--?% ::$ ::$$ GXqy}oqfwq*Orq qnqq* GC@=GD K4Y m-q'vPa!8 a!7vAq!+! kk- a!+a Gu class EIDeathMessageSpawnNotify extends SpawnNotify; var EIDeathMessageMutator EIDMM; simulated event Actor SpawnNotification(Actor A) { if ( EIDMM == None ) return A; if ( A.IsA('EnhancedWeapon') ) EnhancedWeapon(A).EIDMM = EIDMM; else if ( A.IsA('EnhancedProjectile') ) EnhancedProjectile(A).EIDMM = EIDMM; else if ( A.IsA('EnhancedAmmo') ) EnhancedAmmo(A).EIDMM = EIDMM; else if ( A.IsA('EIEffects') ) EIEffects(A).EIDMM = EIDMM; else if ( A.IsA('EnhancedMutator') ) EnhancedMutator(A).EIDMM = EIDMM; else if ( A.IsA('PickupPlus') ) PickupPlus(A).EIDMM = EIDMM; return A; } GW"j W HW G{// EWindow by Wormbo //============================================================================= // EWindowCheckbox - support auto-size based on text size //============================================================================= class EWindowCheckbox extends UWindowCheckbox; var bool bAutoSize; // adjust the size of the control to its Text's size function BeforePaint(Canvas C, float X, float Y) { local float TW, TH; if ( bAutoSize ) { if ( Text == "" ) { TW = 0; TH = WinHeight; } else { if ( Align == TA_Left ) TextSize(C, Text $ " ", TW, TH); else if ( Align == TA_Right ) TextSize(C, " " $ Text, TW, TH); else TextSize(C, Text, TW, TH); TH = Max(TH, WinHeight); } if ( Align == TA_Left ) WinLeft -= TW + TH - WinWidth; else if ( Align == TA_Center ) WinLeft -= (TW + TH - WinWidth) / 2; WinWidth = TW + TH; } Super.BeforePaint(C, X, Y); } L`xMc|.X GGk // EnhancedItems by Wormbo //============================================================================= // EIEffects. //============================================================================= class EIEffects extends Effects abstract; var bool bDestroyMe; // the effect is about to be destroyed, set by DestroyMe() var EIDeathMessageMutator EIDMM; // Destroy this effect. // Needn't be instant destruction. (see PlayerShellEffect) function DestroyMe() { bDestroyMe = True; Destroy(); } final function SetKillType(bool bSplashHit, bool bHeadHit, class DamageProjectileClass) { if ( EIDMM != None ) EIDMM.AddDamageActor(DamageProjectileClass, bSplashHit, bHeadHit); } final function RestoreKillType() { if ( EIDMM != None ) EIDMM.RemoveDamageActor(); } Gd"C+dd Hd GP// EWindow by Wormbo //============================================================================= // EWindowPulldownMenuItem - menu item for EWindowPulldownMenu //============================================================================= class EWindowPulldownMenuItem extends UWindowPulldownMenuItem; var string AltValue; function Select() { if ( SubMenu != None ) { SubMenu.WinLeft = Owner.WinLeft + Owner.WinWidth - Owner.HBorder; SubMenu.WinTop = ItemTop - Owner.VBorder; if ( EWindowPulldownMenu(Owner) != None ) EWindowPulldownMenu(Owner).SubMenu = EWindowPulldownMenu(SubMenu); if ( EWindowPulldownMenu(SubMenu) != None ) EWindowPulldownMenu(SubMenu).ParentMenu = Owner; SubMenu.ShowWindow(); } } function DeSelect() { if ( SubMenu != None ) { if ( EWindowPulldownMenu(Owner) != None && EWindowPulldownMenu(Owner).SubMenu == SubMenu ) EWindowPulldownMenu(Owner).SubMenu = None; if ( EWindowPulldownMenu(SubMenu) != None ) EWindowPulldownMenu(SubMenu).ParentMenu = None; SubMenu.DeSelect(); SubMenu.HideWindow(); } } Gy1// EnhancedItems by Wormbo //============================================================================= // EnhancedArena. // // Features: // - Keeps the Translocator. // - Also checks MPP for correct item classes. //============================================================================= class EnhancedArena extends Arena abstract; var() string KeepClasses[10]; var bool bMIConverterSpawned; static function bool OtherIsA(actor Other, name DesiredType) { return class'EnhancedMutator'.static.OtherIsA(Other, DesiredType); } static final function bool ClassIsA(class aClass, coerce string DesiredType) { return class'EnhancedMutator'.static.ClassIsA(aClass, DesiredType); } function SpawnMIConverter() { local class M; local EnhancedMutator EM; local Inventory Inv; if ( Level.NetMode == NM_Client ) return; // MIConverter is server-side only if ( bMIConverterSpawned ) return; // check, if MIConverter was already spawned ForEach AllActors(class'EnhancedMutator', EM) If ( EM.IsA('MIConverter') ) { bMIConverterSpawned = True; // MIConverter already exists return; } log(class$": Spawning the MIConverter..."); M = class(DynamicLoadObject("MIConverter.MIConverter", class'Class', True)); if ( M != None && Spawn(M) != None ) log(class$": MIConverter spawned."); bMIConverterSpawned = True; } function bool AlwaysKeep(Actor Other) { if ( Other.IsA('MultiItem') ) SpawnMIConverter(); if ( Other.IsA(WeaponName) ) { if ( Weapon(Other).AmmoName != None ) Weapon(Other).PickupAmmoCount = Weapon(Other).AmmoName.Default.MaxAmmo; return true; } if ( Other.IsA(AmmoName) ) { Ammo(Other).AmmoAmount = Ammo(Other).MaxAmmo; return true; } if ( NextMutator != None ) return NextMutator.AlwaysKeep(Other); return false; } function bool CheckReplacement(Actor Other, out byte bSuperRelevant) { local int i; for (i = 0; i < 10; i++) if ( KeepClasses[i] != "" && ClassIsA(Other.Class, KeepClasses[i]) ) return true; return Super.CheckReplacement(Other, bSuperRelevant); } function bool CheckMPP(MultiPickupPlus Other) { local int i; if ( Other.InItem(class'Ammo', i, True) ) { i = 0; while ( i < Other.MaxNumItems ) if ( class(Other.Item[i]) == None || !Other.RemoveItem(i) ) i++; if ( AmmoString != "" && !Other.FindItem(AmmoName, i) ) Other.AddItem(AmmoString); } if ( Other.InItem(class'Weapon', i, True) ) { i = 0; while ( i < Other.MaxNumItems ) if ( class(Other.Item[i]) == None || !Other.RemoveItem(i) ) i++; if ( WeaponString != "" && !Other.FindItem(WeaponName, i) ) Other.AddItem(WeaponString); } return false; } function bool AlwaysKeepInMPP(MultiPickupPlus Other, class ItemClass) { local int i; if ( ItemClass.Name == WeaponName || string(ItemClass) ~= WeaponString || ItemClass == DefaultWeapon || ItemClass.Name == AmmoName || string(ItemClass) ~= AmmoString ) return true; for (i = 0; i < 10; i++) if ( string(ItemClass) ~= KeepClasses[i] ) return true; return false; } G:class EnhancedKeyBindings extends UTExtraKeyBindings; GF "F  HF  RjT tiu o] Other / MiscO] Use HoldableOUse Selected ItemOSelect Next ItemOSelect Prev. ItemR]mutate useholdableR ActivateItemRmutate NextItemRmutate PrevItemGG_ //----------------------------------------------------------------------------- // JumpBootsDummy. //----------------------------------------------------------------------------- // This is a deactivated version of the UT_JumpBoots that displays the boots in // the status doll when added to a player's inventory. It can be used by any // boot-like inventory item that doesn't expand UT_JumpBoots. class JumpBootsDummy extends UT_JumpBoots; function PickupFunction(Pawn Other); function OwnerJumped() { if ( Inventory != None ) Inventory.OwnerJumped(); } state Activated { function EndState(); Begin: } state DeActivated { Begin: } GMWq<-'-~ '$ G,G0H- Go^JD{Hw^ w*r nw^w.*r. .n^~^`-rd%P^-dQ-?I-\Mq!V Umk2YE^ɫГ J xScSMSb l u$v"WXGGGGY#!BBc G[A B3]r*$%r*$R:RA =R%, GGGRGG{// EnhancedItems by Wormbo //============================================================================= // EnhancedAmmo. //============================================================================= class EnhancedAmmo extends TournamentAmmo abstract; struct RegenSuggestion { var() config int Max; var() config int Interval; var() config int Amount; }; var() RegenSuggestion SuggestedRegeneration; // suggests how this type of ammo should be regenerated var() bool bIsSuperWeapon; // this ammo belongs to a super weapon var() name IdenticalTo; // used by OtherIsA() and ClassIsA() to identify new versions of an actor var EIDeathMessageMutator EIDMM; static final function bool OtherIsA(actor Other, name DesiredType) { return class'EnhancedMutator'.static.OtherIsA(Other, DesiredType); } static final function bool ClassIsA(class aClass, coerce string DesiredType) { return class'EnhancedMutator'.static.ClassIsA(aClass, DesiredType); } final function SetKillType(bool bSplashHit, bool bHeadHit, class DamageProjectileClass) { if ( EIDMM != None ) EIDMM.AddDamageActor(DamageProjectileClass, bSplashHit, bHeadHit); } final function RestoreKillType() { if ( EIDMM != None ) EIDMM.RemoveDamageActor(); } G\ac3;r*,%r*,,: GGGK`d wKuw*w*D GTbd7BGX -b %$B S$D?B2 $2B $2D?B2 BC< G[cf8} G~ H] 4 q $ ?,D?r,  ?B?,  D?B ?, ?r?,  $$D?r  ?B  d$D?B  ?r  $D?r - ?B-  BBw $_   G N$  _ G $ ?,_?,  ?,   ?, _?, G 6$_ - - G GC< GMeh+OGG O Aa $ B$A l$D?r  $AD?r  $AD?r ?c  BC< GU gjojGA z "kr*q! A z =:B%, GS^scr*-q-aa    w*wD*D& D GnGV Ga/!`Ga/!Ga!.G-i.G-G-{G-k.$ pGGGwG*G-k* G{GGy L%  -{  L.ChaosUTMedia2.c_vortexsphere 'wL*L?B?H?S?f?y ?, G=class PlayerSphere extends PlayerShellEffect; var() float SizeAdjust; var() bool bUseVortexSphere; // try to find the c_VortexShpere of ChaosUT (looks better) simulated function PreBeginPlay() { local mesh m; if ( !bUseVortexSphere ) return; m = mesh(DynamicLoadObject("ChaosUTMedia2.c_vortexsphere", class'Mesh', True)); // radius of c_vortexsphere is twice the radius of ShockWaveM if ( m != None ) { Mesh = m; DrawScale *= 0.5; StartSize *= 0.5; EndSize *= 0.5; MaxSize *= 0.5; MinSize *= 0.5; SizeAdjust *= 2; } } function PostBeginPlay() { Super.PostBeginPlay(); MultiSkins[1] = Texture; } state Forming { function UpdateAppearance() { switch(FormAnim) { case SFORM_Instant: ScaleGlow = MaxGlow; DrawScale = MaxSize; break; case SFORM_Grow: ScaleGlow = MaxGlow; DrawScale = StartSize * (FormTime - AnimTime) / FormTime + MaxSize * AnimTime / FormTime; break; case SFORM_LightUp: ScaleGlow = MaxGlow * AnimTime / FormTime; DrawScale = MaxSize; break; case SFORM_GrowLightUp: ScaleGlow = MaxGlow * AnimTime / FormTime; DrawScale = StartSize * (FormTime - AnimTime) / FormTime + MaxSize * AnimTime / FormTime; break; } AmbientGlow = Default.AmbientGlow * ScaleGlow; } } state Visible { function UpdateAppearance() { if ( AnimTime > AnimRate ) AnimTime = 0; if ( GlowTime > GlowRate ) GlowTime = 0; switch(VisibleAnim) { case SVIS_Pulse: if ( AnimTime > AnimRate * 0.5 ) DrawScale = MinSize * 2 * (AnimRate - AnimTime) / AnimRate + MaxSize * (AnimTime * 2 - AnimRate) / AnimRate; else DrawScale = MaxSize * (AnimRate - AnimTime * 2) / AnimRate + MinSize * (AnimTime * 2) / AnimRate; break; case SVIS_Expand: DrawScale = MinSize * (AnimRate - AnimTime) / AnimRate + MaxSize * AnimTime / AnimRate; break; case SVIS_Collaps: DrawScale = MaxSize * (AnimRate - AnimTime) / AnimRate + MinSize * AnimTime / AnimRate; break; case SVIS_None: CurOffset = MinSize * FMax(AnimRate - FlashTime, 0) / AnimRate + MaxSize * FlashTime / AnimRate; break; default: DrawScale = MaxSize; break; } switch(GlowAnim) { case SGLOW_LightUp: ScaleGlow = MinGlow * (GlowRate - GlowTime) / GlowRate + MaxGlow * GlowTime / GlowRate; break; case SGLOW_Darken: ScaleGlow = MaxGlow * (GlowRate - GlowTime) / GlowRate + MinGlow * GlowTime / GlowRate; break; case SGLOW_Blink: if ( GlowTime > GlowRate * 0.5 ) ScaleGlow = MinGlow * 2 * (GlowRate - GlowTime) / GlowRate + MaxGlow * (GlowTime * 2 - GlowRate) / GlowRate; else ScaleGlow = MaxGlow * (GlowRate - GlowTime * 2) / GlowRate + MinGlow * (GlowTime * 2) / GlowRate; break; case SGLOW_Restore: ScaleGlow = MinGlow * FMax(GlowRate - FlashTime, 0) / GlowRate + MaxGlow * FlashTime / GlowRate; break; default: ScaleGlow = MaxGlow; break; } AmbientGlow = Default.AmbientGlow * ScaleGlow; } } state Vanishing { function UpdateAppearance() { switch(VanishAnim) { case SVANISH_Instant: ScaleGlow = 0; break; case SVANISH_Fade: ScaleGlow = CurGlow * (VanishTime - AnimTime) / VanishTime; break; case SVANISH_Shrink: DrawScale = CurSize * (VanishTime - AnimTime) / VanishTime + StartSize * AnimTime / VanishTime; break; case SVANISH_ShrinkFade: ScaleGlow = CurGlow * (VanishTime - AnimTime) / VanishTime; DrawScale = CurSize * (VanishTime - AnimTime) / VanishTime + StartSize * AnimTime / VanishTime; break; case SVANISH_GrowFade: ScaleGlow = CurGlow * (VanishTime - AnimTime) / VanishTime; DrawScale = CurSize * (VanishTime - AnimTime) / VanishTime + EndSize * AnimTime / VanishTime; break; } AmbientGlow = Default.AmbientGlow * ScaleGlow; } } GnYX& GTpr78,GX $b %$S m$B22S2 $2S $2B22S2 C< G[qt8r) G~ >gC 4 q $ ?f?,  S?,  S ?, f?,  $f  S  [$S  f  $Df - S-  Sw $_   - 2$  _ - $ ?_?,  ?,   ?, _?, - $_ - - - -C< GMsv+yGG xf Ra $< B$A< $vB< $AvB< 9$AvH< C< G{OqJhu(O!^:O{%{?m:O{^{@BmD?{ GR pJ L5-R pma mpc b  ouhyzae[ F$AEH$?K$?N$ # AnimRate ) AnimTime = 0; if ( GlowTime > GlowRate ) GlowTime = 0; switch(VisibleAnim) { case SVIS_Pulse: if ( AnimTime > AnimRate / 2 ) CurOffset = MinOffset * 2 * (AnimRate - AnimTime) / AnimRate + MaxOffset * (AnimTime * 2 - AnimRate) / AnimRate; else CurOffset = MaxOffset * (AnimRate - AnimTime * 2) / AnimRate + MinOffset * AnimTime * 2 / AnimRate; break; case SVIS_Expand: CurOffset = MinOffset * (AnimRate - AnimTime) / AnimRate + MaxOffset * AnimTime / AnimRate; break; case SVIS_Collaps: CurOffset = MaxOffset * (AnimRate - AnimTime) / AnimRate + MinOffset * AnimTime / AnimRate; break; case SVIS_Restore: CurOffset = MinOffset * FMax(AnimRate - FlashTime, 0) / AnimRate + MaxOffset * FlashTime / AnimRate; break; default: CurOffset = MaxOffset; break; } Fatness = GetIdealFatness(CurOffset); switch(GlowAnim) { case SGLOW_LightUp: ScaleGlow = MinGlow * (GlowRate - GlowTime) / GlowRate + MaxGlow * GlowTime / GlowRate; break; case SGLOW_Darken: ScaleGlow = MaxGlow * (GlowRate - GlowTime) / GlowRate + MinGlow * GlowTime / GlowRate; break; case SGLOW_Blink: if ( GlowTime > GlowRate / 2 ) ScaleGlow = MinGlow * 2 * (GlowRate - GlowTime) / GlowRate + MaxGlow * (GlowTime * 2 - GlowRate) / GlowRate; else ScaleGlow = MaxGlow * (GlowRate - GlowTime * 2) / GlowRate + MinGlow * GlowTime * 2 / GlowRate; break; case SGLOW_Restore: ScaleGlow = MinGlow * FMax(GlowRate - FlashTime, 0) / GlowRate + MaxGlow * FlashTime / GlowRate; break; default: ScaleGlow = MaxGlow; break; } AmbientGlow = Default.AmbientGlow * ScaleGlow; } } state Vanishing { function UpdateAppearance() { switch(VanishAnim) { case SVANISH_Instant: ScaleGlow = 0; break; case SVANISH_Fade: ScaleGlow = CurGlow * (VanishTime - AnimTime) / VanishTime; break; case SVANISH_Shrink: CurOffset = MinOffset * (VanishTime - AnimTime) / AnimRate; break; case SVANISH_ShrinkFade: ScaleGlow = CurGlow * (VanishTime - AnimTime) / VanishTime; CurOffset = MinOffset * (VanishTime - AnimTime) / AnimRate; break; case SVANISH_GrowFade: ScaleGlow = CurGlow * (VanishTime - AnimTime) / VanishTime; CurOffset = MinOffset * (VanishTime - AnimTime) / AnimRate + GetMaxOffset() * AnimTime / AnimRate; break; } Fatness = GetIdealFatness(CurOffset); AmbientGlow = Default.AmbientGlow * ScaleGlow; } } state PickupShell { simulated function Tick(float DeltaTime) { if ( Master == None ) { GotoState('Idle'); return; } Super.Tick(DeltaTime); Mesh = Master.Mesh; DrawScale = Master.DrawScale; Fatness = Clamp(Master.Fatness + MaxOffset, 0, 255); } } GG|i`~be[ԝXԝXԝXԝX H$?K$?H"G"@xzj$?w@FJGGV// this item does nothing but displaying the shield icon around the status doll class ShieldBeltDummy extends UT_ShieldBelt; // all these functions need to be disabled, so the dummy neither removes other armors // nor absorbs damage function int ArmorAbsorbDamage(int Damage, name DamageType, vector HitLocation) { return Damage; } function bool HandlePickupQuery( inventory Item ) { if ( Inventory != None ) return Inventory.HandlePickupQuery(Item); return false; } function PickupFunction(Pawn Other); function ArmorImpactEffect(vector HitLocation); // this item needs bIsAnArmor to work but is not inserted into the temporary armor chain function inventory PrioritizeArmor( int Damage, name DamageType, vector HitLocation ) { local Inventory FirstArmor, InsertAfter; if ( Inventory != None ) FirstArmor = Inventory.PrioritizeArmor(Damage, DamageType, HitLocation); else FirstArmor = None; // don't return self return FirstArmor; } function int ArmorPriority(name DamageType) { return -1; } event float BotDesireability( pawn Bot ) { return -1; } function SetEffectTexture(); // ignore Destroyed function of UT_Shieldbelt // instead execute Destroyed function of TournamentPickup to remove self from pawn's inventory function Destroyed() { Super(TournamentPickup).Destroyed(); } Pm2@FɕГГ v"}"|"GGy// this item does nothing but displaying the thigh pads icon in the status doll class ThighPadsDummy extends ThighPads; function int ArmorAbsorbDamage(int Damage, name DamageType, vector HitLocation) { return Damage; } function bool HandlePickupQuery( inventory Item ) { if ( Inventory != None ) return Inventory.HandlePickupQuery(Item); return false; } function Inventory SpawnCopy(Pawn Other) { return Super(TournamentPickup).SpawnCopy(Other); } // this item needs bIsAnArmor to work but is not inserted into the temporary armor chain function inventory PrioritizeArmor( int Damage, name DamageType, vector HitLocation ) { local Inventory FirstArmor, InsertAfter; if ( Inventory != None ) FirstArmor = Inventory.PrioritizeArmor(Damage, DamageType, HitLocation); else FirstArmor = None; // don't return self return FirstArmor; } function int ArmorPriority(name DamageType) { return -1; } event float BotDesireability( pawn Bot ) { return -1; } GbaNTxj. ljj najQ .qjX aj Azn2CU~}kГГ v"}"|"GG@GGjGGD class HoldableUseMessage extends PickupMessagePlus; static function float GetOffset(int Switch, float YL, float ClipY ) { return ClipY - YL - (128.0 / 768) * ClipY; } static function string GetString( optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject ) { if ( OptionalObject != None ) { if ( Switch == 0 ) return Class(OptionalObject).Default.UseText; else return Class(OptionalObject).Default.ReUseText; } } GBQm)lQUkNwU*2rQU U.Uk}w.*}r.Q U,wU*rQU r.U*U.U,-@ G// EWindow by Wormbo //============================================================================= // EWindowDialogClientWindow - displays tooltips for its controls //============================================================================= class EWindowDialogClientWindow extends UWindowDialogClientWindow abstract; var UWindowSmallCloseButton CloseButton; function Created() { Super.Created(); CloseButton = UWindowSmallCloseButton(CreateWindow(class'UWindowSmallCloseButton', WinWidth-56, WinHeight-24, 48, 16)); } function Notify(UWindowDialogControl C, byte E) { switch(E) { // these are used to display tooltips case DE_MouseMove: if ( UMenuRootWindow(Root) != None && UMenuRootWindow(Root).StatusBar != None) UMenuRootWindow(Root).StatusBar.SetHelp(C.HelpText); break; case DE_MouseLeave: if ( UMenuRootWindow(Root) != None && UMenuRootWindow(Root).StatusBar != None) UMenuRootWindow(Root).StatusBar.SetHelp(""); break; } Super.Notify(C, E); } function GetDesiredDimensions(out float W, out float H) { Super(UWindowWindow).GetDesiredDimensions(W, H); H += 30; } HCr I MaxWidth ) MaxWidth = W; } WinWidth = MaxWidth + (HBorder + TextBorder) * 2; WinHeight = ItemHeight * Count + VBorder * 2; // Take care of bHelp items if ( (UWindowMenuBarItem(Owner) != None && UWindowMenuBarItem(Owner).bHelp) || WinLeft + WinWidth > ParentWindow.WinWidth ) WinLeft = ParentWindow.WinWidth - WinWidth; if ( ParentMenu != None && (WinWidth + WinLeft > ParentWindow.WinWidth || ParentMenu.WinLeft + ParentMenu.WinWidth - ParentMenu.HBorder > WinLeft || WinLeft + WinWidth > Root.WinWidth || (Parent != None && Parent.bOpenedToLeft)) && ParentMenu.WinLeft + ParentMenu.HBorder - WinWidth > 0 ) { WinLeft = ParentMenu.WinLeft + ParentMenu.HBorder - WinWidth; bOpenedToLeft = True; } if ( ParentMenu != None && WinTop + WinHeight > Root.WinHeight && WinHeight < WinTop + ParentMenu.ItemHeight + 2 * VBorder ) WinTop -= WinHeight - ParentMenu.ItemHeight - 2 * VBorder; WinTop = Max(Min(WinTop, Root.WinHeight - WinHeight), 0); WinLeft = Max(Min(WinLeft, Root.WinWidth - WinWidth), 0); } GPR// EnhancedItems by Wormbo //============================================================================= // TimedPowerup // // Activates on pickup and expires after the amount of time initially // specified by FullCharge //============================================================================= class TimedPowerup extends PickupPlus abstract; var() float FinalCount, // if Remaining drops below this the DeactivateSound is played when calling TimedAction() FullCharge, // the amount of charge this item initially has Remaining, // the amount of charge the item still has left TimingInterval; // interval of time for calling TimedAction() var() int FinalCountInterval; // after playing the DeactivateSound this amount of intervals have to pass before playing it again var int FinalCounter; var() bool bPreFinalCount, // play DeactivateSound once when twice the amount of FinalCount is left bDeactivateCount, // play DeactivateSound when Remaining reaches 0 bAddCharge, // add the charge of the picked up item (else restore to FullCharge) bDeactivatedUseCharge; // also uses charge in Deactivated state replication { reliable if ( Role == ROLE_Authority ) FinalCount, Remaining; } simulated function Destroyed() { if ( bActive ) UsedUp(); Super.Destroyed(); } simulated function UsedUp() { if ( !IsInState('Activated') ) TimedOut(); if ( !bActive ) return; SetTimer(0.0, False); DeactivateAction(); bActive = False; SetOwnerDisplay(); ChangedWeapon(); if ( Level.Game != None && Pawn(Owner) != None ) { if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogItemDeactivate(Self, Pawn(Owner)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogItemDeactivate(Self, Pawn(Owner)); } if ( ShellEffect != None ) ShellEffect.Destroy(); if ( Role == ROLE_Authority ) { ResetOwnerSpeed(); ResetDamageFactor(); } } event float BotDesireability( pawn Bot ) { local Inventory Inv; local float desire; local TimedPowerup AlreadyHas; desire = MaxDesireability; AlreadyHas = TimedPowerup(Bot.FindInventoryType(class)); if ( AlreadyHas == None ) return Super.BotDesireability(Bot); if ( AlreadyHas.Remaining > AlreadyHas.FullCharge ) desire *= AlreadyHas.FullCharge / AlreadyHas.Remaining; return desire; } function bool HandlePickupQuery( inventory Item ) { if ( Item.Class == Class ) { if ( bAllowSameClassPickup && bDisplayableInv ) { if ( bAddCharge ) Remaining += TimedPowerup(Item).FullCharge; else Remaining = FullCharge; if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogPickup(Item, Pawn(Owner)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogPickup(Item, Pawn(Owner)); if ( Item.PickupMessageClass == None ) Pawn(Owner).ClientMessage(Item.PickupMessage, 'Pickup'); else Pawn(Owner).ReceiveLocalizedMessage(Item.PickupMessageClass, 0, None, None, Item.Class); PlaySound(Item.PickupSound,,2.0); PlayGlobalSound(PickupPlus(Item).GlobalPickupSound); Item.SetReSpawn(); } return true; } if ( Inventory == None ) return false; return Inventory.HandlePickupQuery(Item); } simulated function ActivateAction(); simulated function TimedAction(); simulated function DeactivateAction(); State Activated { simulated function Timer() { Remaining -= TimingInterval; TimedAction(); if ( Remaining > FinalCount) { if ( bPreFinalCount && Remaining == 2 * FinalCount ) Owner.PlaySound(DeactivateSound); } else if ( Remaining > 0 ) { if ( ++FinalCounter % FinalCountInterval == 0 ) Owner.PlaySound(DeactivateSound); } else { if ( bDeactivateCount ) Owner.PlaySound(DeactivateSound); UsedUp(); Destroy(); } } simulated function EndState() { UsedUp(); } simulated function BeginState() { // (re-)start countdown if ( Remaining == 0 || (Remaining > FullCharge && !bAddCharge) ) Remaining = FullCharge; FinalCount = Min(FinalCount, Remaining - 1); SetTimer(TimingInterval, True); bActive = true; ActivateAction(); } } // this is similar to UsedUp(), but is called instead of that function if in // Deactivated state simulated function TimedOut() { bActive = False; if ( Level.Game != None && Pawn(Owner) != None ) { if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogItemDeactivate(Self, Pawn(Owner)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogItemDeactivate(Self, Pawn(Owner)); } if ( ShellEffect != None ) ShellEffect.Destroy(); if ( Role == ROLE_Authority ) { ResetOwnerSpeed(); ResetDamageFactor(); } } state Deactivated { simulated function Timer() { Remaining -= TimingInterval; if ( Remaining == FinalCount) Owner.PlaySound(DeactivateSound); else { if ( bDeactivateCount ) Owner.PlaySound(DeactivateSound); TimedOut(); Destroy(); } } simulated function BeginState() { if ( bDeactivatedUseCharge ) SetTimer(TimingInterval, True); FinalCount = Min(FinalCount, Remaining - 1); bActive = false; } } GJD// EnhancedItems by Wormbo //============================================================================= // HoldablePowerup. //============================================================================= class HoldablePowerup extends PickupPlus abstract; var() bool bKillsOwner, // using the holdable will kill the owner (e.g. Kamikaze) bMultiUse, // if holdable is used the first time it goes to activated state bInstantAutoUse, // if the holdable detects a usage situation, it will instantly activate bMoreUsageChecks; // if false, checks for good usage will only be done when owner gets hit var bool UseMe, // if not bInstantAutoUse, this will be set to activate the holdable bAutoUseHoldables; // same as EIUseHoldable.bAutoUseHoldables var() localized string UseText, ReUseText; var() class UseMessageClass; function PreBeginPlay() { Super(TournamentPickup).PreBeginPlay(); bAutoUseHoldables = class'EnhancedItems.EIUseHoldable'.Default.bAutoUseHoldables; } function bool HandlePickupQuery( Inventory Item ) { if ( Item.Class == Class && bCanHaveMultipleCopies ) return Super.HandlePickupQuery(Item); return Item.IsA('HoldablePowerup') || Super.HandlePickupQuery(Item); } // executes the functionality of the holdable and returns true if it could be activated function bool DoActiveAction(); function UseHoldable() { Pawn(Owner).PlaySound(ActivateSound); if ( DoActiveAction() ) { if ( UseMessageClass == None && UseText != "" ) Pawn(Owner).ClientMessage(UseText); else if ( UseText != "" ) Pawn(Owner).ReceiveLocalizedMessage(UseMessageClass, 0, None, None, Self.Class); if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogItemActivate(Self, Pawn(Owner)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogItemActivate(Self, Pawn(Owner)); if ( bMultiUse ) GotoState('Activated'); else if ( bCanHaveMultipleCopies && NumCopies > 0 ) NumCopies--; else UsedUp(); } } function bool RecommendUse(name DamageType, int Damage, pawn InstigatedBy, vector HitLocation, optional bool Urgent) { local int ActualDamage; if ( Pawn(Owner) != None ) { if ( Owner.IsA('Bot') || class'EIUseHoldable'.default.bAutoUseHoldables ) if ( GoodUsage(DamageType, Damage, InstigatedBy, Urgent) ) { if ( bInstantAutoUse ) UseHoldable(); else { UseMe = True; SetTimer(0.01, False); } return true; } } return false; } // describes good situations to use the holdable, should be redefined in subclasses function bool GoodUsage(name DamageType, int ActualDamage, pawn InstigatedBy, optional bool Urgent) { return Urgent && !bKillsOwner; } event float BotDesireability( pawn Bot ) { local Inventory Inv; // try to get rid of other holdables before picking this one up for( Inv = Bot.Inventory; Inv != None; Inv = Inv.Inventory ) if ( Inv.IsA('HoldablePowerup') && !HoldablePowerup(Inv).bKillsOwner && !HoldablePowerup(Inv).RecommendUse('None', 0, None, Bot.Location, False) ) return -1; return Super.BotDesireability(Bot); } function Activate() { GoToState('Ready'); } // holdable is ready to activate state Ready { function BeginState() { if ( (bAutoUseHoldables || Owner.IsA('Bot')) && bMoreUsageChecks ) SetTimer(0.1, False); UseMe = False; } function Activate() { UseHoldable(); } function Timer() { if ( bAutoUseHoldables || Owner.IsA('Bot') ) { if ( UseMe ) { UseMe = False; UseHoldable(); return; } if ( !RecommendUse('None', 0, None, Owner.Location, False) && bMoreUsageChecks ) SetTimer(0.1, False); } } } // holdable is active state Activated { function Activate() { UseHoldable(); } function UseHoldable() { Pawn(Owner).PlaySound(ActivateSound); if ( DoActiveAction() ) { if ( UseMessageClass == None && ReUseText != "" ) Pawn(Owner).ClientMessage(ReUseText); else if ( ReUseText != "" ) Pawn(Owner).ReceiveLocalizedMessage(UseMessageClass, 1, None, None, Self.Class); if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogItemActivate(Self, Pawn(Owner)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogItemActivate(Self, Pawn(Owner)); UsedUp(); } } } GG;// EnhancedItems by Wormbo //============================================================================= // EIUseHoldable. // // Features: // - manages item selection and using holdable powerups // - added automatically by any PickupPlus that needs it //============================================================================= class EIUseHoldable extends EnhancedMutator config(EnhancedItems); var bool Initialized; // if true, checking for holdable usage occurs with player pawns, too var globalconfig bool bAutoUseHoldables; var localized string SelectedNone; function PostBeginPlay() { if ( Initialized || bDeleteMe ) return; Initialized = True; Level.Game.BaseMutator.AddMutator(Self); Level.Game.RegisterDamageMutator(Self); } function MutatorTakeDamage(out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation, out Vector Momentum, name DamageType) { local Inventory Inv; if ( NextDamageMutator != None ) NextDamageMutator.MutatorTakeDamage( ActualDamage, Victim, InstigatedBy, HitLocation, Momentum, DamageType ); if ( Victim.IsA('Bot') || bAutoUseHoldables ) { for( Inv = Victim.Inventory; Inv != None; Inv = Inv.Inventory ) if ( Inv.IsA('HoldablePowerup') ) { HoldablePowerup(Inv).RecommendUse(DamageType, ActualDamage, InstigatedBy, HitLocation, True); Break; } } } // modified version of Pawn.NextItem() function NextItem(pawn Other) { local Inventory Inv; if ( Other.SelectedItem == None ) { Other.SelectedItem = SelectNext(Other.Inventory); Return; } if ( Other.SelectedItem.Inventory != None) Other.SelectedItem = SelectNext(Other.SelectedItem.Inventory); else Other.SelectedItem = SelectNext(Other.Inventory); if ( Other.SelectedItem == None ) Other.SelectedItem = SelectNext(Other.Inventory); } // modified version of PlayerPawn.PrevItem() function PrevItem(pawn Other) { local Inventory Inv, LastItem, CurItem; if ( Other.SelectedItem != None ) CurItem = SelectNext(Other.SelectedItem, True); for( Inv = Other.Inventory; Inv != None; Inv = SelectNext(Inv.Inventory, True) ) { if ( LastItem == CurItem ) break; LastItem = Inv; } if ( LastItem != None ) Other.SelectedItem = SelectNext(LastItem); else NextItem(Other); // PrevItem() failed, try NextItem() } // modified version of Inventory.SelectNext() function Inventory SelectNext(Inventory PrevItem, optional bool bQuiet) { if ( PrevItem.IsA('Pickup') && (!PrevItem.IsA('PickupPlus') || !PrevItem.IsInState('Activated') || PickupPlus(PrevItem).bDeactivatable || !Pickup(PrevItem).bAutoActivate) && PrevItem.bActivatable && PrevItem.M_Selected != "" ) { if ( !bQuiet ) Pawn(Owner).ClientMessage(PrevItem.ItemName$PrevItem.M_Selected); return PrevItem; } if ( PrevItem.Inventory != None ) return SelectNext(PrevItem.Inventory, bQuiet); else return None; } function Mutate(string MutateString, PlayerPawn Sender) { local Inventory Inv; local bool bUsedHoldable; if ( MutateString ~= "UseHoldable" ) { for (Inv = Sender.Inventory; Inv != None; Inv = Inv.Inventory) if ( Inv.IsA('HoldablePowerup') ) { HoldablePowerup(Inv).UseHoldable(); bUsedHoldable = True; } if ( !bUsedHoldable ) Sender.ActivateItem(); } Inv = Sender.SelectedItem; if ( MutateString ~= "SelectNext" ) { NextItem(Sender); if ( Inv != None && Sender.SelectedItem == None ) Sender.ClientMessage(SelectedNone); } if ( MutateString ~= "SelectPrev" ) { PrevItem(Sender); if ( Inv != None && Sender.SelectedItem == None ) Sender.ClientMessage(SelectedNone); } if ( NextMutator != None ) NextMutator.Mutate(MutateString, Sender); } Gb] F-'b GV] pg] \  GM424D4%4,b4&b,r4 *wb *4 b 4pbp4vbv4rbr43b3b *b!44%!%!4,w4 *!4B!% a!q! G/GGW_ rk_ w  GGGGGZx @"-x ~ G\GGlavg&]c%c!Ic a- pAnyClassIsA: FoundVc insideWas #Sc]cc]'-c I*a- 稨AnyClassIsA:Wreplaced aV*]'( Gv ZJ >'-v .z^u^::$Zp ^u::$Zp ^uZ^uu?DuD::$^u::$^u?,^uZu s  GLu// EnhancedItems by Wormbo //============================================================================= // EnhancedDeathMessage. // // - used with EnhancedWeapon and EnhancedProjectile // - replaces UT's DeathMessagePlus (replacement through EIDeathMessageMutator) //============================================================================= /* Killing messages use the following placeholders: %k killer %o victim %w weapon %p projectile Suicide messages use the following placeholders: %o victim %w weapon %p projectile If the suicide string does not contain "%o", the suicider's name is placed in front of the string. Switch >1: use DeathMessagePlus for death message Switch 1: Suicide Switch 0: Kill w/ direct hit Switch -1: Kill w/ splash damage Switch -2: Kill head shot Switch -3: Head shot suicide Switch -4: Splash damage kill, but announce head shot Switch -5: Splash damage suicide, but announce head shot RelatedPRI_1 is the Killer. RelatedPRI_2 is the Victim. OptionalObject is the Killer's Weapon or Projectile Class. */ //============================================================================= class EnhancedDeathMessage extends DeathMessagePlus; static function string GetString( optional int iSwitch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject ) { local int HitType; // 0 = direct hit, 1 = head shot, 2 = splash damage local string TempString; if ( OptionalObject == None || iSwitch > 1 || (class(OptionalObject) != None && class(OptionalObject) == None) ) return Super.GetString(iSwitch, RelatedPRI_1, RelatedPRI_2, OptionalObject); if ( RelatedPRI_1 == None || RelatedPRI_1.PlayerName == "" ) return ""; if ( iSwitch == -3 ) { iSwitch = 1; HitType = 1; } if ( iSwitch == -5 ) { iSwitch = 1; HitType = 2; } else if ( iSwitch == -2 ) { iSwitch = 0; HitType = 1; } else if ( iSwitch == -1 || iSwitch == -4 ) { iSwitch = 0; HitType = 2; } switch (iSwitch) { case 0: // Killed somebody if ( RelatedPRI_2 == None || RelatedPRI_2.PlayerName == "" ) return ""; if ( Class(OptionalObject) == None && Class(OptionalObject) == None ) return ""; return ParseKillMessage(RelatedPRI_1.PlayerName, RelatedPRI_2.PlayerName, OptionalObject, HitType); break; case 1: // Suicided TempString = GetSuicideString(OptionalObject, HitType, RelatedPRI_1.bIsFemale); if ( InStr(TempString, "%o") < 0 ) TempString = RelatedPRI_1.PlayerName$TempString; else class'PickupPlus'.static.ReplaceText(TempString, "%o", RelatedPRI_1.PlayerName); return TempString; break; } log("Unexpected message parameters: Switch ="@iSwitch@"OptionalObject ="@OptionalObject@"PRI1:"@(RelatedPRI_1!=None)@"PRI2:"@(RelatedPRI_2!=None)); } static function string ParseKillMessage(string Killer, string Victim, Object Other, int HitType) { local string TempString, WeaponName, ProjectileName; if ( class(Other) != None ) { Switch (HitType) { Case 2: TempString = class(Other).Default.SplashHitString; break; Case 1: TempString = class(Other).Default.HeadHitString; break; default: TempString = class(Other).Default.DirectHitString; break; } WeaponName = class(Other).Default.ItemName; ProjectileName = class(Other).Default.ProjectileName; } else if ( class(Other) != None ) { Switch (HitType) { Case 2: TempString = class(Other).Default.SplashHitString; break; Case 1: TempString = class(Other).Default.HeadHitString; break; default: TempString = class(Other).Default.DirectHitString; break; } if ( class(Other).Default.FiredFrom != None ) WeaponName = class(Other).Default.FiredFrom.Default.ItemName; ProjectileName = class(Other).Default.ProjectileName; } class'PickupPlus'.static.ReplaceText(TempString, "%k", Killer); class'PickupPlus'.static.ReplaceText(TempString, "%o", Victim); class'PickupPlus'.static.ReplaceText(TempString, "%w", WeaponName); class'PickupPlus'.static.ReplaceText(TempString, "%p", ProjectileName); return TempString; } static function string GetSuicideString(Object Other, int HitType, bool bFemale) { local string TempString; if ( class(Other) != None ) { if ( bFemale ) { if ( HitType == 1 ) return class(Other).Default.HeadSuicideFString; TempString = class(Other).Default.SuicideFString; } else { if ( HitType == 1 ) return class(Other).Default.HeadSuicideString; TempString = class(Other).Default.SuicideString; } } else if ( class(Other) != None ) { if ( bFemale ) { if ( HitType == 1 ) return class(Other).Default.HeadSuicideFString; TempString = class(Other).Default.SuicideFString; } else { if ( HitType == 1 ) return class(Other).Default.HeadSuicideString; TempString = class(Other).Default.SuicideString; } } if ( TempString != "" ) { if ( class(Other) != None ) { class'PickupPlus'.static.ReplaceText(TempString, "%p", Class(Other).Default.ProjectileName); if ( Class(Other).Default.FiredFrom != None ) class'PickupPlus'.static.ReplaceText(TempString, "%w", Class(Other).Default.FiredFrom.Default.ItemName); } if ( class(Other) != None ) { class'PickupPlus'.static.ReplaceText(TempString, "%w", Class(Other).Default.ItemName); class'PickupPlus'.static.ReplaceText(TempString, "%p", Class(Other).Default.ProjectileName); } return TempString; } if ( bFemale ) return class'TournamentGameInfo'.Default.FemaleSuicideMessage; else return class'TournamentGameInfo'.Default.MaleSuicideMessage; } static function ClientReceive(PlayerPawn P, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject) { local int PlayerSelect; // 1 = headshot kill, 2 = headshot victim, 3 = headshot suicide Super.ClientReceive(P, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject); if ( P.PlayerReplicationInfo == RelatedPRI_1 ) { if ( RelatedPRI_1 == RelatedPRI_2 ) PlayerSelect = 3; else PlayerSelect = 1; } else if ( P.PlayerReplicationInfo == RelatedPRI_2 ) PlayerSelect = 2; if ( Switch < -1 && PlayerSelect > 0 ) { if ( class(OptionalObject) != None && class(OptionalObject).default.HeadShotMessage != None ) P.ReceiveLocalizedMessage(class(OptionalObject).default.HeadShotMessage, PlayerSelect); else if ( class(OptionalObject) != None && class(OptionalObject).default.HeadShotMessage != None ) P.ReceiveLocalizedMessage(class(OptionalObject).default.HeadShotMessage, PlayerSelect); } } GIiTS_<|iSplashDamage'8|i, SplashDamage'(  GPboV.5r*- /a0 b}b-b-b]10 G`// EnhancedItems by Wormbo //============================================================================= // EnhancedMutator. // // Features: // - can handle MultiPickupPlus replacement // - new RegisterHUDMutator function // - can draw on HUD before and after weapon is drawn // (only if an EnhancedWeapon is selected) // - unregisters from all mutator chains when destroyed // - activates the enhanced death messages of EnhancedWeapon and EnhancedProjectile //============================================================================= class EnhancedMutator extends Mutator abstract config(EnhancedItems); // additional HUD mutator variables var PlayerPawn PlayerOwner; // the PlayerPawn owning the HUD this mutator is registered to var HUD MyHUD; // HUD this mutator is registered to var ChallengeHUD MyChallengeHUD; // ChallengeHUD this mutator is registered to var bool bPendingHUDRegistration; // the RegisterHUDMutator() function has failed, so try again later // Subclass of MultiPickupPlus to use by default in replace functions. var() string MultiPickupBaseClass; // Set this to true if the mutator should not be added more than once. var() bool bAllowOnlyOnce; // The mutator should always create a MultiPickupPlus, // even if there is no need to do so. // This can solve errors with other EnhancedMutators // but can also produce new ones with non-EnhancedMutators. // (Must be implemented in CheckReplacement() for child classes.) var(Advanced) globalconfig bool bAlwaysCreateMPP; var EIDeathMessageMutator EIDMM; var bool bMIConverterSpawned; function AddMutator(Mutator M) { if ( M == Self ) return; // I'm already added to the mutators list else if ( bAllowOnlyOnce && M.Class == Class ) M.Destroy(); // already have a mutator of this class else if ( M != None && !M.bDeleteMe ) Super.AddMutator(M); } // convert ChaosUT.MultiItems to EnhancedItems.MultiPickupPlus // and add new player status icon function PreBeginPlay() { local Mutator M; SpawnMIConverter(); if ( class'PickupPlus'.default.bEnhancedStatusDoll ) SpawnEIChallengeHUD(); if ( !bDeleteMe && EIDMM == None ) { for (M = Level.Game.MessageMutator; M != None; M = M.NextMessageMutator) if ( M.IsA('EIDeathMessageMutator') ) { EIDMM = EIDeathMessageMutator(M); return; } EIDMM = Spawn(class'EnhancedItems.EIDeathMessageMutator'); } } function SpawnMIConverter() { local class M; local EnhancedMutator EM; local Inventory Inv; if ( Level.NetMode == NM_Client ) return; // MIConverter is server-side only if ( bMIConverterSpawned ) return; // check, if MIConverter was already spawned ForEach AllActors(class'EnhancedMutator', EM) If ( EM.IsA('MIConverter') ) { bMIConverterSpawned = True; // MIConverter already exists return; } log(class$": Spawning the MIConverter..."); M = class(DynamicLoadObject("MIConverter.MIConverter", class'Class', True)); if ( M != None && Spawn(M) != None ) log(class$": MIConverter spawned."); bMIConverterSpawned = True; } function SpawnEIChallengeHUD() { local class M; local EnhancedMutator EM; // check, if EIChallengeHUD was already spawned ForEach AllActors(class'EnhancedMutator', EM) if ( EM.IsA('EIChallengeHUD') ) return; // EIChallengeHUD already exists M = class(DynamicLoadObject("EIChallengeHUD.EIChallengeHUD", class'Class', True)); if ( M != None ) Spawn(M); } // correctly unregister this mutator from all linked mutator chains simulated function Destroyed() { local Mutator M; local HUD H; if ( Level.Game != None ) { if ( Level.Game.BaseMutator == Self ) Level.Game.BaseMutator = NextMutator; if ( Level.Game.DamageMutator == Self ) Level.Game.DamageMutator = NextDamageMutator; if ( Level.Game.MessageMutator == Self ) Level.Game.MessageMutator = NextMessageMutator; } ForEach AllActors(Class'Engine.HUD', H) if ( H.HUDMutator == Self ) H.HUDMutator = NextHUDMutator; ForEach AllActors(Class'Engine.Mutator', M) { if ( M.NextMutator == Self ) M.NextMutator = NextMutator; if ( M.NextHUDMutator == Self ) M.NextHUDMutator = NextHUDMutator; if ( M.NextDamageMutator == Self ) M.NextDamageMutator = NextDamageMutator; if ( M.NextMessageMutator == Self ) M.NextMessageMutator = NextMessageMutator; } } final function SetKillType(bool bSplashHit, bool bHeadHit, class DamageProjectileClass) { if ( EIDMM != None ) EIDMM.AddDamageActor(DamageProjectileClass, bSplashHit, bHeadHit); } final function RestoreKillType() { if ( EIDMM != None ) EIDMM.RemoveDamageActor(); } // Mutators sometimes want to work on actors the DMMutator wants to replace. // Use this function to get a reference to the BaseMutator after it has been // replaced by a configurable version. This will not work when the game type // uses a BaseMutator other than DMMutator or EIDMMutator. function EIDMMutator GetDMMutator() { if ( Level.Game.BaseMutator.IsA('EIDMMutator') ) return EIDMMutator(Level.Game.BaseMutator); else if ( Level.Game.BaseMutator.Class == Class'Botpack.DMMutator' ) { ReplaceDMMutator(); if ( Level.Game.BaseMutator.IsA('EIDMMutator') ) return EIDMMutator(Level.Game.BaseMutator); } return None; } function ReplaceDMMutator() { local Mutator M, PrevMutator, BaseNextMutator; local EIDMMutator NewBaseMutator; log("Replacing BaseMutator..."); if ( Level.Game.IsA('DeathMatchPlus') && Level.Game.BaseMutator.Class == Class'Botpack.DMMutator' ) { For ( M = Level.Game.BaseMutator; M != None; M = M.NextMutator ) if ( M.NextMutator == Self ) { PrevMutator = M; break; } if ( PrevMutator != None ) PrevMutator.NextMutator = NextMutator; BaseNextMutator = Level.Game.BaseMutator.NextMutator; NewBaseMutator = Spawn(class'EnhancedItems.EIDMMutator'); if ( NewBaseMutator != None ) { NewBaseMutator.NextMutator = BaseNextMutator; // Usually Self is spawned using BaseMutator.AddMutator(Spawn(Self.Class)) // in GameInfo.InitGame(). The next line redirects this AddMutator() call // to the new BaseMutator. Level.Game.BaseMutator.NextMutator = NewBaseMutator; Level.Game.BaseMutator.Destroy(); Level.Game.BaseMutator = NewBaseMutator; } log("BaseMutator now is"@Level.Game.BaseMutator); } else log("BaseMutator still is"@Level.Game.BaseMutator); } // These function helps identifying projectiles, weapons, ammo and other pickups. static final function bool OtherIsA(actor Other, name DesiredType) { if ( Other == None || DesiredType == '' || DesiredType == 'None' ) return false; if ( Other.IsA(DesiredType) ) return true; if ( Other.IsA('EnhancedProjectile') ) return EnhancedProjectile(Other).IdenticalTo == DesiredType; if ( Other.IsA('EnhancedWeapon') ) return EnhancedWeapon(Other).IdenticalTo == DesiredType; if ( Other.IsA('EnhancedAmmo') ) return EnhancedAmmo(Other).IdenticalTo == DesiredType; if ( Other.IsA('PickupPlus') ) return PickupPlus(Other).IdenticalTo == DesiredType; return false; } // same as Actor.GetItemName() but is a static function static function String StaticGetItemName(string FullName) { local int pos; pos = InStr(FullName, "."); While ( pos != -1 ) { FullName = Right(FullName, Len(FullName) - pos - 1); pos = InStr(FullName, "."); } return FullName; } static final function bool ClassIsA(class aClass, coerce string DesiredType) { local string DesiredClass, DesiredName; local class TestClass; DesiredName = StaticGetItemName(DesiredType); if ( DesiredType != DesiredName ) DesiredClass = DesiredType; if ( aClass == None || DesiredName == "" ) return false; if ( string(aClass) ~= DesiredClass || string(aClass.Name) ~= DesiredName ) return true; if ( class(aClass) != None && string(class(aClass).default.IdenticalTo) ~= DesiredName ) return true; if ( class(aClass) != None && string(class(aClass).default.IdenticalTo) ~= DesiredName ) return true; if ( class(aClass) != None && string(class(aClass).default.IdenticalTo) ~= DesiredName ) return true; if ( class(aClass) != None && string(class(aClass).default.IdenticalTo) ~= DesiredName ) return true; if ( DesiredClass != "" ) TestClass = Class(DynamicLoadObject(DesiredClass, Class'Class', True)); if ( TestClass != None ) return ClassIsChildOf(aClass, TestClass); return false; } // Give a weapon to a player and optionally bring it up as current weapon. function Weapon GiveWeapon(Pawn PlayerPawn, string aClassName, optional bool bBringUp) { local class WeaponClass; local Weapon NewWeapon; WeaponClass = class(DynamicLoadObject(aClassName, class'Class')); if ( PlayerPawn.FindInventoryType(WeaponClass) != None ) return None; newWeapon = Spawn(WeaponClass); if ( newWeapon != None ) { newWeapon.RespawnTime = 0.0; newWeapon.GiveTo(PlayerPawn); newWeapon.bHeldItem = true; newWeapon.GiveAmmo(PlayerPawn); newWeapon.SetSwitchPriority(PlayerPawn); newWeapon.WeaponSet(PlayerPawn); newWeapon.AmbientGlow = 0; if ( PlayerPawn.IsA('PlayerPawn') ) newWeapon.SetHand(PlayerPawn(PlayerPawn).Handedness); else newWeapon.GotoState('Idle'); if ( bBringUp ) { PlayerPawn.Weapon.GotoState('DownWeapon'); PlayerPawn.PendingWeapon = None; PlayerPawn.Weapon = newWeapon; PlayerPawn.Weapon.BringUp(); } } return newWeapon; } // replaces an inventory Other with a MultiPickupPlus, adds Other.Class // and returns the MultiPickupPlus final function MultiPickupPlus ConvertToMPP(inventory Other, optional string MPPClass) { local MultiPickupPlus A; local class OtherClass; OtherClass = Other.Class; A = ReplaceWithMPP(Other, MPPClass); if ( A != None ) A.AddItem(OtherClass); return A; } // This function is called after a MultiPickupPlus is spawned. // It is called for all EnhancedMutators except for the one that created the MPP. function bool CheckMPP(MultiPickupPlus Other) { return false; } // This function is called before an item is removed from a MultiPickupPlus. function bool AlwaysKeepInMPP(MultiPickupPlus Other, class ItemClass) { return false; } // Modified version of the ReplaceWith function. // Replaces an Inventory Other with a MultiPickupPlus and // returns a reference to it. final function MultiPickupPlus ReplaceWithMPP(inventory Other, optional string MPPClass) { local MultiPickupPlus A; local class aClass; if ( Other.Location == vect(0,0,0) ) return None; if ( MPPClass == "" ) MPPClass = MultiPickupBaseClass; aClass = class(DynamicLoadObject(MPPClass, class'Class')); if ( aClass == None && MPPClass != Default.MultiPickupBaseClass ) { log(Name$":"@MPPClass@"is not a valid MultiPickupPlus subclass, using default."); aClass = class(DynamicLoadObject(Default.MultiPickupBaseClass, class'Class')); } if ( aClass == None ) { log(Name$":"@Default.MultiPickupBaseClass@"is not a valid MultiPickupPlus subclass, using class'MultiPickupPlus'."); aClass = class(DynamicLoadObject("EnhancedItems.MultiPickupPlus", class'Class')); } if ( aClass != None ) A = Spawn(aClass, Other.Owner, Other.Tag, Other.Location + (aClass.Default.CollisionHeight - Other.CollisionHeight) * vect(0,0,1), Other.Rotation); if ( Other.MyMarker != None ) { Other.MyMarker.markedItem = A; if ( A != None ) A.MyMarker = Other.MyMarker; Other.MyMarker = None; } if ( A != None ) { if ( Other.Physics != Other.Default.Physics ) { if ( Other.Physics == PHYS_Falling ) A.bForceItemFall = True; else if ( Other.Default.Physics == PHYS_Falling ) A.bAllowItemFall = False; } if ( (!Other.bRotatingPickup || Other.RotationRate == rot(0,0,0)) && (A.Rotation.Pitch != 0 || A.Rotation.Roll != 0) ) A.bAllowItemRotation = False; else A.bAllowItemRotation = (Other.RotationRate != rot(0,0,0) && Other.bRotatingPickup) || !Other.default.bRotatingPickup || Other.default.RotationRate == rot(0,0,0); A.bForceItemRotation = Other.RotationRate != rot(0,0,0) && Other.bRotatingPickup && (!Other.default.bRotatingPickup || Other.default.RotationRate == rot(0,0,0)); A.Event = Other.Event; A.Tag = Other.Tag; A.ReplacedItem = Other.Class; // save, which item class was replaced A.CreatedBy = Self; return A; } log(Name $ ": Error: Couldn't spawn MultiPickupPlus (" $ MPPClass $ ")"); return None; } final function MultiPickupPlus ReplaceWithItemAsMPP(Inventory Other, coerce string aClassName, optional vector NewItemOffset, optional float NewInitTime, optional float NewChance, optional float NDuration) { local MultiPickupPlus MPP; MPP = ReplaceWithMPP(Other); if ( MPP != None ) MPP.AddItem(aClassName, NewItemOffset, NewInitTime, NewChance, NDuration); return MPP; } // Modified version of the ReplaceWith function // Replaces an inventory Other with an inventory of class aClassName and // returns a reference to it final function Inventory ReplaceWithItem(Inventory Other, coerce string aClassName) { local Inventory A; local class aClass; local bool bAllowItemFall, bForceItemFall; local bool bAllowItemRotation, bForceItemRotation; if ( Other.Location == vect(0,0,0) ) return None; aClass = class(DynamicLoadObject(aClassName, class'Class')); if ( aClass != None ) A = Spawn(aClass, Other.Owner, Other.Tag, Other.Location + (aClass.Default.CollisionHeight - Other.CollisionHeight) * vect(0,0,1), Other.Rotation); if ( Other.MyMarker != None ) { Other.MyMarker.markedItem = A; if ( A != None ) A.MyMarker = Other.MyMarker; Other.MyMarker = None; } else if ( A != None ) { A.bHeldItem = true; A.Respawntime = 0.0; } if ( A != None ) { if ( Other.Physics != Other.Class.Default.Physics ) { if ( Other.Physics == PHYS_Falling ) bForceItemFall = True; else if ( Other.Class.Default.Physics == PHYS_Falling ) bAllowItemFall = False; } if ( (!Other.bRotatingPickup || Other.RotationRate == rot(0,0,0)) && (Other.Rotation.Pitch != 0 || Other.Rotation.Roll != 0) ) bAllowItemRotation = False; else bAllowItemRotation = (Other.RotationRate != rot(0,0,0) && Other.bRotatingPickup) || !Other.default.bRotatingPickup || Other.default.RotationRate == rot(0,0,0); bForceItemRotation = Other.RotationRate != rot(0,0,0) && Other.bRotatingPickup && (!Other.default.bRotatingPickup || Other.default.RotationRate == rot(0,0,0)); if ( A.Physics == PHYS_Falling && !bAllowItemFall ) A.SetPhysics(PHYS_None); else if ( A.Physics != PHYS_Falling && bForceItemFall ) A.SetPhysics(PHYS_Falling); A.bRotatingPickup = bAllowItemRotation && (A.bRotatingPickup || bForceItemRotation); A.Event = Other.Event; A.Tag = Other.Tag; return A; } return None; } // You need to set the following three variables in the defaultproperties of // your HUD mutator in order to make it work: /* bAlwaysRelevant=True bNetTemporary=True RemoteRole=ROLE_SimulatedProxy */ // also add bPendingHUDRegistration=True to make the mutator automatically register itself as HUD mutator simulated function RegisterHUDMutator() { local PlayerPawn P; local Mutator M; bPendingHUDRegistration = False; if ( PlayerPawn(Owner) != None ) { P = PlayerPawn(Owner); if ( P.MyHUD != None ) { For (M = P.MyHUD.HUDMutator; M != None; M = M.NextHUDMutator) if ( M.Class == Class ) break; if ( M == None || M.Class != Class ) { NextHUDMutator = P.MyHUD.HUDMutator; MyHUD = P.MyHUD; MyChallengeHUD = ChallengeHUD(MyHud); if ( class'PickupPlus'.default.bDebugMode && P.MyHUD.HUDMutator != None ) log("RegisterHUDMutator: Registered"@Name$", NextHUDMutator is"@P.MyHUD.HUDMutator.Name); else if ( class'PickupPlus'.default.bDebugMode ) log("RegisterHUDMutator: Registered"@Name); P.MyHUD.HUDMutator = Self; PlayerOwner = P; bHUDMutator = True; } } } else ForEach AllActors(class'Engine.PlayerPawn', P) if ( P.MyHUD != None ) { For (M = P.MyHUD.HUDMutator; M != None; M = M.NextHUDMutator) if ( M.Class == Class ) break; if ( M != None && M.Class == Class ) continue; // already registered, check next PlayerPawn NextHUDMutator = P.MyHUD.HUDMutator; MyHUD = P.MyHUD; MyChallengeHUD = ChallengeHUD(MyHud); if ( class'PickupPlus'.default.bDebugMode && P.MyHUD.HUDMutator != None ) log("RegisterHUDMutator: Registered"@Name$", NextHUDMutator is"@P.MyHUD.HUDMutator.Name); else if ( class'PickupPlus'.default.bDebugMode ) log("RegisterHUDMutator: Registered"@Name); P.MyHUD.HUDMutator = Self; PlayerOwner = P; bHUDMutator = True; } if ( !bHUDMutator ) { bPendingHUDRegistration = True; Enable('Tick'); } } // always call Super.Tick(DeltaTime) to ensure the HUD registration works simulated function Tick(float DeltaTime) { if ( Level.NetMode != NM_DedicatedServer && !bHUDMutator && bPendingHUDRegistration ) RegisterHUDMutator(); } // If this function returns true, the mutator will handle drawing the weapon and // the weapon's OldRenderOverlays() function and all PostRenderOverlaysFor() // functions will be skipped. Following PreRenderOverlaysFor() calls for other // mutators or PickupPlus affectors will not be skipped. simulated function bool PreRenderOverlaysFor(Weapon W, Canvas C) { return false; } simulated function PostRenderOverlaysFor(Weapon W, Canvas C); // this is missing in the original PostRender() function of Engine.Mutator simulated function PostRender(Canvas Canvas) { if ( NextHUDMutator != None ) NextHUDMutator.PostRender(Canvas); } Gu3//----------------------------------------------------------------------------- // EIDeathMessageMutator. //----------------------------------------------------------------------------- // This mutator enhances the death messages of EnhancedWeapons and // EnhancedProjectiles by intercepting the regular death messages sent by UT. class EIDeathMessageMutator extends EnhancedMutator; var class DamageActor[5]; // the actor (EnhancedWeapon or EnhancedProjectile) that deals out damage var byte bSplashDamage[5], // whether the damage was splash damage or not bHeadShot[5]; // whether the hit was a head shot or not var bool Initialized, bUseMeInstead; var class EnhancedDeathMessageClass; var class MySpawnNotifyClass; var EIDeathMessageSpawnNotify MySpawnNotify; function AddDamageActor(class NewActor, bool bSplashHit, bool bHeadHit) { local int i; for (i = ArrayCount(DamageActor) - 1; i > 0; i--) { DamageActor[i] = DamageActor[i - 1]; bSplashDamage[i] = bSplashDamage[i - 1]; bHeadShot[i] = bHeadShot[i - 1]; } DamageActor[0] = NewActor; bSplashDamage[0] = int(bSplashHit); bHeadShot[0] = int(bHeadHit); } function RemoveDamageActor() { local int i; for (i = 0; i < ArrayCount(DamageActor) - 1; i++) { DamageActor[i] = DamageActor[i + 1]; bSplashDamage[i] = bSplashDamage[i + 1]; bHeadShot[i] = bHeadShot[i + 1]; } DamageActor[ArrayCount(DamageActor) - 1] = None; bSplashDamage[ArrayCount(bSplashDamage) - 1] = 0; bHeadShot[ArrayCount(bHeadShot) - 1] = 0; } function Spawned() { local SpawnNotify SN; for (SN = Level.SpawnNotify; SN != None; SN = SN.Next) if ( SN.IsA('EIDeathMessageSpawnNotify') ) { MySpawnNotify = EIDeathMessageSpawnNotify(SN); if ( MySpawnNotify.EIDMM == None || bUseMeInstead ) MySpawnNotify.EIDMM = Self; return; } if ( MySpawnNotifyClass != None ) MySpawnNotify = Spawn(MySpawnNotifyClass, Self); if ( MySpawnNotify != None ) MySpawnNotify.EIDMM = Self; } function PreBeginPlay() { Level.Game.RegisterMessageMutator(Self); } function bool MutatorBroadcastLocalizedMessage(Actor Sender, Pawn Receiver, out class Message, out optional int iSwitch, out optional PlayerReplicationInfo RelatedPRI_1, out optional PlayerReplicationInfo RelatedPRI_2, out optional Object OptionalObject) { if ( Message == Level.Game.DeathMessageClass && DamageActor[0] != None ) { Message = EnhancedDeathMessageClass; OptionalObject = DamageActor[0]; if ( iSwitch == 1 && bHeadShot[0] != 0 && bSplashDamage[0] != 0 ) iSwitch = -5; // splash damage suicide w/ headshot message else if ( iSwitch == 0 && bHeadShot[0] != 0 && bSplashDamage[0] != 0 ) iSwitch = -4; // splash damage kill w/ headshot message else if ( iSwitch == 1 && bHeadShot[0] != 0 ) iSwitch = -3; // head shot suicide else if ( iSwitch == 0 && bHeadShot[0] != 0 ) iSwitch = -2; // head shot kill else if ( iSwitch == 0 && bSplashDamage[0] != 0 ) iSwitch = -1; // splash damage kill } if ( NextMessageMutator != None ) return NextMessageMutator.MutatorBroadcastLocalizedMessage(Sender, Receiver, Message, iSwitch, RelatedPRI_1, RelatedPRI_2, OptionalObject); else return true; } GcGG[ fJ L5-[ feq efp o  GF// EWindow by Wormbo //============================================================================= // EWindowPageWindow //============================================================================= class EWindowPageWindow extends UMenuPageWindow; var bool bLoaded; var string ParentPageClass; // load settings and create controls when window is selected for first time (speeds things up) function ShowWindow() { if ( !bLoaded ) LoadSettings(); Super.ShowWindow(); } // Called when page is selected for the first time. // Create controls and load any settings from here. function LoadSettings() { bLoaded = True; } // Can be called by parent to set the position and size of controls. function SetControls(); function GetDesiredDimensions(out float W, out float H) { local int i, k; local string PageClassName, PageProperties; local float MaxW, MaxH, TW, TH; local PlayerPawn P; MaxW = 0; MaxH = 0; Super.GetDesiredDimensions(MaxW, MaxH); i = 0; P = GetPlayerOwner(); P.GetNextIntDesc(ParentPageClass, 0, PageClassName, PageProperties); while ( PageClassName != "" ) { if ( PageClassName ~= string(Class) ) { k = InStr(PageProperties, ","); if ( k >= 0 ) { PageProperties = Mid(PageProperties, k + 1); k = InStr(PageProperties, ","); if ( k == -1 ) MaxW = FMax(float(PageProperties), MaxW); else { MaxW = FMax(float(Left(PageProperties, k)), MaxW); MaxH = FMax(float(Mid(PageProperties, k + 1)), MaxH); } } break; } i++; P.GetNextIntDesc(ParentPageClass, i, PageClassName, PageProperties); } W = MaxW; H = MaxH; } GNt#? GP@Ghrvk%:_a> Y> Y{ s]! EnhancedItems.EWindowPageWindowGGQ'm"Kw'*T-E8R&'M ]'S sR&'N ]'T w'*-ER&'R ]'P R&'O ]'V {]w'* "o]%p'Uw'c* +o]%w'cw'* "o]%w' "o]%p'i]:-E I   G_// EnhancedItems by Wormbo //============================================================================= // MultiPickupPlus. // // Features: // - spawnes one of up to 20 different item classes // - the next item is chosen either randomly or in the order given in the // Items array (see bRandomChoosing, RejectChance[]) // - the next item is spawned after the previous one was picked up or a certein // amount of time has passed (see bEmulateMultiItem, StopEmulation(), // Duration[] and DefaultDuration) // - before the first item is spawned an initial interval of time set for this // item has to pass (can be set individually for each item, can be zero) // - each EnhancedMutator may change values after the MultiPickupPlus has been // initialized through the mutator's CheckMPP() function //============================================================================= class MultiPickupPlus extends Inventory config(EnhancedItems); // maximum number of items per MultiPickupPlus item (must be same like array sizes below) const MaxNumItems = 20; // default duration when emulating MultiItem var() const float DefaultDuration; var byte ImportedFromMI[20]; var() Class Item[20], // list of item classes to spawn ReplacedItem; // if this MPP replaced another item, the class of that // item is stored here (can also be set by map makers var() vector LocationOffset[20]; // offset from the MPP's location to spawn an item // Note: Unlike ChaosUT.MultiItem MPPs calculate // the base offset from the item's CollisionHeight // like the Mutator.ReplaceWith() function. var() float InitRespawnTime[20], // the MPP will wait this periode of time, // until the first item will be spawned Duration[20], // used with bEmulatedMultiItem, duration for the item to stay, // else if not 0 used as respawn time for the item RejectChance[20]; // chance of choosing another item instead of this one var() int NumItems; // Actual number of items this MPP has in its list. (Any items with // an index >= this value are removed in the PreBeginPlay() function.) var() bool bRandomChoosing, // If true the MPP chooses items randomly from its list. bEmulateMultiItem, // The MPP should cycle its item list like ChaosUT.MultiItem does. bEmulateWhenCoopMode, // Set bEmulateMultiItem=True when has weapons and Level.Game.bCoopWeaponMode=True. bNoMutatorCheck, // Don't allow mutators to check the MPP's list of items. bAllowItemRotation, // Items are allowed to rotate. bForceItemRotation, // Spawned items always rotate. (only with bAllowItemRotation) bAllowItemFall, // Items are allowed to rotate. bForceItemFall; // Spawned items always rotate. (only with bAllowItemRotation) // Whether MultiItem emulation is allowed or not. When this is true, // bEmulateMultiItem and bEmulateWhenCoopMode have no effect. var(Advanced) globalconfig bool bNoEmulation; var bool bStarted, bNotified, bDebugMode; var float CurTime; var Inventory CurItem; // currently spawned item var int CurItemIndex, PrevItemIndex, // list index of current and last item spawned CheckCounter; // used for checking recursions var Mutator CreatedBy; // this mutator won't get a CheckMPP() call replication { unreliable if ( Role == ROLE_Authority && NumItems > 0 ) Item; } static final function bool ClassIsA(class aClass, coerce string DesiredType) { return class'EnhancedMutator'.static.ClassIsA(aClass, DesiredType); } // check the MPP's location function CheckLocation() { local vector HitLocation, HitNormal; local bool bCorrectLocation; bCollideWorld = True; // current location ok? bCorrectLocation = SetLocation(Location); // floor check (most likely causes 'Fell out of world' errors if incorrect) if ( !bCorrectLocation && Trace(HitLocation, HitNormal, Location - vect(0,0,1) * CollisionHeight, Location + vect(0,0,1) * CollisionHeight, False) == Level ) bCorrectLocation = SetLocation(HitLocation + vect(0,0,1) * CollisionHeight); if ( !bCorrectLocation && bDebugMode ) log(HitNormal,Name); // trace to sides (wall check) if ( !bCorrectLocation && Trace(HitLocation, HitNormal, Location - vect(1,0,0) * CollisionHeight, Location + vect(1,0,0) * CollisionHeight, False) == Level ) bCorrectLocation = SetLocation(HitLocation + vect(1,0,0) * CollisionHeight); if ( !bCorrectLocation && Trace(HitLocation, HitNormal, Location - vect(-1,0,0) * CollisionHeight, Location + vect(-1,0,0) * CollisionHeight, False) == Level ) bCorrectLocation = SetLocation(HitLocation + vect(-1,0,0) * CollisionHeight); if ( !bCorrectLocation && Trace(HitLocation, HitNormal, Location - vect(0,1,0) * CollisionHeight, Location + vect(0,1,0) * CollisionHeight, False) == Level ) bCorrectLocation = SetLocation(HitLocation + vect(0,1,0) * CollisionHeight); if ( !bCorrectLocation && Trace(HitLocation, HitNormal, Location - vect(0,-1,0) * CollisionHeight, Location + vect(0,-1,0) * CollisionHeight, False) == Level ) bCorrectLocation = SetLocation(HitLocation + vect(0,-1,0) * CollisionHeight); // location ok now? if ( !bCorrectLocation ) Destroy(); bCollideWorld = False; } function PreBeginPlay() { local int i; bDebugMode = class'PickupPlus'.default.bDebugMode; if ( !bNoEmulation && bEmulateWhenCoopMode && Level.Game.bCoopWeaponMode && InItem(class'Weapon', i, True) ) bEmulateMultiItem = True; // set durations, if they are not specified if ( bEmulateMultiItem ) for (i = 0; i < MaxNumItems; i++) if ( Duration[i] == DefaultDuration || Duration[i] <= 0 ) Duration[i] = DefaultDuration * (1 - RejectChance[i]); // remove unused items from list for (i = NumItems; i < MaxNumItems; i++) Item[i] = None; // try to prevent items from falling out of the world CheckLocation(); // clean up other item slots Compact(); } function StopEmulation() { local int i; if ( bEmulateMultiItem && bDebugMode ) log(Name$": Stopping MultiItem emulation."); else if ( !bEmulateMultiItem ) return; bEmulateMultiItem = False; bRandomChoosing = True; for ( i = 0; i < MaxNumItems; i++ ) { if ( RejectChance[i] == 0 ) RejectChance[i] = Max(0, 1 - (Duration[i] / DefaultDuration)); Duration[i] = 0; } //GotoState('ChooseNextItem', 'Begin'); } // find item class by class reference (can find subclasses, doesn't use IdenticalTo) final function bool InItem(class LookFor, out int Index, optional bool bSubClasses, optional bool bCheckReplaced) { local int i; local bool bFoundItem; Index = -1; if ( LookFor == None ) return false; // no item specified for ( i = 0; i < NumItems; i++ ) { if ( Item[i] == None ) continue; else if ( Item[i] == LookFor ) { if ( bDebugMode ) log("InItem: Found"@Item[i]@"inside"@Name@"as #"$i); Index = i; // item found break; } else if ( bSubClasses && ClassIsChildOf(Item[i], LookFor) ) { if ( bDebugMode ) log("InItem: Found"@Item[i]@"(subclass of"@LookFor.Name$") inside"@Name@"as #"$i); Index = i; break; } } if ( Index != -1 ) return true; else if ( ReplacedItem == None ) return false; else if ( LookFor == ReplacedItem && bCheckReplaced ) { if ( bDebugMode ) log("InItem:"@Name@"replaced a"@ReplacedItem); Index = -2; return true; } else if ( bSubClasses && bCheckReplaced && ClassIsChildOf(ReplacedItem, LookFor) ) { if ( bDebugMode ) log("InItem:"@Name@"replaced a"@ReplacedItem@"(subclass of"@LookFor$")"); Index = -2; return true; } return false; // item not found } // find item class by class name (can use IdenticalTo, doesn't find subclasses) final function bool FindItem(name LookFor, out int Index, optional bool bIdenticalClasses, optional bool bCheckReplaced) { local int i; local bool bFoundItem; Index = -1; if ( LookFor == '' || LookFor == 'None' ) return false; // no item specified for (i = 0; i < NumItems; i++) { if ( Item[i] == None ) continue; else if ( Item[i].Name == LookFor ) { if ( bDebugMode ) log("FindItem: Found"@Item[i]@"inside"@Name@"as #"$i); Index = i; // item found break; } else if ( bIdenticalClasses && ((ClassIsChildOf(Item[i], class'EnhancedWeapon') && class(Item[i]).Default.IdenticalTo == LookFor) || (ClassIsChildOf(Item[i], class'PickupPlus') && class(Item[i]).Default.IdenticalTo == LookFor)) ) { if ( bDebugMode ) log("FindItem: Found"@Item[i]@"(identical to"@LookFor$") inside"@Name@"as #"$i); Index = i; break; } } if ( Index != -1 ) return true; else if ( !bCheckReplaced || ReplacedItem == None ) return false; else if ( LookFor == ReplacedItem.Name ) { if ( bDebugMode ) log("FindItem:"@Name@"replaced a"@ReplacedItem); Index = -2; return true; } else if ( bIdenticalClasses && ((ClassIsChildOf(ReplacedItem, class'EnhancedWeapon') && class(ReplacedItem).Default.IdenticalTo == LookFor) || (ClassIsChildOf(ReplacedItem, class'PickupPlus') && class(ReplacedItem).Default.IdenticalTo == LookFor)) ) { if ( bDebugMode ) log("FindItem:"@Name@"replaced a"@ReplacedItem@"(identical to"@LookFor$")"); Index = -2; return true; } return false; // item not found } // find item class through the ClassIsA() function final function bool AnyClassIsA(coerce string LookFor, out int Index, optional bool bCheckReplaced) { local int i; Index = -1; for (i = 0; i < NumItems; i++) { if ( ClassIsA(Item[i], LookFor) ) { if ( bDebugMode ) log("AnyClassIsA: Found"@Item[i]@"inside"@Name@"as #"$i); Index = i; break; } } if ( Index > -1 ) return true; if ( bCheckReplaced && ClassIsA(ReplacedItem, LookFor) ) { if ( bDebugMode ) log("AnyClassIsA:"@Name@"replaced a"@ReplacedItem); Index = -2; return true; } return false; // item not found } function bool AddItem(coerce string NewItem, optional vector NewItemOffset, optional float NewInitTime, optional float NewChance, optional float NDuration) { local int i; local float NewDuration; local class NewItemClass; if ( NDuration == 0.0 && bEmulateMultiItem ) NewDuration = DefaultDuration * (1- NewChance); else NewDuration = NDuration; if ( NewItem == "" || NewItem ~= "None" || InStr(NewItem, ".") == -1 ) { if ( bDebugMode ) log("AddItem: Nothing to add."@NewItem); return false; } i = 0; while (Item[i]!=None) { if ( string(Item[i]) ~= NewItem ) { if ( bDebugMode ) log("AddItem: "@NewItem@"already in"@Name@"as #"$i$". Applying new values."); LocationOffset[i] = NewItemOffset; InitRespawnTime[i] = NewInitTime; RejectChance[i] = NewChance; Duration[i] = NewDuration; return true; } i++; if ( i == MaxNumItems ) return false; else if ( i == NumItems ) break; } NumItems++; Item[i] = LoadItem(NewItem); if ( Item[i]!=None ) { LocationOffset[i] = NewItemOffset; InitRespawnTime[i] = NewInitTime; RejectChance[i] = NewChance; Duration[i] = NewDuration; ImportedFromMI[i] = 0; //GotoState('ChooseNextItem', 'Begin'); if ( bDebugMode ) log("AddItem: Added"@Item[i]@"as item #"$i@"to"@Name@"(now"@NumItems@"items)"); // if ( Level.Game.bCoopWeaponMode && class(Item[i]) != None ) // DisableCoopMode(); return true; } else { NumItems--; return false; } } // disable bCoopWeaponMode and reset bWeaponStay for all weapons on map function DisableCoopMode() { local Weapon w; if ( Level.Game == None || !Level.Game.bCoopWeaponMode ) return; ForEach AllActors(Class'Engine.Weapon', W) { W.bWeaponStay = W.Class.Default.bWeaponStay; W.SetWeaponStay(); } } // Removes an item from the MPP. // Can be prohibited by any EnhancedMutator via AlwaysKeepInMPP() // Returns true if the item was removed or was None. function bool RemoveItem(int ItemIndex) { local int i; local bool bWasEmpty; // avoid errors due to wrong parameter if ( ItemIndex < 0 || ItemIndex >= MaxNumItems ) { if ( ItemIndex == -2 ) log(Self.Name$".RemoveItem: Tried to remove the ReplacedItem value."); log(Self.Name$".RemoveItem: Parameter has to be >= 0 and <"@MaxNumItems@"(is"@ItemIndex$")"); return false; } if ( Item[ItemIndex] != None && AlwaysKeep(Item[ItemIndex]) ) return false; if ( bDebugMode ) log("RemoveItem: Removing item #"$ItemIndex@"("$Item[ItemIndex]$") from"@Name@"("$NumItems@"items)"); Item[ItemIndex] = None; Compact(); //log("RemoveItem: Item #"$ItemIndex@"now is"@Item[ItemIndex]@"("$NumItems@"items left)"); if ( ItemIndex == CurItemIndex ) GotoState('ChooseNextItem', 'Begin'); return true; } // this function removes empty item slots and recalculates the number of items function Compact() { local int i, j; // remove empty slots for (i = 0; i < MaxNumItems; i++) for (j = i + 1; j < MaxNumItems; j++) if ( Item[i] == None && Item[j] != None ) { //log(Name$": Item["$i$"] was empty"); Item[i] = Item[j]; LocationOffset[i] = LocationOffset[j]; RejectChance[i] = RejectChance[j]; InitRespawnTime[i] = InitRespawnTime[j]; Duration[i] = Duration[j]; Item[j] = None; } // recalculate number of items i = 0; NumItems = 0; while ( i < MaxNumItems ) { if ( Item[i] != None ) NumItems++; // if ( Level.Game.bCoopWeaponMode && class(Item[i]) != None ) // Level.Game.bCoopWeaponMode = False; i++; } if ( NumItems == 0 && !IsInState('Idle') ) GotoState('Idle'); } function bool ReplaceItem(int ItemIndex, coerce string NewItem, optional vector NewItemOffset, optional float InitTime, optional float Chance, optional float NDuration, optional bool AlwaysAdd ) { // InItem returns index -2 if the MPP replaced an item of the same class as searched for if ( ItemIndex == -2 && AlwaysAdd ) return AddItem(NewItem, NewItemOffset, InitTime, Chance, NDuration); else if ( RemoveItem(ItemIndex) || AlwaysAdd ) return AddItem(NewItem, NewItemOffset, InitTime, Chance, NDuration); return false; } function class LoadItem(coerce string ItemClass) { local class ClassName; ClassName = Class(DynamicLoadObject(ItemClass, class'Class', True)); if ( String(ClassName) == "None" ) { log(Name$": Loading failed!"@ItemClass@"is not a valid inventory class!"); return None; } else { //log(Name$": Loaded"@ClassName); return ClassName; } } function vector AdjustLocation(int ItemIndex) { local vector NewLocation; NewLocation = Location; if ( ImportedFromMI[ItemIndex] == 0 ) NewLocation.Z += Item[ItemIndex].Default.CollisionHeight - CollisionHeight; NewLocation += LocationOffset[ItemIndex]; return NewLocation; } // call the CheckMPP function of each active EnhancedMutator and EnhancedArena function NotifyMutators() { local Mutator M; if ( bNotified || bNoMutatorCheck ) return; bNotified = True; //log(self$": Notifying Mutators..."); for (M = Level.Game.BaseMutator; M != None; M = M.NextMutator) if ( M.IsA('EnhancedMutator') && M != CreatedBy ) { //log(Name$": Calling"@M.Name$".CheckMPP..."); if ( EnhancedMutator(M).CheckMPP(Self) ) break; } else if ( M.IsA('EnhancedArena') && M != CreatedBy ) { //log(Name$": Calling"@M.Name$".CheckMPP..."); if ( EnhancedArena(M).CheckMPP(Self) ) { break; } } } // call the AlwaysKeepInMPP function of each active EnhancedMutator and EnhancedArena function bool AlwaysKeep(class ItemClass) { local Mutator M; //log(Name$": Asking Mutators if allowed to remove"@ItemClass@"..."); for (M = Level.Game.BaseMutator; M != None; M = M.NextMutator) if ( M.IsA('EnhancedMutator') ) { //log(Name$": Calling"@M.Name$".AlwaysKeepInMPP..."); if ( EnhancedMutator(M).AlwaysKeepInMPP(Self, ItemClass) ) { if ( bDebugMode ) log(M.Name@"wants to keep"@ItemClass@"in"@Name); return true; } } else if ( M.IsA('EnhancedArena') ) { if ( EnhancedArena(M).AlwaysKeepInMPP(Self, ItemClass) ) { if ( bDebugMode ) log(M.Name@"wants to keep"@ItemClass@"in"@Name); return true; } } return false; } // no items to spawn so there's nothing to do auto state Idle { event float BotDesireability( pawn Bot ) { return -1; } Begin: Compact(); Sleep(0.1); CurItemIndex = -1; NotifyMutators(); Compact(); if ( NumItems > 0 ) GotoState('ChooseNextItem'); } // choose another item and spawn it state ChooseNextItem { event float BotDesireability( pawn Bot ) { if ( CurItem != None && !CurItem.bHeldItem ) return CurItem.BotDesireability(Bot); return -1; } Begin: CheckCounter = 0; if ( bEmulateMultiItem && bNoEmulation ) StopEmulation(); if ( CurItem != None && (CurItem.bHeldItem || CurItem.Inventory != None) ) CurItem = None; If ( NumItems == 0 ) GotoState('Idle'); PrevItemIndex = CurItemIndex; Sleep(0.1); Choose: CheckCounter++; // this should never be called if ( CheckCounter % 1000 == 0 ) log(Name$": CheckCounter ="@CheckCounter@"Item["$CurItemIndex$"] ="@Item[CurItemIndex]@ "RejectChance["$CurItemIndex$"] ="@RejectChance[CurItemIndex]); if ( bStarted && CurTime > Duration[CurItemIndex] ) CurTime = Duration[CurItemIndex]; if ( bRandomChoosing ) { CurItemIndex = Rand(NumItems); if ( FRand() > 1.0 - RejectChance[CurItemIndex] && !bEmulateMultiItem ) Goto('Choose'); // item was rejected, choose again } else { CurItemIndex++; If ( CurItemIndex >= NumItems || CurItemIndex < 0 ) CurItemIndex = 0; } // no item in this slot so clean up and choose again if ( Item[CurItemIndex] == None ) { Compact(); if ( NumItems > 0 ) Goto('Choose'); else GotoState('Idle'); } // wait before the item is spawned: // - after another item was picked up // - if this is the first item to be spawned here and there is an InitRespawnTime if ( bStarted && !bEmulateMultiItem ) { if ( Duration[CurItemIndex] == 0 ) Sleep(Item[CurItemIndex].Default.RespawnTime + Rand(7) - 3); else Sleep(Duration[CurItemIndex] + Rand(7) - 3); } else if ( InitRespawnTime[CurItemIndex] != 0 && !bEmulateMultiItem ) { Sleep(InitRespawnTime[CurItemIndex] + RandRange(-5, 5)); bStarted = True; } if ( PrevItemIndex != CurItemIndex || CurItem == None || CurItem.bHeldItem || !bStarted ) { If ( CurItem != None && !CurItem.bHeldItem ) CurItem.Destroy(); // now spawn the item previously chosen CurItem = Spawn(Item[CurItemIndex],,, AdjustLocation(CurItemIndex), Rotation); if ( CurItem == None ) Goto('Choose'); // Spawn failed, choose again if ( CurItem.Physics == PHYS_Falling && !bAllowItemFall ) CurItem.SetPhysics(PHYS_None); else if ( CurItem.Physics != PHYS_Falling && bForceItemFall ) CurItem.SetPhysics(PHYS_Falling); CurItem.bRotatingPickup = bAllowItemRotation && (CurItem.bRotatingPickup || bForceItemRotation); CurItem.RespawnTime = 0.0; // item should not respawn if ( CurItem.IsA('Weapon') ) Weapon(CurItem).bWeaponStay = false; if ( bStarted ) { if ( CurItem.RespawnSound != None ) CurItem.PlaySound(CurItem.RespawnSound); Sleep(Level.Game.PlaySpawnEffect(CurItem)); if ( PickupPlus(CurItem) != None && !bEmulateMultiItem ) if ( PickupPlus(CurItem).GlobalRespawnSound != None ) PickupPlus(CurItem).PlayGlobalSound(PickupPlus(CurItem).GlobalRespawnSound); } } bStarted = True; GotoState('SpawnedItem'); } // an item was spawned, wait until it is picked up or destroyed state SpawnedItem { function BeginState() { local Actor A; if ( Event != '' ) ForEach AllActors(class'Actor', A, Event) A.Trigger(Self, None); if ( MyMarker != None ) MyMarker.markedItem = CurItem; } function Timer () { if ( bEmulateMultiItem && CurTime >= Duration[CurItemIndex] ) { GotoState('ChooseNextItem'); } else if ( CurItem == None ) { if ( bEmulateMultiItem ) GotoState('ItemPickedUp'); else GotoState('ChooseNextItem'); } else if ( CurItem.GetStateName() == 'Sleeping' || CurItem.bHeldItem ) { if ( CurItem.bHeldItem ) CurItem = None; else { CurItem.Destroy(); CurItem = None; } if ( bEmulateMultiItem ) GotoState('ItemPickedUp'); else GotoState('ChooseNextItem'); } else { CurTime += 1.0; SetTimer(1.0, false); } } event float BotDesireability( pawn Bot ) { if ( CurItem != None ) return CurItem.BotDesireability(Bot); return -1; } function EndState() { if ( MyMarker != None ) MyMarker.markedItem = Self; } Begin: CurTime = 0.0; SetTimer(1.0, false); } // CurItem was picked up while in MultiItem emulation mode. // Wait for the periode of time specified in DefaultDuration, then continue. state ItemPickedUp extends Idle { Begin: Sleep(DefaultDuration); GotoState('ChooseNextItem'); } GR// EWindow by Wormbo //============================================================================= // EWindowEditControl - support auto-size based on caption size //============================================================================= class EWindowEditControl extends UWindowEditControl; var bool bAutoSize; function BeforePaint(Canvas C, float X, float Y) { local float TW, TH; if ( bAutoSize ) { TextSize(C, Text, TW, TH); EditBoxWidth = WinWidth - TW; } Super.BeforePaint(C, X, Y); } Gg -ge Goex -g' Gph Gqn D$XKoKox%^^b%Nj@{N|NVb~j,b%jjb&b~j,bKLjKKLjbKoLjb&o@x^bxNjXn Km o GGG]@Gngfu{~t GGU// EWindow by Wormbo //============================================================================= // EWindowComboControl - support auto-size based on caption size //============================================================================= class EWindowComboControl extends UWindowComboControl; var bool bAutoSize; function BeforePaint(Canvas C, float X, float Y) { local float TW, TH; if ( bAutoSize ) { TextSize(C, Text, TW, TH); EditBoxWidth = WinWidth - TW; } Super.BeforePaint(C, X, Y); } vxkweJ?_4 GGo// EnhancedItems by Wormbo //============================================================================= // EnhancedProjectile. // // Features: // - death/suicide messages for projectiles (independant from weapon) // - headshot support with extra damage type, death/suicide messages and // damage factor // - splash damage support with extra damage type and death/suicide messages // and different momentum transfer // - can be used as a "DamageType" by declaring an abstract class and specifying // it as DeathMessageActorClass in EnhancedWeapon/EnhancedProjectile // or as DamageProjectileClass in the SetKillType() function of PickupPlus, // EnhancedAmmo, EIEffect or EnhancedMutator // - can "capture" the firer's DamageScaling and apply it at explosion time //============================================================================= class EnhancedProjectile extends Projectile abstract config(EnhancedItems); var Actor MyTarget; // like Target, but will be replicated to client var(Advanced) globalconfig bool bDropEffects, // the actor should drop some visual effects (for slower machines) bKeepLightEffects; // the actor should not turn off its lighting effects (bad for FPS) // these are available only for projectiles var() class FiredFrom; // weapon class this projectile is fired from (used for %w in // death string, can also be a pickup, only ItemName is used) var() name IdenticalTo; // used by OtherIsA() and ClassIsA() to identify new versions of an actor var() localized string ProjectileName, // name of this projectile (used for %p in death sting) // death strings DirectHitString, // direct hit death message SplashHitString, // splash damage death message HeadHitString, // head shot death message SuicideString, // suicide death message (male) SuicideFString, // suicide death message (female) HeadSuicideString, // head shot suicide death message (male) HeadSuicideFString; // head shot suicide death message (female) // message displayed when killing with a head shot // The message should respond to the Switch parameter in the following way: // 1 = Player is killer // 2 = Player is victim // 3 = Player killed self // (Botpack.DecapitationMessage will always be displayed for killer and victim.) var() class HeadShotMessage; var() bool bCanHeadShoot, // projectile can cause head shots bConstantSplashDamage; // causes the damage in the outer splash area to be as // high as in the center (used in Combo InstaGib DM) var() float HeadShotHeight, // hitting an opponent above this multiplied with the CollisionHeight causes a HeadShot HeadShotDamageFactor; // Damage is multiplied with this if projectile hit victims head var() name HeadDamageType, // type of head shot damage, use 'Decapitated' for "Head Shot!" announcement SplashDamageType; // type of splash damage (When 'Push' is specified here, // actors are just pushed away without being damaged.) var() float DamageRadius, // radius of splash damage, no splash damage if 0 SplashMomentum, // momentum applied from splash damage SplashRangeModifier, // how the Instigator's DamageScaling affects DamageRadius: // splash radius = DamageRadius + (DamageRadius * (Instigator.DamageScaling - 1) * SplashRangeModifier) // SplashRangeModifier = 0: constant splash radius // SplashRangeModifier > 0: DamageFactors greater than 1 have a larger splash radius // SplashRangeModifier < 0: DamageFactors greater than 1 have a smaller splash radius MomentumModifier; // how the Instigator's DamageScaling affects MomentumTransfer and SplashMomentum: // momentum = MomentumTransfer + (MomentumTransfer * (Instigator.DamageScaling - 1) * MomentumModifier) // MomentumModifier = 0: constant momentum transfer // MomentumModifier > 0: DamageFactors greater than 1 apply more momentum transfer // MomentumModifier < 0: DamageFactors greater than 1 apply less momentum transfer var() class ExplosionEffectClass; // effect to spawn when exploding var() int SubMunitionCount; // amount of submunition to spawn when exploding var() class SubMunitionClass; // type of submunition to spawn // Set DeathMessageActorClass to another class to use its death strings. // Must be a subclass of EnhancedWeapon or EnhancedProjectile to work. // Use ReturnMessageActor() to get this value. (Returns Class if wrong // DeathMessageActorClass was specified.) var() class DeathMessageActorClass; // EnhancedProjectiles are not supported by the LifeSpan mutator, // but the LifeSpan mutator is supported by EnhancedProjectile ;-) // Use the LifeSpanMode() function to determine, if LifeSpan is used. var bool bLifeSpanMode, bNoLifeSpan; // used internally by the LifeSpanMode() function var() bool bKeepDamageScaling; // keep the Instigator's DamageScaling of the time the projectile was fired var float SpawnDamageScaling; var EIDeathMessageMutator EIDMM; replication { unreliable if ( Role == ROLE_Authority ) MyTarget; unreliable if ( Role == ROLE_Authority && bNetInitial ) SpawnDamageScaling; } static final function bool OtherIsA(actor Other, name DesiredType) { return class'EnhancedMutator'.static.OtherIsA(Other, DesiredType); } static final function bool ClassIsA(class aClass, coerce string DesiredType) { return class'EnhancedMutator'.static.ClassIsA(aClass, DesiredType); } simulated function Spawned() { Super.Spawned(); if ( bKeepDamageScaling && Role == ROLE_Authority ) { if ( Pawn(Owner) != None ) SpawnDamageScaling = Pawn(Owner).DamageScaling; else if ( Instigator != None ) SpawnDamageScaling = Instigator.DamageScaling; } } function string GetHumanName() { return ProjectileName; } simulated final function bool LifeSpanMode() { local SpawnNotify SN; if ( bNoLifeSpan || bLifeSpanMode ) return bLifeSpanMode; // we search for LifeSpawn (the SpawnNotify class used by the LifeSpan mutator) for (SN = Level.SpawnNotify; SN != None; SN = SN.Next) if ( SN.IsA('LifeSpawn') ) { bLifeSpanMode = True; return True; } bLifeSpanMode = False; bNoLifeSpan = True; return False; } static final function rotator RotationFromVector(vector NewDirection, optional rotator OldRotator) { local rotator NewRotator; NewRotator = rotator(NewDirection); NewRotator.Roll = OldRotator.Roll; return NewRotator; } // Explosion // Used to blow up the projectile. HitLocation, HitNormal and HitActor are optional. // If HitLocation is not specified, the projectile's current location will be used. // If HitActor is not specified and DamageRadius is 0 no damage will be done. simulated function Explosion(optional vector HitLocation, optional vector HitNormal, optional actor HitActor) { if ( HitLocation == vect(0,0,0) ) HitLocation = Location; if ( Role == ROLE_Authority ) { if ( DamageRadius > 0 ) SplashDamage(HitLocation, HitActor); else if ( HitActor != None ) DirectHit(HitLocation, HitActor); if ( SubmunitionCount > 0 ) SpawnSubMunition(HitLocation, HitNormal, SubMunitionCount); } SpawnExplosionEffects(HitLocation, HitNormal); BlowUp(HitLocation); Destroy(); } simulated function HitWall (vector HitNormal, actor Wall) { if ( Role == ROLE_Authority ) { if ( Mover(Wall) != None && Mover(Wall).bDamageTriggered ) Wall.TakeDamage(Damage, Instigator, Location, MomentumTransfer * Normal(Velocity), ''); MakeNoise(1.0); } Explosion(Location + ExploWallOut * HitNormal, HitNormal); } // EstimatedHitNormal // Returns the HitNormal, if the level doesn't change and the projectile flies from CurLocation along // vector Distance and hits something within the range specified by Distance. Returns a vector of // size 0 if it would hit nothing or HitLevel is true and it would hit any other actor than the level. // If HitLevel isn't true HitActor is set like in the Trace function, if HitLevel is true HitActor will // be set to Level or None depending on if it hit level geometry or not. function vector EstimatedHitNormal(out vector HitLocation, out actor HitActor, optional vector CurLocation, optional vector Distance, optional bool bHitLevelOnly, optional vector Extend) { local vector Loc, Dist, HN; local actor Collider; if ( CurLocation == vect(0,0,0) ) Loc = Location; else Loc = CurLocation; if ( Distance == vect(0,0,0) ) Dist = Velocity; else Dist = Distance; Collider = Trace(HitLocation, HN, Dist + Loc, Loc, !bHitLevelOnly, Extend); if ( bHitLevelOnly ) { if ( Collider == Level || Mover(Collider) != None ) { HitActor = Collider; return HN; } } else if ( Collider != None ) { HitActor = Collider; return HN; } HitActor = None; return vect(0,0,0); } // return a subclass of EnhancedWeapon or EnhancedProjectile for the death message function class ReturnMessageActor() { if ( class(DeathMessageActorClass) != None || class(DeathMessageActorClass) != None ) return DeathMessageActorClass; return Class; } final function SetKillType(bool bSplashHit, bool bHeadHit) { if ( EIDMM != None ) EIDMM.AddDamageActor(ReturnMessageActor(), bSplashHit, bHeadHit); } final function RestoreKillType() { if ( EIDMM != None ) EIDMM.RemoveDamageActor(); } // bSpecialHit causes head shot death message for normal and splash hits // (just death/suicide string; announcement only with 'Decapitated' damage) function SplashDamage(optional vector HitLocation, optional actor Other, optional vector HitNormal, optional bool bSpecialHit) { local actor Victims; local float damageScale, dist, momentumScale, ScaledRadius; local vector dir; local name DamageName; if ( bHurtEntry ) return; bHurtEntry = true; ScaledRadius = DamageRadius; if ( Instigator != None ) { if ( bKeepDamageScaling ) ScaledRadius += DamageRadius * (SpawnDamageScaling - 1) * SplashRangeModifier; else ScaledRadius += DamageRadius * (Instigator.DamageScaling - 1) * SplashRangeModifier; } if ( HitLocation == vect(0,0,0) ) HitLocation = Location; SetKillType(True, bSpecialHit); // activate spash hit death message foreach VisibleCollidingActors(class 'Actor', Victims, ScaledRadius, HitLocation) { if ( Victims != Self ) { dir = Victims.Location - HitLocation; dist = FMax(1, VSize(dir)); dir = SplashMomentum * dir / dist; damageScale = 1 - FClamp((dist - Victims.CollisionRadius) / ScaledRadius, 0, 1); if ( bKeepDamageScaling ) momentumScale = SpawnDamageScaling - 1; else if ( Instigator != None ) momentumScale = Instigator.DamageScaling - 1; else momentumScale = 0; momentumScale *= damageScale; if ( bConstantSplashDamage ) damageScale = 1; if ( bKeepDamageScaling && Instigator != None ) damageScale *= SpawnDamageScaling / Instigator.DamageScaling; // direct hit if ( Victims == Other ) { if ( VSize(HitNormal) == 0 ) HitNormal = Normal(Velocity); dir = Normal(dir) * SplashMomentum * momentumScale + HitNormal * MomentumTransfer * momentumScale; if ( bCanHeadShoot && Other.bIsPawn && (HitLocation.Z - Other.Location.Z > HeadShotHeight * Other.CollisionHeight) && (!Instigator.IsA('Bot') || !Bot(Instigator).bNovice) ) { DamageName = HeadDamageType; damageScale *= HeadShotDamageFactor; SetKillType(False, True); // temporarily switch to head shot death message } else { DamageName = MyDamageType; if ( Victims.bIsPawn ) SetKillType(False, bSpecialHit); // temporarily switch to direct hit death message } Victims.TakeDamage ( damageScale * Damage, Instigator, Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * Normal(dir), (damageScale + damageScale * momentumScale * MomentumModifier) * dir, DamageName ); if ( Victims.bIsPawn ) RestoreKillType(); // restore splash hit message } // splash damage hit else { if ( SplashDamageType == 'Push' ) Victims.TakeDamage ( 0, Instigator, Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * Normal(dir), (damageScale + damageScale * momentumScale * MomentumModifier) * dir, 'None' ); else { DamageName = AdjustSplashDamageType(Victims); Victims.TakeDamage ( damageScale * Damage, Instigator, Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * Normal(dir), (damageScale + damageScale * momentumScale * MomentumModifier) * dir, DamageName ); } } } } RestoreKillType(); // deactivate splash hit message bHurtEntry = false; } // bSpecialHit uses head shot message, bSplashHit uses splash damage message instead of direct hit message function DirectHit(vector HitLocation, actor Other, optional vector HitNormal, optional bool bSpecialHit) { local float damageScale, momentumScale; local vector dir; local name DamageName; if ( HitNormal != vect(0,0,0) ) dir = HitNormal * MomentumTransfer; else dir = Normal(Velocity) * MomentumTransfer; damageScale = 1.0; // direct hit if ( Other.Physics == PHYS_Walking && dir.Z < 0 ) dir.Z = 0.25 * dir.Z; if ( bCanHeadShoot && Other.bIsPawn && HitLocation.Z - Other.Location.Z > HeadShotHeight * Other.CollisionHeight && (!Instigator.IsA('Bot') || !Bot(Instigator).bNovice) ) { DamageName = HeadDamageType; damageScale *= HeadShotDamageFactor; SetKillType(False, True); } else { DamageName = MyDamageType; SetKillType(False, bSpecialHit); } if ( bKeepDamageScaling && Instigator != None ) damageScale *= SpawnDamageScaling / Instigator.DamageScaling; if ( bKeepDamageScaling ) momentumScale = SpawnDamageScaling - 1; else if ( Instigator != None ) momentumScale = Instigator.DamageScaling - 1; else momentumScale = 0; Other.TakeDamage ( damageScale * Damage, Instigator, Other.Location - 0.5 * (Other.CollisionHeight + Other.CollisionRadius) * Normal(dir), (damageScale + damageScale * momentumScale * MomentumModifier) * dir, DamageName ); // reset messages RestoreKillType(); } // You might want to use this function to do something with certain actors before // applying damage to them e.g. if this projectile should should make the Shock // Rifle's balls explode, the ball's SuperExplosion function must be called. The // function returns a Name so the DamageType done by the projectile can be set // individually for each actor in splash range. function Name AdjustSplashDamageType(Actor Other) { return SplashDamageType; } simulated function SpawnExplosionEffects(vector HitLocation, vector HitNormal) { local Effects s; if ( Level.NetMode != NM_DedicatedServer ) { if ( ExplosionEffectClass != None ) { s = spawn(ExplosionEffectClass,,, HitLocation, rotator(HitNormal)); s.RemoteRole = ROLE_None; } if ( HitNormal == vect(0,0,0) ) HitNormal = vect(0,0,1); if ( ExplosionDecal != None ) Spawn(ExplosionDecal,,, HitLocation, rotator(HitNormal)); } } function SpawnSubMunition(vector HitLocation, vector HitNormal, int Amount) { local Projectile s; local int i; if ( Amount < 1 || SubMunitionClass == None ) return; for (i = 0; i < Amount; i++) { s = Spawn(SubMunitionClass, Instigator,, HitLocation, rotator(VRand() + HitNormal)); if ( s != None ) { s.Instigator = Instigator; ModifySubMunition(s); } } } function ModifySubMunition(Projectile Other); function BlowUp(vector HitLocation) { MakeNoise(1.0); } // this function is not as flexible in usage as the Explosion() function (see above) simulated function Explode(vector HitLocation, vector HitNormal) { Explosion(HitLocation, HitNormal); } GR // EWindow by Wormbo //============================================================================= // EWindowRightClickMenu - handles more than one submenu //============================================================================= class EWindowRightClickMenu extends EWindowPulldownMenu; function Created() { bTransient = True; Super.Created(); } function RMouseDown(float X, float Y) { LMouseDown(X, Y); } function RMouseUp(float X, float Y) { LMouseUp(X, Y); } function CloseUp(optional bool bByOwner) { Super.CloseUp(bByOwner); HideWindow(); } y]xzv/Ld}2 GG|GG^GGQO// EnhancedItems by Wormbo //============================================================================= // PlayerShellEffect. //============================================================================= class PlayerShellEffect extends EIEffects; var() float FormTime, VanishTime, VisibleTime, AnimTime, GlowTime, FlashTime; var() float MinGlow, MaxGlow; var float CurGlow; var() float GlowRate, AnimRate; var() Enum EFormAnim { SFORM_Instant, // no forming animation SFORM_Grow, // scale size from StartSize to MinSize SFORM_LightUp, // scale ambient glow (transparency) from 0 to MinGlow SFORM_GrowLightUp // scale size from StartSize to MinSize and ambient glow from 0 to MinGlow } FormAnim; var() Enum EVisibleAnim { SVIS_None, // no animation at all SVIS_Pulse, // scale size between MinSize and MaxSize SVIS_Expand, // scale size from MinSize to MaxSize, then jump back to MinSize SVIS_Collaps, // scale size from MaxSize to MinSize, then jump back to MaxSize SVIS_Restore // restore size to MinSize if different } VisibleAnim; var() Enum EGlowAnim { SGLOW_Steady, // ambient glow doesn't change over time SGLOW_LightUp, // scale ambient glow from MaxGlow to MinGlow, then jump back to MaxGlow SGLOW_Darken, // scale ambient glow from MinGlow to MaxGlow, then jump back to MinGlow SGLOW_Blink, // scale ambient glow between MinGlow and MaxGlow SGLOW_Restore // restore ambient glow to MinGlow if different } GlowAnim; var() Enum EVanishAnim { SVANISH_Instant, // disappears instantly SVANISH_Shrink, // scale size to StartSize SVANISH_Fade, // scale ambient glow to 0 SVANISH_ShrinkFade, // scale size to StartSize and ambient glow to 0 SVANISH_GrowFade // scale size to EndSize and ambient glow to 0 } VanishAnim; var PickupPlus Master; // the item that created this effect var() bool bIdleLight; // keep light effect in Idle state // for PlayerSphere (EndSize will be used with SVANISH_GrowFade) var float CurSize; var() float StartSize, MinSize, MaxSize, EndSize; // for PlayerShell var int CurOffset; var() int MinOffset, MaxOffset; function SetFlashTime(float NewFlashTime) { FlashTime = Max(FlashTime, NewFlashTime); } function UpdateFlash(float DeltaTime) { if ( !bDestroyMe && (Owner == None || (Pawn(Owner) != None && Pawn(Owner).Health <= 0)) ) DestroyMe(); if ( Owner.IsA('PlayerPawn') ) bOwnerNoSee = Default.bOwnerNoSee && PlayerPawn(Owner).ViewTarget == None && !PlayerPawn(Owner).bBehindView; if ( FlashTime > 0 ) { FlashTime -= DeltaTime; if ( Default.Style == STY_Translucent ) Style = STY_Normal; } if ( FlashTime < 0 ) FlashTime = 0; if ( FlashTime == 0 && Style != STY_Translucent && Default.Style == STY_Translucent ) Style = STY_Translucent; } function ShowMe() { if ( IsInState('Idle') ) GotoState('Forming'); } // use this instead of Destroy() function DestroyMe() { bDestroyMe = True; VisibleTime = 0.0; if ( IsInState('Visible') || IsInState('Forming') ) { CurSize = DrawScale; CurGlow = ScaleGlow; GotoState('Vanishing', 'Begin'); } else if ( bHidden || !IsInState('Vanishing') ) Destroy(); } state Forming { function Tick(float DeltaTime) { AnimTime += DeltaTime; UpdateAppearance(); UpdateFlash(DeltaTime); } function UpdateAppearance(); Begin: bHidden = False; LightType = Default.LightType; AnimTime = 0.0; UpdateAppearance(); if ( FormAnim != SFORM_Instant && FormTime > 0 ) Sleep(FormTime); GotoState('Visible'); } state Visible { function Tick(float DeltaTime) { AnimTime += DeltaTime; GlowTime += DeltaTime; UpdateAppearance(); UpdateFlash(DeltaTime); } function UpdateAppearance(); Begin: AnimTime = 0.0; GlowTime = 0.0; if ( VisibleTime > 0.0 ) { Sleep(VisibleTime); CurSize = DrawScale; CurGlow = ScaleGlow; MinOffset = CurOffset; GotoState('Vanishing'); } } state Vanishing { function Tick(float DeltaTime) { AnimTime += DeltaTime; UpdateAppearance(); UpdateFlash(DeltaTime); } function UpdateAppearance(); Begin: AnimTime = 0.0; if ( VanishAnim != SVANISH_Instant && VanishTime > 0 ) Sleep(VanishTime); if ( !bDestroyMe ) GotoState('Idle'); else Destroy(); } auto state Idle { Ignores Touch, Tick; function EndState() { FlashTime = 0; Super.EndState(); } Begin: bHidden = True; if ( bIdleLight ) LightType = Default.LightType; else LightType = LT_None; } state PickupShell { simulated function Tick(float DeltaTime) { if ( Master == None ) { GotoState('Idle'); return; } SetLocation(Master.Location); SetRotation(Master.Rotation); Velocity = Master.Velocity; //Mesh = Master.Mesh; DrawScale = Default.DrawScale; AmbientGlow = Default.AmbientGlow; ScaleGlow = Default.ScaleGlow; Fatness = Default.Fatness; Texture = Master.PickupShellSkin; } Begin: bHidden = False; LightType = LT_None; } GVGGX ] <X . ?,8?,@BA GdeTS e$bw.*w.*.Cd $ w.*w.*.C dS Gm]// EnhancedItems by Wormbo //----------------------------------------------------------------------------- // DMMutator. //----------------------------------------------------------------------------- class EIDMMutator extends DMMutator; // you can disable any of these features from other mutators var bool bSetAutoActivate, // sets bAutoActivate (Pickup class) to True bKeepStationaryPawns, // excludes StationaryPawn classes from CheckReplacement() bSetMegaSpeed, // sets higher speed for players if the game type is configured for turbo speed bReplaceWeapons, // replace Unreal weapons bReplaceAmmo, // replace Unreal ammo and Dispersion Pistol upgrade bReplaceHealth, // replace Unreal health items (not Nali Fruit) bReplaceArmor, // replace Kevlar Suit and Assault Vest (Unreal body armor) bReplaceJumpBoots, // replace Unreal Jump Boots (remove them if it's a jump match game) bReplaceShieldbelt, // replace Unreal Shieldbelt bReplaceInvisibility, // replace Unreal Invisibility bReplaceAmplifier; // replace Amplifier (for Dispersion Pistol & Unreal ASMD) with Damage Amplifier var float MegaSpeedFactor; // actual speed factor to use in mega speed games function AddMutator(Mutator M) { if ( M.IsA('NoAlwaysAutoActivate') ) { bSetAutoActivate = False; M.Destroy(); } else Super.AddMutator(M); } function bool AlwaysKeep(Actor Other) { local bool bTemp; if ( bKeepStationaryPawns && Other.IsA('StationaryPawn') ) return true; if ( NextMutator != None ) return ( NextMutator.AlwaysKeep(Other) ); return false; } function bool CheckReplacement(Actor Other, out byte bSuperRelevant) { local Inventory Inv; // replace Unreal I inventory actors by their Unreal Tournament equivalents // set bSuperRelevant to false if want the gameinfo's super.IsRelevant() function called // to check on relevancy of this actor. bSuperRelevant = 1; if ( bSetMegaSpeed && MyGame.bMegaSpeed && Other.bIsPawn && Pawn(Other).bIsPlayer ) { Pawn(Other).GroundSpeed *= MegaSpeedFactor; Pawn(Other).WaterSpeed *= MegaSpeedFactor; Pawn(Other).AirSpeed *= MegaSpeedFactor; Pawn(Other).AccelRate *= MegaSpeedFactor; } Inv = Inventory(Other); if ( Inv == None ) { bSuperRelevant = 0; if ( Other.IsA('TorchFlame') ) Other.NetUpdateFrequency = 0.5; return true; } // probably never used (no mutators allowed in rated games) if ( MyGame.bNoviceMode && MyGame.bRatedGame && Level.NetMode == NM_Standalone ) Inv.RespawnTime *= (0.5 + 0.1 * MyGame.Difficulty); if ( Other.IsA('TournamentWeapon') ) return true; if ( bReplaceWeapons && Other.IsA('Weapon') ) { if ( Other.IsA('Stinger') ) ReplaceWith(Other, "Botpack.PulseGun"); else if ( Other.IsA('Rifle') ) ReplaceWith( Other, "Botpack.SniperRifle" ); else if ( Other.IsA('Razorjack') ) ReplaceWith( Other, "Botpack.Ripper" ); else if ( Other.IsA('Minigun') ) ReplaceWith( Other, "Botpack.Minigun2" ); else if ( Other.IsA('AutoMag') ) ReplaceWith( Other, "Botpack.Enforcer" ); else if ( Other.IsA('Eightball') ) ReplaceWith( Other, "Botpack.UT_Eightball" ); else if ( Other.IsA('FlakCannon') ) ReplaceWith( Other, "Botpack.UT_FlakCannon" ); else if ( Other.IsA('ASMD') ) ReplaceWith( Other, "Botpack.ShockRifle" ); else if ( Other.IsA('GesBioRifle') ) ReplaceWith( Other, "Botpack.UT_BioRifle" ); else if ( Other.IsA('DispersionPistol') ) ReplaceWith( Other, "Botpack.ImpactHammer"); else { bSuperRelevant = 0; return true; } return false; } if ( Other.IsA('TournamentAmmo') ) return true; if ( bReplaceAmmo && Other.IsA('Ammo') ) { if ( Other.IsA('ASMDAmmo') ) ReplaceWith( Other, "Botpack.ShockCore" ); else if ( Other.IsA('RocketCan') ) ReplaceWith( Other, "Botpack.RocketPack" ); else if ( Other.IsA('StingerAmmo') ) ReplaceWith(Other, "Botpack.PAmmo"); else if ( Other.IsA('RazorAmmo') ) ReplaceWith( Other, "Botpack.BladeHopper" ); else if ( Other.IsA('RifleRound') ) ReplaceWith( Other, "Botpack.RifleShell" ); else if ( Other.IsA('RifleAmmo') ) ReplaceWith( Other, "Botpack.BulletBox" ); else if ( Other.IsA('FlakBox') ) ReplaceWith( Other, "Botpack.FlakAmmo" ); else if ( Other.IsA('Clip') ) ReplaceWith( Other, "Botpack.EClip" ); else if ( Other.IsA('ShellBox') ) ReplaceWith( Other, "Botpack.MiniAmmo" ); else if ( Other.IsA('Sludge') ) ReplaceWith( Other, "Botpack.BioAmmo" ); else { bSuperRelevant = 0; return true; } return false; } if ( bSetAutoActivate && Other.IsA('Pickup') ) Pickup(Other).bAutoActivate = true; if ( Other.IsA('TournamentPickup') ) return true; if ( Other.IsA('TournamentHealth') ) return true; //log("Found "$Other$" at "$Other.location); //Assert(false); if ( bReplaceJumpBoots && Other.IsA('JumpBoots') ) { if ( !MyGame.bJumpMatch ) ReplaceWith( Other, "Botpack.UT_JumpBoots" ); } else if ( bReplaceAmplifier && Other.IsA('Amplifier') ) ReplaceWith( Other, "Botpack.UDamage" ); else if ( bReplaceArmor && Other.IsA('KevlarSuit') ) ReplaceWith( Other, "Botpack.ThighPads"); else if ( bReplaceHealth && Other.IsA('SuperHealth') ) ReplaceWith( Other, "Botpack.HealthPack" ); else if ( bReplaceArmor && Other.IsA('Armor') ) ReplaceWith( Other, "Botpack.Armor2" ); else if ( bReplaceHealth && Other.IsA('Bandages') ) ReplaceWith( Other, "Botpack.HealthVial" ); else if ( bReplaceHealth && Other.IsA('Health') && !Other.IsA('NaliFruit') ) ReplaceWith( Other, "Botpack.MedBox" ); else if ( bReplaceShieldbelt && Other.IsA('ShieldBelt') ) ReplaceWith( Other, "Botpack.UT_ShieldBelt" ); else if ( bReplaceInvisibility && Other.IsA('Invisibility') ) ReplaceWith( Other, "Botpack.UT_Invisibility" ); else if ( bReplaceWeapons || !Other.IsA('WeaponPowerUp') ) { bSuperRelevant = 0; return true; } return false; } GQ// EnhancedItems by Wormbo //============================================================================= // EnhancedWeapon. // // Don't use the DeathMessage. Combine DirectHit or SplashDamage with the // hit strings below to create more complex death messages. // Look at EIRazor2 (EIBotpackUpgrade) or MercuryMissile (RocketsUT) for an // example of how to use hit strings and head shot settings. //============================================================================= class EnhancedWeapon extends TournamentWeapon abstract config(EnhancedItems); // this specifies, if the actor should drop some visual effects (for slower machines) var(Advanced) globalconfig bool bDropEffects; var name SamePriorityLike; // used to set the switch priority var() name IdenticalTo; // used by OtherIsA() and ClassIsA() to identify new versions of an actor // used by weapon priority menu var() localized string MenuName; // name to be displayed in weapon priority menu var() Mesh MenuMesh; // mesh to be displayed in weapon priority menu (if None, PickupViewMesh is used) var() float MenuViewScale; // scaling factor for MenuMesh (default is PickupViewScale) var() rotator MenuRotation; // Yaw component will not be used // used to speed up weapons when under the effect of the relic of speed or similar powerup var() float SpeedScale; // for weapons like the Enforcer var EnhancedWeapon SlaveWeapon, MasterWeapon; var bool bIsSlave; var() bool bCustomDrawSlave; // drawing of the slave weapon is handled by subclass var() name DoublePriorityName; var() int DoubleSwitchPriority; var() localized string DoubleName; var() localized string ProjectileName, // name of the (imaginary) projectile fired by this weapon // death strings DirectHitString, // direct hit death message SplashHitString, // splash damage death message HeadHitString, // head shot death message SuicideString, // suicide death message (male) SuicideFString, // suicide death message (female) HeadSuicideString, // head shot suicide death message (male) HeadSuicideFString; // head shot suicide death message (female) // message displayed when killing with a head shot // The message should respond to the Switch parameter in the following way: // 1 = Player is killer // 2 = Player is victim // 3 = Player killed self // (Botpack.DecapitationMessage will always be displayed for killer and victim.) var() class HeadShotMessage; var() bool bCanHeadShoot, // has special head shooting abilities (more damage, different death message) bConstantSplashDamage; // causes the damage in the outer splash area // to be as high as in the center (used in Combo InstaGib DM) var() float Damage, // Damage done when hit with this weapon Range, // range of melee weapon MaxRange, // maximum range of instant hit weapon HeadShotHeight, // hitting an opponent above this multiplied with the // CollisionHeight causes a HeadShot HeadShotDamageFactor; // Damage is multiplied with this if projectile // hit victims head and bCanHeadShoot is true var() name HeadDamageType, // type of head shot damage, use 'Decapitated' for "Head Shot!" announcement SplashDamageType; // type of splash damage (When 'Push' is specified here, // actors are just pushed away without being damaged.) var() float DamageRadius, // radius of splash damage, no splash damage if 0 MomentumTransfer, // momentum applied from direct hits SplashMomentum, // momentum applied from splash damage SplashRangeModifier, // how the Instigator's DamageScaling affects DamageRadius: // splash radius = DamageRadius + (DamageRadius * (Instigator.DamageScaling - 1) * SplashRangeModifier) // SplashRangeModifier = 0: constant splash radius // SplashRangeModifier > 0: DamageFactors greater than 1 have a larger splash radius // SplashRangeModifier < 0: DamageFactors greater than 1 have a smaller splash radius MomentumModifier; // how the Instigator's DamageScaling affects MomentumTransfer and SplashMomentum: // momentum = MomentumTransfer + (MomentumTransfer * (Instigator.DamageScaling - 1) * MomentumModifier) // MomentumModifier = 0: constant momentum transfer // MomentumModifier > 0: DamageFactors greater than 1 apply more momentum transfer // MomentumModifier < 0: DamageFactors greater than 1 apply less momentum transfer var() class ExplosionEffectClass; // effect to play at hit location var() class ExplosionDecal; // impact decal spawned at hit location var() int SubMunitionCount; // amount of submunition to spawn when exploding var() class SubMunitionClass; // type of submunition to spawn // Set this to another class to use its death strings. Must be a subclass of // EnhancedWeapon or EnhancedProjectile to work. Use ReturnMessageActor() to // get this value. (Returns this class if wrong class was specified.) var() class DeathMessageActorClass; var bool bDrawingWeapon; // weapon is not hidden in 1st person view (updated in OldRenderOverlays) var EIDeathMessageMutator EIDMM; replication { unreliable if ( Role == ROLE_Authority && bNetOwner ) SpeedScale, SlaveWeapon, bIsSlave; unreliable if ( Role == ROLE_Authority && bIsSlave ) MasterWeapon; } // add the EIDeathMessageMutator to support enhanced death messages function PreBeginPlay() { local Mutator M; Super.PreBeginPlay(); if ( !bDeleteMe && EIDMM == None ) { for (M = Level.Game.MessageMutator; M != None; M = M.NextMessageMutator) if ( M.IsA('EIDeathMessageMutator') ) { EIDMM = EIDeathMessageMutator(M); return; } EIDMM = Spawn(class'EnhancedItems.EIDeathMessageMutator'); } } static final function bool OtherIsA(actor Other, name DesiredType) { return class'EnhancedMutator'.static.OtherIsA(Other, DesiredType); } static final function bool ClassIsA(class aClass, coerce string DesiredType) { return class'EnhancedMutator'.static.ClassIsA(aClass, DesiredType); } simulated function vector CalcZoomedFireOffset() { local vector DrawOffset, WeaponBob; local Pawn PawnOwner; PawnOwner = Pawn(Owner); DrawOffset = VSize(PlayerViewOffset) / PawnOwner.FOVAngle * vector(PawnOwner.ViewRotation); if ( Level.NetMode == NM_DedicatedServer || (Level.NetMode == NM_ListenServer && Owner.RemoteRole == ROLE_AutonomousProxy) ) DrawOffset += PawnOwner.BaseEyeHeight * vect(0,0,1); else { DrawOffset += PawnOwner.EyeHeight * vect(0,0,1); WeaponBob = BobDamping * PawnOwner.WalkBob; WeaponBob.Z = (0.45 + 0.55 * BobDamping) * PawnOwner.WalkBob.Z; DrawOffset += WeaponBob; } return DrawOffset; } //============================================================================= // Allow HUD mutators and weapon affectors to draw on the canvas right after // the weapon has been rendered and before the HUD is drawn. // Note that any number of PickupPlus items and one TournamentPickup can affect // a TournamentWeapon at the same time but only the PickupPlus items are // allowed to draw on the canvas. simulated function RenderOverlays(Canvas Canvas) { local Mutator M; local PickupPlus A; local bool bOverride; if ( SlaveWeapon != None && !bCustomDrawSlave ) SlaveWeapon.Affector = Affector; else if ( bIsSlave && MasterWeapon != None && !bCustomDrawSlave ) Affector = MasterWeapon.Affector; if ( PlayerPawn(Owner) != None && PlayerPawn(Owner).myHUD != None ) for (M = PlayerPawn(Owner).myHUD.HUDMutator; M != None; M = M.NextHUDMutator) if ( M.IsA('EnhancedMutator') ) bOverride = EnhancedMutator(M).PreRenderOverlaysFor(Self, Canvas) || bOverride; for (A = PickupPlus(Affector); A != None; A = PickupPlus(A.NextAffector)) if ( A.bRenderOverlays ) bOverride = A.PreRenderOverlaysFor(Self, Canvas) || bOverride; if ( !bOverride ) { OldRenderOverlays(Canvas); if ( PlayerPawn(Owner) != None && PlayerPawn(Owner).myHUD != None ) for (M = PlayerPawn(Owner).myHUD.HUDMutator; M != None; M = M.NextHUDMutator) if ( M.IsA('EnhancedMutator') ) EnhancedMutator(M).PreRenderOverlaysFor(Self, Canvas); for (A = PickupPlus(Affector); A != None; A = PickupPlus(A.NextAffector)) if ( A.bRenderOverlays ) A.PostRenderOverlaysFor(Self, Canvas); } if ( SlaveWeapon != None && !bCustomDrawSlave ) SlaveWeapon.RenderOverlays(Canvas); } // OldRenderOverlays() is called by RenderOverlays() or PreRenderOverlays() function // of an EnhancedMutator registered as HUD mutator or a PickupPlus registered as affector. // It does the actual drawing of the weapon. simulated function OldRenderOverlays(Canvas C) { local rotator NewRot; local bool bPlayerOwner; local int Hand; local PlayerPawn PlayerOwner; bDrawingWeapon = !bHideWeapon; if ( bHideWeapon || Owner == None ) bDrawingWeapon = False; PlayerOwner = PlayerPawn(Owner); if ( PlayerOwner != None ) { if ( PlayerOwner.DesiredFOV != PlayerOwner.DefaultFOV ) bDrawingWeapon = False; bPlayerOwner = true; Hand = PlayerOwner.Handedness; if ( Level.NetMode == NM_Client && Hand == 2 ) { bHideWeapon = true; bDrawingWeapon = False; } } if ( !bPlayerOwner || PlayerOwner.Player == None ) Pawn(Owner).WalkBob = vect(0,0,0); if ( bDrawingWeapon && bMuzzleFlash > 0 && bDrawMuzzleFlash && Level.bHighDetailMode && MFTexture != None ) { MuzzleScale = Default.MuzzleScale * C.ClipX / 640.0; if ( !bSetFlashTime ) { bSetFlashTime = true; FlashTime = Level.TimeSeconds + FlashLength; } else if ( FlashTime < Level.TimeSeconds ) bMuzzleFlash = 0; if ( bMuzzleFlash > 0 ) { if ( Hand == 0 ) C.SetPos(C.ClipX / 2 - 0.5 * MuzzleScale * FlashS + C.ClipX * (-0.2 * Default.FireOffset.Y * FlashO), C.ClipY / 2 - 0.5 * MuzzleScale * FlashS + C.ClipY * (FlashY + FlashC)); else C.SetPos(C.ClipX / 2 - 0.5 * MuzzleScale * FlashS + C.ClipX * (Hand * Default.FireOffset.Y * FlashO), C.ClipY / 2 - 0.5 * MuzzleScale * FlashS + C.ClipY * FlashY); C.Style = 3; C.DrawIcon(MFTexture, MuzzleScale); C.Style = 1; } } else if ( bDrawingWeapon ) bSetFlashTime = false; SetLocation(Owner.Location + CalcDrawOffset()); NewRot = Pawn(Owner).ViewRotation; if ( Hand == 0 ) newRot.Roll = -2 * Default.Rotation.Roll; else newRot.Roll = Default.Rotation.Roll * Hand; setRotation(newRot); if ( bDrawingWeapon ) C.DrawActor(Self, False); } function Fire( float Value ) { if ( SlaveWeapon != None ) SlaveWeapon.Affector = Affector; else if ( bIsSlave && MasterWeapon != None ) Affector = MasterWeapon.Affector; if ( AmmoType == None && AmmoName != None ) GiveAmmo(Pawn(Owner)); if ( AmmoType.UseAmmo(1) ) { GotoState('NormalFire'); bPointing = True; bCanClientFire = true; ClientFire(Value); if ( bRapidFire || FiringSpeed > 0 ) Pawn(Owner).PlayRecoil(FiringSpeed * SpeedScale); if ( bInstantHit ) TraceFire(0.0); else ProjectileFire(ProjectileClass, ProjectileSpeed, bWarnTarget); } } function AltFire( float Value ) { if ( SlaveWeapon != None ) SlaveWeapon.Affector = Affector; else if ( bIsSlave && MasterWeapon != None ) Affector = MasterWeapon.Affector; if ( AmmoType == None && AmmoName != None ) GiveAmmo(Pawn(Owner)); if ( AmmoType.UseAmmo(1) ) { GotoState('AltFiring'); bPointing = True; bCanClientFire = true; ClientAltFire(Value); if ( bRapidFire || FiringSpeed > 0 ) Pawn(Owner).PlayRecoil(FiringSpeed * SpeedScale); if ( bAltInstantHit ) TraceFire(0.0); else ProjectileFire(AltProjectileClass, AltProjectileSpeed, bAltWarnTarget); } } // EstimatedHitNormal // Returns the HitNormal, if the level wouldn't change and the projectile would fly from CurLocation along // vector Distance and hits something within the range specified by Distance. Returns a vector of // size 0 if it would hit nothing or HitLevel is true and it would hit any other actor than the level. // If HitLevel isn't true HitActor is set like in the Trace function, if HitLevel is true HitActor will // be set to Level or None depending on if it hit level geometry or not. function vector EstimatedHitNormal ( out vector HitLocation, out actor HitActor, optional vector CurLocation, optional vector Distance, optional bool HitLevel, optional vector Extend) { local vector Loc,Dist,HN; local actor Collider; if ( VSize(CurLocation) == 0 ) Loc = Location; else Loc = CurLocation; if ( VSize(CurLocation) == 0 ) Dist = Velocity; else Dist = Distance; if ( HitLevel ) { Collider = Trace(HitLocation, HN, Dist+Loc, Loc, False, Extend); if ( Collider == Level ) { HitActor = Collider; return HN; } } else { Collider = Trace(HitLocation, HN, Dist+Loc, Loc, True, Extend); if ( Collider != None ) { HitActor = Collider; return HN; } } HitActor = None; return vect(0,0,0); } function class ReturnMessageActor() { if ( class(DeathMessageActorClass) != None || class(DeathMessageActorClass) != None ) return DeathMessageActorClass; return Class; } final function SetKillType(bool bSplashHit, bool bHeadHit) { if ( EIDMM != None ) EIDMM.AddDamageActor(ReturnMessageActor(), bSplashHit, bHeadHit); } final function RestoreKillType() { if ( EIDMM != None ) EIDMM.RemoveDamageActor(); } // bSpecialHit causes head shot death message (no head shot announce) with normal and splash hits function SplashDamage(vector HitLocation, actor Other, vector HitNormal, optional bool bSpecialHit) { local actor Victims; local float damageScale, dist, momentumScale, ScaledRadius; local vector dir; local name DamageName; local string SavedSString, SavedFSString, SavedDString; if( bHurtEntry ) return; bHurtEntry = true; if ( Instigator != None ) ScaledRadius = DamageRadius + (DamageRadius * (Instigator.DamageScaling - 1) * SplashRangeModifier); else ScaledRadius = DamageRadius; SetKillType(True, bSpecialHit); // activate spash hit death message foreach VisibleCollidingActors( class 'Actor', Victims, ScaledRadius, HitLocation ) { if ( Victims != self ) { dir = Victims.Location - HitLocation; dist = FMax(1,VSize(dir)); if ( bConstantSplashDamage ) dist = 1; dir = SplashMomentum * dir / dist; damageScale = 1 - FClamp((dist - Victims.CollisionRadius) / ScaledRadius, 0, 1); if ( Instigator != None ) momentumScale = Instigator.DamageScaling - 1; else momentumScale = 0; momentumScale *= damageScale; // direct hit if ( Victims == Other ) { dir = Normal(dir) * SplashMomentum * momentumScale + Normal(HitNormal) * MomentumTransfer * momentumScale; if ( Instigator != None && Instigator.Weapon != None ) Instigator.Weapon.Class.Default.DeathMessage = DirectHitString; if ( bCanHeadShoot && Other.bIsPawn && (HitLocation.Z - Other.Location.Z > HeadShotHeight * Other.CollisionHeight) && (!Instigator.IsA('Bot') || !Bot(Instigator).bNovice) ) { DamageName = HeadDamageType; damageScale *= HeadShotDamageFactor; SetKillType(False, True); // temporarily switch to head shot death message } else { DamageName = MyDamageType; if ( Victims.bIsPawn ) SetKillType(False, bSpecialHit); // temporarily switch to direct hit death message } Victims.TakeDamage ( damageScale * Damage, Instigator, Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * Normal(dir), (damageScale + damageScale * momentumScale * MomentumModifier) * dir, DamageName ); // reset messages if ( Victims.bIsPawn ) RestoreKillType(); // restore splash hit message } // splash damage hit else { if ( SplashDamageType == 'Push' ) Victims.TakeDamage ( 0, Instigator, Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * Normal(dir), (damageScale + damageScale * momentumScale * MomentumModifier) * dir, 'None' ); else { DamageName = AdjustSplashDamageType(Victims); Victims.TakeDamage ( damageScale * Damage, Instigator, Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * Normal(dir), (damageScale + damageScale * momentumScale * MomentumModifier) * dir, DamageName ); } } } } RestoreKillType(); // deactivate splash hit message bHurtEntry = false; } // bSpecialHit uses head shot message, bSplashHit uses splash damage message instead of direct hit message function DirectHit(vector HitLocation, actor Other, vector HitNormal, optional bool bSpecialHit, optional bool bSplashHit) { local float damageScale, momentumScale; local vector dir; local name DamageName; if ( Other == None ) return; dir = Normal(HitNormal) * MomentumTransfer; damageScale = 1.0; // direct hit if ( bCanHeadShoot && Other.bIsPawn && (HitLocation.Z - Other.Location.Z > HeadShotHeight * Other.CollisionHeight) && (!Instigator.IsA('Bot') || !Bot(Instigator).bNovice) ) { DamageName = HeadDamageType; damageScale *= HeadShotDamageFactor; SetKillType(bSplashHit, True); } else { DamageName = MyDamageType; SetKillType(bSplashHit, bSpecialHit); } if ( Instigator != None ) momentumScale = Instigator.DamageScaling - 1; else momentumScale = 0; Other.TakeDamage ( damageScale * Damage, Instigator, Other.Location - 0.5 * (Other.CollisionHeight + Other.CollisionRadius) * Normal(dir), (damageScale + damageScale * momentumScale * MomentumModifier) * dir, DamageName ); // reset messages RestoreKillType(); } // You might want to use this function to do something with certain actors before // applying damage to them e.g. if this projectile should set of ASMD plasma balls, // the ball's SuperExplosion function must be called. The function returns a Name // so the damagetype done by the projectile can be set individually for each // actor in splash range. function Name AdjustSplashDamageType(Actor Other) { return SplashDamageType; } simulated function SpawnExplosionEffects(vector HitLocation, vector HitNormal) { local Effects s; if ( Level.NetMode != NM_DedicatedServer ) { if ( ExplosionEffectClass != None ) { s = spawn(ExplosionEffectClass,,, HitLocation); s.RemoteRole = ROLE_None; } if ( HitNormal == vect(0,0,0) ) HitNormal = vect(0,0,1); if ( ExplosionDecal != None ) Spawn(ExplosionDecal,,, HitLocation, rotator(HitNormal)); } } function SpawnSubMunition(vector HitLocation, vector HitNormal, int Number) { local Projectile s; local int i; if ( Number < 1 || SubMunitionClass == None ) return; for (i = 0; i < Number; i++) { s = Spawn(SubMunitionClass, Instigator,, HitLocation, rotator(Normal(VRand() + HitNormal))); s.Instigator = Instigator; ModifySubMunition(s); } } function ModifySubMunition(Projectile Other); // Return the switch priority of the weapon (normally AutoSwitchPriority, but may be // modified by environment (or by other factors for bots) function float SwitchPriority() { local int bTemp; if ( bIsSlave ) return -10; if ( !Owner.IsA('PlayerPawn') ) return RateSelf(bTemp); else if ( AmmoType != None && AmmoType.AmmoAmount <= 0 ) { if ( Pawn(Owner).Weapon == Self ) return -0.5; else return -1; } else if ( SlaveWeapon != None && DoublePriorityName != 'None' ) return DoubleSwitchPriority; else return AutoSwitchPriority; } // If this weapon is replacing another one it might use the same switching priority. // Also, if this weapon can have a slave weapon (like Enforcer) it might use a // different priority. function SetSwitchPriority(pawn Other) { local int i; local name PriorityName, temp; local bool bFound, bFoundDouble; if ( PlayerPawn(Other) != None ) { if ( SamePriorityLike == 'None' ) PriorityName = Class.Name; else PriorityName = SamePriorityLike; // get AutoSwitchPriority and DoubleSwitchPriority for (i = 0; i < ArrayCount(PlayerPawn(Other).WeaponPriority); i++) { if ( PlayerPawn(Other).WeaponPriority[i] == PriorityName ) { AutoSwitchPriority = i; bFound = True; } if ( DoublePriorityName != 'None' && PlayerPawn(Other).WeaponPriority[i] == DoublePriorityName ) { DoubleSwitchPriority = i; bFoundDouble = True; } } // didn't find AutoSwitchPriority, so register it if ( !bFound ) for (i = AutoSwitchPriority; i < ArrayCount(PlayerPawn(Other).WeaponPriority); i++) { if ( PlayerPawn(Other).WeaponPriority[i] == '' || PlayerPawn(Other).WeaponPriority[i] == 'None' ) { PlayerPawn(Other).WeaponPriority[i] = PriorityName; break; } else if ( i < ArrayCount(PlayerPawn(Other).WeaponPriority) - 1 ) { temp = PlayerPawn(Other).WeaponPriority[i]; PlayerPawn(Other).WeaponPriority[i] = PriorityName; PriorityName = temp; } } // didn't find DoubleSwitchPriority, so register it if ( !bFoundDouble && DoublePriorityName != 'None' ) { PriorityName = DoublePriorityName; for (i = DoubleSwitchPriority; i < ArrayCount(PlayerPawn(Other).WeaponPriority); i++) { if ( PlayerPawn(Other).WeaponPriority[i] == '' || PlayerPawn(Other).WeaponPriority[i] == 'None' ) { PlayerPawn(Other).WeaponPriority[i] = PriorityName; break; } else if ( i < ArrayCount(PlayerPawn(Other).WeaponPriority) - 1 ) { temp = PlayerPawn(Other).WeaponPriority[i]; PlayerPawn(Other).WeaponPriority[i] = PriorityName; PriorityName = temp; } } } } } G@Y D!<Y GG?, GB~>;( GA// EnhancedItems by Wormbo //============================================================================= // PickupPlus // // Features: // - Global sound effects for respawn and pickup (heard by all players) // - aura effects for the pickup itself and the owning player // - stackable damage/speed/jump-height/air-control factors for owning player // and his selected weapon (fixes the jumpboots bug when using speed relic; // the weapon must be an EnhancedWeapon to support speed scaling) // - new armor and damagetype functions // - weapon affector chain to allow more than one item to affect a weapon // (use FireFunction() and set bFireEffectLast to true or false instead of // using FireEffect() ) // - may draw on HUD before and after weapon is drawn if it is a weapon // affector and the weapon is an EnhancedWeapon (see PreRenderOverlaysFor() ) //============================================================================= class PickupPlus extends TournamentPickup abstract config(EnhancedItems); const MaxDamageFactor = 10.0; const MinDamageFactor = 0.3; const MaxSpeedFactor = 2.5; const MinSpeedFactor = 0.3; // this specifies, if the actor should drop some visual effects (for slower machines) var(Advanced) globalconfig bool bDropEffects; var() bool bDeactivatable, bNeverAutoActivate; var pawn PawnOwner; var() name IdenticalTo; // used by OtherIsA() and ClassIsA() to identify new versions of an actor var() sound GlobalRespawnSound, GlobalPickupSound, DeniedAnnounce; // aura, shield or flashing effect around owner or pickup var PlayerShellEffect ShellEffect, PickupShellEffect; var() class ShellType; var() Texture ShellSkin; // the texture to use on the shell effect var() bool bShellAlwaysOn, // player shell is always visible bMakesInvisible; // the item makes invisible so other items shouldn't add effects var() Texture PickupShellSkin; var() class PickupShellType; // use this maybe with a HUD mutator to play a certain effect on this item's HUD icon var float BlinkIcon; // used with SetDamageFactor() to let multiple items scale players damage var() float AddToDamageFactor; // used with SetSpeedFactor() to let multiple items scale weapons firing speed // this only affects EnhancedWeapons var() float AddToSpeedFactor; // used with SetOwnerSpeed() to let multiple items scale the players jumping height, // Speed and AirControl var() float AddToJumpZFactor, AddToOwnerSpeed, DesiredAirControl; // if these are true the item affects the weapon's/owner's speed/damage factor var() bool bWeaponSpeedUp, bPawnSpeedUp, bPawnDamageUp; // used with SetOwnerMass() to let items scale the players mass/buoyancy var() float AddToMassFactor, AddToBuoyancyFactor; var() bool bPawnMassAffect; // some additional armor properties var() bool bIsSpecialArmor, // armor doesn't use it's charge on damage absorption bAltCharge, // armor uses alternative charge (not shown in total armor charge if bIsAnArmor) bIsChestArmor, // \ bIsThighArmor, // \ bIsShieldArmor, // \ Display this item as chest armor, thigh armor, etc. bIsBeltArmor, // / These need bEnhancedStatusDoll to be true. bIsGlovesArmor, // / (use instead of a dummy item) bIsBootsArmor, // / bIsChestSpecial, // \ bIsThighSpecial, // \ Display this item as chest special, thigh special, etc. bIsShieldSpecial, // \ These need bEnhancedStatusDoll to be true. bIsGlovesSpecial, // / bIsBeltSpecial, // / <- not needed if IdenticalTo == 'GravBelt' bIsJumpBoots; // / <- not needed if IdenticalTo == 'JumpBoots' or 'UT_JumpBoots' var() travel int AltCharge; // amount of armor if bAltCharge is used var() float ProtectedDamageFactor; // damage of ProtectionType is multiplied with this // should play the DeniedAnnounce sound for players inside DeniedRadius when picked up // called by PickupFunction() var() bool bDeniedAnnounce; var() float DeniedRadius; // for replacable pickups var() name ReplaceTag; var() bool bAllowSameClassPickup; // used to let more than one item affect a TournamentWeapon // assigned by RegisterAsAffector() var TournamentPickup NextAffector; var TournamentWeapon AffectedWeapon; var() bool bFireEffectLast, // this item wants to add its firing effect after all other affectors bRenderOverlays; // this item wants to add something to the weapons display var globalconfig bool bDrawShieldOverWeapon, // the item may draw a shield effect on the weapon bEnhancedStatusDoll; // just used for debugging FirstPickupPlus and NextPickupPlus var(Advanced) globalconfig bool bDebugMode; var localized float UnitRatio[4]; var localized string UnitDisplay[4], UnitFullName[4]; var(Advanced) globalconfig string DecimalChar; var(Advanced) globalconfig int UsedUnit; var EIDeathMessageMutator EIDMM; replication { reliable if ( Role == ROLE_Authority && bNetOwner ) NextAffector, AffectedWeapon, bAltCharge, AltCharge, bDeactivatable, bRenderOverlays; } static final function bool OtherIsA(actor Other, name DesiredType) { return class'EnhancedMutator'.static.OtherIsA(Other, DesiredType); } static final function bool ClassIsA(class aClass, coerce string DesiredType) { return class'EnhancedMutator'.static.ClassIsA(aClass, DesiredType); } // FindInventoryType() // Returns an inventory item of the requested class or a subclass if it exists // in the specified pawn's inventory. Optionally a search for identical // PickupPlus items can be performed. static final function Inventory FindInventoryType(Actor Other, name DesiredType, optional bool bFindIdentical) { local Inventory Inv; local int RecursionCount; for (Inv = Other.Inventory; Inv != None; Inv = Inv.Inventory) { if ( RecursionCount++ > 500 ) return None; if ( bFindIdentical && OtherIsA(Inv, DesiredType) ) return Inv; else if ( Other.IsA(DesiredType) ) return Inv; } return None; } function PreBeginPlay() { local Mutator M; local bool bFound; Super.PreBeginPlay(); if ( bDeleteMe ) return; if ( bNeverAutoActivate ) bAutoActivate = False; // override DMMutator's auto-activate modification, if desired // add EIUseHoldable for (M = Level.Game.DamageMutator; M != None; M = M.NextDamageMutator) if ( M.IsA('EIUseHoldable') ) { bFound = True; break; } if ( !bFound ) log(Name$": Adding"@Spawn(class'EnhancedItems.EIUseHoldable').Name$"..."); if ( bEnhancedStatusDoll ) SpawnEIChallengeHUD(); } function SpawnEIChallengeHUD() { local class M; local EnhancedMutator EM; // check, if EIChallengeHUD was already spawned ForEach AllActors(class'EnhancedMutator', EM) if ( EM.IsA('EIChallengeHUD') ) return; // EIChallengeHUD already exists M = class(DynamicLoadObject("EIChallengeHUD.EIChallengeHUD", class'Class', True)); if ( M != None ) Spawn(M); } final function SetKillType(bool bSplashHit, bool bHeadHit, class DamageProjectileClass) { if ( EIDMM != None ) EIDMM.AddDamageActor(DamageProjectileClass, bSplashHit, bHeadHit); } final function RestoreKillType() { if ( EIDMM != None ) EIDMM.RemoveDamageActor(); } // gather general information /* common InfoType strings might look like these: * MaxDefaultOwnerHealth (owner's health gets regenerated up to this value) * CurrentDamageFactor (combination of all active damage multipliers) * CurrentOwnerSpeedFactor (combination of all active speed multipliers) * CurrentWeaponSpeedFactor * CurrentJumpZFactor . * CurrentAirControl . * CurrentOwnerMassFactor . * CurrentOwnerBuoyancyFactor * ... * Of course, others can be used as well. */ function float GetInfoOn(string InfoType, optional string OtherInfo) { local float tmp; tmp = 0; if ( NextPickupPlus() != None ) tmp = NextPickupPlus().GetInfoOn(InfoType); if ( InfoType ~= "CurrentDamageFactor" && bPawnDamageUp ) { if ( tmp <= 0 ) tmp = 1; tmp *= AddToDamageFactor; } else if ( InfoType ~= "CurrentOwnerSpeedFactor" && bPawnSpeedUp ) { if ( tmp <= 0 ) tmp = 1; tmp *= AddToOwnerSpeed; } else if ( InfoType ~= "CurrentJumpZFactor" && bPawnSpeedUp ) { if ( tmp <= 0 ) tmp = 1; tmp *= AddToJumpZFactor; } else if ( InfoType ~= "CurrentAirControl" && bPawnSpeedUp ) tmp = FMax(tmp, DesiredAirControl); else if ( InfoType ~= "CurrentWeaponSpeedFactor" && bWeaponSpeedUp ) { if ( tmp <= 0 ) tmp = 1; tmp *= AddToSpeedFactor; } else if ( InfoType ~= "CurrentOwnerMassFactor" && bPawnMassAffect ) { if ( tmp <= 0 ) tmp = 1; tmp *= AddToMassFactor; } else if ( InfoType ~= "CurrentOwnerBuoyancyFactor" && bPawnMassAffect ) { if ( tmp <= 0 ) tmp = 1; tmp *= AddToBuoyancyFactor; } return tmp; } static simulated function string ConvertDistance(float Distance, optional int NewUnit, optional int OldUnit, optional int Accuracy, optional bool bNoUnit, optional bool bLongName) { local string DistanceText; Default.UsedUnit = Clamp(Default.UsedUnit, 0, ArrayCount(Default.UnitRatio)); if ( NewUnit == 0 ) NewUnit = Default.UsedUnit + 1; if ( OldUnit > 0 ) Distance *= Default.UnitRatio[OldUnit - 1] / Default.UnitRatio[NewUnit - 1]; else Distance /= Default.UnitRatio[NewUnit - 1]; if ( Accuracy > 0 ) DistanceText = int(Distance) $ Default.DecimalChar $ int(int(Distance * 10 ** Accuracy) % 10 ** Accuracy); else if ( Accuracy < 0 ) DistanceText = string(int(Distance / 10 ** Accuracy) * 10 ** Accuracy); else DistanceText = string(int(Distance)); if ( !bNoUnit && bLongName ) return DistanceText @ Default.UnitFullName[NewUnit - 1]; else if ( !bNoUnit ) return DistanceText @ Default.UnitDisplay[NewUnit - 1]; else return DistanceText; } // this is the function which converts strings like "%k killed %o with %w." to something more useful static final function string ReplaceText(out string Text, coerce string Replace, coerce string With, optional bool bNoChange) { local int i; local string Input, Output; Input = Text; i = InStr(Input, Replace); while (i != -1) { Output = Output $ Left(Input, i) $ With; Input = Mid(Input, i + Len(Replace)); i = InStr(Input, Replace); } Output = Output $ Input; if ( !bNoChange ) Text = Output; return Output; } function bool HandlePickupQuery(Inventory Item) { local PlayerPawn P; if ( Item.Class == Class ) { if ( bAllowSameClassPickup ) { if ( bCanHaveMultipleCopies ) { NumCopies++; if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogPickup(Item, Pawn(Owner)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogPickup(Item, Pawn(Owner)); if ( Item.PickupMessageClass == None ) Pawn(Owner).ClientMessage(Item.PickupMessage, 'Pickup'); else Pawn(Owner).ReceiveLocalizedMessage(Item.PickupMessageClass, 0, None, None, Item.Class); Item.PlaySound(Item.PickupSound,, 2.0); PlayGlobalSound(PickupPlus(Item).GlobalPickupSound); Item.SetRespawn(); if ( PickupPlus(Item).bDeniedAnnounce ) ForEach VisibleCollidingActors(class'PlayerPawn', P, DeniedRadius, Location) if ( P != Owner && P.PlayerReplicationInfo != None && !P.PlayerReplicationInfo.bIsSpectator ) P.ClientPlaySound(DeniedAnnounce); } else if ( bDisplayableInv ) { if ( Charge < Item.Charge ) Charge = Item.Charge; if ( bAltCharge && AltCharge < PickupPlus(Item).AltCharge ) AltCharge = PickupPlus(Item).AltCharge; if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogPickup(Item, Pawn(Owner)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogPickup(Item, Pawn(Owner)); if ( Item.PickupMessageClass == None ) Pawn(Owner).ClientMessage(item.PickupMessage, 'Pickup'); else Pawn(Owner).ReceiveLocalizedMessage(Item.PickupMessageClass, 0, None, None, Item.Class); Item.PlaySound(Item.PickupSound,, 2.0); PlayGlobalSound(PickupPlus(Item).GlobalPickupSound); Item.SetReSpawn(); if ( PickupPlus(Item).bDeniedAnnounce ) ForEach VisibleCollidingActors(class'PlayerPawn', P, DeniedRadius, Location) if ( P != Owner && P.PlayerReplicationInfo != None && !P.PlayerReplicationInfo.bIsSpectator ) P.ClientPlaySound(DeniedAnnounce); } } return true; } if ( Inventory == None ) return false; return Inventory.HandlePickupQuery(Item); } function UsedUp() { if ( Pawn(Owner) != None ) { bActivatable = false; Pawn(Owner).NextItem(); if ( Pawn(Owner).SelectedItem == Self ) { Pawn(Owner).NextItem(); if ( Pawn(Owner).SelectedItem == Self ) Pawn(Owner).SelectedItem = None; } if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogItemDeactivate(Self, Pawn(Owner)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogItemDeactivate(Self, Pawn(Owner)); if ( ItemMessageClass != None ) Pawn(Owner).ReceiveLocalizedMessage(ItemMessageClass, 0, None, None, Class); else if ( ExpireMessage != "" ) Pawn(Owner).ClientMessage(ExpireMessage); } Owner.PlaySound(DeactivateSound); Destroy(); } /* RegisterAsAffector() Register your item using this function to receive FireEffect calls. Use FireFunction instead of FireEffect to let other affectors do their stuff, too. Check registration by running this function from time to time since non-PickupPlus affectors will override the Affector property so the chain gets unlinked. To remove the item from the affectors chain use the UnregisterAsAffector(TournamentWeapon) function. Registering to another weapon will automatically unregister this item from the previously affected weapon. */ final function RegisterAsAffector(TournamentWeapon W) { local TournamentPickup A; if ( bDeleteMe ) { UnRegisterAsAffector(W); return; } if ( W == None || W == AffectedWeapon ) return; // already registered to another weapon, unregister first if ( AffectedWeapon != None ) UnRegisterAsAffector(AffectedWeapon); NextAffector = W.Affector; W.Affector = Self; AffectedWeapon = W; } final function UnRegisterAsAffector(TournamentWeapon W) { local PickupPlus A; local string Affectors; if ( W == None ) return; if ( W.Affector == Self ) { W.Affector = NextAffector; NextAffector = None; } else { For (A = PickupPlus(W.Affector); A != None; A = PickupPlus(A.NextAffector)) if ( A.NextAffector == Self ) { A.NextAffector = NextAffector; NextAffector = None; break; // self successfully unregistered } } AffectedWeapon = None; } // If this function returns true, this item will handle drawing the weapon. // In this case, the PostRenderOverlaysFor() functions are not called. simulated function bool PreRenderOverlaysFor(Weapon W, Canvas C) { return false; } simulated function PostRenderOverlaysFor(Weapon W, Canvas C); // make sure this item does not affect any weapon final function UnRegisterFromWeapons() { local TournamentWeapon W; ForEach AllActors(class'TournamentWeapon', W) { if ( IsAffectorOf(W) ) UnRegisterAsAffector(W); if ( W.IsA('EnhancedWeapon') && W.Owner == Owner ) ResetSpeedFactor(W); } } final function bool IsAffectorOf(TournamentWeapon W, optional PickupPlus P) { local PickupPlus Inv; if ( W == None ) return false; if ( P == None ) P = Self; For (Inv = PickupPlus(W.Affector); Inv != None; Inv = PickupPlus(Inv.NextAffector)) if ( Inv == P ) { if ( bDebugMode && W != P.AffectedWeapon ) log("Affecting"@W.Name, P.Name); return true; } return false; } simulated function FireEffect() { if ( !bFireEffectLast ) FireFunction(); if ( NextAffector != None ) NextAffector.FireEffect(); if ( bFireEffectLast ) FireFunction(); } simulated function FireFunction(); // SetDamageFactor. // Sets DamageScaling for owning Pawn. final function SetDamageFactor() { local float newDamageFactor; local PickupPlus I; if ( bDeleteMe ) { ResetDamageFactor(); return; } if ( Pawn(Owner) == None ) return; bPawnDamageUp = True; newDamageFactor = 1.0; //for ( I = Pawn(Owner).Inventory; I != None; I = I.Inventory ) for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( !I.bDeleteMe && I.bPawnDamageUp ) newDamageFactor *= I.AddToDamageFactor; Pawn(Owner).DamageScaling = FClamp(newDamageFactor, MinDamageFactor, MaxDamageFactor); } final function ResetDamageFactor() { local float newDamageFactor; local PickupPlus I; if ( !bPawnDamageUp ) return; bPawnDamageUp = False; if ( Pawn(Owner) == None ) return; newDamageFactor = 1.0; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( I != Self && !I.bDeleteMe && I.bPawnDamageUp ) newDamageFactor *= I.AddToDamageFactor; Pawn(Owner).DamageScaling = FClamp(newDamageFactor, MinDamageFactor, MaxDamageFactor); } // SetOwnerMass. // Sets Mass and Buoyancy for owning Pawn. final function SetOwnerMass() { local float newMassFactor; local PickupPlus I; if ( bDeleteMe ) { ResetOwnerMass(); return; } if ( Pawn(Owner) == None ) return; bPawnMassAffect = True; newMassFactor = 1.0; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( !I.bDeleteMe && I.bPawnMassAffect ) newMassFactor *= I.AddToBuoyancyFactor; Pawn(Owner).Buoyancy = Pawn(Owner).Default.Buoyancy * newMassFactor; newMassFactor = 1.0; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( !I.bDeleteMe && I.bPawnMassAffect ) newMassFactor *= I.AddToMassFactor; Pawn(Owner).Mass = Pawn(Owner).Default.Mass * newMassFactor; } final function ResetOwnerMass() { local float newMassFactor; local PickupPlus I; if ( !bPawnMassAffect ) return; bPawnMassAffect = False; if ( Pawn(Owner) == None ) return; newMassFactor = 1.0; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( I != Self && !I.bDeleteMe && I.bPawnMassAffect ) newMassFactor *= I.AddToBuoyancyFactor; Pawn(Owner).Buoyancy = Pawn(Owner).Default.Buoyancy * newMassFactor; newMassFactor = 1.0; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( I != Self && !I.bDeleteMe && I.bPawnMassAffect ) newMassFactor *= I.AddToMassFactor; Pawn(Owner).Mass = Pawn(Owner).Default.Mass * newMassFactor; } // SetOwnerSpeed. // sets speed, Acceleration and AirControl for the owning Pawn final function SetOwnerSpeed() { local float newFactor; local PickupPlus I; if ( bDeleteMe ) { ResetOwnerSpeed(); return; } if ( Pawn(Owner) == None ) return; bPawnSpeedUp = True; // JumpZ newFactor = Pawn(Owner).Default.JumpZ * Level.Game.PlayerJumpZScaling(); if ( Pawn(Owner).FindInventoryType(class'Botpack.UT_JumpBoots') != None ) newFactor = Pawn(Owner).Default.JumpZ * 3.0; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( !I.bDeleteMe && I.bPawnSpeedUp ) newFactor *= I.AddToJumpZFactor; Pawn(Owner).JumpZ = newFactor; //log("Set"@Owner$".JumpZ to"@newFactor); // AirControl if ( Level.Game.IsA('DeathMatchPlus') ) newFactor = DeathMatchPlus(Level.Game).AirControl; else if ( Pawn(Owner).FindInventoryType(class'Botpack.UT_JumpBoots') != None ) newFactor = 1.0; else newFactor = Pawn(Owner).Default.AirControl; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( !I.bDeleteMe && I.bPawnSpeedUp && I.DesiredAirControl > newFactor ) newFactor = I.DesiredAirControl; Pawn(Owner).AirControl = newFactor; //log("Set"@Owner$".AirControl to"@newFactor); // Speed & Acceleration newFactor = 1.0; if ( Level.Game.IsA('DeathMatchPlus') ) if ( DeathMatchPlus(Level.Game).bMegaSpeed ) newFactor = 1.3; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( !I.bDeleteMe && I.bPawnSpeedUp ) newFactor *= I.AddToOwnerSpeed; Pawn(Owner).GroundSpeed = Pawn(Owner).Default.GroundSpeed * FClamp(newFactor, MinSpeedFactor, MaxSpeedFactor); Pawn(Owner).AirSpeed = Pawn(Owner).Default.AirSpeed * FClamp(newFactor, MinSpeedFactor, MaxSpeedFactor); Pawn(Owner).WaterSpeed = Pawn(Owner).Default.WaterSpeed * FClamp(newFactor, MinSpeedFactor, MaxSpeedFactor); Pawn(Owner).AccelRate = Pawn(Owner).Default.AccelRate * newFactor; } final function ResetOwnerSpeed() { local float newFactor; local PickupPlus I; if ( !bPawnSpeedUp ) return; bPawnSpeedUp = False; if ( Pawn(Owner) == None ) return; // JumpZ newFactor = Pawn(Owner).Default.JumpZ * Level.Game.PlayerJumpZScaling(); if ( Pawn(Owner).FindInventoryType(class'Botpack.UT_JumpBoots') != None ) newFactor = Pawn(Owner).Default.JumpZ * 3.0; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( I != Self && !I.bDeleteMe && I.bPawnSpeedUp ) newFactor *= I.AddToJumpZFactor; Pawn(Owner).JumpZ = newFactor; //log("Set"@Owner$".JumpZ to"@newFactor); // AirControl if ( Level.Game.IsA('DeathMatchPlus') ) newFactor = DeathMatchPlus(Level.Game).AirControl; else if ( Pawn(Owner).FindInventoryType(class'Botpack.UT_JumpBoots') != None ) newFactor = 1.0; else newFactor = Pawn(Owner).Default.AirControl; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( I != Self && !I.bDeleteMe && I.bPawnSpeedUp && I.DesiredAirControl > newFactor ) newFactor = I.DesiredAirControl; Pawn(Owner).AirControl = newFactor; //log("Set"@Owner$".AirControl to"@newFactor); // Speed & Acceleration newFactor = 1.0; if ( Level.Game.IsA('DeathMatchPlus') ) if ( DeathMatchPlus(Level.Game).bMegaSpeed ) newFactor = 1.3; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( I != Self && !I.bDeleteMe && I.bPawnSpeedUp ) newFactor *= I.AddToOwnerSpeed; Pawn(Owner).GroundSpeed = Pawn(Owner).Default.GroundSpeed * FClamp(newFactor, MinSpeedFactor, MaxSpeedFactor); Pawn(Owner).AirSpeed = Pawn(Owner).Default.AirSpeed * FClamp(newFactor, MinSpeedFactor, MaxSpeedFactor); Pawn(Owner).WaterSpeed = Pawn(Owner).Default.WaterSpeed * FClamp(newFactor, MinSpeedFactor, MaxSpeedFactor); Pawn(Owner).AccelRate = Pawn(Owner).Default.AccelRate * newFactor; } // SetSpeedFactor. // Sets the SpeedScale value of the specified weapon if it is an EnhancedWeapon. final function SetSpeedFactor(Weapon W) { local float newSpeedFactor; local PickupPlus I; local EnhancedWeapon EW; if ( bDeleteMe ) { ResetSpeedFactor(W); return; } EW = EnhancedWeapon(W); if ( EW == None || Pawn(Owner) == None ) return; newSpeedFactor = 1.0; bWeaponSpeedUp = True; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( !I.bDeleteMe && I.bWeaponSpeedUp ) newSpeedFactor *= I.AddToSpeedFactor; EW.SpeedScale = EW.default.SpeedScale * FClamp(newSpeedFactor, MinSpeedFactor, MaxSpeedFactor); if ( EW.SlaveWeapon != None ) SetSpeedFactor(EW.SlaveWeapon); } final function ResetSpeedFactor(Weapon W) { local float newSpeedFactor; local PickupPlus I; local EnhancedWeapon EW; if ( !bWeaponSpeedUp ) return; bWeaponSpeedUp = False; EW = EnhancedWeapon(W); if ( EW == None || Pawn(Owner) == None ) return; newSpeedFactor = 1.0; for ( I = FirstPickupPlus(Pawn(Owner)); I != None; I = I.NextPickupPlus() ) if ( I != Self && !I.bDeleteMe && I.bWeaponSpeedUp ) newSpeedFactor *= I.AddToSpeedFactor; EW.SpeedScale = EW.default.SpeedScale * FClamp(newSpeedFactor, MinSpeedFactor, MaxSpeedFactor); if ( EW.SlaveWeapon != None ) ResetSpeedFactor(EW.SlaveWeapon); } // checks if a given DamageType is splash damage (e.g. 'GrenadeSplashDamage', 'JoltedSplashDamage') static function bool IsSplashDamage(coerce string DamageType) { if ( DamageType ~= "SplashDamage" ) return true; if ( Right(DamageType,12) ~= "SplashDamage" ) { //log(DamageType@"is a SplashDamage"); return true; } return false; } // Checks if a DamageType is a "subclass" of another one (e.g. 'RocketDeath' or // 'RocketSplashDamage' are types of 'Rocket'). If 'SplashDamage' is specified as // DesiredType, the IsSplashDamage function is called instead. static function bool DamageIsTypeOf(coerce string TestType, coerce string DesiredType) { if ( DesiredType ~= "SplashDamage" ) return IsSplashDamage(TestType); if ( DesiredType ~= "AllEnviromental" ) return ( DamageIsTypeOf(TestType, 'Corroded') || DamageIsTypeOf(TestType, 'Burned') || DamageIsTypeOf(TestType, 'Frozen') ); if ( Len(TestType) < Len(DesiredType) ) { // log(TestType@"is shorter than"@DesiredType); return false; } if ( TestType ~= DesiredType ) { // log(TestType@"is equal to"@DesiredType); return true; } if ( Left(TestType, Len(DesiredType)) ~= DesiredType ) { // log(TestType@"is a"@DesiredType); return true; } return false; } function int GetCharge() { if ( bAltCharge ) return AltCharge; return Charge; } function bool DamageProtectionFactor(name DamageType, out float Factor) { if ( DamageType != 'None' && DamageType != 'ProtectNone' && (DamageIsTypeOf(DamageType, ProtectionType1) || DamageIsTypeOf(DamageType, ProtectionType2)) ) { Factor = ProtectedDamageFactor; return true; } return false; } function int ArmorAbsorbDamage(int Damage, name DamageType, vector HitLocation) { local int ArmorDamage; local float DamageFactor; if ( DamageType != 'Drowned' ) ArmorImpactEffect(HitLocation); if ( DamageType != 'None' && DamageProtectionFactor(DamageType, DamageFactor) ) return Damage * DamageFactor; if ( DamageType == 'Drowned' ) Return Damage; ArmorDamage = (Damage * ArmorAbsorption) / 100; // special armor doesn't drain its charge when absorbing damage if ( !bIsSpecialArmor && bAltCharge ) { if ( ArmorDamage >= AltCharge ) { ArmorDamage = AltCharge; Destroy(); } else AltCharge -= ArmorDamage; } else if ( !bIsSpecialArmor ) { if ( ArmorDamage >= Charge ) { ArmorDamage = Charge; Destroy(); } else Charge -= ArmorDamage; } return (Damage - ArmorDamage); } function int ArmorPriority(name DamageType) { local float DamageFactor; if ( DamageType == 'Drowned' && !DamageProtectionFactor(DamageType, DamageFactor) ) return 0; DamageFactor = 1.0; // check, if completely blocks damage if ( DamageProtectionFactor(DamageType, DamageFactor) ) if ( DamageFactor == 0.0 ) return 1000000; else return AbsorptionPriority / DamageFactor; return AbsorptionPriority; } // This function checks a pawn's inventory for armors and calculates the // approximate amount of damage the pawn can still take. Armor items with // custom ArmorAbsorbDamage functions could produce errors in this calculation. // Use the DamageProtectionFactor function of PickupPlus to describe custom // damage reduction. static final function int EstimatedPawnHitpoints(Pawn Other, optional name DamageType) { local Inventory Inv; local int HitPoints; local float DamageFactor; HitPoints = Other.Health; for (Inv = Other.Inventory; Inv != None; Inv = Inv.Inventory) { if ( !Inv.bIsAnArmor ) continue; if ( DamageType != '' && DamageType != 'None' && DamageType != 'ProtectNone' ) { if ( PickupPlus(Inv) == None && (Inv.ProtectionType1 == DamageType || Inv.ProtectionType2 == DamageType) ) return MaxInt; // pawn is resistant against this type of damage else if ( PickupPlus(Inv) != None && PickupPlus(Inv).DamageProtectionFactor(DamageType, DamageFactor) ) { if ( DamageFactor == 0 ) return MaxInt; // pawn completely resists this type of damage else HitPoints *= DamageFactor; } } if ( Inv.IsA('PickupPlus') && PickupPlus(Inv).GetCharge() > 0 ) { if ( !PickupPlus(Inv).bIsSpecialArmor ) HitPoints += (PickupPlus(Inv).GetCharge() * Inv.ArmorAbsorption) / 100; } else if ( Inv.Charge > 0 ) HitPoints += (Inv.Charge * Inv.ArmorAbsorption) / 100; } for (Inv = Other.Inventory; Inv != None; Inv = Inv.Inventory) { if ( !Inv.bIsAnArmor ) continue; if ( PickupPlus(Inv) != None ) { if ( PickupPlus(Inv).bIsSpecialArmor && Inv.ArmorAbsorption > 0 ) HitPoints *= 100 / Inv.ArmorAbsorption; } else if ( Inv.Charge == 0 && Inv.ArmorAbsorption > 0 ) HitPoints *= 100 / Inv.ArmorAbsorption; } return HitPoints; } // play a sound effect for all players final function PlayGlobalSound(sound GlobalSound, optional bool bDontPlayInSlot) { local Pawn P; local PlayerPawn Player; for (P = Level.PawnList; P != None; P = P.NextPawn) { if ( P.IsA('PlayerPawn') ) Player = PlayerPawn(P); else continue; if ( bDontPlayInSlot ) { if ( Player.ViewTarget == None ) Player.PlaySound(GlobalSound); else Player.ViewTarget.PlaySound(GlobalSound); } else Player.ClientPlaySound(GlobalSound,, True); } } simulated function CreateShell() { if ( ShellEffect == None || ShellEffect.bDestroyMe || ShellEffect.bDeleteMe ) ShellEffect = Spawn(ShellType, Owner,, Owner.Location, Owner.Rotation); if ( ShellEffect != None ) { ShellEffect.Master = Self; if ( ShellSkin != None ) { ShellEffect.Texture = ShellSkin; ShellEffect.MultiSkins[1] = ShellSkin; } } } simulated function FlashShell(float Duration) { ShowShell(); if ( ShellEffect != None ) { if ( bShellAlwaysOn ) ShellEffect.SetFlashTime(Duration); else ShellEffect.VisibleTime = Duration; } } simulated function ShowShell() { CreateShell(); if ( ShellEffect != None ) ShellEffect.ShowMe(); } simulated function Destroyed() { if ( Role == ROLE_Authority ) { UnRegisterFromWeapons(); ResetDamageFactor(); ResetOwnerSpeed(); ResetOwnerMass(); } if ( ShellEffect != None ) ShellEffect.DestroyMe(); if ( PickupShellEffect != None ) PickupShellEffect.DestroyMe(); Super.Destroyed(); } function PickupFunction(Pawn Other) { local PlayerPawn P; local Inventory I; // remove other PickupPlus with the same ReplaceTag if ( ReplaceTag != 'None' && ReplaceTag != '' ) for (I = Other.Inventory; I != None; I = I.Inventory) if ( I.IsA('PickupPlus') && PickupPlus(I).ReplaceTag == ReplaceTag && I.Class != Class ) I.Destroy(); Super.PickupFunction(Other); if ( bPawnDamageUp ) SetDamageFactor(); if ( bPawnSpeedUp ) SetOwnerSpeed(); if ( bPawnMassAffect ) SetOwnerMass(); if ( bAltCharge ) { AltCharge += Charge; Charge = 0; } if ( bDeniedAnnounce ) ForEach VisibleCollidingActors(class'PlayerPawn', P, DeniedRadius, Location) if ( P != Other && P.PlayerReplicationInfo != None && !P.PlayerReplicationInfo.bIsSpectator ) P.ClientPlaySound(DeniedAnnounce); } function GiveTo(pawn Other) { // make sure I'm not already in an inventory chain if ( Instigator != Other && Instigator != None && Instigator.FindInventoryType(Class) == Self ) Instigator.DeleteInventory(Self); if ( Owner != Other && Pawn(Owner) != None && Pawn(Owner).FindInventoryType(Class) == Self ) Pawn(Owner).DeleteInventory(Self); Instigator = Other; BecomeItem(); Other.AddInventory(Self); if ( bAltCharge ) { AltCharge += Charge; Charge = 0; } PawnOwner = Other; if ( bPawnDamageUp ) SetDamageFactor(); if ( bPawnSpeedUp ) SetOwnerSpeed(); if ( bPawnMassAffect ) SetOwnerMass(); GotoState('Idle2'); } function BecomePickup() { local Pawn P; Super.BecomePickup(); // make sure this item no longer is in any inventory chain for (P = Level.PawnList; P != None; P = P.nextPawn) if ( P.FindInventoryType(Class) == Self ) P.DeleteInventory(Self); Inventory = None; } // Returns whether this item wants to be picked up by Other. This function works // a bit like HandlePickupQuery() but allowes the item to decide for itself if // it wants to allow getting picked up before HandlePickupQuery() is called. function bool AllowPickup(Pawn Other) { return true; } auto state Pickup { function bool ValidTouch(actor Other) { local Actor A; if ( Other.bIsPawn && Pawn(Other).bIsPlayer && Pawn(Other).Health > 0 && AllowPickup(Pawn(Other)) && Level.Game.PickupQuery(Pawn(Other), Self) ) { if ( Event != '' ) foreach AllActors(class 'Actor', A, Event) A.Trigger(Other, Other.Instigator); return true; } return false; } function Touch( actor Other ) { local Inventory Copy; if ( ValidTouch(Other) ) { Copy = SpawnCopy(Pawn(Other)); if ( Copy == None ) return; if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogPickup(Self, Pawn(Other)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogPickup(Self, Pawn(Other)); if ( bActivatable ) { if ( Pawn(Other).SelectedItem == None ) Pawn(Other).SelectedItem = Copy; if ( bAutoActivate && Pawn(Other).bAutoActivate ) Copy.Activate(); } if ( PickupMessageClass == None ) Pawn(Other).ClientMessage(PickupMessage, 'Pickup'); else Pawn(Other).ReceiveLocalizedMessage(PickupMessageClass, 0, None, None, Self.Class); PlaySound (PickupSound,,2.0); PlayGlobalSound (GlobalPickupSound); Pickup(Copy).PickupFunction(Pawn(Other)); if ( PickupPlus(Copy) != None ) PickupPlus(Copy).PawnOwner = Pawn(Other); } } simulated function BeginState() { Super.BeginState(); LightType = Default.LightType; if ( PickupShellType != None ) { PickupShellEffect = Spawn(PickupShellType, Self,, Location, Rotation); if ( PickupShellEffect != None ) { PickupShellEffect.Master = Self; PickupShellEffect.GotoState('PickupShell'); } } } simulated function EndState() { Super.EndState(); LightType = LT_None; if ( PickupShellEffect != None ) PickupShellEffect.Destroy(); } } // modified version of SelectNext() to support bDeactivatable function Inventory SelectNext() { if ( bActivatable && (!bAutoActivate || bDeactivatable) && M_Selected != "" ) { Pawn(Owner).ClientMessage(ItemName$M_Selected); return Self; } if ( Inventory != None ) return Inventory.SelectNext(); else return None; } // modified version of Activate() to support bDeactivatable function Activate() { //log(Name@"in state"@GetStateName()@"activated."); if ( bActivatable ) { if ( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogItemActivate(Self, Pawn(Owner)); if ( Level.Game.WorldLog != None ) Level.Game.WorldLog.LogItemActivate(Self, Pawn(Owner)); if ( M_Activated != "" && (!bAutoActivate || bDeactivatable) ) Pawn(Owner).ClientMessage(ItemName$M_Activated); GoToState('Activated'); } } state Activated { simulated function BeginState() { Super.BeginState(); if ( bShellAlwaysOn ) ShowShell(); } function Activate() { //log(self@"wants to deactivate"); if ( Pawn(Owner) != None && Pawn(Owner).bAutoActivate && bAutoActivate && !bDeactivatable ) return; if ( Pawn(Owner) != None && M_Deactivated != "" ) Pawn(Owner).ClientMessage(ItemName$M_Deactivated); GoToState('DeActivated'); } } state Deactivated { simulated function BeginState() { Super.BeginState(); if ( ShellEffect != None ) ShellEffect.DestroyMe(); } Begin: } //============================================================================= // Sleeping state: Sitting hidden waiting to respawn. State Sleeping { ignores Touch; function BeginState() { BecomePickup(); bHidden = true; } function EndState() { local int i; bSleepTouch = false; for (i = 0; i < 4; i++) if ( Touching[i] != None && Touching[i].IsA('Pawn') ) bSleepTouch = true; } Begin: Sleep(ReSpawnTime); Sleep(Level.Game.PlaySpawnEffect(Self)); PlaySound(RespawnSound); PlayGlobalSound(GlobalRespawnSound); GoToState('Pickup'); } // returns the next PickupPlus in the inventory chain starting from this item final function PickupPlus NextPickupPlus() { local Inventory I; local int Counter; local bool logOwner; local pawn PrevOwner; if ( bDebugMode ) { if ( Pawn(Owner) != None ) logOwner = True; else log("! NextPickupPlus:"@Name@"is not owned by a Pawn"); } // find next PickupPlus for (I = Inventory; I != None; I = I.Inventory) { Counter++; if ( bDebugMode && logOwner ) { if ( Pawn(I.Owner) == None ) log("Found an un-owned item ("$I.Name$") in inventory chain of"@Owner.Name, 'InventoryError'); else if ( i.Owner != Owner ) log("Item"@I.Name@"in same inventory chain like"@Name@"is owned by"@I.Owner.Name@"instead of"@Owner.Name, 'InventoryError'); } if ( I.IsA('PickupPlus') ) { // log("NextPickupPlus is"@I); return PickupPlus(I); } else if ( I == Self ) { if ( bDebugMode ) { if ( logOwner ) log(Name@"loops to itself in inventory chain of"@Owner.Name@"after"@Counter@"steps", 'InventoryError'); else log(Name@"loops to itself after"@Counter@"steps and has no owner", 'InventoryError'); } return None; } else if ( Counter > 500 ) { if ( bDebugMode ) { if ( logOwner ) log("Infinite recursion in inventory chain of"@Owner.Name, 'InventoryError'); else log("Infinite recursion in inventory chain of"@Name, 'InventoryError'); } return None; } } // no PickupPlus found return None; } // finds the first PickupPlus in pawn Other's inventory static final function PickupPlus FirstPickupPlus(Pawn Other) { local Inventory I; local int Counter; local pawn PrevOwner; // no pawn specified if ( Other == None ) { if ( Default.bDebugMode ) log("FirstPickupPlus: No pawn specified."); return None; } // no items in Other's inventory if ( Other.Inventory == None ) { if ( Default.bDebugMode ) log("FirstPickupPlus:"@Other.Name@"has no inventory."); return None; } // find first PickupPlus for(I = Other.Inventory; I != None; I = I.Inventory) { Counter++; if ( Default.bDebugMode && I.Owner != Other ) log("Item"@I.Name@"in inventory chain of"@Other.Name@"is owned by"@I.Owner.Name, 'InventoryError'); if ( I.IsA('PickupPlus') ) { // log("FirstPickupPlus is"@I); return PickupPlus(I); } else if ( Counter > 500 ) { if ( Default.bDebugMode ) log("Infinite recursion in inventory chain of"@Other.Name, 'InventoryError'); return None; } } // no PickupPlus found return None; } GGGX Z iw*??w.*.k.w.*., GGA w*Ow.*r.k.k*tw.*.,*A~ GGGGGGGGGGGrGGT M%T M[wM*DMa/!c MM#ppW: AddingWa ~... GGGGGGGGTTMb MD MxMEMTM{Mf MA{sMMMa TMg M@MI{G MWML{VMBMqonMrtpMN{OMMsMC{D sMrSME MBMt@j@hMnMt Mu MkMh AO @k@[{ {@M{ M9{T {h{Z {BT{{LMZ BvomDw@X@ AA Mz {\ {h MrMKD} MC {b DX{|t~ M{sE_ AxMD@U r] M{Mm{B @ZAz ry @mDKDz D[ MS BN {u {t MuqlMi EMls[ AN{wtLM|@v B}r]M~MzE%qYM|tK@c{WAt M@{p @\E@ qJ Ac{h Bi@uAT @}@wDu@xMA{P Mf@d Bb@x AeM` E"MGEY{yMe@j @jA{{Wqb{cE_@V EQMDsp M@_M{ EMqMFMy@O BVBO{x@] DV{ABT{l qEMB{sA{` M}k{zMOEV E0DoA^rWEsMDkA` EqEDDQ k_AZqU BWENMn{n EgD@AE ARkA_ tp tkMz{YqkBQ{T@WtK@pAUAv An tR @@ qL@XEgsGtR {SEyBM qJAx@j A\ sEB|EEAM{IrY Ai @e{C DuAM{R BJ@S {Jt| {XADAa {PEB0E2rT {_qBELEGBPkA^ Mc TuEzJM}EsE@EqJE]JE]Bv@_EmEM^Ee{bSM]AG E^k{QaEn@H@fA_EMEbAf ESAc AlAY@x @dEEEqE[Ay EA qtE,EmEA{F EQ@zhEBA`E@@CEDqPE%@qhsisjENEmEr@P EJE20AJN EmE=0sHEyAIEQ]E,E$@d@c@fEB[{X EJEZEAEI@gEoEpsQt@gBo sR ENAJ{F EmEL}EpEzA@ DpEEDri E=E@As} AA @J EnEfEG@PE^EAr E5qU{x ADE^pEMn@s@e@j{q M| MoE5EMAqwquEJEGEQEvE0kMEqENEbs K EEE]@Elv_(r oC ~I_ Mfn \J k>z yY HmWA\eCstW gpyFGb VC eyuoC E]S;`a{pI~`M`\V l3Fb>y rAIBBC Rjb[ p}KA Z]e iC xlHG W^ gXvrDgSC aFjqp [nM ko |Z JNfYtiXxK~FC DoSacn r] Af~ OB~ _|nG~7}LH\JL mY ywEHb VQm ex^u$vEx UR\ eB u7y B(d Q^`7{ oHn}b kCz6IIV Y7| h!DvN]Emb]ro@AO60]H MG{\kWF f6Fv$y E@s Ub eI^ to~C$FRIbk rAB6fPx^ `g o_}k N[_l mS{U I!U XWgav$CDaTIbVrm @`Np \|lC{dJZZC~ h[wpGl VlXeH_}~|NO_]B\n6U|OLP [| jjH|DT DQSy b_ qC AR`Px_X mp {V K]Yp g0E w=_GiXRP gzu_Cjs Sicz rl Bq PL _yW mlP |7|J>CYJF izl\ JafZC\j>v xzHqWCnfB vbFMU_eJtAu B60RW BU Qb _6} nQ|m Kg Zs|h7}dQ[rTB7u RxC `QIp5d @m O[^snL}NcKRPnBf}$}Mp\N\ n-~wCkwK yb G$YVNu fk vDF$v VKp fu VMrf~} XL_gvFvUD dLtt6Vh~jxlFkUH cOq rk AHq Pj `Q pfhOGu^o md }sLM Zj hg wp FyVNeAv|Dh RiG aq hSwzf Fze Ub dc urC[ Rj _n oYZM][`itwOFj Tybs qm GPoJ ao pu @m OX^`lK z(/G] vd*EZ o+rZq.IZ O=q ]G m~ |7sKv~P LJ\ jXGU U8rc!fUf\eb tc EW Sp a]cpm Sp d>u uxEw SK b]w q>x @IP]H `g nY}q Kp ZZjw xC{ FM Uk dorj A]Olt ]A} lIzau J`Z ha\ En U"sct Vv fX uz CJP  ^Ym {iJsZ Y=isb }7'ALu M| ]okGAfzsA Jjb YjV hp^wlu GlfWf gju v@u F7w V{ d7v s@b A}RP{ ^l m| |P 7,#KIC n>w ~>YMiD ]ikwV zHIuZgD j{ixzuGC} W|HfCfn{I~yNS \@V jz| yHtH&i|iK//ZIIDIYQi&Hw2HI zXIM;XO SwDc iqwH @wI OV]k l,}zCu wSGFU,c,vOwL  Ed Rx`wn{|beJAoz{ }oK Ll [Eif wIFsV V$Re}iwK FiVf euetOV Y}Hh{my%yf} _G^n A ~ HM`^C m@ |o KW Z[h@ wrFo Uwd@ r]@FNJ]EkdymIcY\gbuwb| GF| V\fe;4&tRfZRu j| z{ H{WzgiwHF iW IfFvxDaRSsd A{OA]wkyqIC WQZfwu@ Co Q`o pJI W N@ \o kJzlHUVNfsvyEqUH dF{ qE@mOl^nmb{ |S K\u [qkFg}bNB} ]Bu l\| |\uKm [l jk yj H^IX^ihe w(/FHuiFJZU$x d$u trDZRIa|qZ\{ Nh].P l`|] Kw\zj%XzoGRE YE hu w^ G%GV//]SYLIen uC=W Q%^ `R n_u~^ sTkA(/l~[yi&^ w+QXEC wM.].^ Kw[ZmkY1^ DwHR5{ZDMUT b0^ qj^ AzPQw0!aS BRPwR^ws|wtZLjxfVb>^ x?=H;P E^ UZ[dw@_ w$m^ lp zLjHK K, rzvR@7-HC u@ +DCC#GUzjd U,!dtUENPZ^ jX03x7v-k^ XO wgg}MNX\[S!wZIX3 ZSjz^ d|^ tpBC ap qE7@Rw^ E5QT(s e} t@^ C_JS(^ ]}^ mP[|^ W^ eGIsCa|A@ ]^ lgqzT %/kzKZAB eAA s^ BMwRQD^ c ^ r0;@^ {cIDW l^ |~Y^K~bpi[rY-K^ xIFzwN-VB!CM K'Zd~<t~qnrW `~{`oGuOb4DIOxqsGz^ z^ IGdW^ {~MxJNIBQ lFRJ^ XUQqhmAY^ ZX:h^ bn^p:aN ^ o k-} ^ j XQAx 1ry ^ k ULy N^ E Q^ S ^ c T!r PjS JI} ^ F &HU o ] C m p} ^ \ ^ j p x sDH IL ZM \ BN m ^ { OtI ^ } qAn Y,y T7-e X ~R [8-P ~ A } M+-~ G  sk qw^ JOU hcd ^ G sYV [ 4|Eo P k `O{ [ 4bJ mDl [ 4Ep Nqu nDf ^ j ^ y q[ 4P I mY [ 4KX rbcD E^(SJB {[ 4K}o H@ WIffi}L[ 4`2Iw[ 4\Ri7[ 4VDE~[ 4S;[b](np*V2n@^ nr*|g fr t@,BP nvz}JCw[ 4XuzTURo{g[ 4mb[ 4A4O^ PJO_[ 4Rnt@^ ^vUmmgB[ 4li[ 4^U0se$chGDWep |^ Kf\Z[ 4avk\W[ 4|s[ 4^ oxZMg gW v[ 4]OEC b]Jrez|[ 4y]v[ 4^oD2M> [ 4N_m m"qZp}"qAEm"_r"_A"G P"G `"_p"_"GT %HO"HW"He"Is"HW A"