Ruined
New video for Ruined is coming!
Genre : 1st Person Shooter, Capture the flag
Engine : UDK
Role : Programmer
Responsible for :
- Implemented weapons’ mechanics and functionality
- Normal gun
- Bolter (for Soldier and Medic class)
- LazCannon (for Heavy class)
- Shotgun (for Scout class)
- Special abilities
- Shield
- Healing wave
- Blackhole
- Force push
- Normal gun
- Implemented class selection and inventory system
- Modified UDK AI’s behavior to interaction with game’s environment
Team size : 7
Code Sample
- ruined_script_pawn_base.uc
- ruined_script_pawn_scout.uc
- ruined_script_projectile_powerthrust.uc
- ruined_script_weapon_heat_beam.uc
- ruined_script_custom_statue.uc
class ruined_script_pawn_base extends UTPawn; var int RegenPerSec; var int Energy; var bool inControlVolume; var ruined_script_controlvolume cv; var float speedMod; var bool isInvis; // abilities variable var class forcePushParticle; var class healingWaveParticle; var class shieldParticle; var repnotify SkeletalMeshComponent shieldMesh; var bool isHealingActivated; var float healingWaveActivateCost; var float healingWaveDrainPerSec; // drain user's energy var float healingWave_lifeDrainDmg; var float healingWave_energyDrainDmg; var float healingWave_healDmg; var float healingWave_radius; var bool isShieldActivated; var float shieldActivateCost; var float shieldDrainPerSec; // drain user's energy var float shieldModifier; var float shieldRadius; var bool isUnderShield; ///// members for the custom mesh var SkeletalMesh defaultMesh; var MaterialInterface defaultMaterial0; var AnimTree defaultAnimTree; var array defaultAnimSet; var AnimNodeSequence defaultAnimSeq; var PhysicsAsset defaultPhysicsAsset; replication { if (bNetDirty) inControlVolume, isShieldActivated, isUnderShield, isHealingActivated, Energy, shieldMesh, RegenPerSec; } simulated function PostBeginPlay() { MovementSpeedModifier *= speedMod; super.PostBeginPlay(); `log("The shield mesh is:"@shieldMesh); // This timer is set for the player cheating health regeneration SetTimer( 0.5f, true, 'EnergyRegen'); } function AddDefaultInventory() { // BLANK FUNCTION - DO NOT DELETE // This function overrides the base function so NOTHING is added to the player's inventory by default } function EnergyRegen() { //if ( Controller.IsA( 'PlayerController' ) && !IsInPain() ) //{ // Health += RegenPerSec; //} local Actor pBase; local TraceHitInfo HitInfo; Energy = Min(Energy+RegenPerSec, 100); if ( Controller.IsA( 'ruined_script_controller_ai' ) ) { Energy = Energy+1000; } isUnderShield = false; foreach VisibleCollidingActors( class'Actor', pBase, shieldRadius, Location,,,,, HitInfo ) { if ( !pBase.bWorldGeometry && (pBase != self) && pBase.GetTeamNum() == GetTeamNum() ) { if (ruined_script_pawn_base(pBase).isShieldActivated) { isUnderShield = true; break; } } } //isInvis = !isInvis; //SetHidden(isInvis); SetHidden(isUnderShield); //`log("Energy: ", true,name); //`log(Energy, true,name); } ///// Abilities function forcePush() { local Actor Victims; local float DamageRadius; local Vector HurtOrigin; local TraceHitInfo HitInfo; local Vector dir; local float portion; local Projectile P; DamageRadius = 275; HurtOrigin = Location; foreach VisibleCollidingActors( class'Actor', Victims, DamageRadius, HurtOrigin,,,,, HitInfo ) { //if ( !Victims.bWorldGeometry && (Victims != self) && (Victims != IgnoredActor) && (Victims.bCanBeDamaged || Victims.bProjTarget) ) if ( !Victims.bWorldGeometry && (Victims != self) && (Victims != Instigator) ) { //`log("actor", true, name); //`log(Victims.ObjectArchetype.Name, true, name); // force push Victims.TakeRadiusDamage(Instigator.Controller, 0, 1500.0f, class 'UTDmgType_LinkPlasma', 200000.0f, HurtOrigin, true, self); } } ForEach AllActors(class'Projectile', P) { if (P.ObjectArchetype.Class != class'ruined_script_projectile_powerthrust') { //`log("actor", true, name); //`log(P.ObjectArchetype.Name, true, name); dir = P.Location - HurtOrigin; portion = VSize(dir) / 1500.0f; if (portion < 1.0f) { P.Velocity = P.Velocity + dir * portion * (10.0f*VSize(P.Velocity)); } } } Spawn(forcePushParticle,,,Location); } function healingWaveTimer() { isHealingActivated = !isHealingActivated; if (isHealingActivated) { if (Energy < healingWaveActivateCost) { isHealingActivated = false; } else { Energy -= healingWaveActivateCost; SetTimer(0.5f, true, 'healingWave'); } } else { SetTimer(0.0f, true, 'healingWave'); } } function healingWave() { //Spawn(healingWaveParticle,,,Location); //Health = Health + RegenPerSec; //return; local Actor Victims; local float DamageRadius; local Vector HurtOrigin; local TraceHitInfo HitInfo; local Vector zeroVec; if (Energy < healingWaveDrainPerSec) { isHealingActivated = false; SetTimer(0.0f, true, 'healingWave'); return; } else { Energy -= healingWaveDrainPerSec; } DamageRadius = healingWave_radius; HurtOrigin = Location; foreach VisibleCollidingActors( class'Actor', Victims, DamageRadius, HurtOrigin,,,,, HitInfo ) { //if ( !Victims.bWorldGeometry && (Victims != self) && (Victims != IgnoredActor) && (Victims.bCanBeDamaged || Victims.bProjTarget) ) if ( !Victims.bWorldGeometry && (Victims != self) && (Victims != Instigator) ) { //`log("actor", true, name); //`log(Victims.ObjectArchetype.Name, true, name); // force push if (Victims.GetTeamNum() == GetTeamNum()) { // on same team, heal Victims.HealDamage(healingWave_healDmg, Controller, class 'UTDmgType_LinkPlasma'); } else { // other team, drain Victims.TakeDamage(healingWave_lifeDrainDmg, Controller, Victims.Location, zeroVec, class 'UTDmgType_LinkPlasma', HitInfo, self); //ruined_script_pawn_base(Victims).Energy -= healingWave_energyDrainDmg; ruined_script_pawn_base(Victims).UseEnergy( healingWave_energyDrainDmg ); //`log(Victims.GetHumanReadableName, true,name); //`log("DRAIN : Health/MP", true,name); //`log(ruined_script_pawn_base(Victims).Health, true,name); //`log(ruined_script_pawn_base(Victims).Energy, true,name); } //Victims.TakeRadiusDamage(Instigator.Controller, 0, 1500.0f, class 'UTDmgType_LinkPlasma', 200000.0f, HurtOrigin, true, self); } } self.HealDamage(healingWave_healDmg, Controller, class 'UTDmgType_LinkPlasma'); Spawn(healingWaveParticle,,,Location); } event UseEnergy(float amount) { Energy -= amount; if (Energy < 0) { Energy = 0; } } simulated function ShieldTimer() { isShieldActivated = !isShieldActivated; if (isShieldActivated) { if (Energy < shieldActivateCost) { isShieldActivated = false; //DetachComponent(shieldMesh); } else { `log("Activating shield:"@shieldMesh); Energy -= shieldActivateCost; SetTimer(0.5f, true, 'shield'); //Spawn(shieldParticle,,,Location); //AttachComponent(shieldMesh); } } else { SetTimer(0.0f, true, 'shield'); //DetachComponent(shieldMesh); } } simulated function shield() { if (Energy < shieldDrainPerSec) { isShieldActivated = false; SetTimer(0.0f, true, 'shield'); //DetachComponent(shieldMesh); return; } else { Energy -= shieldDrainPerSec; } Spawn(shieldParticle,,,Location); } event TakeDamage(int Damage, Controller EventInstigator, vector HitLocation, vector Momentum, class DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser) { local float tmpDmg; tmpDmg = Damage; if (isShieldActivated) { tmpDmg *= shieldModifier; if (EventInstigator != self.Controller) EventInstigator.Pawn.TakeDamage(tmpDmg, EventInstigator, HitLocation, Momentum, DamageType, HitInfo, EventInstigator.Pawn); } else { if (isUnderShield) { tmpDmg *= shieldModifier; } Super.TakeDamage(tmpDmg, EventInstigator, HitLocation, Momentum, DamageType, HitInfo, DamageCauser); } } ///// end of Abilities function bool Died(Controller Killer, class damageType, vector HitLocation) { if ( inControlVolume ) { cv.RemovePlayer(self); cv.RemovePlayer(self); inControlVolume = false; } return super.Died(Killer, damageType, HitLocation); } function bool hasEnergy(int requiredEnergy) { return (Energy >= requiredEnergy); } function Inventory getHeatBeam() { local ruined_script_weapon_heat_beam weap; foreach InvManager.InventoryActors(class'ruined_script_weapon_heat_beam', weap) { return weap; } return None; } //simulated function SetCharacterClassFromInfo(class Info) //{ // super.SetCharacterClassFromInfo(Info); // Mesh.SetSkeletalMesh(defaultMesh); // Mesh.SetMaterial(0,defaultMaterial0); // Mesh.SetPhysicsAsset(defaultPhysicsAsset); // Mesh.AnimSets=defaultAnimSet; // Mesh.SetAnimTreeTemplate(defaultAnimTree); //} DefaultProperties { HealthMax = 300; RegenPerSec = 1.0f; Health = 175; Energy = 100; speedMod = 1.0f; isInvis = false; // abilities variable isHealingActivated = false; healingWaveActivateCost = 25.0f; healingWaveDrainPerSec = 5.0f; healingWave_lifeDrainDmg = 25; healingWave_healDmg = 25; healingWave_energyDrainDmg = 25; healingWave_radius = 300; isShieldActivated = false; shieldActivateCost = 25.0f; shieldDrainPerSec = 5.0f; shieldModifier = 0.5f; shieldRadius = 300; isUnderShield = false; ///// particle effect //healingWaveParticle = class'UTEmit_ShockCombo' forcePushParticle = class'ruined_script_emit_forcepush' healingWaveParticle = class'ruined_script_emit_healingwave' shieldParticle = class'ruined_script_emit_shield' ///// mesh and animation //defaultMesh=SkeletalMesh'Ruined_character.static_mesh.Ruined_character' //defaultMesh=SkeletalMesh'CH_LIAM_Cathode.Mesh.SK_CH_LIAM_Cathode' //defaultMesh=SkeletalMesh'CH_Gibs.Mesh.SK_CH_Gibs_Corrupt_Part04' //defaultMesh=SkeletalMesh'CH_IronGuard_Male.Mesh.SK_CH_IronGuard_MaleA' //defaultAnimTree=AnimTree'CH_AnimHuman_Tree.AT_CH_Human' //defaultAnimSet(0)=AnimSet'CH_AnimHuman.Anims.K_AnimHuman_BaseMale' //defaultPhysicsAsset=PhysicsAsset'CH_AnimCorrupt.Mesh.SK_CH_Corrupt_Male_Physics' //Begin Object Name=WPawnSkeletalMeshComponent // AnimTreeTemplate=AnimTree'CH_AnimHuman_Tree.AT_CH_Human' //End Object Begin Object class=SkeletalMeshComponent Name=sMesh SkeletalMesh=SkeletalMesh'Ruined_Bolter.Mesh.force_field' Scale=3.0 End Object shieldMesh = sMesh; //Components.Add(sMesh) }
class ruined_script_pawn_scout extends ruined_script_pawn_base; simulated function PostBeginPlay() { local ruined_script_weapon_shotgun weap; weap = Spawn( class 'ruined_script_weapon_shotgun', self, , , , , ); super.PostBeginPlay(); if ( weap != None ) { InvManager.AddInventory( weap, false ); } } simulated function SetCharacterClassFromInfo(class Info) { local class tmp; tmp = class 'ruined_script_utfamilyinfo_scout'; super.SetCharacterClassFromInfo(tmp); } DefaultProperties { Health = 75; HealthMax = 125; speedMod = 1.75f }
class ruined_script_projectile_powerthrust extends UTProj_LinkPlasma; var class ComboExplosionEffect; function Init(vector Direction) { super.Init(Direction); Spawn(class'ruined_script_emit_forcepush',,,Location); } simulated function Tick(float deltaTime) { local Actor Victims; local float DamageRadius1; local Vector HurtOrigin; local TraceHitInfo HitInfo; local Vector dir; local float portion; local Projectile P; DamageRadius1 = 275; HurtOrigin = Location; foreach VisibleCollidingActors( class'Actor', Victims, DamageRadius1, HurtOrigin,,,,, HitInfo ) { //if ( !Victims.bWorldGeometry && (Victims != self) && (Victims != IgnoredActor) && (Victims.bCanBeDamaged || Victims.bProjTarget) ) if ( !Victims.bWorldGeometry && (Victims != self) && (Victims != Instigator) ) { //`log("actor", true, name); //`log(Victims.ObjectArchetype.Name, true, name); // force push Victims.TakeRadiusDamage(Instigator.Controller, 0, 1500.0f, class 'UTDmgType_LinkPlasma', 200000.0f, HurtOrigin, true, self); } } ForEach AllActors(class'Projectile', P) { if (P.ObjectArchetype.Class != class'ruined_script_projectile_powerthrust') { //`log("actor", true, name); //`log(P.ObjectArchetype.Name, true, name); dir = P.Location - HurtOrigin; portion = VSize(dir) / 1500.0f; if (portion < 1.0f) { P.Velocity = P.Velocity + dir * portion * (10.0f*VSize(P.Velocity)); } } } super.Tick(deltaTime); } DefaultProperties { ComboExplosionEffect=class'ruined_script_emit_forcepush'; //ProjFlightTemplate=ParticleSystem'Ruined_Shotgun.Particles.Ruined_Shotgun_ForcePush' //ProjExplosionTemplate=ParticleSystem'Ruined_Shotgun.Particles.Ruined_Shotgun_ForcePush' ProjFlightTemplate=none; ProjExplosionTemplate=none; ExplosionSound=SoundCue'Ruined_Sounds.Cues.Ability_Proj' //ProjectileLightClass=class'UTGame.UTShockBallLight' LifeSpan=1.0 Speed=1000 MaxSpeed=2000 AccelRate=0.0 //HurtRadius(Damage, DamageRadius, MyDamageType, MomentumTransfer, AltOrigin); }
class ruined_script_weapon_heat_beam extends UTWeap_LinkGun; var class vehicleDmgType; var() Array EnergyConsume; var bool canFire; replication { if ( bNetDirty ) vehicleDmgType; } /** * Called on the LocalPlayer, Fire sends the shoot request to the server (ServerStartFire) * and them simulates the firing effects locally. * Call path: PlayerController::StartFire -> Pawn::StartFire -> InventoryManager::StartFire * Network: LocalPlayer */ simulated function StartFire(byte FireModeNum) { if ( FireModeNum == 1 ) FireModeNum = 0; else FireModeNum = 1; if ( FireModeNum == 1 ) { if( Instigator == None || !Instigator.bNoWeaponFiring ) { if( Role < Role_Authority ) { // if we're a client, synchronize server ServerStartFire(FireModeNum); } // Start fire locally BeginFire(FireModeNum); } } } /** * This initiates the shutdown of a weapon that is firing. * Network: Local Player */ simulated function StopFire(byte FireModeNum) { if ( FireModeNum == 1 ) FireModeNum = 0; else FireModeNum = 1; // Locally shut down the fire sequence EndFire(FireModeNum); // Notify the server if( Role < Role_Authority ) { ServerStopFire(FireModeNum); } } simulated function FireAmmunition() { local ruined_script_pawn_base holder; holder = ruined_script_pawn_base(Instigator); if (holder.hasEnergy(EnergyConsume[CurrentFireMode])) { holder.Energy -= EnergyConsume[CurrentFireMode]; super.FireAmmunition(); } } simulated function Tick(float DeltaTime) { if ( Instigator != none ) { AmmoCount = ruined_script_pawn_base(Instigator).Energy; } super.Tick(DeltaTime); } function ConsumeBeamAmmo(float Amount) { AmmoCount = ruined_script_pawn_base(Instigator).Energy; super.ConsumeBeamAmmo(Amount); ruined_script_pawn_base(Instigator).Energy = AmmoCount; } simulated function ProcessBeamHit(Vector StartTrace, Vector AimDir, out ImpactInfo TestImpact, float DeltaTime) { local float DamageAmount; local vector PushForce, ShotDir, SideDir; //, HitLocation, HitNormal, AttachDir; local UTPawn UTP; if (canFire && ruined_script_pawn_base(Instigator).hasEnergy(1)) { super.ProcessBeamHit( StartTrace, AimDir, TestImpact, DeltaTime ); // compute damage amount CalcLinkStrength(); DamageAmount = InstantHitDamage[1]; UTP = UTPawn(Instigator); if ( UTP != None ) { DamageAmount = DamageAmount/UTP.FireRateMultiplier; } if ( LinkStrength > 1 ) { DamageAmount *= FClamp(0.75*LinkStrength, 1.5, 2.0); } SavedDamage += DamageAmount * DeltaTime; DamageAmount = int(SavedDamage); SavedAmmoUse += BeamAmmoUsePerSecond * DeltaTime; if (Victim.ObjectArchetype.IsA( 'ruined_script_custom_statue' )) { ConsumeBeamAmmo(SavedAmmoUse);ShotDir = Normal(TestImpact.HitLocation - Location); SideDir = Normal(ShotDir Cross vect(0,0,1)); PushForce = vect(0,0,1) + Normal(SideDir * (SideDir dot (TestImpact.HitLocation - Victim.Location))); PushForce *= (Victim.Physics == PHYS_Walking) ? 0.1*MomentumTransfer : DeltaTime*MomentumTransfer; //`log("Yeah", true, name); ruined_script_custom_statue(Victim).TakeDamage(DamageAmount, Instigator.Controller, TestImpact.HitLocation, PushForce, vehicleDmgType, TestImpact.HitInfo, self); } } else { StopFire(CurrentFireMode); } } DefaultProperties { WeaponRange = 32768.0f; // extended the range of the weapon WeaponLinkDistance = 32768.0f; BeamAmmoUsePerSecond = 5.0f; // disable the ammo to be consume over time canFire = true; EnergyConsume[0] = 0.0f; EnergyConsume[1] = 0.0f; ShotCost(0) = 0; ShotCost(1) = 0; //vehicleDmgType=class'UTDmgType_VehicleExplosion'; //InstantHitDamageTypes(1)=class'UTDmgType_VehicleExplosion'; //vehicleDmgType = class 'UTDmgType_VehicleExplosion'; vehicleDmgType = class'UTDmgType_ScorpionSelfDestruct'; ///// visual properties Begin Object Name=FirstPersonMesh SkeletalMesh=SkeletalMesh'Ruined_Heatgun.Mesh.Ruined_Heatgun' AnimSets(0)=AnimSet'Ruined_Heatgun.Mesh.Ruined_Heatgun_Anim' Materials(0)=Material'Ruined_Heatgun.Materials.Ruined_HeatGun_Mat' Translation=(X=10,Y=30,Z=-3) Rotation=(Yaw=0) Animations=MeshSequenceA Scale=1.2 FOV=60 End Object Begin Object Name=PickupMesh SkeletalMesh=SkeletalMesh'Ruined_Heatgun.Mesh.Ruined_Heatgun' End Object AttachmentClass=class'ruined_script_attachment_heat_beam' WeaponEquipSnd=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_RaiseCue' WeaponPutDownSnd=SoundCue'A_Weapon_Link.Cue.A_Weapon_Link_LowerCue' WeaponFireSnd(0)=SoundCue'Ruined_Sounds.Cues.BoltCue' WeaponFireSnd(1)=SoundCue'Ruined_Sounds.Cues.HeatBeamCue' // Try making sure that no one else can pick-up this weapon // bCanThrow = false; }
class ruined_script_custom_statue extends FracturedStaticMeshActor; var bool isHit; var bool isExplode; var(Statue) int InitStatueHealth; var(Statue) bool isRed; var int statueHealth; replication { if (bNetDirty) statueHealth, isRed, isExplode, InitStatueHealth; } client reliable function TriggerExplosion() { Explode(); isExplode = true; } simulated function PostBeginPlay() { super.PostBeginPlay(); statueHealth = InitStatueHealth; } simulated event TakeDamage(int Damage, Controller EventInstigator, vector HitLocation, vector Momentum, class DmgType, optional TraceHitInfo HitInfo, optional Actor DamageCauser) { local int i; local bool isHurt; isHurt = false; if(FracturedByDamageType.length == 0) { isHurt = TRUE; } else { for(i=0; i { if(DmgType == FracturedByDamageType[i] && (( isRed && EventInstigator.GetTeamNum() == 1 ) || ( !isRed && EventInstigator.GetTeamNum() == 0 ))) { isHurt = TRUE; } } } if ( Role == ROLE_Authority && isHurt ) { statueHealth -= Damage; } if (statueHealth { statueHealth = 0; if ( isRed ) { TriggerGlobalEventClass(class'ruined_script_red_statue_destroyed', self); } else { TriggerGlobalEventClass(class'ruined_script_blue_statue_destroyed', self); } TriggerExplosion(); } } DefaultProperties { FracturedByDamageType.Add(UTDmgType_VehicleExplosion); InitStatueHealth = 500; isHit = false; isRed = false; isExplode = false; //bDelayedStart = false; RemoteRole = ROLE_SimulatedProxy; bAlwaysRelevant = true; }