Why won't my Crates and Boxes Stack?

Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
edited September 2012 in Modding
This will probably get a bit code heavy. There is probably some very simple thing I am not taking into account, but this has been bugging me for 3 months now, so time to get some help :)

Here is the video of the problem...

<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/mVTl52RoITg"></param><embed src="http://www.youtube.com/v/mVTl52RoITg" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>

Here is the code from Crate.lua:

<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>// ======= Copyright © 2003-2012, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\Crate.lua
//
// Created by: Andy Soul Rider Wilson for GorgeCraft Mod
//
// ========= For more information, visit us at <a href="http://www.unknownworlds.com" target="_blank">http://www.unknownworlds.com</a> =====================

Script.Load("lua/OwnerMixin.lua")
Script.Load("lua/TeamMixin.lua")
Script.Load("lua/ClogFallMixin.lua")
Script.Load("lua/DigestMixin.lua")
Script.Load("lua/TechMixin.lua")
Script.Load("lua/EntityChangeMixin.lua")
Script.Load("lua/TargetMixin.lua")

local Shared_GetModel = Shared.GetModel

class 'Crate' (Actor)

Crate.kMapName = "crate"

Crate.kModelName = PrecacheAsset("models/props/refinery/refinery_crate_02.model")

local networkVars = { }


/*Crate.kXExtents = .8
Crate.kYExtents = 1.0
Crate.kZExtents = .3*/
Crate.kRadius = 0.75

// crates take maximum X damage per attack (prevents grenades being too effectfive against them), unless the attack is not a of type Flame)
Crate.kMaxShockDamage = 50

AddMixinNetworkVars(TechMixin, networkVars)
AddMixinNetworkVars(TeamMixin, networkVars)
AddMixinNetworkVars(LiveMixin, networkVars)
AddMixinNetworkVars(GameEffectsMixin, networkVars)

function Crate:OnCreate()

Actor.OnCreate(self)

self.boneCoords = CoordsArray()

InitMixin(self, TechMixin)
InitMixin(self, TeamMixin)
InitMixin(self, LiveMixin)
InitMixin(self, GameEffectsMixin)
InitMixin(self, TeamMixin)
InitMixin(self, TargetMixin)

if Server then

InitMixin(self, OwnerMixin)
InitMixin(self, ClogFallMixin)
InitMixin(self, DigestMixin)
InitMixin(self, EntityChangeMixin)
//InitMixin(self, GorgeStructureMixin)

self:SetUpdates(false)

elseif Client then
self:SetUpdates(true)
end

end

function Crate:OnInitialized()

self:CreatePhysics()

if Server then

local mask = bit.bor(kRelevantToTeam1Unit, kRelevantToTeam2Unit, kRelevantToReadyRoom)

if sighted or self:GetTeamNumber() == 1 then

mask = bit.bor(mask, kRelevantToTeam1Commander)

elseif self:GetTeamNumber() == 2 then

mask = bit.bor(mask, kRelevantToTeam2Commander)

end

self:SetExcludeRelevancyMask( mask )


end

end

function Crate:CreatePhysics()

if self.physicsModel then
Shared.DestroyCollisionObject(self.physicsModel)
self.physicsModel = nil
end

//local crateExtents = LookupTechData(self:GetTechId(), kTechDataMaxExtents)

//self.physicsModel = Shared.CreatePhysicsBoxBody(true, crateExtents, 20, self:GetCoords())
self.physicsModel = Shared.CreatePhysicsSphereBody(true, Crate.kRadius, 20, self:GetCoords())
self.physicsModel:SetGroup(PhysicsGroup.BigStructuresGroup)
self.physicsModel:SetEntity(self)
self.physicsModel:SetPhysicsType(CollisionObject.Static)

end

function Crate:OnDestroy()

if self._renderModel ~= nil then

Client.DestroyRenderModel(self._renderModel)
self._renderModel = nil

end

if self.physicsModel then

Shared.DestroyCollisionObject(self.physicsModel)
self.physicsModel = nil

end

end

function Crate:SpaceClearForEntity(location)
return true
end

function Crate:GetIsFlameAble()
return true
end

function Crate:GetShowCrossHairText(toPlayer)
return false
end

function Crate:GetCanBeHealedOverride()
return false
end

function Crate:SetCoords(coords)

if self.physicsModel then
self.physicsModel:SetBoneCoords(coords, self.boneCoords)
end

if self._renderModel then
self._renderModel:SetCoords(coords)
end

Entity.SetCoords(self, coords)

end

function Crate:SetOrigin(origin)

