Author Topic: Increasingly less simple repair gun  (Read 2397 times)

0 Members and 1 Guest are viewing this topic.

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Increasingly less simple repair gun
This is the first script I've got working, so while it's probably simple and obvious to the real coders here I thought I'd share it for anyone else who's just getting started.
Code: [Select]
#Conditional Hooks

$State: GS_STATE_GAME_PLAY
$Weapon class: Nanite Repair Gun
$On Ship Collision:
[
local repairValue = 40

hv.Ship.HitpointsLeft = hv.Ship.HitpointsLeft+repairValue

if (hv.Ship.HitpointsLeft > hv.Ship.HitpointsMax) then
hv.Ship.HitpointsLeft = hv.Ship.HitpointsMax
end

hv.Self.LifeLeft = 0
]
+Override: true
#End
The 'if' statement is necessary: without it, you can 'repair' your target to well over 100%

This is intended to be used with a custom primary named "Nanite Repair Gun" that does 0 damage. Of course, this doesn't fix the many problems one would expect from such a weapon, including:
Friendly AI will evade your fire.
AI would never use this.

I got rid of the damage particles by using +override and setting lifeleft to 0, but there's no impact effect at all. That could probably be fixed. However, if you don't care about the aesthetics you could let the player use this as-is to repair a cruiser or transport that he's escorting. Careful FREDing might also force the AI to use this in tightly-scripted scenarios.

I don't think shooting your friends with a 0 damage gun will make you a traitor, but the traitor code is complicated. Also, I haven't tested it, but I think this script is flexible enough to be used with a secondary or beam.
« Last Edit: November 17, 2011, 06:30:44 am by Alan Bolte »
Anything worth doing is worth analyzing to death -Iranon

 

Offline SypheDMar

  • 210
  • Student, Volunteer, Savior
    • Minecraft
Re: Very simple repair gun
The GTDr 3301 uses a repair beam, but it's AI-specific. It shoots at stationary targets, though. Would this script help for the AI if it needs to target players?

 

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Re: Very simple repair gun
I don't understand the question. If I had to guess, I'd say you were describing a zero-damage beam being fired at the same time a repair SEXP is active on the same target.

This script causes the weapon object itself (e.g. blob) to repair whatever it impacts. If you can make a ship or turret target players via SEXPs or a different script, then you can use this script to replace that weapon's impact damage with healing. I haven't done any tests with blast weapons.

Also, it occurs to me that if you want a impact particles your best bet it to try to adapt m!m's particle scripts to the purpose, which I have no intention of messing with because wow is that stuff complicated. I'm working on a simple impact explosion, but using the position of the weapon doesn't work because it's inside the hull. LastPosition doesn't seem to work with weapon objects. Currently I'm trying to figure out the collision information that was added in 3.6.13. :banghead: LastPosition was also added in 3.6.13.

So far this does not work with beams. I think the issue is that since beam collisions are handled differently than primary and secondary collisions, I'd need a completely different method. Probably use On Weapon Fired instead of the collision hook, then mess around with frame-by-frame detection of each beam collsiion until the beam shuts down.

Secondaries work, but as expected it only repairs based on a direct impact, the blast has no effect.
« Last Edit: November 14, 2011, 01:46:30 pm by Alan Bolte »
Anything worth doing is worth analyzing to death -Iranon

 

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Re: Very simple repair gun
Here's a variant with an impact effect. Requires 3.6.13 or later. Also requires MediaVPs 3.6.12 unless you change the impact explosion. Since I used LastPosition instead of the collision point, the effect tends to occur slightly above the hull in a way that looks odd at point blank range, but looks fine most of the time.
Code: [Select]
#Conditional Hooks

$Application: FS2_Open
$On Game Init:
[
--impact explosion, check the MediaVP wep.tbm files for which one you want and what radius to use
local texturename = "Akheton_Impact"
imageRadius = 1.8

repairImpactImage = gr.loadTexture(texturename, true)
]

$State: GS_STATE_GAME_PLAY
$Weapon class: Nanite Repair ;;Weapon class is the same name as is displayed on the HUD
$On Ship Collision:
[
local repairValue = 20 --use lower values for weapons with a high rate of fire and vice versa.

hv.Ship.HitpointsLeft = hv.Ship.HitpointsLeft+repairValue

if (hv.Ship.HitpointsLeft > hv.Ship.HitpointsMax) then
hv.Ship.HitpointsLeft = hv.Ship.HitpointsMax
end

local createPos = hv.Self.LastPosition  --can be replaced with proper collision detection if you're picky
local velocity = ba.createVector(0,0,0)

ts.createParticle(createPos, velocity, 1, imageRadius, PARTICLE_BITMAP, -1, false, repairImpactImage)

hv.Self.LifeLeft = 0 -- weapon dies near the end of next frame
hv.Self.Physics.Velocity = hv.Ship.Physics.Velocity --hack to prevent multiple collisions
]
+Override: true
#End

