Blastrobots
Genre : 3D Top-Down Shooter
Engine : UDK
Role : Programmer
Responsible for :
- Implemented weapons’ mechanics and functionality
- Weapon system
- Normal gun
- Flamethrower
- Laser
- Lemon gun – aka Chain gun, Pulse gun, Default gun
- Shotgun
- Special shot – aka Combo shot
- BDL (Big Dang Laser)
- Chain Lightning
- Spinning Flame Sword
- Napalm (Meteor-like fireball)
- Rockettes (Rocket Barrage)
- Travolta (A light ball which spread laser beams)
- YoYo (Boss’s special shot)
- Implemented projectiles, particle effects and visual feedback
- Player’s blinking red when get shot
- Most projectiles coming out from any guns in the game (projectiles’ behavior, eg. speed, trajectory etc.)
- Implemented player’s UI and abilities
- Player’s shield
- Player’s combo shot interact with controller
- Pickup system
- Collaborate, sharing the ideas with level designers about game mechanics and balance. Setting up config files so they can change the value easier.
- Help artists overcome technical difficulties; for example, setting up trigger for animated objects, moving the main characters according to their move speed.
Team size : 14
Code Sample
class BlastroWeapon extends UTWeap_ShockRifle; //var array attachedMesh; var SkeletalMeshComponent attachedMesh[2]; var FireMode FireModeSlot[ 3 ]; var float fillRageInterval; var bool bCanfire; // detect firing mode 0,1 var bool isLeftWeaponFire; var bool isRightWeaponFire; var float lastComboFireAttempt; var FireMode currentMode; var byte currentSlot; var BlastroProjectileGenerator lastShot; var AudioComponent specialWeaponSound; //========================================================================= //========================================================================= function CancelFire() { if ( lastShot != none ) lastShot.Destroy(); } //========================================================================= //========================================================================= simulated function CustomFire() { Fire( 0 ); } //========================================================================= //========================================================================= simulated function Projectile ProjectileFire() { Fire( 1 ); return none; } //========================================================================= //========================================================================= simulated function PostBeginPlay() { updateWeaponAttachment( 0 ); super.PostBeginPlay(); } //========================================================================= //========================================================================= function SetFireMode( int slot, FireModeType type ) { local BlastroGame game; local int otherSlot; local FireMode nextMode; if ( slot == 0 ) otherSlot = 1; else otherSlot = 0; game = BlastroGame( WorldInfo.Game ); nextMode = game.getFireMode( type ); if ( nextMode == FireModeSlot[ otherSlot ] && type != MODE_LEMON ) { FireModeSlot[ otherSlot ] = FireModeSlot[ slot ]; } FireModeSlot[ slot ] = nextMode; FireModeSlot[ 2 ] = game.getComboMode( FireModeSlot[ 0 ], FireModeSlot[ 1 ] ); if (FireModeSlot[ 2 ] == none) { stopFillRage(); } else { startFillRage(); } // reset rage when change the weapon BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).rage = 0.0; updateWeaponAttachment( slot ); StopFire(slot); } function updateWeaponAttachment(int slot) { local int i; local BlastroPawn bPawn; bPawn = BlastroPawn( Instigator ); if ( bPawn == none ) return; // attached mesh to player if ( slot != 2 && Instigator != none ) { for (i = 0; i < 2; ++i) { if (attachedMesh[ i ] != none) attachedMesh[ i ].DetachFromAny(); attachedMesh[ i ] = new class'SkeletalMeshComponent'; attachedMesh[ i ].SetSkeletalMesh( FireModeSlot[ i ].attachedToPlayerMesh ); //bPawn.BlastroMesh.AttachComponentToSocket( attachedMesh[ i ], ( i == 0 ) ? 'weapon_01' :'weapon_02'); bPawn.Mesh.AttachComponentToSocket( attachedMesh[ i ], ( i == 0 ) ? 'WeaponPoint' :'DualWeaponPoint'); } } } function startFillRage() { SetTimer(fillRageInterval, true, 'fillRageBar'); } function stopFillRage() { SetTimer(0.0, true, 'fillRageBar'); } function fillRageBar() { local BlastroPlayerReplicationInfo repInfo; repInfo = BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo); if (repInfo.rageInUse) return; repInfo.rage = Min( repInfo.maxRageValue, repInfo.rage + FireModeSlot[ 2 ].mod_combo_fillRage ); } //========================================================================= //========================================================================= simulated function StartFire(byte FireModeNum) { local FireMode mode; mode = FireModeSlot[ FireModeNum ]; currentSlot = FireModeNum; currentMode = mode; //if ( BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).rageInUse ) if ( !bCanfire ) { return; } if ( mode == none ){ lastComboFireAttempt = WorldInfo.TimeSeconds; return; } if ( FireModeNum == 0 ) { UTPawn(Instigator).CurrentWeaponAttachment.MuzzleFlashPSCTemplate = mode.muzzle; } else if (FireModeNum == 1) { UTPawn(Instigator).CurrentWeaponAttachment.MuzzleFlashAltPSCTemplate = mode.muzzle; } WeaponFireSnd[ FireModeNum ] = mode.fireSound; FireInterval[ FireModeNum ] = 1.0 / ( mode.mod_fastRateOfFire + 1 ); super.StartFire(FireModeNum); } //========================================================================= //========================================================================= simulated function Fire( int slot ) { local Vector FireLoc; local FireMode mode; mode = FireModeSlot[ slot ]; if (slot == 2) { if (BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).rage < BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).maxRageValue) { // not enough rage return; } WeaponPlaySound( mode.fireSound ); } // tell remote clients that we fired, to trigger effects IncrementFlashCount(); FireLoc = GetPhysicalFireStartLoc(); mode.Fire( self, FireLoc, Instigator.Rotation/*GetAdjustedAim( FireLoc ) */ ); } simulated function StopFire(byte FireModeNum) { super.StopFire( FireModeNum ); if( specialWeaponSound != none ) { specialWeaponSound.FadeOut(0.5, 0.2); } } simulated function WeaponPlaySound(SoundCue Sound, optional float NoiseLoudness) { if ( currentMode != none ) { if(currentMode.Class == class'FlamethrowerMode'){ if(specialWeaponSound == none){ specialWeaponSound = Instigator.CreateAudioComponent(Sound, false); } if(!specialWeaponSound.IsPlaying()){ specialWeaponSound.Play(); } } else{ super.WeaponPlaySound(sound, NoiseLoudness); } } } //simulated function Fire( int slot ) //{ // local FireMode mode; // local Vector FireLoc; // mode = FireModeSlot[ slot ]; // if ( BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).rageInUse ) // { // return; // } // if ( mode == none ){ // lastComboFireAttempt = WorldInfo.TimeSeconds; // return; // } // if ( slot == 0 ) // { // UTPawn(Instigator).CurrentWeaponAttachment.MuzzleFlashPSCTemplate = mode.muzzle; // } // else if (slot == 1) // { // UTPawn(Instigator).CurrentWeaponAttachment.MuzzleFlashAltPSCTemplate = mode.muzzle; // } // else if (slot == 2) // { // if (BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).rage < BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).maxRageValue) // { // // not enough rage // return; // } // BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).rage = 0; // BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).rageInUse = true; // } // FireInterval[ slot ] = 1.0 / ( mode.mod_fastRateOfFire + 1 ); // WeaponFireSnd[ slot ]= mode.fireSound; // // tell remote clients that we fired, to trigger effects // IncrementFlashCount(); // FireLoc = GetPhysicalFireStartLoc(); // mode.Fire( self, FireLoc, GetAdjustedAim( FireLoc ) ); //} //========================================================================= //========================================================================= simulated function bool HasAmmo( byte FireModeNum, optional int Amount ) { return true; } //========================================================================= //========================================================================= simulated function bool HasAnyAmmo() { return true; } //========================================================================= //========================================================================= simulated function Destroyed() { CancelFire(); Super.Destroyed(); } //========================================================================= //========================================================================= //simulated function SpawnBeam(vector Start, vector End, bool bFirstPerson) //{ // local ParticleSystemComponent E; // local actor HitActor; // local vector HitNormal, HitLocation; // if ( End == Vect(0,0,0) ) // { // if ( !bFirstPerson || (Instigator.Controller == None) ) // { // return; // } // // guess using current viewrotation; // End = Start + vector(Instigator.Controller.Rotation) * 500;// class'UTWeap_ShockRifle'.default.WeaponRange; // HitActor = Instigator.Trace(HitLocation, HitNormal, End, Start, TRUE, vect(0,0,0),, TRACEFLAG_Bullet); // if ( HitActor != None ) // { // End = HitLocation; // } // } // //E = WorldInfo.MyEmitterPool.SpawnEmitter(ParticleSystem'BB_Weapon_Particles.Particles.BDL_particle_02', Start); // //E.SetVectorParameter('LinkBeamEnd', End); // E = WorldInfo.MyEmitterPool.SpawnEmitter(particlesystem'BB_WP_Lazer.Particles.laser_particle_03', Start); // E.SetVectorParameter('ShockBeamEnd', End); // E.SetDepthPriorityGroup(SDPG_World); //} simulated function ParticleSystemComponent SpawnBeam(ParticleSystem EmitterTemplate, vector Start, vector End, Actor attachedActor, name BeamEndName) { local ParticleSystemComponent E; //local Vector zero; if (attachedActor != none) { E = WorldInfo.MyEmitterPool.SpawnEmitterCustomLifetime(EmitterTemplate); //E = WorldInfo.MyEmitterPool.SpawnEmitter(EmitterTemplate, zero); E.SetAbsolute(false, false, false); E.SetLODLevel(WorldInfo.bDropDetail ? 1 : 0); //E.OnSystemFinished = MyOnParticleSystemFinished; E.bUpdateComponentInTick = true; attachedActor.AttachComponent(E); } else { // no actor to attach E = WorldInfo.MyEmitterPool.SpawnEmitter(EmitterTemplate, Start); } //E.SetVectorParameter('LinkBeamEnd', End); E.SetVectorParameter(BeamEndName, End); E.SetDepthPriorityGroup(SDPG_World); return E; } //========================================================================= //========================================================================= simulated static function bool PassThroughDamage(Actor HitActor) { return (!HitActor.bBlockActors && (HitActor.IsA('Trigger') || HitActor.IsA('TriggerVolume'))) || HitActor.IsA('InteractiveFoliageActor') || HitActor.IsA('BlastroPawn') || HitActor.IsA('EnemyPawn'); } //========================================================================= //========================================================================= //exec function changeWeaponProp(int slotNum, int projParticle, float damage, float damageRadius, float projSpeed, int spreadShot, int fastFire, int piercing, int invisProj, int homing, float homingRadius, float homingCurve, int recursive, float drag, float tlifespan) //{ // mod_projParticle[slotNum] = projParticle; // mod_damage[slotNum] = damage; // mod_damageRadius[slotNum] = damageRadius; // mod_projSpeed[slotNum] = projSpeed; // mod_spreadShot[slotNum] = spreadShot; // mod_fastRateOfFire[slotNum] = fastFire; // mod_piercing[slotNum] = piercing; // mod_invisProj[slotNum] = invisProj; // mod_homing[slotNum] = homing; // mod_homingRadius[slotNum] = homingRadius; // mod_homingCurve[slotNum] = homingCurve; // mod_recursiveShot[slotNum] = recursive; // mod_drag[slotNum] = drag; // mod_lifespan[slotNum] = tlifespan; //} //========================================================================= //========================================================================= simulated function ImpactInfo CalcWeaponFire(vector StartTrace, vector EndTrace, optional out array ImpactList, optional vector Extent) { local vector HitLocation, HitNormal; local Actor HitActor; local TraceHitInfo HitInfo; local ImpactInfo CurrentImpact; // Perform trace to retrieve hit info foreach TraceActors(class 'Actor', HitActor, HitLocation, HitNormal, EndTrace, StartTrace, Extent, HitInfo, TRACEFLAG_Bullet) { CurrentImpact.HitActor = HitActor; CurrentImpact.HitLocation = HitLocation; CurrentImpact.HitNormal = HitNormal; CurrentImpact.RayDir = Normal(EndTrace-StartTrace); CurrentImpact.StartTrace = StartTrace; CurrentImpact.HitInfo = HitInfo; ImpactList[ImpactList.Length] = CurrentImpact; if (HitActor.IsA('StaticMeshActor') || HitActor.IsA('InterpActor')) { break; } } // If we didn't hit anything, then set the HitLocation as being the EndTrace location if( ImpactList.Length == 0 ) { HitLocation = EndTrace; return CurrentImpact; } else { return ImpactList[0]; } } DefaultProperties { //FireInterval[0] = 1.0f; // look in init() fillRageInterval = 0.2; WeaponFireTypes(0)=EWFT_Custom WeaponFireTypes(1)=EWFT_Projectile bCanfire = true; isLeftWeaponFire = false isRightWeaponFire = false lastComboFireAttempt = 0 //WeaponFireSnd[0]=SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_FireCue' //WeaponFireSnd[1]=SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_AltFireCue' //Begin Object Name=Lemon Class='YoyoMode' //End Object Begin Object Name=Lemon Class='LemonMode' End Object FireModeSlot[ 0 ] = Lemon FireModeSlot[ 1 ] = Lemon FireModeSlot[ 2 ] = none AttachmentClass=class'BlastroAttachment_MuzzleFlash' ProjectileSpawnOffset= 0 }
class SpreadMode extends FireMode; var float wiggleRatio; //========================================================================= //========================================================================= simulated function Fire( BlastroWeapon weapon, Vector pos, Rotator aim ) { local int i; local float angleStep; local Rotator curAim; local int flip; local int shotsPerSide; angleStep = spreadAngleDegree / mod_numSpread; shotsPerSide = mod_numSpread / 2; // Shoot one straight forward if ( shotsPerSide * 2 < mod_numSpread ) spawnProjectile( weapon, pos, Vector( aim ) ); for ( i = 0; i < shotsPerSide; ++i ) { for ( flip = -1; flip
1 class RockettesMode extends FireMode; DefaultProperties { projectileClass = class 'BlastroProjectileRockettes' bDestroyLastProjectileOnCancel = true; }
class BlastroProjectileGenerator extends UTProj_LinkPlasma; //const Pi = 3.1415926535897932; //const RadToDeg = 57.295779513082321600; // 180 / Pi //const DegToRad = 0.017453292519943296; // Pi / 180 //const UnrRotToRad = 0.00009587379924285;// Pi / 32768 //const RadToUnrRot = 10430.3783504704527;// 32768 / Pi //const DegToUnrRot = 182.0444; //const UnrRotToDeg = 0.00549316540360483; var float spreadAngleDegree; var bool isExploded; // weapon mods // -1=no_particle, 0=lemon, 1=shotgun, 2=rocket, 3=lazer, 4=flamethrower, 5=chainLighting var int mod_projParticle; var float mod_damage; var float mod_damageRadius; var float mod_projSpeed; var int mod_spreadShot; var int mod_fastRateOfFire; var int mod_piercing; var int mod_invisProj; var int mod_homing; var float mod_homingRadius; var float mod_homingCurve; var int mod_recursiveShot; var float mod_drag; var float mod_lifespan; // boss pattern variable var float tmptime; var float lifetime; var int bulletId; var int numOfBullets; var UTPawn target; var vector initDirection; var int stateParam; var int HomeConeRadians; var float drainRageRate; var float drainRageInterval; // For playing CombotShot Weapon sounds // var AudioComponent weaponSound; var float cueTimer; // state_arg // 0 = normal case // 1 = recursive ignore damage generate actor //========================================================================= //========================================================================= function InitHell(int tmod_projParticle, float tmod_damage, float tmod_damageRadius, float tmod_projSpeed, int tmod_spreadShot, float tmod_fastRateOfFire, int tmod_piercing, int tmod_invisProj, int tmod_homing, float tmod_homingRadius, float tmod_homingCurve, int tmod_recursiveShot, float tmod_drag, float tmod_lifespan, vector Direction, Actor targetActor, int state_arg) { // remember mod variable self.mod_projParticle = tmod_projParticle; self.mod_damage = tmod_damage; self.mod_damageRadius = tmod_damageRadius; self.mod_projSpeed = tmod_projSpeed; self.mod_spreadShot = tmod_spreadShot; self.mod_fastRateOfFire = tmod_fastRateOfFire; self.mod_piercing = tmod_piercing; self.mod_invisProj = tmod_invisProj; self.mod_homing = tmod_homing; self.mod_homingRadius = tmod_homingRadius; self.mod_homingCurve = tmod_homingCurve; self.mod_recursiveShot = tmod_recursiveShot; self.mod_drag = tmod_drag; self.mod_lifespan = tmod_lifespan; self.stateParam = state_arg; //ProjEffects.DeactivateSystem(); ExplosionLightClass=none;//CHANGE LATER, CRAIG switch (mod_projParticle) { case 0 : // lemon ProjFlightTemplate=ParticleSystem'BB_WP_Pulsecannon.Particles.pulsecannon_particle_02'; ProjExplosionTemplate=ParticleSystem'BB_WP_Pulsecannon.Particles.lemon_impact_particle_02'; //ProjExplosionTemplate=none; ExplosionSound=SoundCue'BlastroSFX.LemonGun.Lemon_Impact_1_Cue'; //ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; ExplosionDecal=none; ExplosionLightClass=none; break; case 1 : // shotgun ProjFlightTemplate=ParticleSystem'BB_WP_Shotgun.Particles.shotgun_particle_03'; ProjExplosionTemplate=ParticleSystem'BB_WP_Shotgun.Particles.shotgun_impact_01'; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; ExplosionLightClass=none; break; case 2 : // rocket ProjFlightTemplate=ParticleSystem'BB_WP_Missile.Particles.rocket_particle_01'; ProjExplosionTemplate=ParticleSystem'BB_Weapon_Particles.Particles.explosion_particle_03'; //PlaySound( SoundCue'BlastroSFX.RocketGun.RocketLauncher_Shot29_Cue' ); ExplosionSound=ChooseExplosionSound(); ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; ExplosionLightClass=none; break; case 3 : // lazer ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.laser_particle_01'; ProjExplosionTemplate=ParticleSystem'BB_Weapon_Particles.Particles.explosion_particle_02'; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; break; case 4 : // flamethrower ProjFlightTemplate=ParticleSystem'BB_WP_Flamethrower.Particles.flamethrower_particle_01'; //ProjExplosionTemplate=ParticleSystem'BB_WP_Flamethrower.Particles.smoke_particle_01'; ProjExplosionTemplate=none; ExplosionSound=none; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; break; case 5 : // amanda ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.amandafire_particle_01'; //ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.amanda_01'; ProjExplosionTemplate=none; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; SetDrawScale(5); break; case 6 : // napalm ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.fireball_01'; //ProjExplosionTemplate=ParticleSystem'BB_Weapon_Particles.Particles.explosion_particle_02'; ProjExplosionTemplate=none; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; //ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; ExplosionDecal=none; SetDrawScale(7); break; case 7 : // napalm tail ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.napalmtrail_particles_03'; //ProjExplosionTemplate=ParticleSystem'WP_ShockRifle.Particles.P_WP_ShockRifle_Ball_Impact'; ProjExplosionTemplate=none; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; SetDrawScale(6); break; case 8 : // rockettes ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.rocket_particle_01'; //ProjExplosionTemplate=ParticleSystem'WP_ShockRifle.Particles.P_WP_ShockRifle_Ball_Impact'; ProjExplosionTemplate=none; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; break; case 9 : // flier rockettes ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.minime_particle_01'; //ProjExplosionTemplate=ParticleSystem'WP_ShockRifle.Particles.P_WP_ShockRifle_Ball_Impact'; ProjExplosionTemplate=none; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; break; case 10 : // artillery rain //ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.fireball_particle_01'; ProjFlightTemplate=ParticleSystem'BB_WP_Missile.Particles.rocket_particle_01'; ProjExplosionTemplate=ParticleSystem'BB_Weapon_Particles.Particles.explosion_particle_02'; //ProjExplosionTemplate=none; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; //ExplosionDecal=none; //SetDrawScale(3); break; case 11 : // travolta orb ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.disco_particle_01'; //ProjExplosionTemplate=ParticleSystem'BB_Weapon_Particles.Particles.explosion_particle_02'; ProjExplosionTemplate=none; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; //ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; ExplosionDecal=none; SetDrawScale(2); break; case 12 : // rocket of rockettes ProjFlightTemplate=ParticleSystem'BB_WP_Missile.Particles.rockette_particle_01'; ProjExplosionTemplate=ParticleSystem'BB_Weapon_Particles.Particles.explosion_particle_01'; //ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; ExplosionSound=none; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; ExplosionLightClass=class'UTGame.UTRocketExplosionLight'; break; case 13 : // chronosphere ProjFlightTemplate=ParticleSystem'BB_Item_Particles.Particles.chronosphere_particle_01'; //ProjExplosionTemplate=ParticleSystem'BB_Weapon_Particles.Particles.explosion_particle_02'; ProjExplosionTemplate=none; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; //ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; ExplosionDecal=none; //SetDrawScale(7); break; case 14 : // lazer for travola ProjFlightTemplate=ParticleSystem'BB_WP_Lazer.Particles.laser_particle_04'; ProjExplosionTemplate=ParticleSystem'BB_Weapon_Particles.Particles.explosion_particle_02'; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; break; case 15 : // lightningball ProjFlightTemplate=ParticleSystem'BB_Weapon_Particles.Particles.lightning_particle_01'; //ProjExplosionTemplate=ParticleSystem'BB_Weapon_Particles.Particles.explosion_particle_02'; ProjExplosionTemplate=none; ExplosionSound=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_ImpactCue'; //ExplosionDecal=MaterialInstanceTimeVarying'WP_RocketLauncher.Decals.MITV_WP_RocketLauncher_Impact_Decal01'; ExplosionDecal=none; SetDrawScale(4); break; } //super.Init(Direction); ProjEffects.DeactivateSystem(); SpawnFlightEffects(); if (mod_projParticle == -2) { // use old template, do nothing } else if (mod_projParticle == -1) { // no effect ProjEffects.DeactivateSystem(); ProjEffects = none; } // init mod Damage = mod_damage; DamageRadius = mod_damageRadius; Speed = mod_projSpeed; if (mod_invisProj > 0) { SetHidden( true ); } //drag = mod_drag; //1 - mod_drag; LifeSpan = mod_lifespan; // normally init SetRotation(rotator(Direction)); Velocity = Speed * Direction; Velocity.Z += TossZ; Acceleration = AccelRate * Normal(Velocity); } simulated event HitWall(vector HitNormal, Actor Wall, PrimitiveComponent WallComp) { local KActorFromStatic NewKActor; local StaticMeshComponent HitStaticMesh; MomentumTransfer = 1.0; if ( Wall.bWorldGeometry ) { HitStaticMesh = StaticMeshComponent(WallComp); if ( (HitStaticMesh != None) && HitStaticMesh.CanBecomeDynamic() ) { NewKActor = class'KActorFromStatic'.Static.MakeDynamic(HitStaticMesh); if ( NewKActor != None ) { Wall = NewKActor; } } } ImpactedActor = Wall; if ( Instigator != none ) { if ( Instigator.IsA( 'BlastroPawn' ) && !Wall.bStatic && (DamageRadius == 0) ) { Wall.TakeDamage( Damage, InstigatorController, Location, MomentumTransfer * Normal(Velocity), MyDamageType,, self); } } Explode(Location, HitNormal); ImpactedActor = None; } //========================================================================= //========================================================================= simulated function ProcessTouch (Actor Other, vector HitLocation, vector HitNormal) { if ( isNotSameTeam(Instigator, Other) ) { if ( !Other.IsA('Projectile') || Other.bProjTarget ) { MomentumTransfer = (UTPawn(Other) != None) ? 0.0 : 1.0; if (stateParam != 1) { Other.TakeDamage(Damage, InstigatorController, HitLocation, MomentumTransfer * Normal(Velocity), MyDamageType,, self); } else { //stateParam = 0; } if (mod_piercing > 0) { mod_piercing--; } else { Explode(HitLocation, HitNormal); } } } } //========================================================================= //========================================================================= event Tick( float DeltaTime ) { local UTPawn Victims; local float SearchRadius; local TraceHitInfo HitInfo; local float bestRating; local float curRating; local float angleDiff; local float dist; local Vector disp; bestRating = 10000; SearchRadius = mod_homingRadius; if (mod_homing > 0) { // find target if (target == none) { foreach VisibleCollidingActors( class'UTPawn', Victims, SearchRadius, Location,,,,, HitInfo ) { if ( !Victims.bWorldGeometry && (Victims != Instigator) && (Victims.IsAliveAndWell()) && ( isNotSameTeam(Instigator, Victims) ) ) { disp = Victims.Location - Location; dist = VSize( disp ); if ( SearchRadius != 0 ) // TODO: Logic for when SearchRadius == 0 dist = dist / SearchRadius; angleDiff = Abs( Atan2( Velocity.Y, Velocity.X ) - Atan2( disp.Y, disp.X ) ); if ( angleDiff > 3.14159 ) angleDiff = 3.14159 * 2.0 - angleDiff; if ( angleDiff < HomeConeRadians / 2.0 ) { curRating = angleDiff * dist; if ( curRating < bestRating ) { bestRating = curRating; target = Victims; } } } } } else { // homing - 90000 ori SetRotation(RInterpTo(Rotation,Rotator(target.Location - Location),DeltaTime,mod_homingCurve,true)); Velocity = Normal(Vector(Rotation))* VSize( Velocity ); if (!target.IsAliveAndWell()) { target = none; } } } if (mod_drag != 0) { Velocity -= Velocity * mod_drag * DeltaTime; } super.Tick(DeltaTime); } //========================================================================= // make projectile doens't hurt teammates //========================================================================= simulated function bool HurtRadius ( float BaseDamage, float CurDamageRadius, class DamageType, float Momentum, vector HurtOrigin, optional Actor IgnoredActor, optional Controller InstigatedByController = Instigator != None ? Instigator.Controller : None, optional bool bDoFullDamage ) { local Actor Victim; local bool bCausedDamage; local TraceHitInfo HitInfo; local StaticMeshComponent HitComponent; local KActorFromStatic NewKActor; // Prevent HurtRadius() from being reentrant. if ( bHurtEntry ) return false; bHurtEntry = true; bCausedDamage = false; foreach VisibleCollidingActors( class'Actor', Victim, CurDamageRadius, HurtOrigin,,,,, HitInfo ) { if ( Victim.bWorldGeometry ) { // check if it can become dynamic // @TODO note that if using StaticMeshCollectionActor (e.g. on Consoles), only one component is returned. Would need to do additional octree radius check to find more components, if desired HitComponent = StaticMeshComponent(HitInfo.HitComponent); if ( (HitComponent != None) && HitComponent.CanBecomeDynamic() ) { NewKActor = class'KActorFromStatic'.Static.MakeDynamic(HitComponent); if ( NewKActor != None ) { Victim = NewKActor; } } } if ( !Victim.bWorldGeometry && (Victim != self) && (Victim != IgnoredActor) && ( Victim.bCanBeDamaged || Victim.bProjTarget || Victim.IsA( 'DynamicSMActor' ) ) && isNotSameTeam(Instigator, Victim) ) { Victim.TakeRadiusDamage(InstigatedByController, BaseDamage, CurDamageRadius, DamageType, Momentum, HurtOrigin, bDoFullDamage, self); bCausedDamage = bCausedDamage || Victim.bProjTarget; } } bHurtEntry = false; return bCausedDamage; } //========================================================================= // explode at end of LifeTime //========================================================================= simulated function Explode(vector HitLocation, vector HitNormal) { isExploded = true; super.Explode(HitLocation, HitNormal); } //========================================================================= //========================================================================= simulated function Destroyed() { // Final Failsafe check for explosion effect if (WorldInfo.NetMode != NM_DedicatedServer && !bSuppressExplosionFX) { if (!isExploded) Explode(self.Location, self.Location); SpawnExplosionEffects(Location, vector(Rotation) * -1); } if (ProjEffects != None) { DetachComponent(ProjEffects); WorldInfo.MyEmitterPool.OnParticleSystemFinished(ProjEffects); ProjEffects = None; } if ( weaponSound != none ) { weaponSound.FadeOut( 0.3, 0.3 ); } super.Destroyed(); } //========================================================================= // Helper function //========================================================================= simulated function AOE_Damage(float Radius, float deltaTime) { local UTPawn Victims; local DynamicSMActor SM_Victims; local TraceHitInfo HitInfo; // AOE damage projectiles foreach VisibleCollidingActors( class'UTPawn', Victims, Radius, Location,,,,, HitInfo ) { if ( !Victims.bWorldGeometry && (Victims != Instigator) && (Victims.IsAliveAndWell()) && ( isNotSameTeam( Instigator, Victims ) ) ) { Victims.TakeDamage(Damage*DeltaTime, Instigator.Controller, Victims.Location, MomentumTransfer * Normal(Velocity), MyDamageType,, self); } } foreach VisibleCollidingActors( class'DynamicSMActor', SM_Victims, Radius, Location,,,,, HitInfo ) { if ( !SM_Victims.bWorldGeometry && ( isNotSameTeam( Instigator, SM_Victims ) ) ) { SM_Victims.TakeDamage(Damage*DeltaTime, Instigator.Controller, SM_Victims.Location, MomentumTransfer * Normal(Velocity), MyDamageType,, self); } } } //========================================================================= //========================================================================= simulated function ParticleSystemComponent SpawnBeam(ParticleSystem EmitterTemplate, vector Start, vector End, Actor attachedActor, name BeamEndName) { local ParticleSystemComponent E; //local Vector zero; if (attachedActor != none) { E = WorldInfo.MyEmitterPool.SpawnEmitterCustomLifetime(EmitterTemplate); //E = WorldInfo.MyEmitterPool.SpawnEmitter(EmitterTemplate, zero); E.SetAbsolute(false, false, false); E.SetLODLevel(WorldInfo.bDropDetail ? 1 : 0); E.OnSystemFinished = MyOnParticleSystemFinished; E.bUpdateComponentInTick = true; attachedActor.AttachComponent(E); } else { // no actor to attach E = WorldInfo.MyEmitterPool.SpawnEmitter(EmitterTemplate, Start); } //E.SetVectorParameter('LinkBeamEnd', End); E.SetVectorParameter(BeamEndName, End); E.SetDepthPriorityGroup(SDPG_World); return E; } //========================================================================= //========================================================================= function startDrainRage() { SetTimer(drainRageInterval, true, 'drainRageBar'); } //========================================================================= //========================================================================= function stopDrainRage() { SetTimer(0.0, true, 'drainRageBar'); } //========================================================================= //========================================================================= function drainRageBar() { local BlastroPlayerReplicationInfo repInfo; repInfo = BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo); repInfo.rage = Max( 0, repInfo.rage - drainRageRate ); } //========================================================================= //========================================================================= simulated function ImpactInfo CalcWeaponFire(vector StartTrace, vector EndTrace, optional out array ImpactList, optional vector Extent) { local vector HitLocation, HitNormal; local Actor HitActor; local TraceHitInfo HitInfo; local ImpactInfo CurrentImpact; // Perform trace to retrieve hit info foreach TraceActors(class 'Actor', HitActor, HitLocation, HitNormal, EndTrace, StartTrace, Extent, HitInfo, TRACEFLAG_Bullet) { CurrentImpact.HitActor = HitActor; CurrentImpact.HitLocation = HitLocation; CurrentImpact.HitNormal = HitNormal; CurrentImpact.RayDir = Normal(EndTrace-StartTrace); CurrentImpact.StartTrace = StartTrace; CurrentImpact.HitInfo = HitInfo; ImpactList[ImpactList.Length] = CurrentImpact; if (HitActor.IsA('StaticMeshActor') || HitActor.IsA('InterpActor')) { break; } } // If we didn't hit anything, then set the HitLocation as being the EndTrace location if( ImpactList.Length == 0 ) { HitLocation = EndTrace; return CurrentImpact; } else { return ImpactList[0]; } } //========================================================================= //========================================================================= simulated static function bool PassThroughDamage(Actor HitActor) { return (!HitActor.bBlockActors && (HitActor.IsA('Trigger') || HitActor.IsA('TriggerVolume'))) || HitActor.IsA('InteractiveFoliageActor') || HitActor.IsA('BlastroPawn') || HitActor.IsA('EnemyPawn'); } //========================================================================= //========================================================================= function bool isNotSameTeam(Actor a, Actor b) { if ( a.IsA( 'DynamicSMActor' ) && b.IsA( 'EnemyPawn' ) ) return false; if ( a.IsA( 'EnemyPawn' ) && b.IsA( 'DynamicSMActor' ) ) return false; return a.bWorldGeometry || b.bWorldGeometry || a.IsA( 'BlastroPawn' ) != b.IsA( 'BlastroPawn' ); } simulated function bool ShouldSpawnExplosionLight(vector HitLocation, vector HitNormal) { return false; } //========================================================================= //========================================================================= simulated function PlayComboShotSound() { if ( weaponSound != none ) { if ( !weaponSound.IsPlaying() ) { weaponSound.Play(); } } else { `log("Error: Trying to play Comboshot sound in ProjectileGenerator before it has been created"); } } simulated function SoundCue ChooseExplosionSound() { local int soundChoice; soundChoice = Rand(4); switch ( soundChoice ) { case 0: return SoundCue'BlastroSFX.ROCKETTES.Firework01_Cue'; break; case 1: return SoundCue'BlastroSFX.ROCKETTES.Firework02_Cue'; break; case 2: return SoundCue'BlastroSFX.ROCKETTES.Firework03_Cue'; break; case 3: return SoundCue'BlastroSFX.ROCKETTES.Firework07_Cue'; break; } } simulated function PlayRocketteSound() { local int soundChoice; soundChoice = Rand(4); switch( soundChoice ) { case 0: PlaySound( SoundCue'BlastroSFX.ROCKETTES.RocketLauncher_Shot09_Cue' ); break; case 1: PlaySound( SoundCue'BlastroSFX.ROCKETTES.RocketLauncher_Shot13_Cue' ); break; case 2: PlaySound( SoundCue'BlastroSFX.ROCKETTES.RocketLauncher_Shot40_Cue' ); break; case 3: PlaySound( SoundCue'BlastroSFX.RocketGun.RocketLauncher_Shot29_Cue' ); break; } } //========================================================================= //========================================================================= DefaultProperties { drainRageRate = 0; drainRageInterval = 0.2; isExploded = false; ProjFlightTemplate=ParticleSystem'BB_WP_Pulsecannon.Particles.pulsecannon_particle_01' //ProjExplosionTemplate=ParticleSystem'WP_ShockRifle.Particles.P_WP_ShockRifle_Ball_Impact' ProjExplosionTemplate=none; DecalWidth=128.0 DecalHeight=128.0 Speed=0 AccelRate=0.0 MaxSpeed=0 MaxEffectDistance=7000.0 LifeSpan = 0 spreadAngleDegree = 45.0f target = none HomeConeRadians = 2.09; // Sets timer for SoundCue // cueTimer = 0.1; }
class BlastroProjectileRockettes extends BlastroProjectileGenerator; var ParticleSystem LaserTemplate; var float timer; var float Rockettes_Duration; var int funnelNumber; var float angleDegree; var float distanceFromActor; var float funnelRadius; var float funnelRateOfFire; var float funnelRocketDamage; var float funnelRocketDamageRadius; var float funnelRocketSpeed; var float funnelRocketHomingCurve; var float funnelRocketDuration; var array< BlastroProjectileGenerator > funnelDrones; function InitHell(int tmod_projParticle, float tmod_damage, float tmod_damageRadius, float tmod_projSpeed, int tmod_spreadShot, float tmod_fastRateOfFire, int tmod_piercing, int tmod_invisProj, int tmod_homing, float tmod_homingRadius, float tmod_homingCurve, int tmod_recursiveShot, float tmod_drag, float tmod_lifespan, vector Direction, Actor targetActor, int state_arg) { local int i; local BlastroProjectileRockettes SpawnedProjectile; funnelDrones.Length = 0; if (state_arg == 10) { super.InitHell( -1, //mod_projParticle[slotNum], 0, //mod_damage[slotNum], 0, //mod_damageRadius[slotNum], 0, //mod_projSpeed[slotNum], 0, //mod_spreadShot[slotNum], 0, //mod_fastRateOfFire[slotNum], 0, //mod_piercing[slotNum], 0, //mod_invisProj[slotNum], 0, //mod_homing[slotNum], 0, //mod_homingRadius[slotNum], 0, //mod_homingCurve[slotNum], 0, //mod_recursiveShot[slotNum], 0, //mod_drag[slotNum], Rockettes_Duration, //mod_lifespan[slotNum], Direction, targetActor, 10 ); BlastroWeapon(Instigator.Weapon).bCanfire = false; if (Instigator.Controller.IsA('BlastroPlayerController')) { BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).rageInUse = true; drainRageRate = BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).maxRageValue / self.mod_lifespan * drainRageInterval; startDrainRage(); } for (i = 0; i < funnelNumber; i++) { SpawnedProjectile = Spawn(class 'BlastroProjectileRockettes',,, Instigator.Location); funnelDrones.AddItem( SpawnedProjectile ); SpawnedProjectile.InitHell( 9, //mod_projParticle[slotNum], 0, //mod_damage[slotNum], 0, //mod_damageRadius[slotNum], 0, //mod_projSpeed[slotNum], 0, //mod_spreadShot[slotNum], 0, //mod_fastRateOfFire[slotNum], 1000, //mod_piercing[slotNum], 0, //mod_invisProj[slotNum], 0, //mod_homing[slotNum], 0, //mod_homingRadius[slotNum], 0, //mod_homingCurve[slotNum], 0, //mod_recursiveShot[slotNum], 0, //mod_drag[slotNum], Rockettes_Duration, //mod_lifespan[slotNum], Direction, targetActor, 11+i ); SpawnedProjectile.timer += i / 10.0; SpawnedProjectile.bCollideWorld = false; } // Setup to intermittenly play firing sounds // //SetTimer( 0.5, true, 'PlayRocketteSound' ); } else { super.InitHell( tmod_projParticle, tmod_damage, tmod_damageRadius, tmod_projSpeed, tmod_spreadShot, tmod_fastRateOfFire, tmod_piercing, tmod_invisProj, tmod_homing, tmod_homingRadius, tmod_homingCurve, tmod_recursiveShot, tmod_drag, tmod_lifespan, Direction, targetActor, state_arg ); } } event Tick( float DeltaTime ) { local array< UTPawn > targetArr; local UTPawn Victims; local TraceHitInfo HitInfo; local Rotator r; local Vector axisX; local Vector axisY; local Vector axisZ; local BlastroProjectileGenerator SpawnedProjectile; timer += DeltaTime; if (stateParam > 10) { SetDrawScale( 3.0 ); // position itself r = Instigator.Rotation; r.Yaw += DegToUnrRot * ( (stateParam - 11) - ( funnelNumber - 1 ) * 0.5 ) * (angleDegree / funnelNumber); GetAxes( r, axisX, axisY, axisZ ); SetLocation( VInterpTo(self.Location, Instigator.Location + (Normal(axisX) * -distanceFromActor), DeltaTime, 3) ); SetRotation( RInterpTo(Rotation,Instigator.Rotation,DeltaTime,90000,true) ); // generator if (timer > 1.0/funnelRateOfFire) { PlayRocketteSound(); timer -= 1.0/funnelRateOfFire; // lock target foreach VisibleCollidingActors( class'UTPawn', Victims, funnelRadius, Location,,,,, HitInfo ) { if ( !Victims.bWorldGeometry && (Victims != Instigator) && (Victims.IsAliveAndWell()) && ( isNotSameTeam( Instigator, Victims ) ) ) { targetArr.AddItem(Victims); } } // pick random target SpawnedProjectile = Spawn(class 'BlastroProjectileRockettes',,, self.Location); SpawnedProjectile.InitHell( 12, //mod_projParticle[slotNum], funnelRocketDamage,//5, //mod_damage[slotNum], funnelRocketDamageRadius, //mod_damageRadius[slotNum], funnelRocketSpeed, //mod_projSpeed[slotNum], 0, //mod_spreadShot[slotNum], 0, //mod_fastRateOfFire[slotNum], 0, //mod_piercing[slotNum], 0, //mod_invisProj[slotNum], 1, //mod_homing[slotNum], 0, //mod_homingRadius[slotNum], funnelRocketHomingCurve, //mod_homingCurve[slotNum], 0, //mod_recursiveShot[slotNum], 0, //mod_drag[slotNum], funnelRocketDuration, //mod_lifespan[slotNum], Vector(self.Rotation), self, 0 ); if (targetArr.Length != 0) SpawnedProjectile.target = targetArr[Rand(targetArr.Length)]; } } super.Tick(DeltaTime); } simulated function Destroyed() { local BlastroProjectileGenerator curFunnelDrone; if (stateParam == 10) { foreach funnelDrones( curFunnelDrone ) { curFunnelDrone.Destroy(); } BlastroWeapon(Instigator.Weapon).bCanfire = true; if (Instigator.Controller.IsA('BlastroPlayerController')) { BlastroPlayerReplicationInfo(Instigator.PlayerReplicationInfo).rageInUse = false; stopDrainRage(); } } super.Destroyed(); } DefaultProperties { //bCollideWorld = false; timer = 0; MyDamageType = class 'BlastroDmgType_Rockettes' ///// Useful variable for Level Designer Rockettes_Duration = 4.0;//10.0; LaserTemplate = particlesystem'BB_WP_Lazer.Particles.laser_particle_01' // funnel variable funnelNumber = 5; // angleDegree = 150; // 150 = spread 150 degree behind player distanceFromActor = 150; // funnelRadius = 800; // funnelRateOfFire = 3.0; // // funnel rocket variable funnelRocketDamage = 4000;//5000//100; // funnelRocketDamageRadius = 100; // funnelRocketSpeed = 800; // funnelRocketHomingCurve = 15000; //66000 funnelRocketDuration = 1.1; // }