local newCoords = self:GetCoords()
newCoords.origin = origin

if self.physicsModel then
self.physicsModel:SetBoneCoords(newCoords, CoordsArray())
end

if self._renderModel then
self._renderModel:SetCoords(newCoords)
end

Entity.SetOrigin(self, origin)

end

function Crate:GetModelOrigin()
return self:GetOrigin()
end

if Server then

function Crate:SetGameEffectMask(gameEffect, state)

if gameEffect == kGameEffect.OnFire then

if state == true then
self:SetUpdates(true)
elseif not self:GetIsFalling() then
self:SetUpdates(false)
end

end

end

function Crate:OnClogFall()
self:SetUpdates(true)
end

function Crate:OnClogFallDone()

if not self:GetIsOnFire() then
self:SetUpdates(false)
end

if self.physicsModel then

Shared.DestroyCollisionObject(self.physicsModel)
self:CreatePhysics()

end

end

// simple solution for now to avoid griefing
function Crate:GetCanDiggest(player)
return player:GetIsAlive() and player:GetTeamNumber() == self:GetTeamNumber()
end

function Crate:OnKill()

self:TriggerEffects("death")
DestroyEntity(self)

end

function Crate:GetSendDeathMessageOverride()
return false
end

function Crate:OnCreatedByGorge(gorge)

self:TriggerEffects("spawn", {effecthostcoords = self:GetCoords()})
self:TriggerEffects("clog_slime")

end

elseif Client then

function Crate:GetShowHealthCircle()
return false
end

function Crate:OnUpdateRender()

end

end

function Crate:OnUpdate(deltaTime)

Actor.OnUpdate(self, deltaTime)

if self.physicsModel then

if Client and self:GetOrigin() ~= self.storedOrigin then

self:CreatePhysics()
self.storedOrigin = self:GetOrigin()

end

else
self:CreatePhysics()
end

if Client then

if self._renderModel then

self._renderModel:SetCoords(self:GetCoords())
//DebugCapsule(self:GetOrigin(), self:GetOrigin(), Crate.kRadius, 0, 0.03)

else

self._renderModel = Client.CreateRenderModel(RenderScene.Zone_Default)
self._renderModel:SetModel(Shared.GetModelIndex(Crate.kModelName))

end

end

end

function Crate:GetEffectParams(tableParams)

// Only override if not specified
if not tableParams[kEffectFilterClassName] and self.GetClassName then
tableParams[kEffectFilterClassName] = self:GetClassName()
end

if not tableParams[kEffectHostCoords] and self.GetCoords then
tableParams[kEffectHostCoords] = Coords.GetTranslation( self:GetOrigin() )
end

end

function Crate:ComputeDamageOverride(attacker, damage, damageType, time)

if damageType ~= kDamageType.Flame and damage >= Crate.kMaxShockDamage then
self:TriggerEffects("spawn", {effecthostcoords = self:GetCoords()})
damage = Crate.kMaxShockDamage
end

return damage

end

Shared.LinkClassToMap("Crate", Crate.kMapName, networkVars)</div>

There are 1 or two minor changes to the Clog code. I have used box extents and have tried the radius method as used by the Clog, you can see the commented out lines where I've switched between the 2 for testing. Here is the CrateAbility.lua code:

<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\Weapons\Alien\CrateAbility.lua
//
// Created by: Andy Soul Rider Wilson for GorgeCraft Mod
//
// ========= For more information, visit us at <a href="http://www.unknownworlds.com" target="_blank">http://www.unknownworlds.com</a> =====================

Script.Load("lua/Weapons/Alien/StructureAbility.lua")

class 'CrateAbility' (StructureAbility)

local kMinDistance = 0.1
local kVerticalMinDistance = 0.1
local kCrateOffset = 0.1

function CrateAbility:OverrideInfestationCheck(trace)

if trace.entity and trace.entity:isa("Crate") then
return true
end

return false

end

function CrateAbility:GetIsPositionValid(position, player)

/*local valid = true
local entities = GetEntitiesWithinRange("ScriptActor", position, kVerticalMinDistance)
Shared.SortEntitiesByDistance(position, entities)

for _, entity in ipairs(entities) do

if not entity:isa("Infestation") and not entity == player then

local closestPoint = entity:GetOrigin()
local fromStructure = position - closestPoint
local dotProduct = entity:GetCoords().yAxis:DotProduct(fromStructure)

// check horizontal distance (don't allow build on top of the structure)
valid = ( math.abs( fromStructure:GetLength() ) > kMinDistance and dotProduct < kMinDistance )
break

end

end*/

