Using the MagdalenaMonster as our base monster that we made in the previous tutorial this will show you how to make your monster hold and fire a weapon. Monsters that hold weapons do not work with the UT204RPG stat point system. That is, you will only receive 1 point for killing them. The magdalena base class can be downloaded from here:Magdalana Base Class
This code is from satoremonsterpacks nalifighter but this will seperate it from that package so our monster will not rely on it.
First we need to put in code that spawns the weapon for the monster and initialize some properties. Put these variables at the top of your class, just below the first line like this:
class MagdalenaMonster extends Monster; var() array<string> WeaponClassName; var() float FireRateScale;
Next we need to include the function to spawn the weapon. Weapon spawning must only be done on the server, PostBeginPlay is a good place to initialize things as it gets called at the beginning when the monster spawns.
function PostBeginPlay() { local class<weapon> weaponclass; local int r; Super.PostBeginPlay(); r=Rand(WeaponClassName.Length); weaponclass=class<Weapon>(DynamicLoadObject(WeaponClassName[r],class'class')); if(weaponclass != None) { Weapon=spawn(weaponclass,self); } if(Weapon == None) { return; } Weapon.ExchangeFireModes = 1; Weapon.GiveTo(self); Weapon.AttachToPawn(self); if ( !SavedFireProperties.bInitialized ) { SavedFireProperties.AmmoClass = Weapon.AmmoClass[0]; SavedFireProperties.ProjectileClass = Weapon.AmmoClass[0].default.ProjectileClass; SavedFireProperties.WarnTargetPct = Weapon.AmmoClass[0].default.WarnTargetPct; SavedFireProperties.MaxRange = Weapon.AmmoClass[0].default.MaxRange; SavedFireProperties.bTossed = Weapon.AmmoClass[0].default.bTossed; SavedFireProperties.bTrySplash = Weapon.AmmoClass[0].default.bTrySplash; SavedFireProperties.bLeadTarget = Weapon.AmmoClass[0].default.bLeadTarget; SavedFireProperties.bInstantHit = Weapon.AmmoClass[0].default.bInstantHit; SavedFireProperties.bInitialized = true; } Weapon.ClientState = WS_ReadyToFire; Weapon.GetFireMode(0).FireRate *= FireRateScale; Weapon.GetFireMode(1).FireRate *= FireRateScale; Weapon.GetFireMode(0).AmmoPerFire = 0; Weapon.GetFireMode(1).AmmoPerFire = 0; if(Weapon.bMeleeWeapon == true) { bMeleeFighter = true; } if(Weapon.bSniping == true) { bMeleeFighter = false; } }
Ok that is looking good, we need to set some default properties now, the fire rate and the weapon class names that we want this monster to use. We should also tell this monster that it is not allowed to throw the weapon! Add these bits of code to your script.
function TossWeapon(Vector TossVel) { return; } defaultproperties { WeaponClassName(0)="XWeapons.BioRifle" WeaponClassName(1)="XWeapons.ShockRifle" WeaponClassName(2)="XWeapons.FlakCannon" FireRateScale=1.000000 }
You can have as many Weapons as you want in the defaultproperties because we didn’t specify the length of the array. Now all that is left to add the Ranged Attack function. This is the main attack function and is where we tell the monster what kind of fighter it is. Can it do melee? Can it fire projectiles etc..? In this case we want it to just fire weapons. So add the following weapon firing code.
function RangedAttack(Actor A) { if ( bShotAnim ) { return; } bShotAnim = true; if ( Physics == PHYS_Swimming ) { SetAnimAction(IdleSwimAnim); } if(Weapon != None && Controller.Enemy != None && Weapon.CanAttack(Controller.Enemy) && Controller.Enemy.Health > 0) { Weapon.BotFire(false,); } else if(Weapon.IsFiring()) { Weapon.StopFire(0); Weapon.StopFire(1); } }
If you play with your monster now, you will notice it runs around and fires its weapon at you, what you may not notice is that it doesn’t use the alt-fire function of its weapon much, if at all. This can cause odd behaviour, especially with the ShieldGun. You can leave your monster like this if you want or if you want to make your monster a bit smarter we need to give it a custom controller class. Controllers are the brain behind the monster, they tell it everything. Where to move, who to attack, when to teleport etc… I have separated the NaliFighters controller and provided it here. I hope satore doesn’t mind! To use this controller place the .uc file in the same folder as your monster class. (The Classes folder). Then add this line of code to your defaultproperties section.
defaultproperties { ontrollerClass=Class'MonsterWeaponController' }
Your finished code should look something like this. As a side note the LinkGun when used with our custom controller will cause some log errors to be written. It is recommended to avoid giving your monster this weapon or re-write the weapon to fix these errors.
class MagdalenaMonster extends Monster; var() array<string> WeaponClassName; var() float FireRateScale; function PostBeginPlay() { local class<weapon> weaponclass; local int r; Super.PostBeginPlay(); r=Rand(WeaponClassName.Length); weaponclass=class<Weapon>(DynamicLoadObject(WeaponClassName[r],class'class')); if(weaponclass != None) { Weapon=spawn(weaponclass,self); } if(Weapon == None) { return; } Weapon.ExchangeFireModes = 1; Weapon.GiveTo(self); Weapon.AttachToPawn(self); if ( !SavedFireProperties.bInitialized ) { SavedFireProperties.AmmoClass = Weapon.AmmoClass[0]; SavedFireProperties.ProjectileClass = Weapon.AmmoClass[0].default.ProjectileClass; SavedFireProperties.WarnTargetPct = Weapon.AmmoClass[0].default.WarnTargetPct; SavedFireProperties.MaxRange = Weapon.AmmoClass[0].default.MaxRange; SavedFireProperties.bTossed = Weapon.AmmoClass[0].default.bTossed; SavedFireProperties.bTrySplash = Weapon.AmmoClass[0].default.bTrySplash; SavedFireProperties.bLeadTarget = Weapon.AmmoClass[0].default.bLeadTarget; SavedFireProperties.bInstantHit = Weapon.AmmoClass[0].default.bInstantHit; SavedFireProperties.bInitialized = true; } Weapon.ClientState = WS_ReadyToFire; Weapon.GetFireMode(0).FireRate *= FireRateScale; Weapon.GetFireMode(1).FireRate *= FireRateScale; Weapon.GetFireMode(0).AmmoPerFire = 0; Weapon.GetFireMode(1).AmmoPerFire = 0; if(Weapon.bMeleeWeapon == true) { bMeleeFighter = true; } if(Weapon.bSniping == true) { bMeleeFighter = false; } } function TossWeapon(Vector TossVel) { return; } function RangedAttack(Actor A) { if ( bShotAnim ) { return; } bShotAnim = true; if ( Physics == PHYS_Swimming ) { SetAnimAction(IdleSwimAnim); } if(Weapon != None && Controller.Enemy != None && Weapon.CanAttack(Controller.Enemy) && Controller.Enemy.Health > 0) { Weapon.BotFire(false,); } else if(Weapon.IsFiring()) { Weapon.StopFire(0); Weapon.StopFire(1); } } simulated function PlayDirectionalDeath(Vector HitLoc) { local float Decision; Decision = fRand(); if(Decision < 0.25) { PlayAnim('DeathF',, 0.1); } else if ( Decision > 0.25 && Decision < 0.50) { PlayAnim('DeathB',, 0.1); } else if ( Decision > 0.50 && Decision < 0.75) { PlayAnim('DeathL',, 0.1); } else { PlayAnim('DeathR',, 0.1); } } simulated function PlayDirectionalHit(Vector HitLoc) { local float Decision; Decision = fRand(); if(Decision < 0.25) { PlayAnim('TurnL',, 0.1); } else if ( Decision > 0.25 && Decision < 0.50) { PlayAnim('TurnR',, 0.1); } else if ( Decision > 0.50 && Decision < 0.75) { PlayAnim('TurnL',, 0.1); } else { PlayAnim('TurnR',, 0.1); } } defaultproperties { ControllerClass=Class'MonsterWeaponController' Mesh=SkeletalMesh'Magdalena.Magdalena' Skins(0)=Texture'MagdalenaTextures.magdalena_body' Skins(1)=Texture'MagdalenaTextures.magdalena_head' IdleWeaponAnim="Idle_Biggun" IdleHeavyAnim="Idle_Biggun" IdleRifleAnim="Idle_Rifle" TurnRightAnim="TurnR" TurnLeftAnim="TurnL" CrouchAnims(0)="CrouchF" CrouchAnims(1)="CrouchB" CrouchAnims(2)="CrouchL" CrouchAnims(3)="CrouchR" CrouchTurnRightAnim="Crouch_TurnR" CrouchTurnLeftAnim="Crouch_TurnL" AirStillAnim="Jump_Mid" AirAnims(0)="JumpF_Mid" AirAnims(1)="JumpB_Mid" AirAnims(2)="JumpL_Mid" AirAnims(3)="JumpR_Mid" TakeoffStillAnim="Jump_Takeoff" TakeoffAnims(0)="JumpF_Takeoff" TakeoffAnims(1)="JumpB_Takeoff" TakeoffAnims(2)="JumpL_Takeoff" TakeoffAnims(3)="JumpR_Takeoff" LandAnims(0)="JumpF_Land" LandAnims(1)="JumpB_Land" LandAnims(2)="JumpL_Land" LandAnims(3)="JumpR_Land" DodgeAnims(0)="DodgeF" DodgeAnims(1)="DodgeB" DodgeAnims(2)="DodgeL" DodgeAnims(3)="DodgeR" DoubleJumpAnims(0)="DoubleJumpF" DoubleJumpAnims(1)="DoubleJumpB" DoubleJumpAnims(2)="DoubleJumpL" DoubleJumpAnims(3)="DoubleJumpR" MovementAnims(0)="RunF" MovementAnims(1)="RunB" MovementAnims(2)="RunL" MovementAnims(3)="RunR" SwimAnims(0)="SwimF" SwimAnims(1)="SwimB" SwimAnims(2)="SwimL" SwimAnims(3)="SwimR" WalkAnims(0)="WalkF" WalkAnims(1)="WalkB" WalkAnims(2)="WalkL" WalkAnims(3)="WalkR" WallDodgeAnims(0)="WallDodgeF" WallDodgeAnims(1)="WallDodgeB" WallDodgeAnims(2)="WallDodgeL" WallDodgeAnims(3)="WallDodgeR" IdleRestAnim="Idle_Rest" IdleCrouchAnim="Crouch" IdleSwimAnim="Swim_Thread" IdleChatAnim="idle_chat" FireHeavyRapidAnim="Biggun_Aimed" FireHeavyBurstAnim="Biggun_Burst" FireRifleRapidAnim="Rifle_Aimed" FireRifleBurstAnim="Rifle_Burst" HitSound(0)=Sound'SkaarjPack_rc.injur1sk' HitSound(1)=Sound'SkaarjPack_rc.injur1sk' HitSound(2)=Sound'SkaarjPack_rc.injur1sk' HitSound(3)=Sound'SkaarjPack_rc.injur1sk' DeathSound(0)=Sound'SkaarjPack_rc.death1br' DeathSound(1)=Sound'SkaarjPack_rc.death1br' DeathSound(2)=Sound'SkaarjPack_rc.death1br' DeathSound(3)=Sound'SkaarjPack_rc.death1br' ChallengeSound(0)=Sound'SkaarjPack_rc.scuttle1pp' ChallengeSound(1)=Sound'SkaarjPack_rc.scuttle1pp' ChallengeSound(2)=Sound'SkaarjPack_rc.scuttle1pp' ChallengeSound(3)=Sound'SkaarjPack_rc.scuttle1pp' WeaponClassName(0)="XWeapons.ShieldGun" WeaponClassName(1)="XWeapons.LinkGun" WeaponClassName(2)="XWeapons.FlakCannon" WeaponClassName(3)="XWeapons.SniperRifle" WeaponClassName(4)="XWeapons.ShockRifle" FireRateScale=1.000000 }
TIP – Always make sure your monsters brush their teeth twice a day!
Recent Comments