I'm not sure if I should be doing something to unload the texture from memory. There's a function for doing so, but somehow I can't figure out the syntax, and I'm not sure it's desirable to do so anyway.

I'm thinking about adding the ability to repair the subsystem or turret you hit with this, but I should probably add a config file first.
« Last Edit: November 17, 2011, 11:57:48 am by Alan Bolte »
Anything worth doing is worth analyzing to death -Iranon

 

Offline m!m

  • 211
Re: Very simple repair gun
You could load the animation in an On Game Init hook and then use the returned handle for the particle animation. In that case you don't need to unload the texture as that will be done when the game is closed.
You can also add beam checking using an On Frame hook where you check every beam which should repair for a collision and then repair the ship that got hit.

 

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Re: Very simple repair gun
Thanks!

I implemented your suggestion and updated the script above.
« Last Edit: November 14, 2011, 08:52:34 pm by Alan Bolte »
Anything worth doing is worth analyzing to death -Iranon

 

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Re: Very simple repair gun
Here's an interesting problem with the impact effect: at shallow angles it appears twice. Tested on the latest nightly and 3.6.14RC1. Can't test on 3.6.12 'cause LastPosition doesn't work with that. I'm gonna try switch back to Position and testing it that way, but doubt I'll see anything. Just using normal Position on 3.6.12 causes the same issue, so that's not it.

I'd test the normal weapon impact effects, but they're obscured by the damage particles when hitting hull so they're hard to see.

I think this might have to do with the fact that this box I'm shooting has modeled ridges, so I'm getting two collisions...

Edit: two collisions confirmed via hitpoint change. I wonder, if I had a ship with lots of ridges close together, how many collisions would that register before the weapon gets the hint and stops colliding with things?

[attachment deleted by a basterd]
« Last Edit: November 16, 2011, 05:55:45 pm by Alan Bolte »
Anything worth doing is worth analyzing to death -Iranon

 

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Re: Very simple repair gun
Curiouser and curiouser. Setting lifeleft to any negative number just makes the weapon go on forever.

EDIT: I can see in the code now why setting the LifeLeft to 0 doesn't kill the weapon immediately.
Code: [Select]
if ( wp->lifeleft < 0.0f ) {
[various irrelevant if statements]
obj->flags |= OF_SHOULD_BE_DEAD;
This way, the blob hits the target ship, gets its life set to 0, and then if it collides with something in the next frame the script will run again. Only when the lifeleft has frame time subtracted from it to bring it below 0 will the blob be removed.

It looks like multiple collisions isn't due to the ridges, it's due to the shallow angle, i.e. I can get multiple collisions on the same face.

There's a kill function for ships, but not for objects in general. Either I need to find a different way to get rid of the blob, or I need to change its velocity so that it won't collide with anything else. I think the script is interpreting negative values as nil at some point, though it's not equivalent to using 'nil' in the actual script because doing so causes an error.

EDIT: negating the velocity seems to have done the trick. I'm updating the script above now.

[attachment deleted by a basterd]
« Last Edit: November 16, 2011, 10:26:00 pm by Alan Bolte »
Anything worth doing is worth analyzing to death -Iranon

 

Offline m!m

  • 211
Re: Very simple repair gun
The last time I tried to kill a weapon setting the lifeleft variable to 0 did the trick. No idea why it doesn't work here.
Also I noticed that you have a variable holding the lifetime of the effect for the impact particle. You don't need to do this as the code automagically computes the particle lifetime for the given effect so you can just specify an arbitrary value for the lifetime.

 

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Re: Very simple repair gun
I think my posts are probably a bit incoherent seeing as how I'm on a fair bit of vicodin at the moment (nose surgery, doin' fine, etc.). Setting lifetime to 0 does kill the weapon, but not until near the end of the following frame, so it's possible to have a double collision. It's not the least bit obvious and honestly I'm surprised I even noticed. If you could point me toward whatever script you're talking about that has lifetime = 0 I'd like to take a look at it and see if it works differently for some reason.

Actually, it should be possible for this script to collide forever, but that would require an intersection of weapon and geometry such that it collides every frame, thus setting the lifetime back to 0 every frame.
Anything worth doing is worth analyzing to death -Iranon

 

Offline m!m

  • 211
Re: Increasingly less simple repair gun
Oh sorry, I must have misread your posts then. I didn't use lifetime = 0 in a situation where the weapon was colliding so I think that that was the cause why I didn't see this before...

 

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Re: Increasingly less simple repair gun
Cool. What doesn't kill the weapon is setting lifetime to negative numbers. I can't follow the C code well enough to figure out why though.

 The velocity change I've used instead is kind of hackish. I could try to create an array of recent collisions and prevent them from recurring, but that's complicated and I'm still learning the basics. I guess what I'm wondering is whether I should mark this as a bug or if it's supposed to be a feature.