return true

end

function CrateAbility:GetEnergyCost(player)
return kDropCrateEnergyCost
end

function CrateAbility:GetDropRange()
return kGCDropRange
end

function CrateAbility:GetPrimaryAttackDelay()
return 1.0
end

function CrateAbility:GetIconOffsetY(secondary)
return kAbilityOffset.Hydra
end

function CrateAbility:GetGhostModelName(ability)
return Crate.kModelName
end

function CrateAbility:GetDropStructureId()
return kTechId.Crate
end

function CrateAbility:GetSuffixName()
return "crate"
end

function CrateAbility:GetDropClassName()
return "Crate"
end

function CrateAbility:GetDropMapName()
return Crate.kMapName
end</div>

Note I've coded out the positioning code that stops you from building on top of the structure, but still nothing works....

Here is the code from TechData.lua.....

<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->        { [kTechDataId] = kTechId.Clog, [kTechDataAllowConsumeDrop] = true, [kTechDataAllowStacking] = true,  [kTechDataMapName] = Clog.kMapName,                        [kTechDataDisplayName] = "CLOG",           [kTechDataCostKey] = kClogCost,  [kTechDataMaxHealth] = kClogHealth, [kTechDataMaxArmor] = kClogArmor, [kTechDataModel] = Clog.kModelName, [kTechDataRequiresInfestation] = false, [kTechDataPointValue] = kClogPointValue },
        { [kTechDataId] = kTechId.Crate, [kTechDataAllowConsumeDrop] = true, [kTechDataAllowStacking] = true,  [kTechDataMapName] = Crate.kMapName,                        [kTechDataDisplayName] = "CRATE",           [kTechDataCostKey] = kCrateCost,  [kTechDataMaxHealth] = kCrateHealth, [kTechDataMaxArmor] = kCrateArmor, [kTechDataModel] = Crate.kModelName, [kTechDataRequiresInfestation] = false, [kTechDataMaxExtents] = Vector(Crate.kXExtents, Crate.kYExtents, Crate.kZExtents), [kTechDataPointValue] = kCratePointValue },
        { [kTechDataId] = kTechId.Box, [kTechDataAllowConsumeDrop] = true,   [kTechDataAllowStacking] = true,  [kTechDataMapName] = Box.kMapName,                        [kTechDataDisplayName] = "BOX",           [kTechDataCostKey] = kBoxCost,  [kTechDataMaxHealth] = kBoxHealth, [kTechDataMaxArmor] = kBoxArmor, [kTechDataModel] = Box.kModelName, [kTechDataRequiresInfestation] = false, [kTechDataMaxExtents] = Vector(Box.kXExtents, Box.kYExtents, Box.kZExtents), [kTechDataPointValue] = kBoxPointValue },<!--c2--></div><!--ec2-->

Crates and Boxes can be consumed, but they can't be stacked. Where is the code coming from that is breaking this? Or what am I overlooking in my implementation?

Here is the Box.lua code, followed by the BoxAbility.lua code:

<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>// ======= Copyright © 2003-2012, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\Box.lua
//
// Created by: Andy Soul Rider Wilson for GorgeCraft Mod
//
// ========= For more information, visit us at <a href="http://www.unknownworlds.com" target="_blank">http://www.unknownworlds.com</a> =====================

Script.Load("lua/OwnerMixin.lua")
Script.Load("lua/TeamMixin.lua")
Script.Load("lua/ClogFallMixin.lua")
Script.Load("lua/DigestMixin.lua")
Script.Load("lua/TechMixin.lua")
Script.Load("lua/EntityChangeMixin.lua")
//Script.Load("lua/GorgeStructureMixin.lua")
Script.Load("lua/TargetMixin.lua")

local Shared_GetModel = Shared.GetModel

class 'Box' (Actor)

Box.kMapName = "box"

Box.kModelName = PrecacheAsset("models/props/generic/generic_crate_01.model")

local networkVars = { }


Box.kXExtents = .8
Box.kYExtents = 1.0
Box.kZExtents = .3
//Box.kRadius = 0.75

// boxs take maximum X damage per attack (prevents grenades being too effectfive against them), unless the attack is not a of type Flame)
Box.kMaxShockDamage = 50

AddMixinNetworkVars(TechMixin, networkVars)
AddMixinNetworkVars(TeamMixin, networkVars)
AddMixinNetworkVars(LiveMixin, networkVars)
AddMixinNetworkVars(GameEffectsMixin, networkVars)


