Jump to content

Recommended Posts

I'm making a throwable grenade item. However, I'd like it to be also usable as regular melee weapon.

The problem is - character throws the item, no matter what. I tried setting up new actions for left and right mouse button.

Still, on left click (melee) character just runs up to the enemy and throws the grenade.

 

Here's what I did so far. Grenade's prefab:

local assets =
{
	-- Animation files used for the item.
	Asset("ANIM", "anim/ullapool_caber.zip"),
	Asset("ANIM", "anim/swap_ullapool_caber.zip"),
	
	Asset("ANIM", "anim/ullapool_caber_dud.zip"),
	Asset("ANIM", "anim/swap_ullapool_caber_dud.zip"),

	-- Inventory image and atlas file used for the item.
    Asset("ATLAS", "images/inventoryimages/ullapool_caber.xml"),
    Asset("IMAGE", "images/inventoryimages/ullapool_caber.tex"),
	
	Asset("ATLAS", "images/inventoryimages/ullapool_caber_dud.xml"),
    Asset("IMAGE", "images/inventoryimages/ullapool_caber_dud.tex"),
}

local function MakeDud(inst)
	inst.components.weapon:SetDamage(17)
	inst.components.weapon.onattack = nil
	if inst.components.explosive then
		inst:RemoveComponent("explosive")
	end
	if inst.components.complexprojectile then
		inst:RemoveComponent("complexprojectile")
	end
	if inst:HasTag("caber_throwable") then
		inst:RemoveTag("caber_throwable")
	end
	if not inst.components.fuel then
		inst:AddComponent("fuel")
		inst.components.fuel.fuelvalue = TUNING.SMALL_FUEL
	end
	if not inst.components.finiteuses then
		inst:AddComponent("finiteuses")
		inst.components.finiteuses:SetMaxUses(10)
		inst.components.finiteuses:SetUses(10)
		inst.components.finiteuses:SetOnFinished(inst.Remove)
	end
	if not inst.components.tool then
		inst:AddComponent("tool") -- to trigger 'break' animation
	end
	inst.components.inventoryitem.atlasname = "images/inventoryimages/ullapool_caber_dud.xml"
	inst.components.inventoryitem:ChangeImageName("ullapool_caber_dud")
	
	inst.AnimState:SetBank("ullapool_caber_dud")
    inst.AnimState:SetBuild("ullapool_caber_dud")
    inst.AnimState:PlayAnimation("swap")
	
	if inst.components.equippable and inst.components.equippable:IsEquipped() 
	and inst.components.inventoryitem and inst.components.inventoryitem.owner then
		local owner = inst.components.inventoryitem.owner
		owner.AnimState:OverrideSymbol("swap_object", "swap_ullapool_caber_dud", "swap_ullapool_caber_dud")
	end
	
	inst.iscaberdud = true
end

local function ExplodeCaber(inst)
	local owner = nil
	local target = nil
	if inst.components.inventoryitem.owner and inst.components.inventoryitem.owner.components.combat and inst.components.inventoryitem.owner.components.combat.target then
		owner = inst.components.inventoryitem.owner
		target = owner.components.combat.target
		SpawnPrefab("explode_small").Transform:SetPosition(target.Transform:GetWorldPosition())
	else
		SpawnPrefab("explode_small").Transform:SetPosition(inst.Transform:GetWorldPosition())
	end
	--Change into a dud (if not thrown)
	if inst.components.equippable:IsEquipped() then
		MakeDud(inst)
	end
end

local function ForceExplosion(inst)
	if inst.components.explosive then
		inst.components.explosive:OnBurnt()
	end
end

local function onequip(inst, owner) 
	if inst.iscaberdud == nil then
		owner.AnimState:OverrideSymbol("swap_object", "swap_ullapool_caber", "swap_ullapool_caber")
	else
		owner.AnimState:OverrideSymbol("swap_object", "swap_ullapool_caber_dud", "swap_ullapool_caber_dud")
	end
    owner.AnimState:Show("ARM_carry") 
    owner.AnimState:Hide("ARM_normal") 
end

local function onunequip(inst, owner) 
    owner.AnimState:Hide("ARM_carry") 
    owner.AnimState:Show("ARM_normal") 
end

