Legacy:Mod Ideas/Killstick - Unreal Wiki

# Legacy:Mod Ideas/Killstick

### From Unreal Wiki, The Unreal Engine Documentation Site

< Legacy:Mod Ideas

### NOTE:

Currently in the process of a complete recode, will post once complete

## Description

The Killstick is based off of a weapon used in the online comic Megatokyo.

## How it works

Here's the basics: this weapon works much like the normal sniper rifle. however, when this weapon is fully charged, it consumes all ammo to create a huge explosion, simmilar to the ion cannnon. To charge the weapon you hold the trigger, pull trigger normally for normal shots

## Unreal Script Code

I already have the majority of the code for this down.

### General Description

This weapons combines code from at least 4 different weapons in UT2003: the zoom super shock rifle, the sniper rifle, the shield gun (charging), and the redeemer/ion cannon. I started by extending my main weapon class from zoom super shock rifle so the gun could zoom, this also allowed me to use the shock rifle beam code for the fire effect. I then started working on adding the charge function by looking at the code for the shield gun and grabbing bits of what i needed. I attempted to use the code from the shield gun for the charge effect, but things got weird (see code once it's up). I then looked at the sniper rilfe code and found what lines enabled headshots and copied those. Finally, i found the Mod_Ideas/NukeRifles here and liked how he did the spawning of a dummy projectile to get the redeemer explosion, and i did the same.

### Killstick.uc

    //Created by Syntax_Error
    class Killstick extends ZoomSuperShockRifle
    config(user); //So weapon preference settings are stored alongside all the standard weapons.

    simulated function float ChargeBar()  //this sets what the charge bar measures
    {
            return FMin(1,FireMode[0].HoldTime/KillstickFire(FireMode[0]).MaxHoldTime);
    }
    defaultproperties
    {
        ItemName="Killstick" //The text you see when you switch to the weapon and in various other places.
        IconMaterial=Material'InterfaceContent.Hud.SkinA' //Texture where the icon to be show in the weapon bar is.
        IconCoords=(X1=322,Y1=372,X2=444,Y2=462) //Position of icon in that texture.

        //vars for zoom reticle
        innerArrowsX=42.000000
        innerArrowsY=42.000000
        ArrowColor=(R=255,A=255)
        TargetColor=(B=255,G=255,R=255,A=255)
        NoTargetColor=(B=200,G=200,R=200,A=255)
        FocusColor=(B=126,G=90,R=71,A=215)
        ChargeColor=(B=255,G=255,R=255,A=255)
        RechargeOrigin=(X=600.000000,Y=330.000000)
        RechargeSize=(X=10.000000,Y=-180.000000)

        bShowChargingBar=True //shows charge bar
        FireModeClass(0)=KillstickFire
        FireModeClass(1)=KillstickZoom
        DrawScale=0.4
        Mesh=mesh'mtWeapon.killstick' //What you see in 1st person.
        BobDamping=2.3 //How much the weapon moves about as you walk.

        PickupClass=class'KillstickPickup'
        EffectOffset=(X=100,Y=10,Z=7.5) //Where effects are drawn. Used for start location of InstantFire beam effects.

        //animations
        SelectAnim="Select"
        PutDownAnim="PutDown"
        DisplayFOV=60

        PlayerViewOffset=(X=-3,Y=6,Z=-3) //Position of the weapon in 1st person
        PlayerViewPivot=(Pitch=0,Roll=0,Yaw=0) //Rotation of the model in 1st person.
        UV2Texture=Material'XGameShaders.WeaponEnvShader' //What does this do?

        AttachmentClass=class'KillstickAttachment'//third person mesh

        SelectSound=Sound'WeaponSounds.LinkGun.SwitchToLinkGun'
        SelectForce="SwitchToLightningGun" //The various 'Force' variables are for force feedback mice etc.

        AIRating=0.69 //How much bots want to use this weapon.
        CurrentRating=0.69

        //priority of weapon
        Priority=13
        DefaultPriority=13

        InventoryGroup=9 //Which slot the weapon occupies.
        GroupOffset=4 //This must be different to all other weapons that occupy the same InventoryGroup.
    }

### KillstickFire.uc

    //Created by Syntax_Error
    //::TODO:: bigger beam on charged shot, adjust damage on charged shot
    //:::::::: no double charge/flash effects

    class KillstickFire extends ShockBeamFire;

    var sound ChargeSound;
    var Emitter ChargeEmitter;

    /********this is the code i used for the charge effect*********
    simulated function DestroyEffects() //destorys effects
    {
        if (chargingemitter != None)
        {
            chargingemitter.Destroy();
        }
            Super.DestroyEffects();
    }

    simulated function InitEffects() //initalises effects
    {
            if ( Level.NetMode != NM_DedicatedServer )
            {
                    ChargingEmitter= Spawn(class'KillstickChargeEffect');
                    //chargingemitter.mRegenPause = true; //::part of xEffects::
            }
        Super.InitEffects();
    }

    function DrawMuzzleFlash(Canvas Canvas) //draws and places charge effect
    {

        if (ChargeEmitter != None && HoldTime > 0.0 && !bNowWaiting)
        {
                    ChargeEmitter.SetLocation( Weapon.GetEffectStart() );
            Canvas.DrawActor( ChargeEmitter, false, false, Weapon.DisplayFOV );
        }

        if (FlashEmitter != None)
        {
            FlashEmitter.SetLocation( Weapon.GetEffectStart() );
            if ( Weapon.WeaponCentered() )
                            FlashEmitter.SetRotation(Weapon.Instigator.GetViewRotation());
            else
                            FlashEmitter.SetRotation(Weapon.Rotation);
            Canvas.DrawActor( FlashEmitter, false, false, Weapon.DisplayFOV );
        }

        if ( (Instigator.AmbientSound == ChargeSound)
                    && ((HoldTime <= 0.0) || bNowWaiting) )
            Instigator.AmbientSound = None;

    }
    ********************************************************************/
    function PlayPreFire() //this execs when the trigger is pulled
    {
        Weapon.LoopAnim('Charge', 1, 0); //loop charging animation until trigger is released
        weapon.PlayOwnedSound(ChargeSound, SLOT_Interact, TransientSoundVolume,,,, false); //plays charging sound
    }

    function DoFireEffect()
    {
        local Vector StartTrace;
        local Rotator R, Aim;

        Instigator.MakeNoise(1.0);

        // the to-hit trace always starts right in front of the eye
        StartTrace = Instigator.Location + Instigator.EyePosition();
        Aim = AdjustAim(StartTrace, AimError);
            R = rotator(vector(Aim) + VRand()*FRand()*Spread);
        DoTrace(StartTrace, R);
    }

    function DoTrace(Vector Start, Rotator Dir)
    {
            local Vector X;

            X = vector(Dir);

            TracePart(Start,Start+X*TraceRange,X,Dir,Instigator);
    }

    function bool AllowMultiHit()
    {
            return false;
    }

    function TracePart(Vector Start, Vector End, Vector X, Rotator Dir, Pawn Ignored)
    {
        local Vector HitLocation, HitNormal;
        local Actor Other;
        local float dist;

        Other = Ignored.Trace(HitLocation, HitNormal, End, Start, true);

        if ( (Other != None) && (Other != Ignored) )
        {
            if ( !Other.bWorldGeometry )
            {
                Other.TakeDamage(DamageMax, Instigator, HitLocation, Momentum*X, DamageType);
                HitNormal = Vect(0,0,0);
                if ( (Pawn(Other) != None) && (HitLocation != Start) && AllowMultiHit() )
                                    TracePart(HitLocation,End,X,Dir,Pawn(Other));
            }
        }
        else
        {
            HitLocation = End;
            HitNormal = Vect(0,0,0);
        }
        SpawnBeamEffect(Start, Dir, HitLocation, HitNormal, 0);
            //headshot check and damage def
        if(Other.GetClosestBone( HitLocation, X, dist, 'head', 8 ) == 'head')
            Other.TakeDamage(70 * 2, Instigator, HitLocation, Momentum*X, Class'DamTypeKillstickHeadShot');

        if( Instigator.bDeleteMe != true )
        {
            if(HoldTime>=2.4)           //spawn the dummy if weapon is fully charged
            {
               Spawn(class'KillstickDummy',Instigator,, HitLocation - (100*Normal(HitLocation - Start)) , Dir);
               Weapon.Ammo[0].UseAmmo(50,true); //consumes all ammo if fully charged
            }
        }
    }

    function SpawnBeamEffect(Vector Start, Rotator Dir, Vector HitLocation, Vector HitNormal, int ReflectNum)
    {
        local ShockBeamEffect Beam;

        if ( (Instigator.PlayerReplicationInfo.Team != None) && (Instigator.PlayerReplicationInfo.Team.TeamIndex == 1) )
                    Beam = Spawn(BeamEffectClass,,, Start, Dir);
            else
                    Beam = Spawn(BeamEffectClass,,, Start, Dir);
        if (ReflectNum != 0) Beam.Instigator = None; // prevents client side repositioning of beam start
        Beam.AimAt(HitLocation, HitNormal);

    }

    function PlayFiring()  //this execs when trigger is released
    {
        //DestroyEffects(); //destroy charging effect
        Super.PlayFiring();
    }

    defaultproperties
    {

        BeamEffectClass=Class'KillstickFireEffect'
        //FireSound=Sound'WeaponSounds.TAGRifle.IonCannonBlast'
        ChargeSound=Sound'WeaponSounds.TAGRifle.TAGFireB'
        FireForce="LightningGunFire"
        PreFireAnim="charge"
        bFireOnRelease=True  //don't fire untill trigger is released
        MaxHoldTime=2.5 // how long trigger must be held to fully charge

        TraceRange=17000 //Maximum range of the weapon.
        Momentum=1000 //How much the victim is pushed when hit.
        AmmoClass=class'KillstickAmmo' //ammo class call
        AmmoPerFire=1 //how much ammo used per shot
        DamageType=class'DamTypeKillstick' //damage type class call
        DamageMin=70 //same damage as sniper rifle
        DamageMax=70

        FireRate=1.800000//How fast it fires. same rate as sniper rifle
        BotRefireRate=1.8 //How fast bots should try to fire.
        AimError=800 //How accurate bots are.
        bPawnRapidFireAnim=false

        //These settings controll how your view shakes when you fire.
        ShakeOffsetMag=(X=-15.0,Y=0.0,Z=10.0)
        ShakeOffsetRate=(X=-4000.0,Y=0.0,Z=4000.0)
        ShakeOffsetTime=1.6
        ShakeRotMag=(X=0.0,Y=0.0,Z=0.0)
        ShakeRotRate=(X=0.0,Y=0.0,Z=0.0)
        ShakeRotTime=2

        FlashEmitterClass=Class'KillstickFlash1st' //mussle flash effect

    }

### KillstickDummy.uc

    //Created by Syntax_Error
    //dummy projectile class for spawning the explosion
    //borrowed lotsa code from the redemmer
    class KillstickDummy extends Projectile;

    var    RedeemerTrail SmokeTrail;

    // camera shakes //
    var() vector ShakeRotMag;           // how far to rot view
    var() vector ShakeRotRate;          // how fast to rot view
    var() float  ShakeRotTime;          // how much time to rot the instigator's view
    var() vector ShakeOffsetMag;        // max view offset vertically
    var() vector ShakeOffsetRate;       // how fast to offset view vertically
    var() float  ShakeOffsetTime;       // how much time to offset view
    var bool bExploded;

    auto state InstantBoom //go immediatly to explosion state
    {
    Begin:
            BlowUp(Location);
    }

    /**************commented out, not used****************
    simulated function Destroyed()
    {
            if ( SmokeTrail != None )
                    SmokeTrail.Destroy();
            Super.Destroyed();
    }

    simulated function PostBeginPlay()
    {
            local vector Dir;

            if ( bDeleteMe || IsInState('Dying') )
                    return;

            Dir = vector(Rotation);
            Velocity = speed * Dir;

            if ( Level.NetMode != NM_DedicatedServer)
            {
                    SmokeTrail = Spawn(class'RedeemerTrail',self,,Location - 40 * Dir);
                    SmokeTrail.SetBase(self);
            }
    }

    event bool EncroachingOn( actor Other )
    {
            if ( Other.bWorldGeometry )
                    return true;

            return false;
    }
    **************************************************/

    simulated function ProcessTouch (Actor Other, Vector HitLocation)
    {
            if ( Other != instigator )
                    Explode(HitLocation,Vect(0,0,1));
    }

    simulated function Explode(vector HitLocation, vector HitNormal)
    {
            BlowUp(HitLocation);
    }

    simulated function PhysicsVolumeChange( PhysicsVolume Volume )
    {
    }

    simulated function Landed( vector HitNormal )
    {
            BlowUp(Location);
    }

    simulated function HitWall(vector HitNormal, actor Wall)
    {
            BlowUp(Location);
    }

    function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation,
                                                            Vector momentum, class<DamageType> damageType)
    {
            if ( Damage > 0 )
            {
                    if ( InstigatedBy == None )
                            BlowUp(Location);
                    else
                    {
                            Spawn(class'SmallRedeemerExplosion');
                        SetCollision(false,false,false);
                        HurtRadius(Damage, DamageRadius*0.125, MyDamageType, MomentumTransfer, Location);
                        Destroy();
                    }
            }
    }

    simulated event FellOutOfWorld(eKillZType KillType)
    {
            BlowUp(Location);
    }

    function BlowUp(vector HitLocation)
    {
        Spawn(class'NewIonEffect',,, HitLocation - 100 * Normal(Velocity), Rot(0,16384,0));
            MakeNoise(1.0);
            SetPhysics(PHYS_None);
            bHidden = true;
        GotoState('Dying');
    }

    state Dying
    {
            function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation,
                                                            Vector momentum, class<DamageType> damageType) {}

        function BeginState()
        {
                    bHidden = true;
                    SetPhysics(PHYS_None);
                    SetCollision(false,false,false);
                    if ( !bExploded )
                    {
                            Spawn(class'IonCore',,, Location, Rotation);
                            ShakeView();
                    }
                    InitialState = 'Dying';
                    if ( SmokeTrail != None )
                            SmokeTrail.Destroy();
        }

        function ShakeView()
        {
            local Controller C;
            local PlayerController PC;
            local float Dist, Scale;

            for ( C=Level.ControllerList; C!=None; C=C.NextController )
            {
                PC = PlayerController(C);
                if ( PC != None && PC.ViewTarget != None )
                {
                    Dist = VSize(Location - PC.ViewTarget.Location);
                    if ( Dist < DamageRadius * 2.0)
                    {
                        if (Dist < DamageRadius)
                            Scale = 1.0;
                        else
                            Scale = (DamageRadius*2.0 - Dist) / (DamageRadius);
                        C.ShakeView(ShakeRotMag*Scale, ShakeRotRate, ShakeRotTime, ShakeOffsetMag*Scale, ShakeOffsetRate, ShakeOffsetTime);
                    }
                }
            }
        }

    Begin:
        PlaySound(sound'WeaponSounds.TAGRifle.IonCannonBlast');
        HurtRadius(Damage, DamageRadius*0.125, MyDamageType, MomentumTransfer, Location);
        Sleep(0.5);
        HurtRadius(Damage, DamageRadius*0.300, MyDamageType, MomentumTransfer, Location);
        Sleep(0.2);
        HurtRadius(Damage, DamageRadius*0.475, MyDamageType, MomentumTransfer, Location);
        Sleep(0.2);
        HurtRadius(Damage, DamageRadius*0.650, MyDamageType, MomentumTransfer, Location);
        Sleep(0.2);
        HurtRadius(Damage, DamageRadius*0.825, MyDamageType, MomentumTransfer, Location);
        Sleep(0.2);
        HurtRadius(Damage, DamageRadius*1.000, MyDamageType, MomentumTransfer, Location);
        Destroy();
    }

    defaultproperties
    {
         ShakeRotMag=(Z=250.000000)
         ShakeRotRate=(Z=2500.000000)
         ShakeRotTime=6.000000
         ShakeOffsetMag=(Z=10.000000)
         ShakeOffsetRate=(Z=200.000000)
         ShakeOffsetTime=10.000000
         Speed=1000.000000
         MaxSpeed=1000.000000
         Damage=250.000000
         DamageRadius=1500.000000
         MomentumTransfer=200000.000000
         MyDamageType=Class'DamTypeKillstick'
         LightType=LT_Steady
         LightEffect=LE_QuadraticNonIncidence
         LightBrightness=255.000000
         LightRadius=6.000000
         LightHue=28
         //DrawType=DT_StaticMesh  //removed mesh
         //StaticMesh=StaticMesh'WeaponStaticMesh.RedeemerMissile'
         bDynamicLight=True
         bNetTemporary=False
         //AmbientSound=Sound'WeaponSounds.Misc.redeemer_flight'
         DrawScale=0.500000
         AmbientGlow=96
         bUnlit=False
         SoundRadius=100.000000
         SoundVolume=255
         TransientSoundVolume=1.000000
         TransientSoundRadius=5000.000000
         CollisionRadius=24.000000
         CollisionHeight=12.000000
         bProjTarget=True
         bFixedRotationDir=True
         RotationRate=(Roll=50000)
         DesiredRotation=(Roll=30000)
         ForceType=FT_DragAlong
         ForceRadius=100.000000
         ForceScale=5.000000
    }