function Box:OnCreate()

Actor.OnCreate(self)

self.boneCoords = CoordsArray()

InitMixin(self, TechMixin)
InitMixin(self, TeamMixin)
InitMixin(self, LiveMixin)
InitMixin(self, GameEffectsMixin)

InitMixin(self, TeamMixin)
InitMixin(self, TargetMixin)
InitMixin(self, EntityChangeMixin)

if Server then

InitMixin(self, OwnerMixin)
InitMixin(self, ClogFallMixin)
InitMixin(self, DigestMixin)

//InitMixin(self, GorgeStructureMixin)

self:SetUpdates(false)

elseif Client then
self:SetUpdates(true)
end

end

function Box:OnInitialized()

self:CreatePhysics()

if Server then

local mask = bit.bor(kRelevantToTeam1Unit, kRelevantToTeam2Unit, kRelevantToReadyRoom)

if sighted or self:GetTeamNumber() == 1 then

mask = bit.bor(mask, kRelevantToTeam1Commander)

elseif self:GetTeamNumber() == 2 then

mask = bit.bor(mask, kRelevantToTeam2Commander)

end

self:SetExcludeRelevancyMask( mask )


end

end

function Box:CreatePhysics()

if self.physicsModel then
Shared.DestroyCollisionObject(self.physicsModel)
self.physicsModel = nil
end

local boxExtents = LookupTechData(self:GetTechId(), kTechDataMaxExtents)

self.physicsModel = Shared.CreatePhysicsBoxBody(true, boxExtents, 20, self:GetCoords())
self.physicsModel:SetGroup(PhysicsGroup.MediumStructuresGroup)
self.physicsModel:SetEntity(self)
self.physicsModel:SetPhysicsType(CollisionObject.Static)

end

function Box:OnDestroy()

if self._renderModel ~= nil then

Client.DestroyRenderModel(self._renderModel)
self._renderModel = nil

end

if self.physicsModel then

Shared.DestroyCollisionObject(self.physicsModel)
self.physicsModel = nil

end

end

function Box:SpaceClearForEntity(location)
return true
end

function Box:GetIsFlameAble()
return true
end

function Box:GetShowCrossHairText(toPlayer)
return false
end

function Box:GetCanBeHealedOverride()
return false
end

function Box:SetCoords(coords)

if self.physicsModel then
self.physicsModel:SetBoneCoords(coords, self.boneCoords)
end

if self._renderModel then
self._renderModel:SetCoords(coords)
end

Entity.SetCoords(self, coords)

end

function Box:SetOrigin(origin)

local newCoords = self:GetCoords()
newCoords.origin = origin

if self.physicsModel then
self.physicsModel:SetBoneCoords(newCoords, CoordsArray())
end

if self._renderModel then
self._renderModel:SetCoords(newCoords)
end

Entity.SetOrigin(self, origin)

end

function Box:GetModelOrigin()
return self:GetOrigin()
end

if Server then

function Box:SetGameEffectMask(gameEffect, state)

if gameEffect == kGameEffect.OnFire then

if state == true then
self:SetUpdates(true)
elseif not self:GetIsFalling() then
self:SetUpdates(false)
end

end

end

function Box:OnClogFall()
self:SetUpdates(true)
end

function Box:OnClogFallDone()

if not self:GetIsOnFire() then
self:SetUpdates(false)
end

if self.physicsModel then

Shared.DestroyCollisionObject(self.physicsModel)
self:CreatePhysics()

end

end

// simple solution for now to avoid griefing
function Box:GetCanDiggest(player)
return player:GetIsAlive() and player:GetTeamNumber() == self:GetTeamNumber()
end

function Box:OnKill()

self:TriggerEffects("death")
DestroyEntity(self)

end

function Box:GetSendDeathMessageOverride()
return false
end

function Box:OnCreatedByGorge(gorge)

self:TriggerEffects("spawn", {effecthostcoords = self:GetCoords()})
self:TriggerEffects("clog_slime")

end

elseif Client then

function Box:GetShowHealthCircle()
return false
end

function Box:OnUpdateRender()

end

end

function Box:OnUpdate(deltaTime)

Actor.OnUpdate(self, deltaTime)

if self.physicsModel then

if Client and self:GetOrigin() ~= self.storedOrigin then

self:CreatePhysics()
self.storedOrigin = self:GetOrigin()

end

else
self:CreatePhysics()
end

if Client then

if self._renderModel then

self._renderModel:SetCoords(self:GetCoords())
//DebugCapsule(self:GetOrigin(), self:GetOrigin(), Box.kRadius, 0, 0.03)