local function OnHitCaber(inst, attacker, target)
    ForceExplosion(inst)
	
	if inst.components.explosive then
		local x, y, z = inst.Transform:GetWorldPosition()
		local ents = TheSim:FindEntities(x, y, z, inst.components.explosive.explosiverange, nil, { "INLIMBO" })
		for k, v in ipairs(ents) do
			if v:IsValid() and not v:IsInLimbo() then
				if v.components.combat ~= nil and (attacker.drunkscrumpy == nil or attacker.drunkscrumpy == 0) and not v:HasTag("demoman") then
					v.components.combat:GetAttacked(attacker, inst.components.explosive.explosivedamage*0.75, nil) -- ullapool caber when thrown (150 dmg)
				elseif v.components.combat ~= nil and (attacker.drunkscrumpy ~= nil and attacker.drunkscrumpy > 0) and not v:HasTag("demoman") then
					v.components.combat:GetAttacked(attacker, (inst.components.explosive.explosivedamage*0.75)*2, nil) -- CRIT ullapool caber when thrown (300 dmg)
				elseif v.components.combat ~= nil and (attacker.drunkscrumpy == nil or attacker.drunkscrumpy == 0) and v:HasTag("demoman") then
					v.components.combat:GetAttacked(attacker, (inst.components.explosive.explosivedamage*0.75)*0.5, nil) -- ullapool caber when thrown (150 dmg)
				elseif v.components.combat ~= nil and (attacker.drunkscrumpy ~= nil and attacker.drunkscrumpy > 0) and v:HasTag("demoman") then
					v.components.combat:GetAttacked(attacker, ((inst.components.explosive.explosivedamage*0.75)*2)*0.5, nil) -- CRIT ullapool caber when thrown (300 dmg)
				end
				v:PushEvent("explosion", { explosive = inst })
			end
		end
	end
    inst:Remove()
end

local function onthrown(inst)
    inst:AddTag("NOCLICK")
    inst.persists = false

    inst.AnimState:PlayAnimation("spin_loop", true)

    inst.Physics:SetMass(1)
    inst.Physics:SetCapsule(0.2, 0.2)
    inst.Physics:SetFriction(0)
    inst.Physics:SetDamping(0)
    inst.Physics:SetCollisionGroup(COLLISION.CHARACTERS)
    inst.Physics:ClearCollisionMask()
    inst.Physics:CollidesWith(COLLISION.WORLD)
    inst.Physics:CollidesWith(COLLISION.OBSTACLES)
    inst.Physics:CollidesWith(COLLISION.ITEMS)
end

local function ReticuleTargetFn()
    local player = ThePlayer
    local ground = TheWorld.Map
    local x, y, z
    --Attack range is 8, leave room for error
    --Min range was chosen to not hit yourself (2 is the hit range)
    for r = 6.5, 3.5, -.25 do
        x, y, z = player.entity:LocalToWorldSpace(r, 0, 0)
        if ground:IsPassableAtPoint(x, y, z) then
            return Vector3(x, y, z)
        end
    end
    return Vector3(x, y, z)
end

local function getstatus(inst, viewer)
    return inst.iscaberdud == true and "DUD" or nil
end

local function onsave(inst, data)
	if data and inst.iscaberdud ~= nil then
		data.iscaberdud = inst.iscaberdud
	end
end

local function onpreload(inst, data)
	if data and data.iscaberdud ~= nil then
		inst.iscaberdud = data.iscaberdud
	end
end

local function onload(inst, data)
	if inst.iscaberdud ~= nil then
		MakeDud(inst)
	end
end