## TODO

-charging effect either will not display or will spawn in the wrong location until weapon is charged <– Experiment with PlayerOffset and SmallWeaponOffset to align the effect up with the weapon

-damage adjustment for ammo on charged shot not yet implimented-

-larger beam for charged shot (is this possible?) –done, spawning larger beam now and in the right direction :D

-texturing on all meshes –started texturing, going inda slow for now

Syntax_Error

http://www.devildogsoft.com

## Discussion

EntropicLqd: Sounds very similar to Mod Ideas/Charging Shock Rifle

Syntax_Error: It is, except it doesn't auto charge, you must hold the trigger to charge, much like the shield gun

lemme restate the charge effect problem: when the effect initializes, it auto spawns on the weapon base, and only attaches to the weapon when it is charged... weird huh O_o

still have not had a chance to get to my own computer yet >_< it'll put the code up as soon as i get a chance

Syntax_Error: Yeay, code is up, this isnt everything, but it's a start. I'll put up individual pages as soon as i can.

Syntax_Error: Sorry for the long time away, doing taxes isnt much fun. looking for the Special DVD ed. of 2004 now, and will transfer all MOD stuff to it.

Syntax_Error: Holy #$&^ it has been a long time since i update here. Major changes to code, and most of the problems have been fixed. only annoying one left is the whole double charge/mussleflash effect (i'll get a screen up to show you) planning on putting in reload so if u have 50 ammo you can fire multiple large blasts (just not quickly ;)) also starting up the dual shotgun weapon, suggestions for alt-fire are welcome.