else

self._renderModel = Client.CreateRenderModel(RenderScene.Zone_Default)
self._renderModel:SetModel(Shared.GetModelIndex(Box.kModelName))

end

end

end

function Box:GetEffectParams(tableParams)

// Only override if not specified
if not tableParams[kEffectFilterClassName] and self.GetClassName then
tableParams[kEffectFilterClassName] = self:GetClassName()
end

if not tableParams[kEffectHostCoords] and self.GetCoords then
tableParams[kEffectHostCoords] = Coords.GetTranslation( self:GetOrigin() )
end

end

function Box:ComputeDamageOverride(attacker, damage, damageType, time)

if damageType ~= kDamageType.Flame and damage >= Box.kMaxShockDamage then
self:TriggerEffects("spawn", {effecthostcoords = self:GetCoords()})
damage = Box.kMaxShockDamage
end

return damage

end

Shared.LinkClassToMap("Box", Box.kMapName, networkVars)</div>

<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\Weapons\Alien\BoxAbility.lua
//
// Created by: Andy Soul Rider Wilson for GorgeCraft Mod
//
// ========= For more information, visit us at <a href="http://www.unknownworlds.com" target="_blank">http://www.unknownworlds.com</a> =====================

Script.Load("lua/Weapons/Alien/StructureAbility.lua")

class 'BoxAbility' (StructureAbility)

local kMinDistance = 1
local kVerticalMinDistance = 1
local kBoxOffset = 0.1

function BoxAbility:OverrideInfestationCheck(trace)

if trace.entity and trace.entity:isa("Box") then
return true
end

return false

end

function BoxAbility:GetIsPositionValid(position, player)

local valid = true
local entities = GetEntitiesWithinRange("ScriptActor", position, kVerticalMinDistance)
Shared.SortEntitiesByDistance(position, entities)

for _, entity in ipairs(entities) do

if not entity:isa("Infestation") and not entity == player then

local closestPoint = entity:GetOrigin()
local fromStructure = position - closestPoint
local dotProduct = entity:GetCoords().yAxis:DotProduct(fromStructure)

// check horizontal distance (don't allow build on top of the structure)
//valid = ( math.abs( fromStructure:GetLength() ) > kMinDistance and dotProduct < kMinDistance ) or dotProduct > kVerticalMinDistance
break

end

end

return valid

end

function BoxAbility:GetEnergyCost(player)
return kDropBoxEnergyCost
end

function BoxAbility:GetDropRange()
return kGCDropRange
end

function BoxAbility:GetPrimaryAttackDelay()
return 1.0
end

function BoxAbility:GetIconOffsetY(secondary)
return kAbilityOffset.Hydra
end

function BoxAbility:GetGhostModelName(ability)
return Box.kModelName
end

function BoxAbility:GetDropStructureId()
return kTechId.Box
end

function BoxAbility:GetSuffixName()
return "box"
end

function BoxAbility:GetDropClassName()
return "Box"
end

function BoxAbility:GetDropMapName()
return Box.kMapName
end</div>

Any help is greatly appreciated. As you can see I have tried differring approaches throughout both codes to solve the problem, but nothing gives.... Any Help is greatly appreciated.

<!--coloro:orange--><span style="color:orange"><!--/coloro--><sup>Changed <strike>all code tags</strike> all but techdata.lua to codebox for easier reading. - Angelusz</sup><!--colorc--></span><!--/colorc-->

Thanks Angelusz, I didn't know codebox existed on these forums..

Comments

  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    check out DropStructureAbility.lua in function DropStructureAbility:GetPositionForStructure(player)

    <div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'> // If it hits something, position on this surface (must be the world or another structure)
    if trace.fraction < 1 then

    if trace.entity == nil then
    validPosition = true

    elseif trace.entity:isa("Infestation") or trace.entity:isa("Clog") then
    validPosition = true
    end

    displayOrigin = trace.endPoint

    end</div>

    validPosition is defined false on top of that function
  • Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
    edited September 2012
    Thanks Sewlek, I'll get on that right away. This has been bugging me for ages!


    Edit - Crates are now stacking, but their physics boxes are all over the place..... I can get say X and Y extents correct, then when I adjust the Z extent, the others go out of whack again, same for any combination in the 3, really wierd, haha.
  • DepotDepot The ModFather Join Date: 2002-11-09 Member: 7956Members
    Soul_Rider, your INBOX here is full dude. Messaged at 'the other place'. :)
Sign In or Register to comment.