How to implement a new alien class?
countbasie
Join Date: 2008-12-27 Member: 65884Members
in Modding
<div class="IPBDescription">Noob trying to mod</div>Hey,
I want to add a new alien class. Basically just to have another model for the skulk. I know how to implement the model, but I can only apply it to the original skulk.
I want a lua file called like 'skulk1' and a console command to choose it in cheats mode. So that I can have an original skulk and the other skulk standing next to it. Any ideas?
I tried changing
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->class 'Skulk' (Alien)
Skulk.kMapName = "skulk"<!--c2--></div><!--ec2-->
to
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->class 'Skulk1' (Alien)
Skulk.kMapName = "skulk1"<!--c2--></div><!--ec2-->
But it doesn't work - is there a file that defines all classes that are in the game?
I want to add a new alien class. Basically just to have another model for the skulk. I know how to implement the model, but I can only apply it to the original skulk.
I want a lua file called like 'skulk1' and a console command to choose it in cheats mode. So that I can have an original skulk and the other skulk standing next to it. Any ideas?
I tried changing
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->class 'Skulk' (Alien)
Skulk.kMapName = "skulk"<!--c2--></div><!--ec2-->
to
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->class 'Skulk1' (Alien)
Skulk.kMapName = "skulk1"<!--c2--></div><!--ec2-->
But it doesn't work - is there a file that defines all classes that are in the game?
Comments
If you want to have a different skulk model, you just change the model in the skulk file to the name of the new model.
If you want to create a new alien based off the skulk, then copy the file, and rename it entirely to skulk1.
For example, just fixing what you have done above:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->class 'Skulk1' (Alien)
Skulk1.kMapName = "skulk1"
Skulk1.kModelName = PrecacheAsset("models/alien/skulk/skulk1.model")
local kViewModelName = PrecacheAsset("models/alien/skulk/skulk1_view.model")
local kSkulkAnimationGraph = PrecacheAsset("models/alien/skulk/skulk1.animation_graph")
if Server then
Script.Load("lua/Skulk1_Server.lua", true)
elseif Client then
Script.Load("lua/Skulk1_Client.lua", true)
end
Skulk1.kAirAcceleration = 40
function Skulk1:OnCreate()<!--c2--></div><!--ec2-->
Gives you an idea of what you'll be editing etc. I've deleted a lot of line here, as this is just to demonstrate...
Then you need to go into TechData.lua and add the Tech data for the new skulk, goto to TechTree Constants, to add the skulk1, also you need to go to the alien team and add skulk1 there, and so on throughout the neccesary files..
If you want to do it this way it is a lot of work, or you could just point the skulk at a different model for the simple fix.
As a special bonus here is one of my customised aliens, although It isn't an alien, because I have changed the base class as well.... It is a Gorge created for v2 of GorgeCraft. Note this is not an alien anymore, it is a Fort1. (Yes I have designed new Teams and Player Classes for GorgeCraft v2, as well as new game modes.)
Here is a code box incorporating the code, so you can get an idea of what you would need to do to create a new skulk. This is still a vanilla Gorge in code at teh moment, yet to amend it though..
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>
// ======= Copyright © 2003-2011, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\FortsGorge.lua
//
// Created by: Andy Wilson for GorgeCraft (soulrider@modbeans.com)
//
// ========= For more information, visit us at <a href="http://www.unknownworlds.com" target="_blank">http://www.unknownworlds.com</a> =====================
Script.Load("lua/Utility.lua")
Script.Load("lua/Fort1.lua")
Script.Load("lua/Weapons/Alien/SpitSpray.lua")
Script.Load("lua/Weapons/Alien/InfestationAbility.lua")
Script.Load("lua/Weapons/Alien/DropStructureAbility.lua")
Script.Load("lua/Weapons/Alien/DropStructureAbility2.lua")
Script.Load("lua/Weapons/Alien/DropStructureAbility3.lua")
Script.Load("lua/Weapons/Alien/WebStalk.lua")
Script.Load("lua/Weapons/Alien/BileBomb.lua")
Script.Load("lua/Weapons/Alien/Absorb.lua")
Script.Load("lua/Mixins/BaseMoveMixin.lua")
Script.Load("lua/Mixins/GroundMoveMixin.lua")
Script.Load("lua/Mixins/CameraHolderMixin.lua")
Script.Load("lua/DissolveMixin.lua")
class 'FortsGorge' (Fort1)
if Server then
Script.Load("lua/FortsGorge_Server.lua")
end
local networkVars =
{
bellyYaw = "private float",
timeSlideEnd = "private time",
startedSliding = "private boolean",
sliding = "boolean"
}
AddMixinNetworkVars(BaseMoveMixin, networkVars)
AddMixinNetworkVars(GroundMoveMixin, networkVars)
AddMixinNetworkVars(CameraHolderMixin, networkVars)
AddMixinNetworkVars(DissolveMixin, networkVars)
FortsGorge.kMapName = "fortsgorge"
FortsGorge.kModelName = PrecacheAsset("models/alien/gorge/gorge.model")
local kViewModelName = PrecacheAsset("models/alien/gorge/gorge_view.model")
local kGorgeAnimationGraph = PrecacheAsset("models/alien/gorge/gorge.animation_graph")
FortsGorge.kSlideLoopSound = PrecacheAsset("sound/NS2.fev/alien/gorge/slide_loop")
FortsGorge.kBuildSoundInterval = .5
FortsGorge.kBuildSoundName = PrecacheAsset("sound/NS2.fev/alien/gorge/build")
FortsGorge.kXZExtents = 0.5
FortsGorge.kYExtents = 0.475
local kMass = 80
local kJumpHeight = 2.4
local kInfestationStartSlideForce = 7.5
local kStartSlideForce = 7
local kViewOffsetHeight = 0.6
local kMaxGroundSpeed = 9
local kMaxSlidingSpeed = 17
local kSlidingMoveInputScalar = 0.1
local kBuildingModeMovementScalar = 0.001
local kSlideCoolDown = 0.5
FortsGorge.kAirZMoveWeight = 2.5
FortsGorge.kAirStrafeWeight = 2.5
FortsGorge.kAirBrakeWeight = 0.1
local kGorgeBellyYaw = "belly_yaw"
local kGorgeLeanSpeed = 2
function FortsGorge:OnCreate()
InitMixin(self, BaseMoveMixin, { kGravity = Player.kGravity })
InitMixin(self, GroundMoveMixin)
InitMixin(self, CameraHolderMixin, { kFov = kGorgeFov })
Fort1.OnCreate(self)
InitMixin(self, DissolveMixin)
self.bellyYaw = 0
self.timeSlideEnd = 0
self.startedSliding = false
self.sliding = false
self.verticalVelocity = 0
end
function FortsGorge:OnInitialized()
Fort1.OnInitialized(self)
self:SetModel(FortsGorge.kModelName, kGorgeAnimationGraph)
if Server then
self.slideLoopSound = Server.CreateEntity(SoundEffect.kMapName)
self.slideLoopSound:SetAsset(FortsGorge.kSlideLoopSound)
self.slideLoopSound:SetParent(self)
else
self:AddHelpWidget("GUIGorgeHealHelp", 2)
self:AddHelpWidget("GUIGorgeBellySlideHelp", 2)
end
end
function FortsGorge:GetInfestationBonus()
return kGorgeInfestationSpeedBonus
end
function FortsGorge:GetCeleritySpeedModifier()
return kGorgeCeleritySpeedModifier
end
function FortsGorge:GetCarapaceSpeedReduction()
return kGorgeCarapaceSpeedReduction
end
if Client then
local kGorgeHealthbarOffset = Vector(0, 0.7, 0)
function Gorge:GetHealthbarOffset()
return kGorgeHealthbarOffset
end
function FortsGorge:OverrideInput(input)
local activeWeapon = self:GetActiveWeapon()
if activeWeapon and (activeWeapon:isa("DropStructureAbility") or activeWeapon:isa("DropStructureAbility2")or activeWeapon:isa("DropStructureAbility3")) then
input = activeWeapon:OverrideInput(input)
end
Player.OverrideInput(self, input)
end
end
function FortsGorge:GetBaseArmor()
return kGorgeArmor
end
function FortsGorge:GetArmorFullyUpgradedAmount()
return kGorgeArmorFullyUpgradedAmount
end
function FortsGorge:GetMaxViewOffsetHeight()
return kViewOffsetHeight
end
function FortsGorge:GetCrouchShrinkAmount()
return 0
end
function FortsGorge:GetExtentsCrouchShrinkAmount()
return 0
end
function FortsGorge:GetViewModelName()
return kViewModelName
end
function FortsGorge:GetJumpHeight()
return kJumpHeight
end
function FortsGorge:GetIsBellySliding()
return self.sliding
end
function FortsGorge:HandleJump(input, velocity)
if not self:GetIsBellySliding() then
return Fort1.HandleJump(self, input, velocity)
end
return false
end
local function GetIsSlidingDesired(self, input)
if bit.band(input.commands, Move.MovementModifier) == 0 then
return false
end
if self.crouching then
return false
end
if self:GetVelocity():GetLengthXZ() < 3 then
if self:GetIsBellySliding() then
return false
end
else
local zAxis = self:GetViewCoords().zAxis
zAxis.y = 0
zAxis:Normalize()
if GetNormalizedVectorXZ(self:GetVelocity()):DotProduct( zAxis ) < 0.2 then
return false
end
end
return true
end
// Handle transitions between starting-sliding, sliding, and ending-sliding
local function UpdateGorgeSliding(self, input)
PROFILE("FortsGorge:UpdateGorgeSliding")
local slidingDesired = GetIsSlidingDesired(self, input)
if slidingDesired and not self.sliding and self.timeSlideEnd + kSlideCoolDown < Shared.GetTime() and self:GetIsOnGround() and self:GetEnergy() >= kBellySlideCost then
self.sliding = true
self.startedSliding = true
if Server then
if not GetHasSilenceUpgrade(self) then
self.slideLoopSound:Start()
end
end
self:DeductAbilityEnergy(kBellySlideCost)
end
if not slidingDesired and self.sliding then
self.sliding = false
if Server then
self.slideLoopSound:Stop()
end
self.timeSlideEnd = Shared.GetTime()
end
// Have Gorge lean into turns depending on input. He leans more at higher rates of speed.
if self:GetIsBellySliding() then
local desiredBellyYaw = 2 * (-input.move.x / kSlidingMoveInputScalar) * (self:GetVelocity():GetLength() / self:GetMaxSpeed())
self.bellyYaw = Slerp(self.bellyYaw, desiredBellyYaw, input.time * kGorgeLeanSpeed)
end
end
function FortsGorge:GetCanRepairOverride(target)
return true
end
function FortsGorge:HandleButtons(input)
PROFILE("FortsGorge:HandleButtons")
Fort1.HandleButtons(self, input)
UpdateGorgeSliding(self, input)
end
function FortsGorge:OnUpdatePoseParameters(viewModel)
PROFILE("FortsGorge:OnUpdatePoseParameters")
Fort1.OnUpdatePoseParameters(self, viewModel)
self:SetPoseParam(kGorgeBellyYaw, self.bellyYaw * 45)
end
function FortsGorge:ConstrainMoveVelocity(moveVelocity)
Fort1.ConstrainMoveVelocity(self, moveVelocity)
if self:GetIsBellySliding() then
moveVelocity:Scale(0)
end
end
function FortsGorge:GetGroundFrictionForce()
if self:GetIsBellySliding() then
return ConditionalValue(self:GetGameEffectMask(kGameEffect.OnInfestation), 0.1, 0.3)
end
return Fort1.GetGroundFrictionForce(self)
end
function FortsGorge:SetCrouchState(newCrouchState)
self.crouching = newCrouchState
end
function FortsGorge:GetMaxSpeed(possible)
if possible then
return kMaxGroundSpeed
end
return kMaxGroundSpeed * self:GetMovementSpeedModifier()
end
function FortsGorge:GetMass()
return kMass
end
function FortsGorge:OnUpdateAnimationInput(modelMixin)
PROFILE("FortsGorge:OnUpdateAnimationInput")
Fort1.OnUpdateAnimationInput(self, modelMixin)
if self:GetIsBellySliding() then
modelMixin:SetAnimationInput("move", "belly")
end
end
function FortsGorge:GetAirMoveScalar()
return 0
end
function FortsGorge:GetCanCloakOverride()
return not self:GetIsBellySliding()
end
FortsGorge.kSlideControl = 1
function FortsGorge:ModifyVelocity(input, velocity)
Fort1.ModifyVelocity(self, input, velocity)
if not self:GetIsOnGround() and input.move:GetLength() ~= 0 or self:GetIsBellySliding() then
local moveLengthXZ = velocity:GetLengthXZ()
local previousY = velocity.y
local adjustedZ = false
local bellySliding = self:GetIsBellySliding()
if input.move.z ~= 0 then
local redirectedVelocityZ = GetNormalizedVectorXZ(self:GetViewCoords().zAxis) * input.move.z
if input.move.z < 0 then
redirectedVelocityZ = GetNormalizedVectorXZ(velocity)
redirectedVelocityZ:Normalize()
local xzVelocity = Vector(velocity)
xzVelocity.y = 0
VectorCopy(velocity - (xzVelocity * input.time * FortsGorge.kAirBrakeWeight), velocity)
else
redirectedVelocityZ = redirectedVelocityZ * input.time * ConditionalValue(bellySliding, FortsGorge.kSlideControl, FortsGorge.kAirZMoveWeight) + GetNormalizedVectorXZ(velocity)
redirectedVelocityZ:Normalize()
redirectedVelocityZ:Scale(moveLengthXZ)
redirectedVelocityZ.y = previousY
VectorCopy(redirectedVelocityZ, velocity)
adjustedZ = true
end
end
if input.move.x ~= 0 then
local redirectedVelocityX = GetNormalizedVectorXZ(self:GetViewCoords().xAxis) * input.move.x
if adjustedZ then
redirectedVelocityX = redirectedVelocityX * input.time * ConditionalValue(bellySliding, FortsGorge.kSlideControl, FortsGorge.kAirStrafeWeight) + GetNormalizedVectorXZ(velocity)
else
redirectedVelocityX = redirectedVelocityX * input.time * ConditionalValue(bellySliding, FortsGorge.kSlideControl, 2) + GetNormalizedVectorXZ(velocity)
end
redirectedVelocityX:Normalize()
redirectedVelocityX:Scale(moveLengthXZ)
redirectedVelocityX.y = previousY
VectorCopy(redirectedVelocityX, velocity)
end
end
// Give a little push forward to make sliding useful
if self.startedSliding then
if self:GetIsOnGround() then
local pushDirection = GetNormalizedVectorXZ(self:GetViewCoords().zAxis)
local force = ConditionalValue(self:GetGameEffectMask(kGameEffect.OnInfestation), kInfestationStartSlideForce, kStartSlideForce) * self:GetSlowSpeedModifier()
local impulse = pushDirection * force
velocity.x = velocity.x * 0.7 + impulse.x
velocity.y = velocity.y * 0.7 + impulse.y
velocity.z = velocity.z * 0.7 + impulse.z
end
self.startedSliding = false
end
end
function FortsGorge:GetPitchSmoothRate()
return 1
end
function FortsGorge:GetPitchRollRate()
return 3
end
local kMaxSlideRoll = math.rad(20)
function FortsGorge:GetDesiredAngles()
local desiredAngles = Alien.GetDesiredAngles(self)
if self:GetIsBellySliding() then
desiredAngles.pitch = - self.verticalVelocity / 10
desiredAngles.roll = GetNormalizedVectorXZ(self:GetVelocity()):DotProduct(self:GetViewCoords().xAxis) * kMaxSlideRoll
end
return desiredAngles
end
function FortsGorge:PreUpdateMove(input, runningPrediction)
self.prevY = self:GetOrigin().y
end
function FortsGorge:PostUpdateMove(input, runningPrediction)
if self:GetIsBellySliding() and self:GetIsOnGround() then
local velocity = self:GetVelocity()
local yTravel = self:GetOrigin().y - self.prevY
local xzSpeed = velocity:GetLengthXZ()
xzSpeed = xzSpeed + yTravel * -4
if xzSpeed < kMaxSlidingSpeed or yTravel > 0 then
local directionXZ = GetNormalizedVectorXZ(velocity)
directionXZ:Scale(xzSpeed)
velocity.x = directionXZ.x
velocity.z = directionXZ.z
self:SetVelocity(velocity)
end
self.verticalVelocity = yTravel / input.time
end
end
if Client then
function FortsGorge:OnProcessMove(input)
Fort1.OnProcessMove(self, input)
self.currentTechId = nil
self.ghostStructureCoords = nil
self.ghostStructureValid = false
self.showGhostModel = false
local weapon = self:GetActiveWeapon()
if weapon and (weapon:isa("DropStructureAbility") or weapon:isa("DropStructureAbility2") or weapon:isa("DropStructureAbility3")) then
self.currentTechId = weapon:GetActiveStructure():GetDropStructureId()
self.ghostStructureCoords = weapon:GetGhostModelCoords()
self.ghostStructureValid = weapon:GetIsPlacementValid()
self.showGhostModel = weapon:GetShowGhostModel()
end
end
function FortsGorge:GetShowGhostModel()
return self.showGhostModel
end
function FortsGorge:GetGhostModelTechId()
return self.currentTechId
end
function FortsGorge:GetGhostModelCoords()
return self.ghostStructureCoords
end
function FortsGorge:GetIsPlacementValid()
return self.ghostStructureValid
end
end
function FortsGorge:GetCanAttack()
return Fort1.GetCanAttack(self) and not self:GetIsBellySliding()
end
Shared.LinkClassToMap("FortsGorge", FortsGorge.kMapName, networkVars)</div>
Thanks a lot mate! I'll check it out.
Jibrail:
I didn't apply a new model yet, I just checked if I can replace the Skulk model with the Lerk one. That works pretty well, of course. (Just replace the paths in here
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Skulk.kModelName = PrecacheAsset("models/alien/skulk/skulk.model")
local kViewModelName = PrecacheAsset("models/alien/skulk/skulk_view.model")
local kSkulkAnimationGraph = PrecacheAsset("models/alien/skulk/skulk.animation_graph")<!--c2--></div><!--ec2-->
Since I'm completely new to modding I will try to get an own model in it sometime, but not now :D