local function init()
	local inst = CreateEntity()

	inst.entity:AddTransform()
	inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddNetwork()

    MakeInventoryPhysics(inst)

    inst.AnimState:SetBank("ullapool_caber")
    inst.AnimState:SetBuild("ullapool_caber")
    inst.AnimState:PlayAnimation("swap")

	inst:AddTag("caber")
	inst:AddTag("caber_throwable")
	
	inst.entity:SetPristine()
	
	inst:AddComponent("reticule")
    inst.components.reticule.targetfn = ReticuleTargetFn
    inst.components.reticule.ease = true
	
    if not TheWorld.ismastersim then
        return inst
    end

	inst:AddComponent("explosive")
    inst.components.explosive:SetOnExplodeFn(ExplodeCaber)
    inst.components.explosive.explosivedamage = TUNING.ULLAPOOL_CABER_DAMAGE -- default 200
	inst.components.explosive.range = 6
	inst.components.explosive.lightonexplode = false
	
    inst:AddComponent("weapon")
    inst.components.weapon:SetDamage(0) -- Explosion will deal damage
	inst.components.weapon:SetOnAttack(ForceExplosion)
	inst.components.weapon.attackrange = nil
    
    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem.atlasname = "images/inventoryimages/ullapool_caber.xml"
    inst.components.inventoryitem.imagename = "ullapool_caber"
    
	inst:AddComponent("complexprojectile")
	inst.components.complexprojectile:SetHorizontalSpeed(15)
    inst.components.complexprojectile:SetGravity(-35)
    inst.components.complexprojectile:SetLaunchOffset(Vector3(.25, 1, 0))
    inst.components.complexprojectile:SetOnLaunch(onthrown)
    inst.components.complexprojectile:SetOnHit(OnHitCaber)
	
    inst:AddComponent("equippable")
    inst.components.equippable:SetOnEquip(onequip)
    inst.components.equippable:SetOnUnequip(onunequip)
    
	inst.iscaberdud = nil
	
	inst:AddComponent("inspectable")
    inst.components.inspectable.getstatus = getstatus
	
	--inst:RemoveTag("projectile")
	--inst:RemoveTag("thrown")
	--inst:RemoveTag("throw")
	
	MakeHauntableLaunch(inst)
	
	inst.OnSave = onsave
	inst.OnPreLoad = onpreload
	inst.OnLoad = onload
	
    return inst
end

return Prefab("common/inventory/ullapool_caber", init, assets)

And here's some new actions in modmain I tried making:

-- Ullapolean Throw! ----------------------------------
local ULLATHROW = GLOBAL.Action({ priority= 10, distance= 10, mount_valid=true })	
ULLATHROW.str = "Throw"
ULLATHROW.id = "ULLATHROW"
ULLATHROW.fn = function(act)
	if act.invobject and act.doer then
        if act.invobject.components.complexprojectile and act.invobject:HasTag("caber_throwable") and act.doer.components.inventory then
            local projectile = act.doer.components.inventory:DropItem(act.invobject, false)
            if projectile then
                local pos = nil
                if act.target then
                    pos = act.target:GetPosition()
                    projectile.components.complexprojectile.targetoffset = {x=0,y=1.5,z=0}
                else
                    pos = act.pos
                end
                projectile.components.complexprojectile:Launch(pos, act.doer)
                return true
            end
        end
    end
end
AddAction(ULLATHROW)

local ullathrowing_handler = ActionHandler(ACTIONS.ULLATHROW, "throw")
AddStategraphActionHandler("wilson", ullathrowing_handler)

AddComponentAction("POINT", "complexprojectile", function(inst, doer, pos, actions, right)
    if inst:HasTag("caber") and inst:HasTag("caber_throwable") and right then
        table.insert(actions, ACTIONS.ULLATHROW)
    end
end)

AddComponentAction("EQUIPPED", "complexprojectile", function(inst, doer, target, actions, right)
    if inst:HasTag("caber") and inst:HasTag("caber_throwable") and right then
        table.insert(actions, ACTIONS.ULLATHROW)
    end
end)

AddStategraphActionHandler("wilson_client", ullathrowing_handler)

-- Ullapolean Hit! ----------------------------------

local ULLAHIT = GLOBAL.Action({ priority= 11, distance= nil, canforce=true, mount_valid=true, rangecheckfn=nil })	
ULLAHIT.str = "Attack"
ULLAHIT.id = "ULLAHIT"
ULLAHIT.fn = function(act)
	act.doer.components.combat:DoAttack(act.target)
	return true
end
AddAction(ULLAHIT)

local ullahitting_handler = ActionHandler(ACTIONS.ULLAHIT, "attack")
AddStategraphActionHandler("wilson", ullahitting_handler)

AddComponentAction("SCENE", "combat", function(inst, doer, actions, right)
    if not right and
    doer:CanDoAction(ACTIONS.ULLAHIT) and inst:HasTag("caber") and inst:HasTag("caber_throwable") and
    inst.replica.health ~= nil and not inst.replica.health:IsDead() and
    inst.replica.combat ~= nil and inst.replica.combat:CanBeAttacked(doer) then
        table.insert(actions, ACTIONS.ULLAHIT)
    end
end)

AddStategraphActionHandler("wilson_client", ullahitting_handler)

Any help is appreciated!

Edited by PanAzej
PHP-code colors make it easier to look at...
Link to comment
https://forums.kleientertainment.com/forums/topic/68895-grenade-problems/
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...