| Home Page | Recent Changes

Mod Ideas/Killstick

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.

The Unreal Engine Documentation Site

Wiki Community

Topic Categories

Recent Changes

Offline Wiki

Unreal Engine

Console Commands

Terminology

FAQs

Help Desk

Mapping Topics

Mapping Lessons

UnrealEd Interface

UnrealScript Topics

UnrealScript Lessons

Making Mods

Class Tree

Modeling Topics

Chongqing Page

Log In