« Last Edit: November 17, 2011, 11:44:19 am by Alan Bolte »
Anything worth doing is worth analyzing to death -Iranon

 

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Re: Increasingly less simple repair gun
On a hunch, I decided to try a small change to lua.cpp, like so:
Code: [Select]
ADE_VIRTVAR(LifeLeft, l_Weapon, "number", "Weapon life left (in seconds)", "number", "Life left (seconds) or 0 if weapon handle is invalid")
{
object_h *oh=NULL;
float nll = -100.0f;
if(!ade_get_args(L, "o|f", l_Weapon.GetPtr(&oh), &nll))
return ade_set_error(L, "f", 0.0f);

if(!oh->IsValid())
return ade_set_error(L, "f", 0.0f);

weapon *wp = &Weapons[oh->objp->instance];

if(ADE_SETTING_VAR && nll > -100.0f) {
wp->lifeleft = nll;
}

return ade_set_args(L, "f", wp->lifeleft);
}
This had the effect I'd hoped for: I can now set weapon lifetime to a negative value, and the weapon will die instead of continuing on forever. It did not, however, fix the multiple collision bug, so it's quite pointless.

The funny thing is that I've tried as hard as I can to replicate the bug for weapons that haven't had their collision code overridden, and as far as I can tell the bug does not occur. I'm just going to have to read through the collision code some more to find out what it's doing to prevent repeats...

I think I misread the problem to begin with. If I set the lifetime to 0 during the collision process, then weapon_process_post() should decrease the lifetime by frametime, see that the lifetime is less than 0, and flag the weapon OF_SHOULD_BE_DEAD. That means that I was wrong about collisions happening in consecutive frames - they must somehow be happening in the same frame.
Anything worth doing is worth analyzing to death -Iranon

 

Offline Wanderer

  • Wiki Warrior
  • 211
  • Mostly harmless
Re: Increasingly less simple repair gun
Key issue regarding beams is that beams are not weapons per se in the game engine. They (beam objects) are whole different beasts compared to actual weapon objects.
Do not meddle in the affairs of coders for they are soggy and hard to light

 

Offline Alan Bolte

  • 28
  • Deneb III
    • @Compellor
Re: Increasingly less simple repair gun
I haven't worked on this for a while, but I intend to release a completed version eventually with a test mission. For now, I thought I'd better put the whole script up as it is presently. This version is dependent upon the mediaVPs, a custom texture for the weapon particle, and an addition to the weapon table.

Code: [Select]
#Conditional Hooks

$Application: FS2_Open
$On Game Init:
[
--impact explosion, check the MediaVP wep.tbm files for which one you want and what radius to use
local texturename = "Akheton_Impact"
imageRadius = 1.8

repairImpactImage = gr.loadTexture(texturename, true)

--Render particle instead of laser
local texturename = "naniteparticle2"
laserRadius = 0.5

repairLaserImage = gr.loadTexture(texturename, true)
]

$State: GS_STATE_GAME_PLAY
$Weapon class: Nanite Repair ;;Weapon class is the same name as is displayed on the HUD
$On Ship Collision:
[
local repairValue = 350 --use lower values for weapons with a high rate of fire and vice versa.

hv.Ship.HitpointsLeft = hv.Ship.HitpointsLeft+repairValue

if (hv.Ship.HitpointsLeft > hv.Ship.HitpointsMax) then
hv.Ship.HitpointsLeft = hv.Ship.HitpointsMax
end

local createPos = hv.Self.LastPosition  --can be replaced with proper collision detection if you're picky
local velocity = ba.createVector(0,0,0)

ts.createParticle(createPos, velocity, 1, imageRadius, PARTICLE_BITMAP, -1, false, repairImpactImage)

hv.Self.LifeLeft = 0 -- weapon not flagged for death until all collisions this frame have been checked
hv.Self.Physics.Velocity = hv.Ship.Physics.Velocity --hack to prevent multiple collisions
]
+Override: true

$State: GS_STATE_GAME_PLAY
$Weapon class: Nanite Repair ;;Weapon class is the same name as is displayed on the HUD
$On Object Render:
[
local createPos = hv.Self.Position
local velocity = hv.Self.Physics.Velocity
local time = 0.016667

if lastTime then
if ((time + lastTime) < mn.getMissionTime()) then
ts.createParticle(createPos, velocity, time, laserRadius, PARTICLE_BITMAP, -1, false, repairLaserImage)
local lastTime = mn.getMissionTime()
end
else
ts.createParticle(createPos, velocity, time, laserRadius, PARTICLE_BITMAP, -1, false, repairLaserImage)
local lastTime = mn.getMissionTime()
end
]

$State: GS_STATE_GAME_PLAY
$Weapon class: Nanite Repair ;;Weapon class is the same name as is displayed on the HUD
$On Weapon Fired:
[
if hv.User == hv.Player then
local soundPos = hv.User.Position
local time = 0.6

if lastTimeSound then
if ((time + lastTimeSound) < mn.getMissionTime()) then
soundHandle = ad.playGameSound(192)
end
else soundHandle = ad.playGameSound(192)
end

lastTimeSound = mn.getMissionTime()
end
]
#End
Anything worth doing is worth analyzing to death -Iranon