Foxpaw: For a shotgun weapon, there's a couple of things that come to mind for a secondary fire. Basically, shotguns are neat because there is a variety of ammunition available for them. Their lack of rifling allows for much more flexible ammunition. Anyways, although it wouldn't be entirely realistic, you could have primary fire be one type of ammo, while secondary fire was the other. For instance, one could be slugs and the other buckshot. Or one could fire "less lethal" beanbag rounds that would slow down or otherwise hinder your opponent to set up for another (more lethal) shot. Flares would be somewhat less useful. Flechette rounds are available, but would behave similar to buckshot in-game (only better!) Incendiary rounds are available, though I'm not really sure what they're for. I think smaller slug-bearing sabots may also be available.

Also you could have one fire be semi-auto and the other pump-action. Select fire shotguns have more power in pump-action mode because in semi-auto mode a significant amount of the expanding powder gases are used to cycle the weapon, leaving less to propel the projectile.

Anyways, just thought I'd toss out some ideas. A good secondary fire is essential to prevent it from being just a tracefire flak cannon.

Syntax_Error: Thanks for the suggestions, I really like the semi-auto and pump-aciton idea. That should work well with what i had planned for dual wielding: where primary fire is a powerful double shot, and alt is rapid, alternating single shots. If you only have one shotgun, primary would be pump, while alt would be the less powerful semi-auto. Would the spead change for each one? To say it another way, which type is more accurate? FYI, once I get this started I'll put up a seperate wiki page, and maybe start a page for my info.

Foxpaw: Hmm, that's a tough question. Pump action would have higher chamber pressures which would give the buckshot more momentum leaving the barrel. That might cause it to stay on course more, making it have less spread. On the other hand, the faster moving pump-action buckshot would be less stable in flight due to it's higher velocity. One of these factors would likely outweigh the other - but I don't know which one.

##### Views

- Legacy
- Discussion
- Current revision

##### Search