*E@\xz\LwŠˢ%v-ObLc\NoneMegaMortar_Team MegaMortarMegaMortar_TargetingEngineCoreSystemSpecialLoop MultiSkinsMortarTakeDamageCanHit IgnoreThisEulerReIncrement IsVehicle ValidTarget SetTeamSkinMegaMortar_DamageMegaMortar_Firing MakeSound RemoveIdiot DrawScalebCollideWorldCollisionHeightCollisionRadiusAllPostBeginPlayClientMessageEventUnrealISearchAndDestroyBeginNumPredictionSteps bDestroyable AdvancedMesh PlayerPawnbShootVehiclesbShootMonstersbShootPlayers RefireTimeGoldTex GreenTexBlueTexRedTex MortarHullMortarFlameExplosion TakeDamageMegaMortarShellBotspeedDamage MaxSpeedHealthExplodeTeam bEnabledbCollideWhenPlacing Destroyed ShakeViewTickTimer CheatFlyingbStatic DrawTypeTrigger LifeSpan UnrealShareEffectsbHiddenFirePhysics bNoDeleteAX BlockAllZYi HurtRadius Location PointRegion ScriptTextZoneTerminalVelocitybHighDetailMode ZoneGravityS DeltaTimeOtherP Momentum HitLocationV NameProperty HitNormalEventInstigator Velocity TextBuffer bTeamGameGameRegionBaseTargetZoneRStartOwnerNetModeSpecialDamageString ReturnValueMomentumTransfer EffectSound1HReducedDamageTypeqBSObject ScriptedPawn NaliRabbitBird1bIsWussObjectPropertyFlameExplosion HorseFlyShortSmokeGenFloatProperty TargetDist FlakShellProjAimDirMaster BoolPropertyPackageClass LevelInfoAlsoBSLessBS StarshipC_bs4C_bs3C_bs2C_bs1AncientA_bsaXFX pinkbunny ErikEnergy MegaMortarA IntProperty GameInfo Projectile ZoneInfoPlayerReplicationInfo FunctionLevel BytePropertyMoverbSeeStealthedActorPawnbEvilState WetTexture StartHealth FireTextureSkipThisMoronTotalIgnoredIdiotsIgnoreTheseIdiots LaunchSpeedLaunchVelocityPredictedLocationTempRefireTime LaunchAngleBubbleLocationMyHullTextureVectorStructClassProperty DamageType RemoteRoleEhStructProperty OldLocation MoronIndex StrProperty DeathMortarsP2  KJM0+ -ҾԝXԝXU Ħ2$4$3$CB$$@'  @dO\BEU ĦԝX > Y-ԝXԝX1111ԝXԝXԝX1ԝXԝXԝX-1---1ԝXԝX1111-ԝX11-----ԝXԝXԝXtԝXtԝXԝX> Y> Y"/"/ԝXtt{#Utt  ,+*)($@@'&%!5"78 " @#W9   $C$B@?- 6!U Ħ?S$C$B 0S"#+(!AY.)22ܣ}rԝXC$ A<:*,-./1"N25%>B=/Qw.*9!{ was blasted by a mortar.]{ forgot to stand back when shooting a giant tank full of mortars..  = s //============================================================================= // PlaceableBlockall. //============================================================================= class MortarHull expands BlockAll; function TakeDamage( int Damage, Pawn EventInstigator, vector HitLocation, vector Momentum, name DamageType) { if ( MegaMortar(Owner) != None && (DamageType != 'Special' || (Level.Game.SpecialDamageString != " was blasted by a mortar." && Level.Game.SpecialDamageString != " forgot to stand back when shooting a giant tank full of mortars.")) ) MegaMortar(Owner).MortarTakeDamage( Damage ); } j//============================================================================= // MortarFlameExplosion. //============================================================================= class MortarFlameExplosion expands FlameExplosion; function MakeSound() { PlaySound (EffectSound1,,6.0); } simulated function PostBeginPlay() { local actor a; Super.PostBeginPlay(); if ( Level.NetMode != NM_DedicatedServer && Level.bHighDetailMode ) { a = Spawn(class'ShortSmokeGen'); a.RemoteRole = ROLE_None; } MakeSound(); } [7H ha+"a  #a*<o$a=' C=Y om# a # #B Dc -7:%&7S:&&5p:,&2:,&1 EGAr9 --w*U-&Mega Mortar(s) activated!'(Mega Mortar(s) deactivated!' 6< >6a+P F{  r*(Fr--(a--'r.*.&- -/(3.%::$La/!$6.!.a!>(w.*.-r.*r.* -.(w.*.-w.*w.*w.* -,(4w.*a/!1 -0(- :,w.*&:.:(' M//============================================================================= // MegaMortarShell. //============================================================================= class MegaMortarShell expands FlakShell; var MegaMortar Master; var Actor Target; simulated function Tick(float DeltaTime) { Super.Tick(DeltaTime); SetRotation(rotator(Velocity)); } function Explode(vector HitLocation, vector HitNormal) { local vector start; local vector BS, AlsoBS; local actor LessBS; if ( Master != None && Target != None ) { LessBS = Trace(BS, AlsoBS, Target.Location, (Location+(HitNormal*10))); if (LessBS == Level || Mover(LessBS) != None || LessBS.bStatic) Master.IgnoreThis(Target); } Level.Game.SpecialDamageString = " was blasted by a mortar."; HurtRadius(damage, 300, 'Special', MomentumTransfer, HitLocation); Level.Game.SpecialDamageString = Level.Game.default.SpecialDamageString; start = Location + 10 * HitNormal; Spawn( class'MortarFlameExplosion',,,Start); /* Spawn(class 'MasterChunk',,,Start); Spawn( class 'Chunk2',, '', Start); Spawn( class 'Chunk3',, '', Start); Spawn( class 'Chunk4',, '', Start); Spawn( class 'Chunk1',, '', Start); Spawn( class 'Chunk2',, '', Start); */ Destroy(); } I4oV4},|,Vehicles)}, |, SR_Vehicles*}, |, CardboardBox' H36@w* w*a+: "?, rw.*-   was blasted by a mortar.C!?3#?, "a ) #a e// Generated by MeshMaker (c) 2001 by Mychaeel //============================================================================= // MegaMortar. If you think you kick butt with that Flak Cannon, this will // teach you otherwise. It can hit any nonmoving target with perfect accuracy, // as long as the required launch velocity isn't too high; and it does a // reasonably good job of hitting moving ones, too. //============================================================================= class MegaMortar expands Actor; #exec obj load file=..\Textures\Starship.utx #exec obj load file=..\Textures\Ancient.utx package=Ancient #exec obj load file=..\Textures\XFX.utx package=XFX #exec mesh import mesh=MegaMortarA anivfile=Models\MegaMortarA_a.3d datafile=Models\MegaMortarA_d.3d x=0 y=0 z=0 mlod=0 #exec mesh origin mesh=MegaMortarA x=0 y=0 z=0 #exec mesh sequence mesh=MegaMortarA seq=All startframe=0 numframes=1 #exec meshmap new meshmap=MegaMortarA mesh=MegaMortarA #exec meshmap scale meshmap=MegaMortarA x=0.37500 y=0.37500 z=0.75000 var(MegaMortar_Team) Texture RedTex, BlueTex, GreenTex, GoldTex; var(MegaMortar_Firing) float RefireTime; var(MegaMortar_Targeting) bool bShootPlayers; var(MegaMortar_Targeting) bool bSeeStealthed; var(MegaMortar_Targeting) bool bShootMonsters; var(MegaMortar_Targeting) bool bShootVehicles; var(MegaMortar_Targeting) bool bEvil; var(MegaMortar_Damage) bool bDestroyable; var int StartHealth; var(MegaMortar_Damage) int Health; var(MegaMortar_Team) byte Team; var(MegaMortar_Firing) bool bEnabled; // Number of times it recalculates to try to hit moving targets. // (higher = slightly more accurate, but more resource-consuming) var(Advanced) int NumPredictionSteps; // Internal stuff var Pawn P; var Actor Q; var Actor Target; var float TargetDist; var bool SkipThisMoron; var int TotalIgnoredIdiots; var Actor IgnoreTheseIdiots[100]; var vector AimDir; var float R; var float h; var float LaunchSpeed; var vector LaunchVelocity; var vector V; var vector OldLocation; var int i; var vector PredictedLocation; var MegaMortarShell Proj; var int TempRefireTime; var float LaunchAngle; var vector BubbleLocation; var MortarHull MyHull; function PostBeginPlay() { Super.PostBeginPlay(); SetRotation(rot(0,0,0)); MyHull = Spawn(class'MortarHull', self,, (Location + vect(0,0,-64)) ); MyHull.SetBase(Self); StartHealth = Health; SetTeamSkin(); SetPhysics(PHYS_Falling); SetTimer(0.1, true); } function Timer() { if ( OldLocation == vect(0,0,0) || OldLocation != Location ) { OldLocation = Location; MyHull.SetLocation(Location + vect(0,0,-64)); BubbleLocation = Location + vect(0,0,65); } } function SetTeamSkin() { if ( Level.Game.bTeamGame ) { if ( Team == 0 ) MultiSkins[1] = RedTex; else if ( Team == 1 ) MultiSkins[1] = BlueTex; else if ( Team == 2 ) MultiSkins[1] = GreenTex; else if ( Team == 3 ) MultiSkins[1] = GoldTex; } } function Trigger( Actor Other, Pawn EventInstigator ) { bEnabled = !bEnabled; if ( EventInstigator != None ) { if ( bEnabled ) EventInstigator.ClientMessage("Mega Mortar(s) activated", 'Event', True); else EventInstigator.ClientMessage("Mega Mortar(s) deactivated", 'Event', True); } } function bool ValidTarget(Actor A) { // don't shoot nothing if ( A == None ) return false; // don't shoot the level if ( A == Level || A.bStatic || A.bNoDelete ) return false; // shoot vehicles (stuff below applies only to pawns) if ( IsVehicle(A) && bShootVehicles ) return true; // don't shoot it if it's not a pawn or vehicle, or if it's a dead // pawn or one with an Invisibility powerup ( if bSeeStealthed is false ) if ( ( Pawn(A) == None || Pawn(A).Health < 1 ) || ( A.bHidden && !bSeeStealthed ) ) return false; // basic checks for shooting pawns; variable-based ones are below if ( Pawn(A).Health <= 0 || A.Physics == PHYS_Flying || (A.IsA('PlayerPawn') && (PlayerPawn(A).ReducedDamageType == 'All' || PlayerPawn(A).IsInState('CheatFlying'))) ) return false; // don't shoot monsters if bShootMonsters is false if ( ScriptedPawn(A) != None && !ScriptedPawn(A).bIsWuss && NaliRabbit(A) == None && Bird1(A) == None && !bShootMonsters ) return false; // be nice to the nali...if bEvil is false! muhahahaha....? if ( ((ScriptedPawn(A) != None && ScriptedPawn(A).bIsWuss) || NaliRabbit(A) != None || Bird1(A) != None || HorseFly(A) != None) && !bEvil ) return false; // don't shoot players or bots if bShootPlayers is false if ( ( PlayerPawn(A) != None || A.IsA('Bot') ) && !bShootPlayers ) return false; // don't shoot team members if this is a team game if ( Level.Game.bTeamGame && Team != 255 && Pawn(A).PlayerReplicationInfo != None && Pawn(A).PlayerReplicationInfo.Team == Team ) return false; // if it passed all those checks, open fire! return true; } // wacky way to check if A is a vehicle from Vehicles.u or SR_Vehicles.u (which are really the same) without loading either one! function bool IsVehicle( actor A ) { local string S; S = String(A.Class); if ( (Len(S) > 8 && Left(S, 8) ~= "Vehicles") || (Len(S) > 11 && Left(S, 11) ~= "SR_Vehicles") || (Len(S) > 12 && Left(S, 12) ~= "CardboardBox") ) return true; } auto state SearchAndDestroy { Begin: TempRefireTime = RefireTime + 0.1; Loop: sleep(TempRefireTime); TempRefireTime = RefireTime + 0.1; Target = None; if ( !bEnabled ) GoTo('Loop'); foreach AllActors(class'Actor', Q) { SkipThisMoron = False; if ( (Target == None || VSize(BubbleLocation - Q.Location) < TargetDist) && ValidTarget(Q) ) { for ( i = 0; i < TotalIgnoredIdiots; i++ ) { if ( IgnoreTheseIdiots[i] == Q && Trace(V, LaunchVelocity, Q.Location, BubbleLocation, true) != Q ) { SkipThisMoron = True; TempRefireTime = 0.1; } else if ( IgnoreTheseIdiots[i] == Q ) RemoveIdiot(i); } if ( !SkipThisMoron ) { Target = Q; TargetDist = VSize(BubbleLocation - Q.Location); } } } if ( Target != None && CanHit() ) { TempRefireTime = RefireTime; // launch projectile up into "launch bubble" Proj = Spawn(class'MegaMortarShell',,, (Location + Vect(0,0,-49))); Proj.Velocity.Z = sqrt(2*(-Region.Zone.ZoneGravity.Z)*114); Proj.Master = Self; Proj.Target = Target; sleep(Abs(Proj.Velocity.Z)/(-Region.Zone.ZoneGravity.Z)); // find launch speed + angle LaunchAngle = (PI / 4); V = (Target.Location - BubbleLocation); V.Z = 0; R = VSize(V); h = (Target.Location.Z - BubbleLocation.Z); // adjust angle for low targets LaunchSpeed = 0; while ( h < (R*tan(LaunchAngle)) && LaunchAngle > 0 && LaunchSpeed <= Region.Zone.ZoneTerminalVelocity ) { LaunchAngle -= (PI/16); LaunchSpeed = sqrt(((-Region.Zone.ZoneGravity.Z)*R*R)/(2*(cos(LaunchAngle)*cos(LaunchAngle))*((R*tan(LaunchAngle))-h))); } LaunchAngle += (PI/16); // adjust angle for high targets while ( h >= (R*tan(LaunchAngle)) && LaunchAngle < ((PI / 2)-(PI/16)) ) { LaunchAngle += (PI/16); } if ( h < (R*tan(LaunchAngle)) ) { LaunchSpeed = sqrt(((-Region.Zone.ZoneGravity.Z)*R*R)/(2*(cos(LaunchAngle)*cos(LaunchAngle))*((R*tan(LaunchAngle))-h))); // don't shoot at something that's too far away to hit if ( LaunchSpeed > Region.Zone.ZoneTerminalVelocity ) { //IgnoreThis(Target); TempRefireTime = 0.1; Proj.Destroy(); } else { // predict target's location on landing and recalculate several times for(i = 0; i < NumPredictionSteps; i++) EulerReIncrement(); if ( PredictedLocation == vect(0,0,0) ) { V = (Target.Location - BubbleLocation); V.Z = 0; AimDir = (V/VSize(V)); } else { V = (PredictedLocation - BubbleLocation); V.Z = 0; AimDir = (V/VSize(V)); } // dunno if this works...but try to do it "bullet style" if gravity is very low (the above will set LaunchSpeed very small or 0) if ( Abs(Region.Zone.ZoneGravity.Z) < 10 ) { LaunchSpeed = Region.Zone.ZoneTerminalVelocity; LaunchAngle = Atan(h/R); } LaunchVelocity.X = (((cos(LaunchAngle))*AimDir.X)*LaunchSpeed); LaunchVelocity.Y = (((cos(LaunchAngle))*AimDir.Y)*LaunchSpeed); LaunchVelocity.Z = ((sin(LaunchAngle))*LaunchSpeed); // destroy the projectile + spawn a new one so it gets replicated Proj.Destroy(); Proj = Spawn(class'MegaMortarShell',,, BubbleLocation); Proj.Velocity = LaunchVelocity; Proj.Master = Self; Proj.Target = Target; PredictedLocation = vect(0,0,0); } } else { TempRefireTime = 0.1; Proj.Destroy(); } } GoTo('Loop'); } function EulerReIncrement() { if ( PredictedLocation == vect(0,0,0) ) PredictedLocation = Target.Location + (Target.Velocity*(((R)/(LaunchSpeed*(cos(LaunchAngle))))/NumPredictionSteps)); else PredictedLocation = PredictedLocation + (Target.Velocity*(((R)/(LaunchSpeed*(cos(LaunchAngle))))/NumPredictionSteps)); V = (PredictedLocation - BubbleLocation); V.Z = 0; R = VSize(V); h = (PredictedLocation.Z - BubbleLocation.Z); LaunchSpeed = sqrt(((-Region.Zone.ZoneGravity.Z)*R*R)/(2*(cos(LaunchAngle)*cos(LaunchAngle))*((R*tan(LaunchAngle))-h))); } function IgnoreThis(Actor Eh) { for ( i = 0; i < TotalIgnoredIdiots; i++ ) if (IgnoreTheseIdiots[i] == Eh) return; IgnoreTheseIdiots[TotalIgnoredIdiots] = Eh; ++TotalIgnoredIdiots; } function bool CanHit() { LaunchAngle = (PI / 4); V = (Target.Location - BubbleLocation); V.Z = 0; R = VSize(V); h = (Target.Location.Z - BubbleLocation.Z); // adjust angle for low targets LaunchSpeed = 0; while ( h < (R*tan(LaunchAngle)) && LaunchAngle > 0 && LaunchSpeed <= Region.Zone.ZoneTerminalVelocity ) { LaunchAngle -= (PI/16); LaunchSpeed = sqrt(((-Region.Zone.ZoneGravity.Z)*R*R)/(2*(cos(LaunchAngle)*cos(LaunchAngle))*((R*tan(LaunchAngle))-h))); } LaunchAngle += (PI/16); // adjust angle for high targets while ( h >= (R*tan(LaunchAngle)) && LaunchAngle < ((PI / 2)-(PI/16)) ) { LaunchAngle += (PI/16); } if ( h < (R*tan(LaunchAngle)) ) { LaunchSpeed = sqrt(((-Region.Zone.ZoneGravity.Z)*R*R)/(2*(cos(LaunchAngle)*cos(LaunchAngle))*((R*tan(LaunchAngle))-h))); // don't shoot at something that's too far away to hit if ( LaunchSpeed > Region.Zone.ZoneTerminalVelocity ) { //IgnoreThis(Target); TempRefireTime = 0.1; return false; } } else return false; return true; } function RemoveIdiot(int MoronIndex) { for ( i = MoronIndex; i < TotalIgnoredIdiots; i++ ) if ( i < 100 && i < (TotalIgnoredIdiots-1) ) IgnoreTheseIdiots[i] = IgnoreTheseIdiots[i+1]; else IgnoreTheseIdiots[i] = None; --TotalIgnoredIdiots; } function MortarTakeDamage(int Damage) { local int DeathMortars; local PlayerPawn P2; if ( !bDestroyable ) return; Health = Health - Damage; if ( Health <= 0 ) { GoToState(''); for ( i = 0; i < 10; i++ ) { V = (VRand()*128); V.Z = (-96 + (FRand()*64)); Spawn(class'MortarFlameExplosion',,, (Location+V)); } foreach RadiusActors(class'PlayerPawn', P2, 10000) P2.ShakeView( 1, 2000, 100 ); Level.Game.SpecialDamageString = " forgot to stand back when shooting a giant tank full of mortars."; HurtRadius(1000, 500, 'Special', 10000, (Location+vect(0,0,-64))); Level.Game.SpecialDamageString = Level.Game.default.SpecialDamageString; DeathMortars = 5+(FRand()*10); for ( i = 0; i < DeathMortars; i++ ) { V = (VRand()*128); V.Z = (-96 + (FRand()*64)); LaunchVelocity = 2000*VRand(); Proj = Spawn(class'MegaMortarShell',,, (Location+V)); Proj.Velocity = LaunchVelocity; } Destroy(); } } function Destroyed() { if ( MyHull != None ) MyHull.Destroy(); Super.Destroyed(); } LSD=a?D= *G- !/a0  j-!(ir *   '  %6 r )wa   ' -!'D=,,r i-!  '   10ow * D a  #D6  @66 ?,r   a6  66 I@?,   66  6 t ?%6I@?,66 ?,I@?,I@?,I@?,I@?,W66 ?,6D= aT%   #   66  666 ?, 666666 a a         #oD= a ! xP *]"B] #     ?     ?   66 6 66 ?, Q$ 7$Q%7-r$ $  RU A^%8I@?,   66  6 / ?%6I@?,66 ?,xI@?,I@?,I@?,I@?,@266 ?,/6D=(4(' T8f)w8nW,d&&d*  CCCR[Cc[qC C ! ! UUUU=!!96CXCX5__5??69=?? ཯ UyvBA@ '~X} < ~U@<0=X=_==>?G0@HU(`U_QǶ얹'^~chjdddddddddd dd  d dd d dd d ddddddddddddddddddddddddddddd  H H x x6 !6OjpȪޤMpoژΎKon򎎸dIm>#4I!J>In!WJGlIWGm DIEkܕElE"CifXfCkfXjS6Ah@!*Ai@@!?g6>J?h6>=g#Gf=#; e ;f 9 d ^h9e ^5 5dh] !] ! e 6!e]6!]Sߘee66S456467895854:;9:98<=;<;:>?=>=<@A?@?>BCABA@DECDCBFGEFEDHIGHGFJKIJIHLMKLKJNOMNMLPQOPONRSQRQP76S7SR7RP.@7PN@2J7NL2JLJ7LJLJd@7JHd@v.7HFv.7FDD47D84D:8D<:2D><L2D@>dLDB@vdQSjڴ[^_c[_`cf[`acf7[abc7[bcc[cTcc[\]cTZ[g8gTYZg8TXYgTWXgfTVWg7fTUVg87[]^c103,3.".0+23132)2+,+3(/2.30%/()(2#0/1/0"0#%#/.$-'-$"$.,.-+-*'*-,-+)+*(*&'&*)*(%(&#&$'$&%&#"#$12/AOlq  #',16;@EJOT Ydimrw|  !,16;@EJOTY^b grw| CCCR[Cvt~?@ABCDEL"#!"E !DE CD=> BC ;< AB 9: @A 78 ?@56?FGHIJKL34F01FG./GH,-HI)*IJ$%JK#$KL !"#$%=%*+MNPtu=>MOP2MNkNklmnopqrstOPRuv;<OQRQRTvw9:QSTSTVwx78SUVUVXxy56UWXWXZyz34WYZYZ\z01Y[\[\^stuvwxyz./[]^]^`rs,-]_`_`bqr)*+_ababdpq(acdcdfop'cefefhno&eghghjmngij{ijlm2ikl{|}~||}}~~;>9<8:573604&2{.1,/)-(+'(&'CCCR[Cq>>@????V; s* -* ;%q!%, ?,6«?,@a ) 8/a6 (@F(;?DB10 forgot to stand back when shooting a giant tank full of mortars.zDC!@F#%D?,?, %%?,6«?,@? a    a Z&mXP::$-&a &$  a @ 9X:\.w*a DDE^EtqpEW}LEFvPEyEUE_DCEYyZvdEvygqQECETycvUylE$EuE}v`Ez}SEoDIDeEEEay DECxYT5Y}JEwEv}MEKC?yjEVEXyXY:CbYOY<DPCT}3EDTnY=Y/CH[7yo[tEyYAE]CEE|[GE{[kE[YrEEaY6E#E\oLoJoMoKDN]qDeoOFbRFdQl p,h |,N H-IIT-\ b-h o-0H{-p C1@ O1f \1m i1r v1j C2k P2i \2LV i2f u2g A37 N3f [3O h3-Uw?n LB5 YBMH eB8 rBA ~BB KC( XCF_ dCw qC  ~Ce KDM^ WDMi dDRu qDXz ~DYI JE~ WEX{ cE.zpE! jGMs vG` CH% OH& [H] gH' sH) H* LIM[ YILIfI+ tIHW AJ, MJVx ZJ?s fJMG rJX3 Jc KK?3 WK?_cK/EqKR4~ vN)R4utX?[iaiwa=n`cyNeAGGgFX Ni<&[itAjR4XuqIm M\Y6muLm bR4qnU_ ^t JRY \ ViTm dKSmo bn)WP)(g?Z O:0\